unity 实现简易打飞碟游戏

一、简介

游戏共有5个回合,每个回合中会有随机产生的飞碟飞过屏幕,玩家需要做的事情就是用鼠标尽量快和多地点击飞碟。
每个飞碟对应一定的分数,目前的设置是:
【红色飞碟 3分】、【绿色飞碟 2分】、【蓝色飞碟 1分】
游戏的目的是在规定回合内得到尽可能高的分数。

二、实现效果

三、代码框架

基本延用了上一个游戏中的框架,包括动作与动作管理器、场景控制器和用户GUI,更新的部分包括:

  • 动作由移动船只、移动角色变成了移动飞碟
  • 将主控制器的功能分散到几个控制器上,包括分数控制器、飞碟产生器
  • 增加了场景单实例的代码

四、具体实现

(一)Actions动作与动作管理器
1. SSAction 动作基类
public class SSAction : ScriptableObject
{public bool enable = true;public bool destroy = false;public GameObject gameObject { get; set;}public Transform transform {get; set;}public IActionCallback callback {get; set;}protected SSAction() {}// Start is called before the first frame updatepublic virtual void Start(){throw new System.NotImplementedException();}// Update is called once per framepublic virtual void Update(){throw new System.NotImplementedException();}
}
2. CCFlyAction 飞碟动作类

飞碟的运动有简单的两个属性:水平方向速度和垂直方向速度。
飞碟从飞碟工厂出来的时候被定位在相机视角边缘,随着运动进入相机视角,在被玩家点击或者飞出相机视角(即玩家不能再看到它时)时,飞碟和动作一起被销毁。

//飞碟从界面左右两侧飞入,离开界面时运动结束
public class CCFlyAction : SSAction
{public float speedX;public float speedY;public static CCFlyAction GetSSAction(float x, float y) {CCFlyAction action = ScriptableObject.CreateInstance<CCFlyAction>();action.speedX = x;action.speedY = y;return action;}// Start is called before the first frame updatepublic override void Start(){}// Update is called once per framepublic override void Update(){//Debug.Log("flyaction update");if (this.transform.gameObject.activeSelf == false) {//飞碟已经被"销毁"this.destroy = true;this.callback.SSActionEvent(this);return;}Vector3 vec3 = Camera.main.WorldToScreenPoint (this.transform.position);if (vec3.x < -100 || vec3.x > Camera.main.pixelWidth + 100 || vec3.y < -100 || vec3.y > Camera.main.pixelHeight + 100) {this.destroy = true;this.callback.SSActionEvent(this);return;}transform.position += new Vector3(speedX, speedY, 0) * Time.deltaTime * 2;}
}
3. IActionCallback 事件回调接口
public enum SSActionEventType:int {Started, Completed}
public interface IActionCallback
{//回调函数void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Completed,int intParam = 0,string strParam = null,Object objectParam = null);
}
4. SSActionManager 动作管理类基类

新增了一个函数RemainActionCount(),用于判断每回合中剩余的动作数量(即飞碟数量),只有这个值为0才进入下一回合。

public class SSActionManager : MonoBehaviour
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();private List<SSAction> waitingAdd = new List<SSAction>();private List<int> waitingDelete = new List<int>(); // Start is called before the first frame updateprotected void Start(){}// Update is called once per frameprotected void Update(){//Debug.Log("ssactionmanager update");foreach (SSAction ac in waitingAdd) {actions[ac.GetInstanceID()] = ac;}waitingAdd.Clear();//Debug.Log(actions.Count);foreach(KeyValuePair<int, SSAction> kv in actions) {SSAction ac = kv.Value;if (ac.destroy) {waitingDelete.Add(ac.GetInstanceID());} else if (ac.enable) {//Debug.Log("ssactionmanager update");ac.Update();}}foreach(int key in waitingDelete) {SSAction ac = actions[key];actions.Remove(key);Destroy(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameObject, SSAction action, IActionCallback manager) {//Debug.Log("run action");action.gameObject = gameObject;action.transform = gameObject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}public int RemainActionCount() {return actions.Count;}
}
5. CCActionManager 动作管理类

动作结束时会调用动作管理者实现的回调函数,即IActionCallback接口中的SSActionEventType,动作管理者将动作绑定的游戏对象(飞碟)销毁。

