改进飞碟(Hit UFO)游戏:

游戏截图:

1,作业要求
游戏内容要求:
1,按adapter模式设计图修改飞碟游戏
2,使它同时支持物理运动与运动学(变换)运动

2,设计思路
1,分析adapter模式
adapter模式的核心思想是让不同的实现类同时实现一个接口,其他类再用这个接口来实例化使得其他类不会因为接口不兼容而只能使用其中一个类。比如我们做一个游戏IO,它要有一个统一输入接口,能够兼容游戏手柄、键鼠、手机等多种输入设备。
adapter模式如图所示:

2,分析物理运动
刚体是一个组件。一个游戏对象加上刚体之后游戏引擎就会对其进行物理效果模拟。同时我们也可以给这个对象施加各种作用力,让它运动起来。
刚体有各种属性:
Mass:指定物体的质量
Drag:空气阻力,影响物体的移动速度和移动距离
Angular Drag:物体旋转时受到的空气阻力
Use Gravity:是否使用重力
Is Kinematic:是否动态
Interpolate:平滑方式
Collision Detection:碰撞检测
Freeze Position/Rotation :在三个轴上防止进行位置/旋转的变化
通过各种属性的设定,可以模拟现实中物体的物理效果。

3,具体设计
添加一个有关物理运动的类PhysicActionManager,实现在FirstSceneController类中能够由用户选择使用哪种运动方式来决定使用哪个动作管理类。题目要求使用adapter模式,即两个动作管理类应该同时实现一个接口,于是抽象出两个动作管理类应该在FirstSceneController类中使用的方法,作为一个接口IActionManager。这样就符合了题目要求。
具体而言,PhysicActionManager类也继承了SSActionManager类,复制CCActionManager类的代码,然后修改Update()和Start()方法,通知SSActionManager类它的子类是谁。
然后在SSActionManager类中添加一个属性flag,两个子类可以修改它,进而影响SSActionManager类中的Update()方法。
在FirstSceneManager类中修改动作管理器的类型为接口IActionManager,添加某些方法来影响IActionManager的具体实例。
另外,在DiskFactory中为新生成的对象添加刚体,在UserGUI中添加按钮代码给用户选择使用哪一种方式来使飞碟运动。
以上就是对前一次作业的修改设计。

3,部分代码
PhysicActionManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PhysicActionManager : SSActionManager, ISSActionCallback, IActionManager
{private FirstSceneControl sceneControl;private List<CCFlyAction> flys = new List<CCFlyAction>();private int diskNumber = 0;private List<SSAction> used = new List<SSAction>();private List<SSAction> free = new List<SSAction>();public void setDiskNumber(int dn){diskNumber = dn;}public int getDiskNumber(){return diskNumber;}public SSAction getSSAction(){SSAction action = null;if (free.Count > 0){action = free[0];free.Remove(free[0]);}else{action = ScriptableObject.Instantiate<CCFlyAction>(flys[0]);}used.Add(action);return action;}public void freeSSAction(SSAction action){foreach (SSAction a in used){if (a.GetInstanceID() == action.GetInstanceID()){a.reset();free.Add(a);used.Remove(a);break;}}}protected void Start(){sceneControl = (FirstSceneControl)Director.getInstance().current;sceneControl.actionManager = this;flys.Add(CCFlyAction.getCCFlyAction());base.flag = false;}private new void Update(){if (sceneControl.getGameState() == GameState.RUNNING){base.Update();}else{base.stopRigidbodyAction();}}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed, int intPram = 0, string strParm = null, Object objParm = null){if (source is CCFlyAction){diskNumber--;Singleton<DiskFactory>.Instance.freeDisk(source.gameObject);freeSSAction(source);}}public void startThrow(Queue<GameObject> diskQueue){foreach (GameObject i in diskQueue){runAction(i, getSSAction(), (ISSActionCallback)this);}}
}

SSActionManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;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>();protected bool flag = true;protected void Update(){foreach (SSAction action in waitingAdd){actions[action.GetInstanceID()] = action;}waitingAdd.Clear();foreach (KeyValuePair<int, SSAction> i in actions){SSAction value = i.Value;if (value.destroy){waitingDelete.Add(value.GetInstanceID());}else if (value.enable && flag){value.Update();}else if (value.enable && flag == false){value.FixedUpdate();}}foreach (int i in waitingDelete){SSAction ac = actions[i];actions.Remove(i);DestroyObject(ac);}}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 stopRigidbodyAction(){foreach (SSAction action in actions.Values){action.stopAction();}}
}

