unity-3d:打飞碟游戏

  • 1、编写一个简单的鼠标打飞碟(Hit UFO)游戏
    • **uml类图**
    • Director
    • DiskData
    • DiskFactory
    • FirstController
    • FlyActionManager
    • Interface
    • ScoreRecorder
    • Singleton
    • SSAction
    • SSActionManager
    • UFOFlyAction
    • UserGUI
    • 运行效果
    • 源码
    • 2、编写一个简单的自定义 Component (选做)

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

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

uml类图

Director

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//场景控制,负责各个场景的切换
public class Director : System.Object
{private static Director _instance;public ISceneController currentScenceController { get; set; }//说明derictor采用的是单例模式public static Director getInstance(){if (_instance == null){_instance = new Director();}return _instance;}
}

DiskData

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//飞碟数据信息,每一个飞碟都会附加该内容
public class DiskData : MonoBehaviour {public int score = 1;//飞碟的分数public Vector3 direction;//飞碟方向public Vector3 scale = new Vector3(1, 1, 1);//飞碟大小
}

DiskFactory

注意观察到该工厂类的实现是单实例的

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//飞碟工厂,实现了一个对象池,管理飞碟对象
public class DiskFactory : MonoBehaviour {public GameObject diskPrefab = null;private List<DiskData> used = new List<DiskData>();private List<DiskData> free = new List<DiskData>();public GameObject GetDisk(int round){int choice = 0;int scope = 1, scope1 = 4, scope2 = 7;float startY = -10f;string tag;diskPrefab = null;//产生一个随机数,这个随机数等下被用来选择生成的飞碟if(round == 1)choice = Random.Range(0, scope);else if(round == 2)choice = Random.Range(0, scope1);else if(round == 3)choice = Random.Range(0, scope2);//如果随机数小于最小的范围scope,选择disk1;//如果随机数大于等于最小的范围scope,如果随机数小于范围scope1,选择disk2;//如果随机数大于等于范围scope1,选择disk3;if (choice <= scope)tag = "disk1";else if(choice >= scope && choice < scope1)tag = "disk2";elsetag = "disk3";//选出一个对象池中的名字为tag的飞碟for(int i = 0; i < free.Count; i++){if(free[i].tag == tag){diskPrefab = free[i].gameObject;free.Remove(free[i]);break;}}//如果没有找到,则创建一个新的飞碟对象if(diskPrefab == null){//根据tag生成不同的飞碟对象if (tag == "disk1")diskPrefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk1"), new Vector3(0, startY, 0), Quaternion.identity);else if(tag == "disk2")diskPrefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk2"), new Vector3(0, startY, 0), Quaternion.identity);else if(tag == "disk3")diskPrefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk3"), new Vector3(0, startY, 0), Quaternion.identity);//飞碟对象属性初始化float ranX = Random.Range(-1f, -1f) < 0 ? -1 : 1;diskPrefab.GetComponent<DiskData>().direction = new Vector3(ranX, startY, 0);diskPrefab.transform.localScale = diskPrefab.GetComponent<DiskData>().scale;}//新飞碟对象添加一个飞碟数据的componentused.Add(diskPrefab.GetComponent<DiskData>());return diskPrefab;}//当时用free队列中的对象时候,删除free队列中的对应对象public void FreeDisk(GameObject disk){for (int i = 0; i < used.Count; i++){if (disk.GetInstanceID() == used[i].gameObject.GetInstanceID()){used[i].gameObject.SetActive(false);free.Add(used[i]);used.Remove(used[i]);break;}}}}

FirstController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//主场景控制器
public class FirstController : MonoBehaviour, ISceneController, IUserAction
{public FlyActionManager actionManager;//当前动作管理器public DiskFactory diskFactory;//飞碟工厂,作管理飞碟用public UserGUI userGUI;//用户交互public ScoreRecorder scoreRecorder;//得分控制器private Queue<GameObject> diskQueue = new Queue<GameObject>();//当前场景中的所有飞碟private List<GameObject> diskNotHit = new List<GameObject>();//没有被击中的飞碟,会显示在游戏界面中private int round = 1;//游戏的轮次,初始化为第一轮,第二、三轮会越来越难private float speed = 2f;private bool isPlayGame = false;private bool isGameOver = false;private bool isGameStart = false;private int scoreRound2 = 10;//当达到这个分数标志游戏进入第二轮private int scoreRound3 = 20;//当达到这个分数标志游戏进入第三轮//初始化相关成员变量void Start (){Director director = Director.getInstance();     director.currentScenceController = this;             diskFactory = Singleton<DiskFactory>.Instance;scoreRecorder = Singleton<ScoreRecorder>.Instance;actionManager = gameObject.AddComponent<FlyActionManager>() as FlyActionManager;userGUI = gameObject.AddComponent<UserGUI>() as UserGUI;}//void Update (){if(isGameStart){if (isGameOver){CancelInvoke("LoadResources");}if (!isPlayGame){InvokeRepeating("LoadResources", 1f, speed);isPlayGame = true;}ThrowDisk();if (scoreRecorder.score >= scoreRound2 && round == 1){round = 2;speed = speed - 0.6f;CancelInvoke("LoadResources");isPlayGame = false;}else if (scoreRecorder.score >= scoreRound3 && round == 2){round = 3;speed = speed - 0.5f;CancelInvoke("LoadResources");isPlayGame = false;}}}//根据轮次初始化该轮对应的飞碟public void LoadResources(){diskQueue.Enqueue(diskFactory.GetDisk(round)); }//投出飞碟private void ThrowDisk(){float position_x = 16;                       if (diskQueue.Count != 0){GameObject disk = diskQueue.Dequeue();diskNotHit.Add(disk);disk.SetActive(true);float ran_y = Random.Range(1f, 4f);float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;disk.GetComponent<DiskData>().direction = new Vector3(ran_x, ran_y, 0);Vector3 position = new Vector3(-disk.GetComponent<DiskData>().direction.x * position_x, ran_y, 0);disk.transform.position = position;float power = Random.Range(10f, 15f);float angle = Random.Range(15f, 28f);actionManager.UFOFly(disk,angle,power);}for (int i = 0; i < diskNotHit.Count; i++){GameObject temp = diskNotHit[i];if (temp.transform.position.y < -10 && temp.gameObject.activeSelf == true){diskFactory.FreeDisk(diskNotHit[i]);diskNotHit.Remove(diskNotHit[i]);userGUI.BloodReduce();}}}//当飞碟被点击的时候的处理函数public void Hit(Vector3 pos){Ray ray = Camera.main.ScreenPointToRay(pos);RaycastHit[] hits;hits = Physics.RaycastAll(ray);bool not_hit = false;for (int i = 0; i < hits.Length; i++){RaycastHit hit = hits[i];if (hit.collider.gameObject.GetComponent<DiskData>() != null){for (int j = 0; j < diskNotHit.Count; j++){if (hit.collider.gameObject.GetInstanceID() == diskNotHit[j].gameObject.GetInstanceID()){not_hit = true;}}if(!not_hit){return;}diskNotHit.Remove(hit.collider.gameObject);scoreRecorder.Record(hit.collider.gameObject);Transform explode = hit.collider.gameObject.transform.GetChild(0);explode.GetComponent<ParticleSystem>().Play();StartCoroutine(WaitingParticle(0.08f, hit, diskFactory, hit.collider.gameObject));break;}}}public int GetScore(){return scoreRecorder.score;}public void Restart(){isGameOver = false;isPlayGame = false;scoreRecorder.score = 0;round = 1;speed = 2f;}public void GameOver(){isGameOver = true;}IEnumerator WaitingParticle(float wait_time, RaycastHit hit, DiskFactory disk_factory, GameObject obj){yield return new WaitForSeconds(wait_time); hit.collider.gameObject.transform.position = new Vector3(0, -9, 0);disk_factory.FreeDisk(obj);}public void BeginGame(){isGameStart = true;}
}

FlyActionManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//具体的动作管理器,用来管理飞碟的动作
public class FlyActionManager : SSActionManager {public FirstController controller;public UFOFlyAction flyAction;//将其实例化void Start () {controller = (FirstController)Director.getInstance().currentScenceController;controller.actionManager = this;}//调用基类中的RunAction函数,让飞碟运动起来public void UFOFly(GameObject disk, float angle, float power){flyAction = UFOFlyAction.GetSSAction(disk.GetComponent<DiskData>().direction, angle, power);this.RunAction(disk, flyAction, this);}
}

Interface

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public enum SSActionEventType : int { Started, Competeted }
//动作管理器接口
public interface ISSActionCallback
{void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null);
}
//场景控制器接口
public interface ISceneController
{void LoadResources();
}
//界面和场景控制器的接口
public interface IUserAction
{void Restart();void Hit(Vector3 pos);void GameOver();int GetScore();void BeginGame();
}

ScoreRecorder

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//得分记录器
public class ScoreRecorder : MonoBehaviour {public int score;// Use this for initializationvoid Start () {score = 0;}public void Record(GameObject disk){int temp = disk.GetComponent<DiskData>().score;score += temp;}public void Reset(){score = 0;}
}

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

SSAction

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//所有动作基类
public class SSAction : ScriptableObject
{public bool enable = true;public bool destroy = false;public GameObject gameobject;public Transform transform;public ISSActionCallback callback;protected SSAction() { }public virtual void Start(){throw new System.NotImplementedException();}public virtual void Update(){throw new System.NotImplementedException();}
}

SSActionManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;//场景管理基类public class SSActionManager : MonoBehaviour, ISSActionCallback
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();                //保存所以已经注册的动作private List<SSAction> waitingAdd = new List<SSAction>();                                   //动作的等待队列,在下一帧队列中动作会注册到动作管理器里private List<int> waitingDelete = new List<int>();                                          //动作的删除队列,在下一帧队列中动作会被在注册队列中删除protected void Update(){foreach (SSAction ac in waitingAdd)            //把等待队列里所有的动作注册到动作管理器里actions[ac.GetInstanceID()] = ac;waitingAdd.Clear();//若动作被标记为删除,则将其加入删除队列;若标记为激活,则调用其Update函数foreach (KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if (ac.destroy){waitingDelete.Add(ac.GetInstanceID());}else if (ac.enable){ac.Update();}}//删除队列中的所有动作被删除foreach (int key in waitingDelete){SSAction ac = actions[key]; actions.Remove(key); DestroyObject(ac);}waitingDelete.Clear();}//初始化动作public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameobject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null){}
}