public class CCActionManager : SSActionManager, IActionCallback
{public RoundController sceneController;public CCFlyAction action;// Start is called before the first frame updateprotected new void Start(){sceneController = (RoundController)SSDirector.getInstance().currentSceneController;sceneController.actionManager = this;}// Update is called once per frame// protected new void Update()// {// }public void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Completed,int intParam = 0,string strParam = null,Object objectParam = null) {factory.FreeDisk(source.transform.gameObject);}public void MoveDisk(GameObject disk) {action = CCFlyAction.GetSSAction(disk.GetComponent<DiskAttributes>().speedX, disk.GetComponent<DiskAttributes>().speedY);RunAction(disk, action, this);}
}
(二)Controllers 控制器
1. DiskFactory 飞碟生成器

用于生产飞碟。

GetDisk(int round)被主控制器调用,round(回合数)会影响所生产的飞碟的速度、大小等属性。
有两个列表used和free,存放的是飞碟属性(包括分数、速度),可以循环使用,提高飞碟的产生效率。

飞碟初始位置随机,可能为屏幕的四个角落之一。
根据飞碟的分数和回合数设置飞碟的大小和速度。

public class MyException : System.Exception
{public MyException() { }public MyException(string message) : base(message) { }
}
public class DiskAttributes : MonoBehaviour
{//public GameObject gameobj;public int score;public float speedX;public float speedY;
}
public class DiskFactory : MonoBehaviour
{List<GameObject> used;List<GameObject> free;System.Random rand;// Start is called before the first frame updatevoid Start(){used = new List<GameObject>();free = new List<GameObject>();rand = new System.Random();//Disk disk = GetDisk(1); }public GameObject GetDisk(int round) {GameObject disk;if (free.Count != 0) {disk = free[0];free.Remove(disk);}else {disk = GameObject.Instantiate(Resources.Load("Prefabs/disk", typeof(GameObject))) as GameObject;disk.AddComponent<DiskAttributes>();}//根据不同round设置diskAttributes的值//随意的旋转角度disk.transform.localEulerAngles = new Vector3(-rand.Next(20,40),0,0);DiskAttributes attri = disk.GetComponent<DiskAttributes>();attri.score = rand.Next(1,4);//由分数来决定速度、颜色、大小attri.speedX = (rand.Next(1,5) + attri.score + round) * 0.2f;attri.speedY = (rand.Next(1,5) + attri.score + round) * 0.2f;if (attri.score == 3) {disk.GetComponent<Renderer>().material.color = Color.red;disk.transform.localScale += new Vector3(-0.5f,0,-0.5f);}else if (attri.score == 2) {disk.GetComponent<Renderer>().material.color = Color.green;disk.transform.localScale += new Vector3(-0.2f,0,-0.2f);}else if (attri.score == 1) {disk.GetComponent<Renderer>().material.color = Color.blue;}//飞碟可从四个方向飞入(左上、左下、右上、右下)int direction = rand.Next(1,5);if (direction == 1) {disk.transform.Translate(Camera.main.ScreenToWorldPoint(new Vector3(0, Camera.main.pixelHeight * 1.5f, 8)));attri.speedY *= -1;}else if (direction == 2) {disk.transform.Translate(Camera.main.ScreenToWorldPoint(new Vector3(0, Camera.main.pixelHeight * 0f, 8)));}else if (direction == 3) {disk.transform.Translate(Camera.main.ScreenToWorldPoint(new Vector3(Camera.main.pixelWidth, Camera.main.pixelHeight * 1.5f, 8)));attri.speedX *= -1;attri.speedY *= -1;}else if (direction == 4) {disk.transform.Translate(Camera.main.ScreenToWorldPoint(new Vector3(Camera.main.pixelWidth, Camera.main.pixelHeight * 0f, 8)));attri.speedX *= -1;}used.Add(disk);disk.SetActive(true);Debug.Log("generate disk");return disk;}public void FreeDisk(GameObject disk) {disk.SetActive(false);//将位置和大小恢复到预制,这点很重要!disk.transform.position = new Vector3(0, 0,0);disk.transform.localScale = new Vector3(2f,0.1f,2f);if (!used.Contains(disk)) {throw new MyException("Try to remove a item from a list which doesn't contain it.");}Debug.Log("free disk");used.Remove(disk);free.Add(disk);}
}
2. Singleton 单实例代码

用于单实例化飞碟工厂

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;  }  }
}

可以这样使用:

DiskFactory factory = Singleton<DiskFactory>.Instance;
3. ISceneController 场景控制器接口

其中包含的方法必须被主控制器实现。

public interface ISceneController
{void LoadSource();
}
4. SSDirector 导演类
public class SSDirector : System.Object
{private static SSDirector _instance;public ISceneController currentSceneController {get; set;}public static SSDirector getInstance() {if (_instance == null) {_instance = new SSDirector();}return _instance;}
}
5. ScoreController 计分器