CCFlyAction.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CCFlyAction : SSAction
{float acceleration;float horizontalSpeed;Vector3 direction;float time;Rigidbody rigidbody;// Vector3 old;public static CCFlyAction getCCFlyAction(){CCFlyAction action =  ScriptableObject.CreateInstance<CCFlyAction>();return action;}public override void Start(){enable = true;acceleration = 9.8f;time = 0;// old = gameObject.transform.position;horizontalSpeed = gameObject.GetComponent<DiskData>().getSpeed();direction = gameObject.GetComponent<DiskData>().getDirection();rigidbody = gameObject.GetComponent<Rigidbody>();if (rigidbody){rigidbody.velocity = horizontalSpeed * direction;}}public override void Update(){if (gameObject.activeSelf){time += Time.deltaTime;transform.Translate(Vector3.down * acceleration * time * Time.deltaTime);transform.Translate(direction * horizontalSpeed * Time.deltaTime);clear();}}public override void FixedUpdate(){if (gameObject.activeSelf){clear();}}private void clear(){if (this.transform.position.y < -4){this.destroy = true;this.enable = false;this.callback.SSActionEvent(this);}}public override void stopAction(){if (rigidbody){rigidbody.velocity = Vector3.zero;rigidbody.useGravity = false;}}
}

FirstSceneManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FirstSceneControl : MonoBehaviour, ISceneControl, IUserAction {public IActionManager actionManager { set; get; }public ScoreRecorder scoreRecorder { set; get; }public Queue<GameObject> diskQueue = new Queue<GameObject>();private ActionMode actionMode = ActionMode.NOTSET;private int diskNumber = 0;private int currentRound = -1;private float time = 0;private GameState gameState = GameState.START;void Awake(){Director director = Director.getInstance();director.current = this;diskNumber = 10;this.gameObject.AddComponent<ScoreRecorder>();this.gameObject.AddComponent<DiskFactory>();scoreRecorder = Singleton<ScoreRecorder>.Instance;director.current.loadResources();}public void loadResources(){}private void Update(){if(actionMode == ActionMode.NOTSET || actionManager == null){return;}if(actionManager.getDiskNumber() == 0 && gameState == GameState.RUNNING){gameState = GameState.ROUND_FINISH;gameState = GameState.ROUND_FINISH;if(actionMode == ActionMode.PHYSIC){gameState = GameState.FUNISH;return;}if(currentRound == 2){gameState = GameState.FUNISH;currentRound = 0;return;}}if(actionManager.getDiskNumber() == 0 && gameState == GameState.ROUND_START){currentRound++;nextRound();actionManager.setDiskNumber(10);gameState = GameState.RUNNING;}if(time > 1 && gameState != GameState.PAUSE){throwDisk();time = 0;}else{time += Time.deltaTime;}}private void nextRound(){DiskFactory diskFactory = Singleton<DiskFactory>.Instance;for(int i = 0; i < diskNumber; i++){diskQueue.Enqueue(diskFactory.getDisk(currentRound, actionMode));}actionManager.startThrow(diskQueue);}void throwDisk(){if(diskQueue.Count != 0){GameObject disk = diskQueue.Dequeue();Vector3 pos = new Vector3(-disk.GetComponent<DiskData>().getDirection().x * 10, Random.Range(0f, 4f), 0);disk.transform.position = pos;disk.SetActive(true);}}public int getScore(){return scoreRecorder.score;}public GameState getGameState(){return gameState;}public ActionMode getActionMode(){return actionMode;}public void setGameState(GameState gameState){this.gameState = gameState;}public void setActionMode(ActionMode mode){actionMode = mode;if(actionMode == ActionMode.PHYSIC){this.gameObject.AddComponent<PhysicActionManager>();}else if(actionMode == ActionMode.KINEMATIC){this.gameObject.AddComponent<CCActionManager>();}}public void hit(Vector3 pos){RaycastHit[] hits = Physics.RaycastAll(Camera.main.ScreenPointToRay(pos));for(int i = 0; i < hits.Length; i++){RaycastHit hit = hits[i];if(hit.collider.gameObject.GetComponent<DiskData>() != null){scoreRecorder.record(hit.collider.gameObject);hit.collider.gameObject.transform.position = new Vector3(0, -5, 0);}}}
}

