鼠标打飞碟游戏

作业要求

1、编写一个简单的鼠标打飞碟(Hit UFO)游戏

  • 游戏内容要求:

    1. 游戏有 n 个 round,每个 round 都包括10 次 trial;
    2. 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
    3. 每个 trial 的飞碟有随机性,总体难度随 round 上升;
    4. 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
  • 游戏的要求:
    • 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
    • 近可能使用前面 MVC 结构实现人机交互与游戏模型分离

2、改进飞碟(Hit UFO)游戏:

  • 游戏内容要求:

    1. adapter模式 设计图修改飞碟游戏
    2. 使它同时支持物理运动与运动学(变换)运动

项目文档

游戏说明

  • 这是一个用Unity3D实现的HitUFO游戏,玩家通过鼠标点击飞出的飞碟来获取分数。

  • 游戏规则:

    • 中间的红色飞碟回发射出若干小飞碟,玩家通过鼠标点击,击中飞碟则获得对应的分数。

    • 一局游戏有5个回合,每个回合的难度不同,每个回合有10波,一波会发射出若干个飞碟,飞碟按照不同的方向和速度从红色的母飞碟中飞出。

    • 一共有五种飞碟,它们通过颜色区分,不同的飞碟的分数、速度范围和方向范围都不一样

    • 以下是回合的设置和飞碟的设置:

      回合 1 2 3 4 5
      Trial的数量 10 10 10 10 10
      Trial的时间间隔(秒) 1.8 1.6 1.4 1.2 1.0
      飞碟的等级范围 1-5 1-5 1-5 1-5 1-5
      一个Trial的飞碟个数 5 7 10 14 19
      • 在回合的设定中:一轮飞碟数目固定,但飞碟的等级是随机的,则将了游戏的不确定性。
      飞碟等级 1 2 3 4 5
      颜色 黄色 绿色 青色 蓝色 黑色
      重量(千克) 0.6-1.4 1.2-2.8 1.4-4.6 1.6-6.4 1-9
      分值 50 100 500 1000 5000
      速度方向 -0.1~0.1 -2~2 -5~5 -10~10 -20~20
      力的方向 -1~1 -2~2 -5~5 -10~10 -20~20
      • 在飞碟的设定中:速度的方向的范围大小对应于发射范围的大小,越小范围越集中,越容易点击,力的方向和大小对发射后的轨迹有影响,值越大说明越难击中
    • 计分遵循五轮叠加,显然黑色的飞碟更值得点击。

游戏效果


项目配置过程

  1. 新建一个3D项目
  2. 下载 Assets 文件夹,替换项目的空 Assets 文件夹
  3. 进入 Scenes 文件夹中双击 HitUFO 场景

实现思路 & 模块介绍

  • 文件布局:

    • /Assets

      • /Resources

        • /Icon // 游戏图标
        • /Material // 颜色材料
        • /Prefabs // 五种不同颜色的飞碟预制
        • /SkyBox // 天空盒
      • /Scenes // 游戏场景
      • /Scripts
        • /Controller

          • /Action // 动作模块

            • CCActionManager.cs // 平移运动管理器
            • CCFlyAction.cs // 平移运动实现
            • IActionManager.cs // 动作管理器接口
            • ISSActionCallback.cs // 回调接口
            • PhysisActionManager.cs // 物理运动管理器
            • PhysisFlyAction.cs // 物理运动实现
            • SSAction.cs // 抽象动作
            • SSActionManager.cs // 动作管理器模板
          • /Round // 回合模块
            • RoundController.cs
          • /Score // 计分模块
            • ScoreRecorder.cs
          • FirstController.cs
          • ISceneController.cs
          • Singleton.cs
          • SSDirector.cs
        • /Model
          • /Disk //飞碟模型

            • DiskData.cs // 飞碟基本数据
            • DiskFactory.cs // 工厂模式产生飞碟
        • /View //交互模型
          • IUserAction.cs
          • UserGUI.cs
  • 在这个项目的组织上,和前两个作业基本一致,有很多代码都可以直接复用,如导演类、各种接口以及运动管理器模板等等。

  • UML类图:

