- 游戏内容要求:
- 游戏有 n 个 round,每个 round 都包括10 次 trial;
- 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
- 每个 trial 的飞碟有随机性,总体难度随 round 上升;
- 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
- 游戏的要求:
- 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
- 近可能使用前面 MVC 结构实现人机交互与游戏模型分离
- 必须使用对象池管理飞碟对象。
- 建议使用物理引擎管理飞碟飞行路径。
对象池:
对象池(Object Pool)是一种用于高效管理和复用对象的设计模式,特别是在需要频繁创建和销毁大量相似对象的场景中(如子弹、敌人、特效等)。其核心思想是:当你不再需要一个对象时,并不是销毁它,而是将它返回池中,以便以后重用,避免了反复的内存分配和垃圾回收的开销,从而提高性能。
伪代码如下:
class ObjectPool:
// 对象池的构造函数,初始化池,设定池的大小和对象类型
function initialize(prefab, initialSize):
pool = empty list
this.prefab = prefab // 对象的预设(或模板)
// 填充池
for i from 1 to initialSize:
obj = createNewObject(prefab) // 创建一个新的对象
obj.setActive(false) // 初始对象不活动(不显示)
pool.add(obj)
// 从池中获取一个对象
function getObject():
// 查找一个未激活的对象
for obj in pool:
if obj.isActive() == false:
obj.setActive(true) // 激活对象
return obj
// 如果池中没有可用对象,则创建新对象
newObj = createNewObject(prefab)
pool.add(newObj)
return newObj
// 将一个对象归还到池中
function returnObject(obj):
obj.setActive(false) // 禁用对象
// 此时对象会被池重新管理,等待下次使用
// 创建一个新的对象
function createNewObject(prefab):
// 根据预设(或模板)创建新对象
return new Object(prefab)
游戏代码实现:
(一)动作类和动作管理器
在上一个游戏框架,运动动力学基础上增加物理刚体运动:
物体添加刚体属性后,本身就有了重力,只需要一个水平方向的初速度。
用物理刚体实现的飞碟动作类和飞碟动作管理类如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//飞碟动作类(物理刚体运动)
public class PhysicFlyAction : SSAction
{
public float speedX;
public static PhysicFlyAction GetSSAction(float x) {
PhysicFlyAction action = ScriptableObject.CreateInstance<PhysicFlyAction>();
action.speedX = x;
return action;
}
// Start is called before the first frame update
public override void Start()
{
gameObject.GetComponent<Rigidbody>().isKinematic = false;
gameObject.GetComponent<Rigidbody>().velocity = new Vector3(speedX * 10, 0, 0);
gameObject.GetComponent<Rigidbody>().drag = 1;
}
// Update is called once per frame
public override void Update()
{
if (this.transform.gameObject.activeSelf == false) {
this.destroy = true;
this.callback.SSActionEvent(this);
return;
}
Vector3 vec3 = Camera.main.WorldToScreenPoint (this.transform.position);
if (vec3.x < -100 || vec3.x > Camera.main.pixelWidth + 100 || vec3.y < -100 || vec3.y > Camera.main.pixelHeight + 100) {
this.destroy = true;
this.callback.SSActionEvent(this);
return;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//(物理刚体)动作管理器
//Adapter模式
public class PhysicActionManager : SSActionManager, IActionCallback, IActionManager
{
public RoundController sceneController;
public PhysicFlyAction action;
public DiskFactory factory;
// Start is called before the first frame update
protected new void Start()
{
sceneController = (RoundController)SSDirector.getInstance().currentSceneController;
sceneController.actionManager = this as IActionManager;
factory = Singleton<DiskFactory>.Instance;
}
//Update is called once per frame
protected new void Update(){}
public void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Completed,
int intParam = 0,
string strParam = null,
Object objectParam = null) {
factory.FreeDisk(source.transform.gameObject);
}
public override void MoveDisk(GameObject disk) {
action = PhysicFlyAction.GetSSAction(disk.GetComponent<DiskAttributes>().speedX);
RunAction(disk, action, this);
}
public void Fly(GameObject disk) {
MoveDisk(disk);
}
public int RemainActionCount() {
return actions.Count;
}
}
(二)控制器类
(三)用户接口和UI
Github地址:fang2368/mycode