3D游戏编程作业4 您所在的位置:网站首页 trial游戏 3D游戏编程作业4

3D游戏编程作业4

2023-06-04 22:43| 来源: 网络整理| 查看: 265

与游戏世界交互 && 物理系统与碰撞

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

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

博客地址:Github 博客

项目地址:Gitee 博客

作业4:Hit UFO 打飞碟:哔哩哔哩_bilibili

项目文档 项目配置过程

将 Assets 文件夹下的文件全拖入新建项目后,点击新导入的 Scene/ 中的 Hit UFO 场景,开始游戏后即可打开项目。

游戏规则 按下 Space 空格键发射飞碟,按下鼠标左键点击飞碟。 在飞碟消失前,点击飞碟得分,飞碟消失则扣分,不同难度不同颜色的飞碟分数不同。 游戏共有 10 个 Round ,每个 Round 共有 10 次 Trial ,游戏难度随 Round 增加。 游戏胜利的条件为:玩家在完成 10 个 Round (即 100 次 Trial)后,其分数非负。其余所有的情况都视为**游戏失败* 工厂模式、Adapter、 MVC

本次项目依然按照 MVC 框架实现,并且根据工厂模式、适配器模式进行面向对象设计。

Model GameModel :裁判类,管理游戏关卡和判断游戏胜负。 UFOModel :飞碟实体,初始化飞碟的属性、速度,提供设置函数。 View GameGUI :显示轮次、得分、游戏操作按钮,展示游戏画面。 Controller Ruler :判断游戏状态,控制飞碟的各种特性(位置、方向、得分、大小)。 Director :导演类,控制场景切换。 GameController :场景控制类,控制游戏场景。 UFOFactory :带有缓存的飞碟工厂,负责创建、生成飞碟对象。 Interface:适配器模式的接口,用于重载 SetAction 方法,设置游戏对象的运动学模型。 PhysicActionManager:对物体添加重力和施加 Impulse,实现动力学模型。 CCActionManager:使用刚体实现运动学转换运动模型。 Editors UFOEditor :UFO 游戏对象的编辑器(如果摄像机位置不同,可以通过更改脚本属性来设置飞碟的初始位置) 带缓存的工厂模式

对象的新建和销毁在游戏中的开销是巨大的,一个游戏中有众多的对象,我们应该使用对象池,带缓存的工厂模式,降低对象的新建和销毁开销。在本次项目中,我使用了带缓存的工厂模式管理不同飞碟的生产和回收,且该工厂是场景单实例的:

public class UFOFactory { public enum Color { Red, Green, Blue, Yellow, Purple } private static UFOFactory factory; // 单例 // 正在使用的飞碟 private List occupied = new List(); // 未被使用的飞碟 private List released = new List(); public static Vector3 invisible = new Vector3(0, -10, 0); // 单例 public static UFOFactory GetInstance() { return factory ?? (factory = new UFOFactory()); } // 获取特定颜色的飞碟 public GameObject Get(Color color) { GameObject ufo; // 决定是否生产 if (released.Count == 0) { ufo = Object.Instantiate(Resources.Load("Prefabs/UFO"), invisible, Quaternion.identity); ufo.AddComponent(); } else { ufo = released[0]; released.RemoveAt(0); } // 设置颜色 Material material = Object.Instantiate(Resources.Load("Materials/" + color.ToString("G"))); ufo.GetComponent().material = material; occupied.Add(ufo); return ufo; } // 回收飞碟对象 public void Put(GameObject ufo) { var rigidbody = ufo.GetComponent(); rigidbody.velocity = Vector3.zero; rigidbody.angularVelocity = Vector3.zero; rigidbody.useGravity = false; ufo.transform.position = invisible; occupied.Remove(ufo); released.Add(ufo); } }

在 UFOFactory 工厂模式中,使用两个列表来分别维护正在使用和未被使用的飞碟对象。使用 GetInstance 静态方法实现单例模式,使用 Get 获取特定颜色的飞碟对象和使用 Put 回收飞碟对象。

实体

UFO 实体 UFOModel 继承于 MonoBehaviour 类,管理飞碟对象的初始位置、初始速度和缩放比例,其具体内容如下。

public class UFOModel : MonoBehaviour { public int score; public static Vector3 startPosition = new Vector3(-4, -2, -10); public static Vector3 startSpeed = new Vector3(0.5f, 1.0f, 1.0f); public static Vector3 localScale = new Vector3(1, 0.05f, 1); private int leftOrRight; private float speedScale = 1; private int id; public Vector3 GetSpeed() { Vector3 velocity = (this.speedScale) * startSpeed; velocity.x *= leftOrRight; return velocity; } public int GetId() { return this.id; } public void SetSpeedScale(float scale) { this.speedScale = scale; } public void SetSide(int side) { Vector3 location = startPosition; location.x *= side; location.y += GetId() * 0.1f; transform.position = location; leftOrRight = side; } public void SetLocalScale(float x, float y, float z) { Vector3 scale = localScale; scale.x *= x; scale.y *= y; scale.z *= z; transform.localScale = scale; } public void SetLocation(float x, float y, float z) { startPosition.x = x; startPosition.y = y; startPosition.z = z; } public void SetId(int id) { this.id = id; } 控制器

在场景控制器 GameController 的 Update 函数中,监听用户输入,如鼠标左键或空格键,并且做出相应的动作,触发击中飞碟或生成飞碟等等:

void Update() { var invisibleUFOs = UFOs.FindAll(x => (x.transform.position.y = 10f)); foreach (var ufo in invisibleUFOs) { OnMissUFO(ufo); } if (model.game == GameState.Gamming) { if (model.scene == SceneState.Shooting && Input.GetButtonDown("Fire1")) { // 光标拾取单个游戏对象 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);// 构建射线 if (Physics.Raycast(ray, out RaycastHit hit) && hit.collider.gameObject.tag == "UFO") { OnHitUFO(hit.collider.gameObject); // 点击飞碟 } } // 发射飞碟 if (model.scene == SceneState.Waiting && Input.GetKeyDown("space")) { model.scene = SceneState.Shooting; model.NextTrial(); // 若玩家满足胜利条件,按下空格不发射飞碟 if (model.game == GameState.Win) { return; } UFOs.AddRange(ruler.GetUFOs()); } if (UFOs.Count == 0) { model.scene = SceneState.Waiting; } } }

由于 GameController 源码较长,只展示其中 update() 部分。

通过控制器沟通不同的场景,但还需要实现 Ruler 类来进行飞碟的发射和调用工厂模式:

public class Ruler { private readonly int currentRound; private System.Random random; private static Array colors = Enum.GetValues(typeof(UFOFactory.Color)); private static int[] UFOCount = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // 数量池子 private static int[] score = { 1, 2, 5, 5, 10 }; // 不同颜色对应不同分数,速度,大小 private static float[] speed = { 0.2f, 0.4f, 0.6f, 0.8f, 1.0f }; private static float[] scale = { 1.8f, 1.4f, 1f, 0.8f, 0.6f }; private IActionManager actionManager; // 运动学模型 public Ruler(int currentRound, IActionManager actionManager) { this.currentRound = currentRound; this.random = new System.Random(); this.actionManager = actionManager; // 设置运动学模型 } public int GetUFOCount() { return UFOCount[currentRound]; } public List GetUFOs() { List ufos = new List(); var index = random.Next(colors.Length); // var color = (UFOFactory.Color)colors.GetValue(index); // 随机生成颜色 var count = GetUFOCount(); // 当前 Round 下飞碟产生数 for (int i = 0; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有