以下是整个项目关键模块的说明:

  • 单实例模板

    通过设计这样的一个模板类,可以让所有继承了MonoBehaviour的类可以简单使用单例模式,在获取单例模式对象时,只需Singleton<ClassName>.Instance,例如获取单例飞碟工厂对象:

    diskFactory = Singleton<DiskFactory>.Instance;
    

    单例模式的代码:

    // @file: Assets/Controller/Singleton.cs
    public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    {protected static T instance;public static T Instance {  get {  if (instance == null) { instance = (T)FindObjectOfType (typeof(T));  if (instance == null) {  Debug.LogError ("An instance of " + typeof(T) + " is needed in the scene, but there is none.");  }  }  return instance;  }  }
    }
    
  • 飞碟数据模板:一个飞碟有级别、质量、颜色、分数、速度和外力这些属性,我们提供使用ScriptableObject文件定制属性配置的功能,这样就能直接从 Asset 中将配置好的数据拖入。

    // @file: Assets/Model/DiskData.cs
    [System.Serializable]
    public class DiskData : MonoBehaviour
    {[Tooltip("飞碟级别")]public int level;[Tooltip("飞碟质量")]public float mass;[Tooltip("飞碟颜色")]public Color color;[Tooltip("击中分数")]public int score;[Tooltip("初始速度")]public Vector3 speed;[Tooltip("恒定外力")]public Vector3 force;
    }[CreateAssetMenu(fileName = "DiskItem", menuName = "(ScriptableObject)DiskItem")]
    public class DiskItem : ScriptableObject
    {public string Name;[Tooltip("飞碟属性")]public DiskData diskData;
    }
    
  • 道具工厂和对象池

    • 在游戏中我们会频繁需要多个Disk对象,频繁地系统生成和销毁对象会对游戏造成不必要的负担,因此我们引入对象池。

    • 顾名思义,对象池是一个存放了多个对象的池子,它维护两个队列,一个包含空闲的对象,另一个包含正在工作的对象。当我们需要生成一个游戏对象时,我们首先考虑空闲队列是否有空闲对象给我们直接使用,如果没有空闲对象在考虑系统生成新的游戏对象。

    • 在程序运行的过程中我们动态维护对象池,一个对象完成其工作时将其加入到空闲对象池中,一个对象正在忙碌则将其放进忙碌队列中。

    • 在代码中,我们通过维护两个DiskData的链表来维护创建的所有飞碟对象,通过GetDisk来从对象池中获取对象,通过FreeDisk()来返还游戏对象。具体的代码分析我们在下一节中给出。

  • 飞碟运动模块:通过GetComponent()为游戏对象添加这些属性:

    // @file: Assets/Controller/Action/PhysisFlyActon.cs
    // @line: 24-27
    this.gameObject.GetComponent<Rigidbody>().isKinematic = false;
    this.gameObject.GetComponent<Rigidbody>().velocity = speed;
    this.gameObject.GetComponent<ConstantForce>().force = force;
    this.gameObject.GetComponent<ConstantForce>().torque = new Vector3(0.2F, 0, -0.2F);
    

    飞碟默认受重力影响,我们设置了初速度的方向、力的方向和力矩的方向,前二者给游戏对象提供初速度和加速度,而力矩能够让飞碟产生一个轻轻摆动的效果,让飞碟飞出后能有姿态的变化。

    而对于实现动作分离的其他部分,和上一次作业的内容基本一致,在此不再赘述。

  • 回合控制器 RoundController 的设计

    • 五个属性分别表示

      // @file: Assets/Controller/Round/RoundController.cs
      // @line: 12-17
      float time; // 计时,当time满足一个trial的时间间隔时清零
      int round;  // 当前的回合数
      int trial;  // 当前轮数
      int diskNum;// 当前回合一轮飞出的飞碟数目
      bool start; // 回合开始的标记
      
    • Start()函数:初始化,为属性赋值并获取单例对象

    • SetMode(bool isPhysis)函数:选择是否使用物理学运动模型,根据结果分选不同的运动管理器CCActionManager or PhysisActionManager

      // @file: Assets/Controller/Round/RoundController.cs
      // @line: 34-39
      if(isPhysis){actionManager = Singleton<PhysisActionManager>.Instance as IActionManager;
      }
      else{actionManager = Singleton<CCActionManager>.Instance as IActionManager;
      }
      
    • GenerateDisk(int level):通过飞碟工厂产生飞碟对象,并为他赋予动作

      // @file: Assets/Controller/Round/RoundController.cs
      // @line: 43-46
      GameObject disk = diskFactory.GetDisk(level);
      disk.transform.position = new Vector3(0, 0, 0); // 飞碟的发射点
      disk.SetActive(true);
      actionManager.Fly(disk);
      
    • Update()函数:时间敏感,相隔指定时间(Trial)发射一波飞碟,处理Round、Trial次数的切换

      if(start){time += Time.deltaTime;if(round > 5){ // 一共5轮start = false;return;}if(trial == 10){ // 每轮10波// NEXT ROUNDtrial = 0;round++;diskNum += round;}if(time >= 2.0F - round * 0.2F){ // 每波生成 diskNum 个飞碟// NEXT TRIALtime = 0.0F;for(int i = 0; i < diskNum; i++){GenerateDisk(Random.Range(1,6));}            trial++;}
      }
      

核心算法

  1. 游戏对象的回收算法

    • 因为在飞碟的设定中,不同的飞碟有着不同的颜色,对此我们创建了五个颜色不同的飞碟预制。

    • 这使得,在创建一个飞碟时,它已经被制定了对应的预制(即飞碟颜色不能更改)

    • 导致我们在对象池的会后利用时,一个蓝色飞碟只能使用对象池中空闲的蓝色飞碟,而不能使用其他颜色的飞碟。(也即只能重用同等级的飞碟)

    • 因此有GetDisk()的代码如下:

      // @file: Assets/Model/Disk/DiskFactory.cs
      // @line: 22-47
      GameObject disk = null;// 在空闲队列中寻找级别相同的对象,如果有则直接使用
      bool find = false;
      for(int i = 0; i < freeDisks.Count; i++){if(freeDisks[i].level == level){disk = freeDisks[i].gameObject;freeDisks.RemoveAt(i);find = true;break;}
      }//如果找不到级别相同的飞碟对象,需要调用 Instantiate 新建一个
      if(find == false){disk = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>(Prefabs[level - 1]), Vector3.zero, Quaternion.identity);disk.AddComponent<DiskData>();disk.AddComponent<Rigidbody>();disk.AddComponent<ConstantForce>();
      }//最后更新飞碟的速度、力的数据,让飞碟轨迹每次不同
      if(disk != null){DiskData diskData = disk.GetComponent<DiskData>();setDiskData(diskData, level);busyDisks.Add(diskData);
      }return disk;
      
  2. 不同等级的飞碟生成算法:粗暴的数学拼凑来获得游戏说明那一节飞碟属性表的效果,通过Random每次生成不同的轨迹。

    // @file: Assets/Model/Disk/DiskFactory.cs
    // @line: 62-98
    if(level <= 1){diskData.level = 1;diskData.mass = 1.0F + Random.Range(-1F, 1F) * 0.4F;diskData.score = 50;diskData.speed = new Vector3(Random.Range(-0.1F, 0.1F), Random.Range(-0.1F, 0.1F), Random.Range(-0.1F, 0.1F));diskData.force = new Vector3(Random.Range(-1F, 1F), Random.Range(-1F, 1F), Random.Range(-1F, 1F));
    }
    else if(level == 2){diskData.level = 2;diskData.mass = 2.0F + Random.Range(-1F, 1F) * 0.8F;diskData.score = 100;diskData.speed = new Vector3(Random.Range(-2F, 2F), Random.Range(-2F, 2F), Random.Range(-2F, 2F));diskData.force = new Vector3(Random.Range(-2F, 2F), Random.Range(-2F, 2F), Random.Range(-2F, 2F));
    }
    else if(level == 3){diskData.level = 3;diskData.mass = 3.0F + Random.Range(-1F, 1F) * 1.6F;diskData.score = 500;diskData.speed = new Vector3(Random.Range(-5F, 5F), Random.Range(-5F, 5F), Random.Range(-5F, 5F));diskData.force = new Vector3(Random.Range(-5F, 5F), Random.Range(-5F, 5F), Random.Range(-5F, 5F));}
    else if(level == 4){diskData.level = 4;diskData.mass = 4.0F + Random.Range(-1F, 1F) * 2.4F;diskData.score = 1000;diskData.speed = new Vector3(Random.Range(-10F, 10F), Random.Range(-10F, 10F), Random.Range(-10F, 10F));diskData.force = new Vector3(Random.Range(-10F, 10F), Random.Range(-10F, 10F), Random.Range(-10F, 10F));}
    else if(level >= 5){diskData.level = 5;diskData.mass = 5.0F + Random.Range(-1F, 1F) * 4.0F;diskData.score = 5000;diskData.speed = new Vector3(Random.Range(-20F, 20F), Random.Range(-20F, 20F), Random.Range(-20F, 20F));diskData.force = new Vector3(Random.Range(-20F, 20F), Random.Range(-20F, 20F), Random.Range(-20F, 20F));
    }
    