DiskFactory.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DiskFactory : MonoBehaviour {public GameObject diskPrefab;public List<DiskData> used = new List<DiskData>();public List<DiskData> free = new List<DiskData>();private void Awake(){diskPrefab = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/disk"), Vector3.zero, Quaternion.identity);diskPrefab.SetActive(false);}public GameObject getDisk(int round, ActionMode mode){GameObject disk = null;if(free.Count > 0){disk = free[0].gameObject;free.Remove(free[0]);}else{disk = GameObject.Instantiate<GameObject>(diskPrefab, Vector3.zero, Quaternion.identity);disk.AddComponent<DiskData>();}if(mode == ActionMode.PHYSIC && disk.GetComponent<Rigidbody>() == null){disk.AddComponent<Rigidbody>();}int start;switch (round){case 0: start = 0; break;case 1: start = 100; break;default: start = 200; break;}int selectColor = Random.Range(start, round * 499);round = selectColor / 250;DiskData diskData = disk.GetComponent<DiskData>();Renderer renderer = disk.GetComponent<Renderer>();Renderer childRenderer = disk.transform.GetChild(0).GetComponent<Renderer>();float ranX = Random.Range(-1, 1) < 0 ? -1.2f : 1.2f;Vector3 direction = new Vector3(ranX, 1, 0);switch (round){case 0:diskData.setDiskData(new Vector3(1.35f, 1.35f, 1.35f), Color.white, 4.0f, direction);renderer.material.color = Color.white;childRenderer.material.color = Color.white;break;case 1:diskData.setDiskData(new Vector3(1f, 1f, 1f), Color.gray, 6.0f, direction);renderer.material.color = Color.gray;childRenderer.material.color = Color.gray;break;case 2:diskData.setDiskData(new Vector3(0.7f, 0.7f, 0.7f), Color.black, 8.0f, direction);renderer.material.color = Color.black;childRenderer.material.color = Color.black;break;}used.Add(diskData);diskData.name = diskData.GetInstanceID().ToString();disk.transform.localScale = diskData.getSize();return disk;}public void freeDisk(GameObject disk){DiskData temp = null;foreach (DiskData i in used){if (disk.GetInstanceID() == i.gameObject.GetInstanceID()){temp = i;}}if (temp != null){temp.gameObject.SetActive(false);free.Add(temp);used.Remove(temp);}}
}

UserGUI.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;public class UserGUI : MonoBehaviour {private IUserAction action;bool isFirst = true;GUIStyle red;GUIStyle black;bool pause_flag = true;void Start () {action = Director.getInstance().current as IUserAction;black = new GUIStyle("button");black.fontSize = 20;red = new GUIStyle();red.fontSize = 30;red.fontStyle = FontStyle.Bold;red.normal.textColor = Color.red;red.alignment = TextAnchor.UpperCenter;}private void OnGUI(){if (action.getGameState() == GameState.FUNISH){GUI.Label(new Rect(Screen.width / 2 - 100, Screen.height / 2 - 150, 200, 100), action.getScore() >= 30 ? "你胜利了" : "你失败了", red);if(GUI.Button(new Rect(Screen.width / 2 - 60, Screen.height / 2 - 50, 120, 40), "重新开始", black)){SceneManager.LoadScene("DiskAttack");}return;}Rect rect = new Rect(Screen.width / 2 - 100, 0, 200, 40);Rect rect2 = new Rect(Screen.width / 2 - 60, 60, 120, 40);if (Input.GetButtonDown("Fire1") && action.getGameState() != GameState.PAUSE){Vector3 pos = Input.mousePosition;action.hit(pos);}if (!isFirst){GUI.Label(rect, "你的分数: " + action.getScore().ToString(), red);}else{GUIStyle blackLabel = new GUIStyle();blackLabel.fontSize = 16;blackLabel.normal.textColor = Color.black;GUI.Label(new Rect(Screen.width / 2 - 250, 120, 500, 200), "一共3个关卡,每一个关卡有10个飞碟,飞碟" +"的颜色是不一样的\n如果攻击白色的飞碟,你会得到1分。如果攻击灰色的飞碟\n" +"则会得到2分,如果攻击黑色的飞碟(速度最快),你会得到4分。\n" +"游戏结束时得到超过30分就胜利了!", blackLabel);}if (pause_flag){if (action.getGameState() == GameState.RUNNING && GUI.Button(rect2, "暂停", black)){action.setGameState(GameState.PAUSE);}else if (action.getGameState() == GameState.PAUSE && GUI.Button(rect2, "继续", black)){action.setGameState(GameState.RUNNING);}}if(action.getActionMode() == ActionMode.NOTSET){if(GUI.Button(new Rect(Screen.width / 2 - 60, 0, 120, 40), "物理模式", black)){action.setActionMode(ActionMode.PHYSIC);pause_flag = false;}if (GUI.Button(rect2, "运动学模式", black)){action.setActionMode(ActionMode.KINEMATIC);}}else if (isFirst && GUI.Button(rect2, "开始", black)){isFirst = false;action.setGameState(GameState.ROUND_START);}if(!isFirst && action.getGameState() == GameState.ROUND_FINISH && GUI.Button(rect2, "下一关卡", black)){action.setGameState(GameState.ROUND_START);}}
}

3D游戏设计作业5:改进飞碟(Hit UFO)游戏相关推荐

  1. 3D游戏设计作业(四)

    一.下载 Fantasy Skybox FREE, 构建自己的游戏场景 1.下载Fantasy Skybox   2.创建material   3.将下载好的素材拖动到material中  4.显示效 ...

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

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

  3. 顶级游戏设计大师谈如何成为一名游戏设计师![转]

    顶级游戏设计大师谈如何成为一名游戏设计师! 作者:chris crawford 是计算机游戏设计界的元老,至今已经设计.发布了14款值得称道的游戏. 阿,我年轻的朋友们,你们想成为游戏设计师,所以来问 ...

  4. HTML5 canvas 游戏设计:创建一个经典的魔塔游戏

    整个项目都已经开源,项目地址:https://github.com/m8705/MAGIC-TOWER-JS 注:这是我高中时候的作品,BUG 很多,已经不再更新了.下载项目到本地就能玩. 前言 魔塔 ...

  5. 游戏设计小议 番外篇一 电脑游戏的通用层次结构

    本篇对当今电脑游戏层次结构特点进行一个总结. 如今的游戏种类丰富多样,以一种层次结构显然无法全面概况,不过这个总结可以为游戏的共性提供参考以便指导今后的编程过程. 那么,按照层次关系自下而上,一个游戏 ...

  6. c语言 2d游戏设计教程,C语言编写简单2D游戏

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 为了实现鼠标控制飞机飞行,当鼠标一移动,获取鼠标X的坐标,在消息处理函数中加入下列代码: x = LOWORD(lParam); 如果鼠标的X坐标大于窗口 ...

  7. 顶级游戏设计大师谈如何成为一名游戏设计师!

    看了这篇文章,觉得和自己的现状非常现实,颇有感悟 作者:chris crawford 是计算机游戏设计界的元老,至今已经设计.发布了14款值得称道的游戏. 阿,我年轻的朋友们,你们想成为游戏设计师,所 ...

  8. 基于python的2048游戏设计_用python写一个2048游戏

    self.randomGenerateNumberself.randomGenerateNumber 然后,当玩家按下方向键(↑↓←→)时,这个二维列表要根据玩家的操作指令进行更新,主要分为两个部分: ...

  9. 3D游戏编程 作业六 打飞碟改进

    前言 这次的任务是实现物理学运动,结果我发现在上次作业中我全给实现了. 所以这次只要简单实现adapter就行了. model脚本:github 原版代码:上次作业 一.任务要求 二. 项目展示 我的 ...

最新文章

  1. Java一个线程能否结束另一个永不停止的线程
  2. 教师资格证考试计算机知识题库,教师资格证考试题库
  3. C++学习笔记(五)--指针、NULL、引用
  4. 探索未知种族之osg类生物---呼吸分解之更新循环一
  5. Python基础—08-函数使用(02)
  6. GDG Xian: 假如我是一个浏览器
  7. 苹果多款产品降价:iPhone XS系列降价500元 14天内可退差价
  8. 程序设计与算法----分治之归并排序
  9. 微软 Edge bug 导致黑客窃取用户在任意站点的机密信息,颁发2万美元奖金
  10. 垂直的SeekBar:VerticalSeekBar
  11. 局域网限制网速软件_五款大学生小众有用软件,学长亲荐
  12. PFC颗粒流 指定文件路径输出方法
  13. 各大IT公司经典面试题总结
  14. sqlserver 汉字转拼音(转载)
  15. 笔记本自动打开计算机,笔记本电脑自动开机是什么原因
  16. android设计模式面试,从外包公司到今日头条offer,吐血整理
  17. 如何在电脑上安装虚拟机和系统。全网最全教程,不接受反驳。
  18. arduino数字端口输出电压可驱动多大继电器呢_单片机实例分享,自制数字示波器...
  19. Interactive natural language question answering over knowledge graphs论文导读
  20. StringUtil方法全集

热门文章

  1. 手写 bind 函数
  2. php stream_socket_sendto,socket_sendto()
  3. password authentication failed for user “##““
  4. 无向图邻接矩阵的存储C语言,使用邻接矩阵存储无向图
  5. Ubuntu系统目录
  6. 做新时代弄潮儿!文创产业智能化的融合与颠覆
  7. java实现潜艇大战游戏_java潜艇大战游戏源码项目
  8. 多可文档管理系统下载文件的几种方式
  9. Python爬虫——京东商品信息 前期准备
  10. CSS 3实战(全彩印刷)