改进飞碟(Hit UFO)游戏

游戏内容要求

  1. 按adapter模式设计图修改飞碟游戏
  2. 使它同时支持物理运动与运动学(交换)运动

编程实践

本次作业直接在上一次打飞碟游戏的基础上增加adapter设计模式(增加一个内含PhysisActionManagerCCActionManager接口的ActionManagers类),提供一个运动的统一接口,根据玩家的具体操作再决定是调用物理运动类还是运动学动作管理器类。也就是游戏同时存在两个飞碟运动模式,支持物理运动和运动学互相切换

  • Adapter(适配器)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。做法是将类自己的接口包裹在一个已存在的类中。有时也称为包装样式/包装。

本次作业采用的Adapter模式属于对象适配器模式,即adapter类持有不同的动作管理器对象,并实现对应的想提供的目标接口

本次游戏的结构UML图如下:

玩家切换运动模式的方法是在游戏界面点击鼠标右键,但并不会马上中断游戏切换运动模式,而是在下一个trail开始时进行切换

动作接口

首先在原来的SceneController类中再定义一个统一的动作接口(模板类),包含了物理运动和运动学动作管理器类都需要实现的方法addForceOnUFO(GameObject UFO),适配器类Adapter继承该接口。

  public interface IActionManager{void addForceOnUFO(GameObject UFO);}

用户接口

当用户接口类UserInterface中的Update()方法检测到鼠标右键被按下时,调用方法切换动作管理器。修改后的UserInterfaceUpdate()方法如下:

    // Update is called once per framevoid Update () {//检测鼠标点击(左键)if (Input.GetMouseButtonDown(0)){Vector3 mousePos = Input.mousePosition;action.hitUFO(mousePos);}//检测用户按下空格if (Input.GetKeyDown(KeyCode.Space)){action.launchUFO();}//检测鼠标右键点击if (Input.GetButtonDown("Fire2")){action.switchActionModeNextRound();}}

相应地,在SceneController类的IUserAction接口中增加该switchActionInNextRound()方法的声明:

    public interface IUserAction{void launchUFO();void hitUFO(Vector3 mousePos);void switchActionModeNextRound();}

适配器类