基于Unity3D实现的HitUFO鼠标打飞碟游戏相关推荐

  1. unity3d开发鼠标打飞碟游戏(Hit UFO)

    这次我们用Unity3d开发一个简单的打飞碟游戏 游戏简介 游戏有3个回合,每个回合会发射n中颜色的飞碟,击中飞碟会得到相应的分数,其中,击中黄色飞碟得1分,击中蓝色飞碟得2分,红色飞碟4分,击不中不 ...

  2. 基于Unity3D开发的智能巡逻兵小游戏

    智能巡逻兵小游戏 作业要求 游戏设计要求:智能巡逻兵 创建一个地图和若干巡逻兵(使用动画): 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址.即每次确定下一个目标位置,用自己当前位置为原点计 ...

  3. Unity3D游戏编程-鼠标打飞碟

    Unity3D游戏编程-鼠标打飞碟 文章目录 Unity3D游戏编程-鼠标打飞碟 一.作业要求 二.项目配置 三.项目演示 视频演示 项目下载 文字说明 项目截图 四.前置内容 MVC模式 动作管理器 ...

  4. Unity3d Note5(鼠标打飞碟(Hit UFO)游戏)

    1.作业要求 2.具体设计 (1).制备预制体作为飞碟 (2).了解一下Singleton模板类 (3).了解一下工厂模式 (3).设计具体要实现的类 3.程序代码 成果视频 1.作业要求 编写一个简 ...

  5. 【Unity3d学习】使用物理引擎——打飞碟游戏的物理引擎改进与射箭游戏设计

    文章目录 写在前面 HitUFO的物理引擎改进版本 物理引擎的改进版本思路与实现 PhysicsAction PhysicsManager 新接口类IActionManager 动作管理器基类的变化 ...

  6. 基于Unity3d的虚拟装配中的机械运动仿真

    基于Unity3d的虚拟装配中的机械运动仿真 前言 1.创建缸体相关的物体和对象 2.鼠标随意拖动和旋转物体的脚本 3.利用标记点进行虚拟装配 4.缸体的旋转 前言 在研究基于unity3d的虚拟装配 ...

  7. unity3d 模拟电脑实现_基于Unity3D三维电脑组装实验系统的实现

    0 基于 Unity3D 三维电脑组装实验系统的实现 [摘要] 实验教学不仅能够培养学生的动手能力,而且还能起到巩固课本上理论知识 的作用.但是由于我们国家人口基数庞大,教育资源有限,实验器材紧缺, ...

  8. unity3d 模拟电脑实现_毕业论文 基于Unity3D的三维虚拟电脑组装实验系统开发

    第 0 页 基于 Unity3D 三维电脑组装实验系统的实现 [摘要] 实验教学不仅能够培养学生的动手能力,而且还能起到巩固课本上理论知识 的作用.但是由于我们国家人口基数庞大,教育资源有限,实验器材 ...

  9. 基于Unity3D技术的纸牌消除游戏

    基于Unity3D技术的纸牌消除游戏 1 项目的创建和资源的导入 在Project下创建好需要的四个文件夹,其中Resources文件夹是用来存放A-K和大小王正面纸牌资源,Textture文件夹用来 ...

  10. 基于Unity3D的AR小游戏开发【100011412】

    本科毕业设计(论文) GRADUATION DESIGN(THESIS) 基于 Unity3D 的增强现实游戏程序 摘要 增强现实(AR)作为一项新兴技术近年来被越来越多的人群所获知,AR 也渐渐走进 ...