UFOFlyAction

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//飞碟飞行动作
public class UFOFlyAction : SSAction {public float gravity = -5;//重力private Vector3 startVector;private Vector3 gravityVector = Vector3.zero;private float time;private Vector3 currentAngle = Vector3.zero;private UFOFlyAction(){}public static UFOFlyAction GetSSAction(Vector3 direction, float angle, float power){UFOFlyAction action = CreateInstance<UFOFlyAction>();if (direction.x == -1){action.startVector = Quaternion.Euler(new Vector3(0, 0, -angle)) * Vector3.left * power;}else{action.startVector = Quaternion.Euler(new Vector3(0, 0, angle)) * Vector3.right * power;}return action;}//每一帧更新飞碟位置public override void Update(){time += Time.fixedDeltaTime/5;gravityVector.y = gravity * time/5;transform.position += (startVector + gravityVector) * Time.fixedDeltaTime/10;currentAngle.z = Mathf.Atan((startVector.y + gravityVector.y) / startVector.x);transform.eulerAngles = currentAngle;if(this.transform.position.y < -10){this.destroy = true;this.callback.SSActionEvent(this);}}public override void Start(){}
}

UserGUI

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class UserGUI : MonoBehaviour
{private IUserAction action;public int life = 10;//每个GUI的styleGUIStyle boldStyle = new GUIStyle();GUIStyle scoreStyle = new GUIStyle();GUIStyle textStyle = new GUIStyle();GUIStyle overStyle = new GUIStyle();private int score = 0;private bool gameStart = false;void Start (){action = Director.getInstance().currentScenceController as IUserAction;}void OnGUI (){boldStyle.normal.textColor = new Color(1, 0, 0);boldStyle.fontSize = 20;textStyle.normal.textColor = new Color(0,0,0, 1);textStyle.fontSize = 20;scoreStyle.normal.textColor = new Color(1,0,1,1);scoreStyle.fontSize = 20;overStyle.normal.textColor = new Color(1, 0, 0);overStyle.fontSize = 25;if (gameStart){//用户射击if (Input.GetButtonDown("Fire1")){Vector3 pos = Input.mousePosition;action.Hit(pos);}GUI.Label(new Rect(10, 5, 200, 50), "Score:", textStyle);GUI.Label(new Rect(80, 5, 200, 50), action.GetScore().ToString(), scoreStyle);GUI.Label(new Rect(Screen.width - 120, 5, 50, 50), "Life:", textStyle);GUI.Label(new Rect(Screen.width - 50, 5, 50, 50), life.ToString(), textStyle);//游戏结束if (life == 0){score = action.GetScore();GUI.Label(new Rect(Screen.width / 2 - 20, Screen.width / 2 - 250, 100, 100), "Game Over", overStyle);GUI.Label(new Rect(Screen.width / 2 - 10, Screen.width / 2 - 200, 50, 50), "Score:", textStyle);GUI.Label(new Rect(Screen.width / 2 + 50, Screen.width / 2 - 200, 50, 50), score.ToString(), textStyle);if (GUI.Button(new Rect(Screen.width / 2 - 20, Screen.width / 2 - 150, 100, 50), "Restart")){life = 10;action.Restart();return;}action.GameOver();}}else{GUI.Label(new Rect(Screen.width / 2 - 30, Screen.width / 2 - 350, 100, 100), "Hit UFO!", overStyle);if (GUI.Button(new Rect(Screen.width / 2 - 25, Screen.width / 2 - 250, 100, 50), "Game Start")){gameStart = true;action.BeginGame();}}}public void BloodReduce(){if(life > 0)life--;}
}

