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

    • 游戏内容要求
    • 游戏的要求
    • 游戏实现
      • 文件结构
      • c#文件
        • DiskFactory
        • DiskFactoryController
        • FirstController
        • RoundController
        • SceneController
        • ScoreController
        • UserInterface
  • 资源

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

游戏内容要求

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

    游戏的要求

  • 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!

  • 尽可能使用前面 MVC 结构实现人机交互与游戏模型分离

游戏实现

总的来说,这次代码写的比较随意,冗余部分过多,而且没有很好的组织结构,函数的布置相对来说有点混乱,所以为了弥补这方面的不足,尽量做了好看的效果,加了一点粒子系统,当然也是参考了往届的博客。

文件结构

文本结构

资源结构

预制结构

c#文件

DiskFactory

单例模式,得到飞碟id,得到飞碟对象,释放飞碟对象,为了避免开销大的问题,没有用destory,而是设置为diskList[id].SetActive(false);

using UnityEngine;
using System.Collections;
using System.Collections.Generic;public class DiskFactory : System.Object
{private static DiskFactory _instance;private static List<GameObject> diskList; public GameObject disk;      public static DiskFactory getInstance(){if (_instance == null){_instance = new DiskFactory();diskList = new List<GameObject>();}return _instance;}public int getDiskId(){for (int i = 0; i < diskList.Count; ++i){if (!diskList[i].activeInHierarchy){return i;}}diskList.Add(GameObject.Instantiate(disk) as GameObject);return diskList.Count - 1;}public GameObject getDiskObject(int id){if (id > -1 && id < diskList.Count){return diskList[id];}return null;}public void free(int id){if (id > -1 && id < diskList.Count){diskList[id].GetComponent<Rigidbody>().velocity = Vector3.zero;//diskList[id].rigidbody.velocity = Vector3.zero;diskList[id].transform.localScale = disk.transform.localScale;diskList[id].SetActive(false);}}
}

DiskFactoryController

初始化disk,这次程序中的所有初始化,都是在类中声明为public,然后将预制拖到文件当中,而没有用Instantiate函数,感觉这样比较符合我的编程习惯。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DiskFactoryController : MonoBehaviour
{public GameObject disk;void Awake(){DiskFactory.getInstance().disk = disk;}
}

FirstController

包括场景的设置,发射飞碟的提示,发射飞碟,释放飞碟,得分。

  • 发射飞碟,大小,颜色,位置,方向都是随机的,但是没有与分数挂钩,都是打中一个得十分,每回合打完第十次进入下一回合,打完三回合,结束游戏。
  • FixedUpdate中用timeToNextEmission -= Time.deltaTime实现倒计时。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;public class FirstController : MonoBehaviour
{public Color[] TotalColor = {Color.black,Color.blue,Color.cyan,Color.green,Color.grey,Color.red,Color.yellow };public float EmissionDelay = 1f;public float timeToNextEmission;private bool isCounting;private bool isShooting;public bool getIsCounting() { return isCounting; }public bool getIsShooting() { return isShooting; }private List<GameObject> disks = new List<GameObject>();   private List<int> diskIds = new List<int>();               private int diskScale;                  private Color diskColor;               private Vector3 emissionPosition;          private Vector3 emissionDirection;         private float emissionSpeed;private int emissionNumber;                 private bool isEmissionEnable;               private SceneController scene;private RoundController roundController;void Awake(){scene = SceneController.getInstance();scene.setFirstController(this);}public void setting(int scale, Color color, Vector3 emitPos, Vector3 emitDir, float speed, int num){diskScale = scale;diskColor = color;emissionPosition = emitPos;emissionDirection = emitDir;emissionSpeed = speed;emissionNumber = num;}public void MakeEmissionDiskable(){if (!isCounting && !isShooting){timeToNextEmission = EmissionDelay;isEmissionEnable = true;}}void emissionDisks(){scene.setTrial(scene.getTrial()+1);for (int i = 0; i < emissionNumber; ++i){diskIds.Add(DiskFactory.getInstance().getDiskId());disks.Add(DiskFactory.getInstance().getDiskObject(diskIds[i]));diskScale = Random.Range(1,3);disks[i].transform.localScale *= diskScale;int chooseColor = Random.Range(0, 7);disks[i].GetComponent<Renderer>().material.color = TotalColor[chooseColor];disks[i].transform.position = new Vector3(Random.Range(-2.5f,2.5f), emissionPosition.y + i, emissionPosition.z);disks[i].SetActive(true);emissionDirection.x = emissionDirection.x * Random.Range(-1, 1);disks[i].GetComponent<Rigidbody>().AddForce(emissionDirection * Random.Range(emissionSpeed * 5, emissionSpeed * 10) / 10, ForceMode.Impulse);}if(scene.getTrial() == 10){scene.nextRound();}if(scene.getRound() == 4){scene.gameOver();}}void freeADisk(int i){DiskFactory.getInstance().free(diskIds[i]);disks.RemoveAt(i);diskIds.RemoveAt(i);}void FixedUpdate(){if (timeToNextEmission > 0){isCounting = true;timeToNextEmission -= Time.deltaTime;}else{isCounting = false;if (isEmissionEnable){emissionDisks();isEmissionEnable = false;isShooting = true;}}}void Update(){for (int i = 0; i < disks.Count; i++){if (!disks[i].activeInHierarchy){  scene.getScoreController().hitDisk(); freeADisk(i);}else if (disks[i].transform.position.y < 0){   scene.getScoreController().hitGround(scene.getRound()); freeADisk(i);}}if (disks.Count == 0){isShooting = false;}}
}

RoundController

回合控制,一共设置三关,除了速度,数量是真正预设的,其他的都会被被发射之前随机设置,第一关每次一个,速度为2,第二关每次两个,速度为4,第三关每次3此,速度为8。

using UnityEngine;
using UnityEngine.UI;
using System.Collections;public class RoundController : MonoBehaviour
{private Color color;private Vector3 emissionPositon;private Vector3 emissionDiretion;private float speed;private SceneController scene;public int trial = 0;void Awake(){SceneController.getInstance().setRoundController(this);scene = SceneController.getInstance();}void Start(){scene.nextRound();}public void loadRoundData(int round){trial = 0;switch (round){case 1:    color = Color.green;emissionPositon = new Vector3(-2.5f, 0.2f, -5f);emissionDiretion = new Vector3(24.5f, 40.0f, 67f);speed = 2;SceneController.getInstance().getFirstController().setting(1, color, emissionPositon, emissionDiretion.normalized, speed, 1);break;case 2:    color = Color.red;emissionPositon = new Vector3(2.5f, 0.2f, -5f);emissionDiretion = new Vector3(-24.5f, 35.0f, 67f);speed = 4;SceneController.getInstance().getFirstController().setting(1, color, emissionPositon, emissionDiretion.normalized, speed, 2);break;case 3:color = Color.cyan;emissionPositon = new Vector3(2.5f, 0.2f, -5f);emissionDiretion = new Vector3(-24.5f, 35.0f, 67f);speed = 8;SceneController.getInstance().getFirstController().setting(1, color, emissionPositon, emissionDiretion.normalized, speed, 3);break;}}
}

SceneController

实现一些基本函数,没有在SceneController中实现其他的类的实例化,但是在用到的其他类的Awake函数中,调用set…函数,使得可以用其他类的函数,

using UnityEngine;
using System.Collections;public interface GameInterface
{void MakeEmissionDiskable();bool isCounting();bool isShooting();int getRound();int getScore();int getTimeToNextEmissionTime();void nextRound();void setScore(int point);void setRound(int input);int getTrial();void setTrial(int input);void gameOver();
}public class SceneController : System.Object, GameInterface
{private static SceneController _instance;private RoundController _roundController;private FirstController _firstController;private ScoreController _scoreController;private UserInterface _userInterface;private int _round;private int _score;private int _trial;public bool isGameOver;public static SceneController getInstance(){if (_instance == null){_instance = new SceneController();}return _instance;}public void setFirstController(FirstController input){_firstController = input;}internal FirstController getFirstController(){return _firstController;}public void setScoreController(ScoreController input){_scoreController = input;}internal ScoreController getScoreController(){return _scoreController;}internal UserInterface getUserInterface(){return _userInterface;}public void setUserInterface(UserInterface input){_userInterface = input;}public void setRoundController(RoundController input){_roundController = input;}internal RoundController getRoundController(){return _roundController;}public void MakeEmissionDiskable(){_firstController.MakeEmissionDiskable();}public bool isCounting(){return _firstController.getIsCounting();}public bool isShooting(){return _firstController.getIsShooting();}public int getRound(){return _round;}public void setRound(int input){_round = input;}public int getScore(){return _score;}public int getTimeToNextEmissionTime(){return (int)_firstController.timeToNextEmission + 1;}public void setScore(int input){_score = input;}public void nextRound(){_roundController.loadRoundData(++_round);}public int getTrial(){return _roundController.trial;}public void setTrial(int input){_roundController.trial = input;}public void gameOver(){isGameOver = true;_userInterface.gameOver();}
}

ScoreController

分数管理,击中一个10分,一个落地,第一关扣5分,第二关扣20分,第三关扣45分。

using UnityEngine;
using System.Collections;public class ScoreController : MonoBehaviour
{private int oneDiskScore = 10;private int oneDiskFail = 5;private SceneController scene;void Awake(){scene = SceneController.getInstance();scene.setScoreController(this);}public void hitDisk(){scene.setScore(scene.getScore() + oneDiskScore);}public void hitGround(int input){scene.setScore(scene.getScore() - oneDiskFail * input * input);}
}

UserInterface

用户界面,包括射击子弹,粒子系统,界面提示。游戏结束后,按space空格键可以重新开始,每次射击有0.25秒的间隔。

using UnityEngine;
using UnityEngine.UI;
using System.Collections;public class UserInterface : MonoBehaviour
{public Text mainText;   public Text scoreText;  public Text roundText; private int round; public GameObject bullet;          public ParticleSystem explosion;    public float fireRate = .25f;      public float speed = 500f;public bool isGameOver = false;private float nextFireTime;private GameInterface gameInterface;private SceneController scene;public void Awake(){scene = SceneController.getInstance();scene.setUserInterface(this);}void Start(){bullet = GameObject.Instantiate(bullet) as GameObject;explosion = GameObject.Instantiate(explosion) as ParticleSystem;gameInterface = SceneController.getInstance() as GameInterface;}public void gameOver(){isGameOver = true;mainText.text = "GameOver,put down SPACE to Reset";}void Update(){if(Input.GetKeyDown("space") && isGameOver){scene.setRound(0);scene.nextRound();isGameOver = false;}if (!isGameOver){if (gameInterface.isCounting()){//mainText.text = ((int)gameInterface.getTimeToNextEmissionTime()).ToString();mainText.text = "Trial " + (gameInterface.getTrial() + 1).ToString();}else{gameInterface.MakeEmissionDiskable();if (gameInterface.isShooting()){mainText.text = "";}if (gameInterface.isShooting() && Input.GetMouseButtonDown(0) && Time.time > nextFireTime){nextFireTime = Time.time + fireRate;Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);bullet.GetComponent<Rigidbody>().velocity = Vector3.zero;//bullet.rigidbody.velocity = Vector3.zero;                     bullet.transform.position = transform.position;bullet.GetComponent<Rigidbody>().AddForce(ray.direction * speed, ForceMode.Impulse);RaycastHit hit;if (Physics.Raycast(ray, out hit) && hit.collider.gameObject.tag == "Disk"){explosion.transform.position = hit.collider.gameObject.transform.position;explosion.GetComponent<Renderer>().material.color = hit.collider.gameObject.GetComponent<Renderer>().material.color;//explosion.renderer.material.color = hit.collider.gameObject.renderer.material.color;explosion.Play();hit.collider.gameObject.SetActive(false);}}}roundText.text = "Round: " + gameInterface.getRound().ToString();scoreText.text = "Score: " + gameInterface.getScore().ToString();if (round != gameInterface.getRound()){round = gameInterface.getRound();mainText.text = "Round " + round.ToString() + " !";}}}
}

资源

视频及资源

3D游戏编程4--打飞碟相关推荐

  1. 3D游戏编程实践——打飞碟(Hit UFO)游戏运动与物理兼容版

    这次编程实践是在上一次实践的基础上,增加了物理运动,做到了运动学和物理运动会的兼容.而原来的代码只实现了运动学部分. 首先需要实现物理运动部分的Action类和ActionManager类. 相比起运 ...

  2. 3D游戏编程:第5次作业

    3D游戏编程:第5次作业 文章目录 3D游戏编程:第5次作业 编写一个简单的鼠标打飞碟(HitUFO)游戏 游戏要求 项目地址与演示视频 代码实现 代码挂载 代码组织结构 代码简析 1 飞碟运动控制器 ...

  3. 3D游戏编程学习笔记(五):与游戏世界交互

    一.前言 本次3D游戏编程我们将设计一个简单打飞碟(Hit UFO)有游戏. 二.游戏基本内容及规定 游戏基本内容 游戏有 n 个 round,每个 round 都包括10 次 trial: 每个 t ...

  4. 3D游戏编程与设计-井字棋

    3D游戏编程与设计-井字棋 目录 3D游戏编程与设计-井字棋 A. 简答题 1. 解释游戏对象(GameObjects)和资源(Assets)的区别与联系 ① 游戏对象 ② 资源 2. 下载几个游戏案 ...

  5. 3d游戏编程(转帖)

    3d游戏编程(转帖) 我先声明,我不是编程高手,我还只是个初学者,但我觉得我所知道的对刚入门3D游戏编程的新手,应该能让他们少走弯路,我也很想用朝语来写,但是朝语的词 汇库很久没有更新过了,有些专业的 ...

  6. 3D游戏编程与设计作业10

    3D游戏编程与设计作业10 环境说明 Unity3D 导航与寻路 Agent 和 Navmesh 练习 Obstacle和Off-Mesh-Link练习 P&D 过河游戏智能帮助实现 状态图 ...

  7. 3D游戏编程与设计——游戏的本质章节作业与练习

    3D游戏编程与设计--游戏的本质章节作业与练习 18342138 郑卓民 3D游戏编程与设计--游戏的本质章节作业与练习 作业与练习: 游戏名称及简介: 游戏的随机性 游戏的玩法与目标 游戏的冲突 游 ...

  8. 3D 游戏编程与设计:第3次作业

    3D 游戏编程与设计:第3次作业 姓名:韩宝欣 学号:20331013 代码仓库:https://gitee.com/sse_20331013/3d-game.git 文章目录 3D 游戏编程与设计: ...

  9. 开始利用CSDN做学习笔记,从windows 游戏编程大师技巧和3D游戏编程大师开始

    利用两个月的空余时间将windows 游戏编程大师技巧和3D游戏编程大师技巧看了一遍. 第一遍读的并不深入,代码也没有仔细研究.特别是3D下册,基本只是草草浏览了一遍而已.这一遍是为了对整体有个印象和 ...

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

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

最新文章

  1. 16、设计模式-行为型模式-命令模式
  2. 借东西的小人阿莉埃蒂
  3. Linux内核常见FAQ
  4. WeChat报错navigateTo:fail can not navigateTo a tabbar page
  5. 一个娃娃竟然拍出50万......
  6. JavaScript中的call,apply,bind学习总结
  7. linux命令里的xz是干嘛的,linux xz命令详解
  8. 感应联动不是梦,穿透屏幕“闻”见花香你敢信?
  9. 前端实现街道地图_来自法国的注重保护个人隐私的开源地图
  10. 如何导入gradle版本不同的Android项目
  11. Android App Architecture使用详解
  12. IDL实现高分一号数据辐射定标TASK(二)
  13. 【27】Python100例基础练习题6
  14. php整数型转字符串,php如何将整数转为字符串
  15. 电工学习笔记————稳压二极管伏安特性
  16. 计算机二级office树的知识,计算机二级office选择题白话串讲--二叉树,是什么树?(1)...
  17. 多行文字省略(涵盖标点符号,中英文等复杂字符串)
  18. 双目相机:基于双目视觉的目标测距
  19. CSS3科技雷达扫描动画js特效
  20. matlab怎么导入程序出错,Matlab导入数据时出错!十分困扰!

热门文章

  1. 下载laravel框架
  2. 腾讯翻译君在线翻译怎么翻译整个文件_PDF文档如何直接翻译?有了这个逆天网站,3秒完成整个文件翻译...
  3. 在计算机英语中 input的意思是,计算机英语词汇解释
  4. [笔记]SD卡相关资料
  5. B站还有多久成为天涯
  6. 因子分析法基于matlab,因子分析matlab
  7. 嵌入式软件开发笔试面试知识点总结-ARM部分
  8. css学习25:设置文本样式
  9. ip地址切换批处理脚本
  10. oracle误删表恢复方法