基本介绍

  • 游戏内容要求
  1. 游戏有 n 个 round,每个 round 都包括10 次 trial;
  2. 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
  3. 每个 trial 的飞碟有随机性,总体难度随 round 上升;
  4. 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
  • 游戏的要求

    • 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
    • 近可能使用前面 MVC 结构实现人机交互与游戏模型分离

游戏效果

游戏设置round = 3,难度依次增加,每个 round 都包括10 次 trial。
飞碟分三等,蓝、绿、红,速度依次增加,射入角度等随机。

开始效果

运行中(建议选择Maximize On Play)

游戏结束

设计UML

这一次的设计完全是按照老师给的UML来做的,所以就不单独画啦~

部分代码解释

这次的作业是大部分沿用了之前作业的代码,重复代码略

  • SSDirector.cs
  • Singleton

场景单实例类,当所需的实例第一次被需要时,在场景内搜索该实例,下一次使用时不需要搜索直接返回。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;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;}}
}
  • Disk

Disk中数据为飞碟类型type,分数score,颜色color

public class Disk : MonoBehaviour {public int type = 1;public int score = 1;                               public Color color = Color.white;
}
  • DiskFactory

老师给的伪代码

getDisk(ruler)
BEGINIF (free list has disk) THENa_disk = remove one from listELSEa_disk = clone from PrefabsENDIFSet DiskData of a_disk with the rulerAdd a_disk to used listReturn a_disk
END
FreeDisk(disk)
BEGINFind disk in used listIF (not found) THEN THROW exceptionMove disk from used to free list
END

维护两个列表,一个是正在使用的飞碟,一个是空闲飞碟。当场景控制器需要获取一个飞碟时,先在空闲列表中寻找可用的空闲飞碟,如果找不到就根据预制重新实例化一个飞碟。回收飞碟的逻辑为遍历使用列表,当有飞碟已经完成了所有动作,即位置在摄像机之下,则回收。

public class DiskFactory : MonoBehaviour {private List<Disk> used = new List<Disk>();private List<Disk> free = new List<Disk>();public GameObject GetDisk(int type) {GameObject disk_prefab = null;//寻找空闲飞碟,如果无空闲飞碟则重新实例化飞碟if (free.Count>0) {for(int i = 0; i < free.Count; i++) {if (free[i].type == type) {disk_prefab = free[i].gameObject;free.Remove(free[i]);break;}}     }if(disk_prefab == null) {if(type == 1) {disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk1"),new Vector3(0, -10f, 0), Quaternion.identity);}else if (type == 2) {disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk2"),new Vector3(0, -10f, 0), Quaternion.identity);}else {disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk3"),new Vector3(0, -10f, 0), Quaternion.identity);}disk_prefab.GetComponent<Renderer>().material.color = disk_prefab.GetComponent<Disk>().color;}used.Add(disk_prefab.GetComponent<Disk>());disk_prefab.SetActive(true);return disk_prefab;}public void FreeDisk() {for(int i=0; i<used.Count; i++) {if (used[i].gameObject.transform.position.y <= -10f) {free.Add(used[i]);used.Remove(used[i]);}}          }public void Reset() {FreeDisk();}
}
  • SSAction
  • SSActionManager
  • SequenceAction
  • DiskFlyAction

通过位置变换和角度变换模拟飞碟的飞行,也可以使用刚体组件(Rigidbody)实现。当飞碟的高度在摄像机观察范围之下时则动作停止。

public class DiskFlyAction : SSAction {public float gravity = -5;                                 //向下的加速度private Vector3 start_vector;                              //初速度向量private Vector3 gravity_vector = Vector3.zero;             //加速度的向量,初始时为0private Vector3 current_angle = Vector3.zero;              //当前时间的欧拉角private float time;                                        //已经过去的时间private DiskFlyAction() { }public static DiskFlyAction GetSSAction(int lor, float angle, float power) {//初始化物体将要运动的初速度向量DiskFlyAction action = CreateInstance<DiskFlyAction>();if (lor == -1) {action.start_vector = Quaternion.Euler(new Vector3(0, 0, -angle)) * Vector3.left * power;}else {action.start_vector = Quaternion.Euler(new Vector3(0, 0, angle)) * Vector3.right * power;}return action;}public override void Update() {//计算物体的向下的速度,v=attime += Time.fixedDeltaTime;gravity_vector.y = gravity * time;//位移模拟transform.position += (start_vector + gravity_vector) * Time.fixedDeltaTime;current_angle.z = Mathf.Atan((start_vector.y + gravity_vector.y) / start_vector.x) * Mathf.Rad2Deg;transform.eulerAngles = current_angle;//如果物体y坐标小于-10,动作就做完了if (this.transform.position.y < -10) {this.destroy = true;this.callback.SSActionEvent(this);      }}public override void Start() { }
}
  • FlyActionManager

飞碟的动作管理类,当场景控制器需要发射飞碟时就调用DiskFly使飞碟飞行。

public class FlyActionManager : SSActionManager {public DiskFlyAction fly;  public FirstController scene_controller;           protected void Start() {scene_controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;scene_controller.action_manager = this;     }//飞碟飞行public void DiskFly(GameObject disk, float angle, float power) {int lor = 1;if (disk.transform.position.x > 0) lor = -1;fly = DiskFlyAction.GetSSAction(lor, angle, power);this.RunAction(disk, fly, this);}
}
  • ScoreRecorder

记分器类的逻辑比较简单。初始状态分数变量score为0,此后每次击中飞碟则累加上此飞碟对应的分数,重新开始游戏则重置score为0。

/*记录分数*/
public class ScoreRecorder : MonoBehaviour {private float score;void Start () {score = 0;}public void Record(GameObject disk) {score += disk.GetComponent<Disk>().score;}public float GetScore() {return score;}public void Reset() {score = 0;}
}
  • UserGUI

将分数,Round,Trial显示出来,有按钮控制游戏开始和重新开始即可。比较重要的一点时使用Input.GetButtonDown(“Fire1”)检测鼠标左键的点击。