运行效果

源码

使用方法:创建一个unity3d项目。退出项目,将Assets文件夹替换为该Assets文件夹。然后打开项目,创建GameObject,并挂载FirstController脚本,然后运行游戏。

2、编写一个简单的自定义 Component (选做)

  • 用自定义组件定义几种飞碟,做成预制
      参考官方脚本手册 https://docs.unity3d.com/ScriptReference/Editor.html
      实现自定义组件,编辑并赋予飞碟一些属性

    除了最开始的飞碟之外,还额外做了两种飞碟,都附加了DiskdData属性

unity-3d:打飞碟游戏相关推荐

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

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

  2. Unity 3D为策略游戏创建地图学习教程

    MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch 语言:英语+中英文字幕(根据原英文字幕机译更准确) |时长:30节课(7h 42m) |大小:5 GB 含项目文 ...

  3. unity 3D作业-狩猎游戏

    unity 3D作业-狩猎游戏 视角为第一人称,手拿斧头可以砍野猪和僵尸等怪物,有背景音乐和打击音效,游戏详情请看下列动态图:(下载链接在文末) 点我下载链接

  4. 为什么要选择 Unity 3D来开发游戏?

    选择合适的游戏引擎对于移动游戏开发项目的成功至关重要.功能丰富的 Unity 3D 引擎有助于针对跨多个设备兼容的不同平台进行游戏开发.游戏引擎具有许多资源,例如即时资产.IDE.在线社区帮助.免费教 ...

  5. 小白学习Unity 3D做经典游戏坦克大战日常

    老师 | Trigger 学习者 |小白 出品 | Siki 学院 Hello,小伙伴们.接下来小白跟Trigger老师做一款2D游戏坦克大战.从素材.代码到场景和UI的游戏开发.小白把日常遇到的问题 ...

  6. Unity 3D-learning 打飞碟游戏改进版ben

    一.改进打飞碟游戏 游戏内容要求: 按 adapter模式 设计图修改飞碟游戏 使它同时支持物理运动与运动学(变换)运动 adapter模式设计简要展示: SceneController 类,作为 A ...

  7. Unity 3D 入门小游戏 小球酷跑(下)

    文章目录 一.障碍物自动生成 二.障碍物自动销毁 三.障碍物颜色随机组 四.碰到障碍物颜色提示 五.分数 总结 一.障碍物自动生成 为了保证游戏结束之前有源源不断的障碍物生成,所以要实现随机生成位置不 ...

  8. Unity 3D 创建简单的几何模型 || Unity 3D Assets 游戏资源目录管理

    Unity 3D 创建简单的几何模型 Unity 3D 是一个强大的游戏开发引擎.在游戏开发中使用的模型常常是从外部导入的,Unity 3D 为了方便游戏开发者快速创建模型,提供了一些简单的几何模型, ...

  9. Unity 3D游戏开发项目《战斗吧!勇士》

    目录 版权声明:本博客涉及的内容是对本人游戏作品<战斗吧!勇士>项目的总结,发布在网络上,旨在大家交流学习.互相促进.严禁用于其他一切用途. 摘要 游戏开发技术概述 Unity 3D 游戏 ...

  10. 使用 Unity 3D 开发游戏的几个架构设计难点

     Unity 3D 引擎对于开发者来说,入手非常快,因为它采用的是 C# 作为开发语言,这也大大降低了开发者的门槛.但凡只要懂一门编程语言的人都能使用 Unity 3D 引擎开发,另外 Unity 3 ...