最新文章

  1. 4.9.3 方法注释
  2. tenserflow.js 环境搭建
  3. 2018“硅谷技划”随笔(一):再论中美员工福利巨大差距的背后
  4. 无锁HashMap的原理与实现
  5. 从零实现一个自定义 HTML5 播放器
  6. hadoop 提交程序并监控运行
  7. 单片机c语言应用100例第3版课后答案,单片机C语言应用100例(第3版)(含光盘1张)...
  8. python中的get函数_python之函数用法get()
  9. 10分钟带你了解python_ComeOn!10分钟带你了解Python的变量和数据类型
  10. Intel Sandy Bridge/Ivy Bridge架构/微架构/流水线 (12) - 执行核
  11. STM32 FSMC/FMC原理保姆级讲解(一)
  12. TKDE2022 | 最新深度学习推荐系统综述:从协同过滤到信息增强的推荐系统
  13. 如何用sklearn创建机器学习分类器?这里有一份上手指南
  14. html5表单新增验证属性,HTML5表单增强属性
  15. 软件基本功能测试用例,测试用例实例—常见功能测试点().docx
  16. 修改注册表解决每次打开office2010都会出现正在配置的问题
  17. Android学习笔记之MeasureSpec
  18. android控制动态按钮,Android编程动态按钮实现方法
  19. tp5框架中调用支付宝线上资金预授权alipay.fund.auth.order.app.freeze接口
  20. 我喜欢邓丽君,死掉了;

热门文章

  1. Markdown表格——复杂表格
  2. matlab 拉普拉斯求解,matlab解拉普拉斯方程.ppt
  3. VC dimension(Vapnik-Chervonenkis dimension)
  4. 盛世zeepower远程距离隔空无线充投放商用 低频磁共振无线充电技术——充电有效距离 20-45mm
  5. Vue删除表格数据-调用逻辑
  6. 解密Google Deepmind AlphaGo围棋算法
  7. Android计分器课程设计,课程设计题八:篮球比赛计分器
  8. 日立hgp电梯mcub03主板原理图
  9. VC编程中,判断野指针
  10. 高等数学中的求极限公式