  • FirstController

最重要的部分是场景控制器,游戏开始之后,设置一个定时器,每隔一定时间从飞碟工厂中获取一个飞碟并发射,检测用户点击发送的射线是否与飞碟发生碰撞,有则通知记分员加分并且通知工厂回收飞碟。

部分重要函数代码如下:

  1. Update函数每一帧检测鼠标点击,并根据round调整规则。
 void Update () {if(running) {count++;if (Input.GetButtonDown("Fire1")) {Vector3 pos = Input.mousePosition;Hit(pos);}switch (round) {case 1: {if (count >= 150) {count = 0;SendDisk(1);trial += 1;if (trial == 10) {round += 1;trial = 0;}}break;}case 2: {if (count >= 100) {count = 0;if (trial % 2 == 0) SendDisk(1);else SendDisk(2);trial += 1;if (trial == 10) {round += 1;trial = 0;}}break;}case 3: {if (count >= 50) {count = 0;if (trial % 3 == 0) SendDisk(1);else if(trial % 3 == 1) SendDisk(2);else SendDisk(3);trial += 1;if (trial == 10) {running = false;}}break;}default:break;} disk_factory.FreeDisk();}}
  1. SendDisk 从工厂中拿飞碟并根据种类设置发射参数,然后调用动作管理器执行动作。
   private void SendDisk(int type) {//从工厂中拿一个飞碟GameObject disk = disk_factory.GetDisk(type);//飞碟位置float ran_y = 0;float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;//飞碟初始所受的力和角度float power = 0;float angle = 0;if (type == 1) {ran_y = Random.Range(1f, 5f);power = Random.Range(5f, 7f);angle = Random.Range(25f,30f);}else if (type == 2) {ran_y = Random.Range(2f, 3f);power = Random.Range(10f, 12f);angle = Random.Range(15f, 17f);}else {ran_y = Random.Range(5f, 6f);power = Random.Range(15f, 20f);angle = Random.Range(10f, 12f);}disk.transform.position = new Vector3(ran_x*16f, ran_y, 0);action_manager.DiskFly(disk, angle, power);}
  1. Hit函数检测射线与飞碟是否碰撞,如碰撞则计分并回收飞碟。
    public void Hit(Vector3 pos) {Ray ray = Camera.main.ScreenPointToRay(pos);RaycastHit[] hits;hits = Physics.RaycastAll(ray);for (int i = 0; i < hits.Length; i++) {RaycastHit hit = hits[i];if (hit.collider.gameObject.GetComponent<Disk>() != null) {score_recorder.Record(hit.collider.gameObject);hit.collider.gameObject.transform.position = new Vector3(0, -10, 0);}}}

后记

这一次主要使用了工厂模式,复用已经实例化的对象节约资源,鼠标点击事件的检测以及射线与游戏对象的碰撞。

之后可以改进一下飞碟原型以及被击中之后的效果。

代码

【Unity3D】简单的鼠标打飞碟(Hit UFO)游戏相关推荐

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

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

  2. Unity实现简易打飞碟(Hit UFO)

    Unity实现简易打飞碟(Hit UFO) 前言 这是中山大学数据科学与计算机学院2019年3D游戏编程与设计的第四次作业 所有项目与代码已上传至github当中,欢迎大家访问. github个人主页 ...

  3. 3D游戏编程与设计作业6-Unity实现打飞碟游戏改进版(Hit UFO)

    改进飞碟(Hit UFO)游戏 游戏内容要求 按adapter模式设计图修改飞碟游戏 使它同时支持物理运动与运动学(交换)运动 编程实践 本次作业直接在上一次打飞碟游戏的基础上增加adapter设计模 ...

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

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

  5. Unity3D -- Hit UFO

    目录 一.游戏内容 二.UML图 三.游戏的实现 1. DiskFactory 2. SSAction 3. SSActionManager 4. ISceneController 5. UserGU ...

  6. unity实现鼠标打飞碟(Hit UFO)游戏

    unity实现鼠标打飞碟(Hit UFO)游戏 游戏规则及要求 规则:玩家初始有5条生命,每漏过一个飞碟,生命减一.游戏分数的增加与命中飞碟时的位置有关,越早击中飞碟分数越高.游戏有四档难度,随分数递 ...

  7. Unity实现鼠标打飞碟(Hit UFO)adapter模式

    Unity实现鼠标打飞碟(Hit UFO)adapter模式 与上一版本的变化 按 adapter模式设计图修改飞碟游戏 使它同时支持物理运动与运动学(变换)运动 适配器模式 适配器模式(Adapte ...

  8. Unity实现简易打飞碟改进版(Hit UFO)

    Unity实现简易打飞碟改进版(Hit UFO) 前言 这是中山大学数据科学与计算机学院2019年3D游戏编程与设计的第六次作业 所有项目与代码已上传至github当中,欢迎大家访问. github个 ...

  9. 改进飞碟(Hit UFO)游戏

    1.改进飞碟(Hit UFO)游戏: 游戏内容要求: 按 adapter模式 设计图修改飞碟游戏 使它同时支持物理运动与运动学(变换)运动 新增的类或者有修改的类如下: ActionManagerAd ...

  10. 3D游戏设计作业5:改进飞碟(Hit UFO)游戏

    改进飞碟(Hit UFO)游戏: 游戏截图: 1,作业要求 游戏内容要求: 1,按adapter模式设计图修改飞碟游戏 2,使它同时支持物理运动与运动学(变换)运动 2,设计思路 1,分析adapte ...

最新文章

  1. 【go】sdk + idea-plugin 开发工具安装
  2. 使用SqlBulkCopy数据导入和复制
  3. python上传excel文件_flask上传excel文件,无须存储,直接读取内容
  4. 静态路由实验配置举例
  5. 服务器任务栏不显示程序,Win10任务栏不显示应用程序标签怎么办?
  6. python核心编程豆瓣_python核心编程一书笔记之第一篇
  7. 深入理解的JavaScript函数编程
  8. java中 t无法对齐,java – 即使X应匹配T,也无法将X转换为T?
  9. linux 源代码安装mysql5.5_linux下通过源码包安装MySql5.5
  10. 现代电视原理期末复习
  11. 【文献阅读】CCNet: Criss-Cross Attention for Semantic Segmentation
  12. sphinxapi.php 详解,【转】Sphinx PHP api全文检索的例子
  13. 一个并肩战斗的同事将离开团队,去家乡追寻梦想
  14. Photoshop CS5 轻松匹配图像颜色
  15. html2canvas黑背景,解决canvas转base64/jpeg时透明区域变成黑色背景的方法
  16. P3435 [POI2006]OKR-Periods of Words [Kmp, next数组]
  17. ChinaSoft 论坛巡礼 | 服务生态系统的构建、运维与演化
  18. hyperledger fabric 2.3.3 环境搭建教程
  19. attributeerror: module 'numpy.random' has no attribute 'randon'
  20. LDF转Excel;LDF转位定义;Excel转LDF;Excel转位定义;MatrixCreat(一)之LIN矩阵详解

热门文章

  1. 中兴 ZXV10 B860AV2.1-A 中国移动盒子 开adb和wifi(海南盒子);适用于大部分(除两款外)不打开adb 进行安装软件或抓取日志
  2. 计算电磁学基础知识及数值方法汇总
  3. 接口测试用例设计 - 实战篇
  4. 市场项目交接文档初稿
  5. 中国移动加快自主创新推动我国主导4G标准引领国际
  6. 【ICnet2018】ICNet for Real-Time Semantic Segmentation on High-Resolution Images
  7. word如何快速找到自己需要的符号/特殊符号?(干货满满)
  8. 离散数学及其应用 前言
  9. C++多线程函数_beginthread/_beginthreadex/CreateThread
  10. 杭电ACM2000题