最新文章

  1. 解决 json_encode 中文乱码
  2. Fun 3.0 发布——资源部署、依赖下载、代码编译等功能又又又增强啦!
  3. centos6.7x86_64php7安装笔记 new
  4. 如何pspice模型转成saber模型
  5. 四元素与欧拉角之间的转换
  6. 错误代码 insufficient-isv-permissions 错误原因: ISV权限不足
  7. java.lang.NoSuchMethodError: org.jaxen.dom4j.DocumentNavigator.getInstance()【可能的解决办法】
  8. 使用AD13设计PCB的技巧总结
  9. 基于python mediapipe的视频或者图片更换背景
  10. 深度学习硬件购买指南
  11. 440 亿美元成交!Twitter 「卖身」马斯克
  12. python自动化plc_PYTHON – 让“Monty 语言”进入自动化行业:第 4 部分
  13. 一文带你重新审视CAP理论与分布式系统设计
  14. 【js】判断是否包含数字
  15. HTML5期末大作业:电商购物网站设计——电商购物网站设计(55页) 电商网页设计制作 简单静态HTML网页作品 购物网页作业成品 学生商城网站模板
  16. MySQL数据库入门学习教程(mysql基础+高级)
  17. 函数的连续性和间断点——“高等数学”
  18. 比网易更狠!华为13年工龄员工离职被诉敲诈,羁押长达251天
  19. 芯片热阻系数学习 芯片温度
  20. python中join什么意思_python里join是什么意思

热门文章

  1. 司法官论托普的“倒掉” (转,深刻揭示软件公司经营之路)
  2. VMware ESXI 5.5 注册码
  3. Paper Reading:BigGAN
  4. python 回归方程及回归系数的显著性检验_回归方程及回归系数的显著性检验
  5. mysql pxc集群介绍_MySQL中PXC集群的介绍
  6. 高校社团管理系统的设计与开发学习论文
  7. STM32编译生成的BIN文件详解
  8. php视频教程打包下载 - 网络上最好的php视频教程
  9. 单片机c语言双边拉幕灯,51单片机C语言入门教程
  10. 深度学习涉及到的高等数学知识点总结