初始化时将自身设置为主控制器的分数控制器。

public class ScoreController : MonoBehaviour
{int score;public RoundController roundController;public UserGUI userGUI;// Start is called before the first frame updatevoid Start(){roundController = (RoundController)SSDirector.getInstance().currentSceneController;roundController.scoreController = this;userGUI = this.gameObject.GetComponent<UserGUI>();}public void Record(GameObject disk) {score += disk.GetComponent<DiskAttributes>().score;userGUI.score = score;}}
6. RoundController 主控制器

连接用户与游戏,分别需要实现场景控制器的接口和用户操作的接口。
Update的主要工作:在每个回合中从工厂获取飞碟,为飞碟绑定动作,令其开始运动。

public class RoundController : MonoBehaviour, ISceneController, IUserAction
{int round = 0;int max_round = 5;float timer = 0.5f;GameObject disk;DiskFactory factory ;public CCActionManager actionManager;public ScoreController scoreController;public UserGUI userGUI;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){if (userGUI.mode == 0) return;GetHit();gameOver();if (round > max_round) {return;}timer -= Time.deltaTime;if (timer <= 0 && actionManager.RemainActionCount() == 0) {//从工厂中得到10个飞碟,为其加上动作for (int i = 0; i < 10; ++i) {disk = factory.GetDisk(round);actionManager.MoveDisk(disk);//Thread.Sleep(100);}round += 1;if (round <= max_round) {userGUI.round = round;}timer = 4.0f;}}void Awake() {SSDirector director = SSDirector.getInstance();director.currentSceneController = this;director.currentSceneController.LoadSource();gameObject.AddComponent<UserGUI>();gameObject.AddComponent<CCActionManager>();gameObject.AddComponent<ScoreController>();gameObject.AddComponent<DiskFactory>();factory = Singleton<DiskFactory>.Instance;userGUI = gameObject.GetComponent<UserGUI>();}public void LoadSource() {}public void gameOver() {if (round > max_round && actionManager.RemainActionCount() == 0)userGUI.gameMessage = "Game Over!";}public void GetHit() {if (Input.GetButtonDown("Fire1")) {Camera ca = Camera.main;Ray ray = ca.ScreenPointToRay(Input.mousePosition);//Return the ray's hitRaycastHit hit;if (Physics.Raycast(ray, out hit)) {scoreController.Record(hit.transform.gameObject);hit.transform.gameObject.SetActive(false);}}}
}
(三)Viewers 用户接口与用户GUI
1. IUserAction 用户接口
public interface IUserAction {void gameOver();void GetHit();
}
2. UserGUI 用户界面
public class UserGUI : MonoBehaviour
{public int mode;public int score;public int round;public string gameMessage;private IUserAction action;public GUIStyle bigStyle, blackStyle, smallStyle;//自定义字体格式public Font pixelFont;private int menu_width = Screen.width / 5, menu_height = Screen.width / 10;//主菜单每一个按键的宽度和高度// Start is called before the first frame updatevoid Start(){mode = 0;gameMessage = "";action = SSDirector.getInstance().currentSceneController as IUserAction;//pixelStyle//pixelFont = Font.Instantiate(Resources.Load("Fonts/ThaleahFat", typeof(Font))) as Font;//if (pixelFont == null) Debug.Log("null");//pixelFont.fontSize = 50;//pixelFont = Arial;//大字体初始化bigStyle = new GUIStyle();bigStyle.normal.textColor = Color.white;bigStyle.normal.background = null;bigStyle.fontSize = 50;bigStyle.alignment=TextAnchor.MiddleCenter;//blackblackStyle = new GUIStyle();blackStyle.normal.textColor = Color.black;blackStyle.normal.background = null;blackStyle.fontSize = 50;blackStyle.alignment=TextAnchor.MiddleCenter;//小字体初始化smallStyle = new GUIStyle();smallStyle.normal.textColor = Color.white;smallStyle.normal.background = null;smallStyle.fontSize = 20;smallStyle.alignment=TextAnchor.MiddleCenter;}// Update is called once per framevoid Update(){}void OnGUI() {//GUI.skin.button.font = pixelFont;GUI.skin.button.fontSize = 35;switch(mode) {case 0:mainMenu();break;case 1:GameStart();break;}       }void mainMenu() {GUI.Label(new Rect(Screen.width / 2 - menu_width * 0.5f, Screen.height * 0.1f, menu_width, menu_height), "Hit UFO", bigStyle);bool button = GUI.Button(new Rect(Screen.width / 2 - menu_width * 0.5f, Screen.height * 3 / 7, menu_width, menu_height), "Start");if (button) {mode = 1;}}void GameStart() {GUI.Label(new Rect(300, 60, 50, 200), gameMessage, bigStyle);GUI.Label(new Rect(0,0,100,50), "Score: " + score, smallStyle);GUI.Label(new Rect(560,0,100,50), "Round: " + round, smallStyle);}
}

五、项目地址

github地址

六、可改进的地方

  • 寻找合适的飞碟或飞盘贴图,增加自旋效果
  • 给飞碟加上更复杂的轨迹,比如上下左右起伏
  • 增加击中飞碟时的画面效果,比如飞碟破碎或爆炸

unity 实现简易打飞碟游戏相关推荐

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

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

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

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

  3. Unity 3D-learning 简单打飞碟游戏

    一.编写一个简单的打飞碟游戏 游戏内容要求: 游戏有 n 个 round,每个 round 都包括10 次 trial: 每个 trial 的飞碟的色彩.大小.发射位置.速度.角度.同时出现的个数都可 ...

  4. Unity打造简易的GalGame游戏剧本编辑引擎

    GalGame相比其它类型的游戏场景简单,游戏要素不多,靠的是精美的画面和动人的剧情以及舒服的BGM.游戏根据玩家做出的不同选择产生不同的结局,而这个触发条件往往是和主角的好感度有关. 对于这样的游戏 ...

  5. Unity实战之模拟飞碟

    Unity实战之模拟飞碟 unity实现简易打飞碟游戏. 项目地址 Unity飞碟实现效果 游戏规则 一共10轮,每轮10s 轮次越高,难度越大. 每轮的一定时间都会生成一定数量的飞碟,一共有四种颜色 ...

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

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

  7. unity 3D打飞碟游戏,虚拟现实大作业

    unity 3D打飞碟游戏(下载链接在文末),包含游戏菜单,按钮,分数记载等等 点我下载资源 https://download.csdn.net/download/weixin_43474701/34 ...

  8. Unity游戏设计之飞碟游戏

    编制一个射飞碟游戏. 具体要求如下: 1 假设有一支枪在摄像机位置(0,1,-10),在(0,0,0-10-20)放置三个小球作为距离标记,调整视角直到小球在下中部 2 将鼠标所在平面坐标,转换为子弹 ...

  9. 【游戏开发】unity教程4 打飞碟小游戏

    github传送门:https://github.com/dongzizhu/unity3DLearning/tree/master/hw4/Disk 视频传送门:https://space.bili ...

最新文章

  1. Java 异常处理的 9 个最佳实践 1
  2. java 二进制报文头_转自:java 文件格式二进制头文件校验
  3. devops的公开课
  4. django model
  5. c++预处理命令 #line 用法
  6. python断点续传下载_python requests 断点续传下载
  7. Silverlight 4 帮助文件例子的连接
  8. JavaScript实现累加和累乘
  9. AJAX(七)jsonp实战--天气预报
  10. 【超级有用】大数据的压缩格式
  11. Kali exiftool图片信息工具
  12. [RK3288][Android6.0] WiFi之cfg80211知识点小结
  13. useEffect副作用的使用
  14. Android NKD环境搭建 若干问题.
  15. 管理系统中计算机应用课本,自考学习0051管理系统中计算机应用 自考教材.pdf...
  16. 装机必备,微软常用运行库合集 2022最新版
  17. 2011国信蓝点(桥)杯C语言试题
  18. linux运行倩女,在Linux下可用Wine安装和运行新倩女幽魂、迷你世界
  19. opencv-python 指静脉的手指轮廓提取实现
  20. win7激活之系统保留分区的设置与隐藏

热门文章

  1. n-gram的理解与实现
  2. windows10电脑开热点只能用5G频段,不能开2.4G热点,提示所选网络波段不可用
  3. 申请163邮箱,如何申请邮箱,邮箱如何申请?
  4. Java笔记(一)发展史与开发工具简介
  5. 数字旅游——智慧景区三维可视化综合运营平台
  6. 中国股市是否出现非理性繁荣?(转载)
  7. 联合高斯分布(Joint Gaussian)的推导
  8. Win7项目分享part1:Windows7准备的3个阶段
  9. 蓝桥杯 无聊的逗 Python题解
  10. 【涨粉秘籍】如何快速涨粉并转化为铁粉。