接着编写最重要的适配器类UFOActionAdapter,该类需要实现IActionManager接口(实现不同模式的addForceOnUFO(GameObject UFO)方法的调用),并且持有PhysisActionManagerCCActionManager对象,用一个整数型成员变量WhichActionManager来记录当前使用的是哪一个动作管理器,值为0表示当前处于物理运动模式,值为1表示当前处于运动学动作管理器模式,只需要WhichActionManager = 1-WhichActionManager就能实现切换运动模式。代码如下:

    public class UFOActionAdapter : IActionManager{private PhysisActionManager physisActionManager;private CCActionManager ccActionManager;int whichActionManager = 0; // 0 -> PhysisActionManager, 1 -> CCActionManagerpublic UFOActionAdapter(){physisActionManager = PhysisActionManager.getInstance();ccActionManager = CCActionManager.getInstance();}public void switchActionMode(){whichActionManager = 1 - whichActionManager;}public void addForceOnUFO(GameObject UFO){if(whichActionManager == 0){physisActionManager.addForce(UFO);}else{ccActionManager.addForce(UFO);}}}

在SceneController中使用bool型成员变量switchActionManager来标记是否需要切换运动模式,初始化为false,表示初始不做模式切换时游戏处于物理运动模式。代码如下:

private bool switchActionManager = false;

如果switchActionModeNextRound()方法被调用,则将switchActionManager置为true:

    public void switchActionModeNextRound(){myStatusCtrl.showSwitchText();switchActionManager = true;}

并且在每一轮trail开始时检测switchActionManager是否为true,若为true则切换运动模式并将switchActionManager重置为false:

    public void launchUFO(){//每次发射之前清0分数if (switchActionManager){switchActionManager = false;myUFOCtrl.switchActionManager();}myStatusCtrl.resetScore();myUFOCtrl.launchUFO();}

物理运动管理器类

定义物理运动管理器,主要实现给游戏对象添加一个xyz轴方向上都是在一定数值范围内随机生成的瞬时力,代码如下:

    public class PhysisActionManager{private SceneController scene;private static PhysisActionManager instance;private PhysisActionManager(){scene = SceneController.getInstance();}public static PhysisActionManager getInstance(){if (instance == null) instance = new PhysisActionManager();return instance;}private Vector3 getRandomForce(){int x = UnityEngine.Random.Range(-30, 31);int y = UnityEngine.Random.Range(30, 41);int z = UnityEngine.Random.Range(20, 31);float t = 0.7f + scene.getTrailNum() / 20;return new Vector3(x, y, z) * t;}public void addForce(GameObject UFO){Vector3 force = getRandomForce();UFO.GetComponent<Rigidbody>().useGravity = true;UFO.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);}}

运动学运动管理器

运动学管理器模式下的物体不使用重力属性,即把游戏对象的刚体属性useGravity设为false,并且给刚体一个初速度使其沿某个方向运动,代码如下:

    public class CCActionManager{private SceneController scene;private static CCActionManager instance;private CCActionManager(){scene = SceneController.getInstance();}public static CCActionManager getInstance(){if (instance == null) instance = new CCActionManager();return instance;}public void addForce(GameObject UFO){// 控制飞碟向某个随机方向持续移动UFO.GetComponent<Rigidbody>().useGravity = false;UFO.GetComponent<Rigidbody>().velocity = new Vector3(5, 15, 5);}}

飞碟控制类

飞碟控制类UFOController中需要定义一个适配器成员对象,用来在launchUFOs(roundNum)函数里(发射飞碟时)调用不同模式下的addForceOnUFO(GameObject)方法。修改后的UFOController类如下:

using CarolSum.com;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class UFOController : MonoBehaviour {//预设文件public GameObject PlaneItem, LauncherItem, ExplosionItem;public Material greenMat, redMat, blueMat;private GameObject plane, launcher, explosion;private SceneController scene;private UFOActionAdapter adapter;//发射每一个飞碟的时间间隔private const float LAUNCH_GAP = 0.1f;// Use this for initializationvoid Start () {scene = SceneController.getInstance();scene.setUFOController(this);plane = Instantiate(PlaneItem);launcher = Instantiate(LauncherItem);explosion = Instantiate(ExplosionItem);adapter = new UFOActionAdapter();}// Update is called once per framevoid Update () {UFOFactory.getInstance().detectLandingUFOs();}public void launchUFO(){int trailNum = scene.getTrailNum() > 3 ? 3 : scene.getTrailNum();Debug.Log("发射!");if (!UFOFactory.getInstance().isLaunching()){StartCoroutine(launchUFOs(trailNum));}}IEnumerator launchUFOs(int roundNum){for(int i = 0; i<roundNum; i++){GameObject UFO = UFOFactory.getInstance().getUFO();UFO.transform.position = launcher.transform.position;UFO.GetComponent<MeshRenderer>().material = getMaterial(scene.getTrailNum());adapter.addForceOnUFO(UFO);//每隔LAUNCH_GAP时间发射一个UFOyield return new WaitForSeconds(LAUNCH_GAP);}}public void switchActionManager(){adapter.switchActionMode();}public void hitUFO(Vector3 mousePos){Ray ray = Camera.main.ScreenPointToRay(mousePos);RaycastHit hit;if(Physics.Raycast(ray, out hit)){if (hit.collider.gameObject.tag.Equals("UFO")){createExplosion(hit.collider.gameObject.transform.position);scene.addScore();UFOFactory.getInstance().RecyclingUFO(hit.collider.gameObject);}}}private void createExplosion(Vector3 position){explosion.transform.position = position;explosion.GetComponent<ParticleSystem>().GetComponent<Renderer>().material = getMaterial(scene.getTrailNum());explosion.GetComponent<ParticleSystem>().Play();}private Material getMaterial(int roundNum){switch(roundNum % 3){case 0:return redMat;case 1:return greenMat;case 2:return blueMat;default:return redMat; }}}

游戏各预制的属性设置如下:
Canvas:
Explosion:

Launcher:

Plane:

UFO:

Main Camera挂载

Empty对象挂载

最终运行效果如下:

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

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

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

  2. 3D游戏编程与设计作业09

    3D游戏编程与设计作业09 UGUI基础 画布 基础概念 测试渲染模式 UI布局基础 基本概念 锚点练习 UI组件与元素 基本概念 Mask练习 动画练习 富文本测试 简单血条 血条(Health B ...

  3. 3D游戏编程与设计作业4-Skybox_牧师与魔鬼进阶版

    基本操作演练 下载Fantasy Skybbox FREE,构建自己的游戏场景 直接在上一次作业的Priests and Devils游戏场景中添加天空盒和地形构建场景.首先在Unity Assets ...

  4. 3D游戏编程与设计作业六

    改进飞碟(Hit UFO)游戏 要求 按 adapter模式 设计图修改飞碟游戏 使它同时支持物理运动与运动学(变换)运动 实现 原项目:3D编程与游戏设计作业五 仅仅对其中的一些类进行改动就能实现. ...

  5. 3D游戏编程与设计作业2-太阳系-Priests and Devils

    简答题 一.游戏对象运动的本质是什么?   游戏对象的本质是游戏对象每一帧的由空间属性决定的坐标随时间发生改变,其中空间属性包括对象transform属性中的空间位置Position属性.旋转角度Ro ...

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

    游戏分类与热点探索 使用思维导图描述游戏的分类.(游戏分类方法特别多) 所使用的思维导图绘图工具为mindmaster. 结合手机游戏市场的下载量与排名等数据,结合游戏分类图,描述游戏市场的热点. 华 ...

  7. 3D游戏编程与设计作业四

    第四次3D编程作业 本次作业源代码链接:点击此处进行跳转 一. 基本操作演练 下载Fantasy Skybox Free,构建自己的游戏场景 场景总览图: 游玩截图: 写一个简单的总结,总结游戏对象的 ...

  8. 3D游戏编程与设计作业三

    第三次3D编程作业 本次作业源代码链接:点击此处进行跳转 1. 简答并用程序验证 游戏对象运动的本质是什么 游戏对象空间属性(坐标.旋转度.大小)的变化 请用三种以上方法,实现物体的抛物线运动 此处我 ...

  9. 3D游戏编程与设计作业4——使用skybox构建游戏场景

    步骤1: 首先下载支持使用Fantacy Skybox FREE 的Unity版本(2021.3) 步骤2:打开unity store, 搜索Fantacy Skybox FREE 并进行下载 步骤3 ...

最新文章

  1. strlen() sizeof()
  2. C++ 性能剖析 (四):Inheritance 对性能的影响
  3. 5 随窗口改变大小_C4D默认界面两个关于坐标轴的窗口有什么区别
  4. 浙江省高校计算机等级考试三级考什么容易,浙江省高校计算机等级考试大纲(三级)(3)...
  5. 专业的在线ps照片处理网页源码
  6. java url utf 8_java中文乱码解决之道(八)—–解决URL中文乱码问题
  7. 女人离婚后不要孩子,你怎么看?
  8. 数据分析中常用的数据模型
  9. C#判断文字是否为汉字
  10. php多进程结合Linux利器split命令实现把大文件分批高效处理
  11. matlab difittool,matlab工具箱下载安装和使用方法的汇总|Toolbox 大全
  12. qtableview 查询_QTableView 操作SQLite
  13. I don't know what to say 事件的 NPM 包中奖名单,有你在用的吗?
  14. 腾讯地图实现微信小程序地图定位教程
  15. Xposed框架动态调试第三方APP—实战演示
  16. 【老生谈算法】matlab实现RSA算法源码——RSA算法
  17. 【genius_platform软件平台开发】第九十四讲:int64_t的格式化问题(lld和PRId64)
  18. 重新定义未来的汽车芯片角色 拼算力只是第一步
  19. SAP schema增强
  20. 广州尚顶网络科技有限公司二维码防伪防窜系统

热门文章

  1. IM 协议 IMPP、PRIM、SIMPLE、XMPP
  2. 电阻、电感、电容、电子元件认识
  3. VE和C-5A巨型飞机
  4. 计算机二级python基本操作题(一)
  5. 关于段错误(Segfault at 8 ip 00sxsfsestewetst sp 003skle9lsnxse09.....)问题的处理
  6. HTML实战案例6:制作阿里巴巴用户注册页面
  7. 【图像分类】2018-CBAM ECCV
  8. 原型模式(Prototype Pattern)
  9. n个点坐标解三角形个数
  10. 自动驾驶 l5 ai_强AI和弱AI的真实故事以及适用于自动驾驶汽车的信息