飞碟游戏改进
这次作业在上一次打飞碟游戏的基础上增加了adapter设计模式,用来统一物理运动和运动学动作管理器的接口,使得游戏可以动态改变飞碟的行为,同时支持物理运动和运动学变换,具有更高的可扩展性。
适配器模式
在设计模式中,适配器模式(英语:adapter pattern)有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类能在一起工作,做法是将类自己的接口包裹在一个已存在的类中。
在这个游戏中我采用对象适配器模式,adapter类持有不同的动作管理器对象,并实现想暴露的接口,这样做使用成本更低且更加灵活。具体结构可看UML图。
UML图
关键代码解释
动作管理器统一接口
首先定义我希望得到的动作接口
public interface IActionManager
{
void addForceOnUFO(GameObject UFO);
}
适配器类
UFOActionAdapter 类实现了上面定义的接口并且分别持有PhysisActionManager 和CCActionManager 的单例对象。whichActionManager 用来表示当前使用的动作管理器是哪一个。
public class UFOActionAdapter : IActionManager
{
private PhysisActionManager physisActionManager;
private CCActionManager ccActionManager;
int whichActionManager = 0; // 0 -> CCActionManager, 1 -> PhysisActionManager
public UFOActionAdapter()
{
physisActionManager = PhysisActionManager.getInstance();
ccActionManager = CCActionManager.getInstance();
}
public void switchActionMode()
{
whichActionManager = 1 - whichActionManager;
}
public void addForceOnUFO(GameObject UFO)
{
if(whichActionManager == 1)
{
physisActionManager.addForce(UFO);
}
else
{
ccActionManager.addForce(UFO);
}
}
}
物理运动管理器
PhysisActionManager主要给游戏对象刚体添加一个一定范围内随机生成的力,并且模式为Impulse模式,表示一个瞬时的力。
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;
}
public void addForce(GameObject UFO)
{
Vector3 force = getRandomForce();
UFO.GetComponent<Rigidbody>().useGravity = true;
UFO.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);
}
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;
}
}
运动学运动管理器
CCActionManager把游戏对象刚体属性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);
}
}
用户接口
UserInterface类的Update方法中检测鼠标右键,当被按下的时候切换动作管理器。
if (Input.GetButtonDown("Fire2"))
{
action.switchActionInNextRound();
}
我们应该是等到下一个trial开始的时候才执行动作管理器的更改(如果需要更改的话),这里我在场记中用一个成员变量来标记是否需要更改,在控制发射飞碟之前再根据这个值来执行修改。代码如下:
public void switchActionInNextRound()
{
myStatusCtrl.showSwitchText();
switchActionManager = true;
}
public void launchUFO()
{
if (switchActionManager)
{
switchActionManager = false;
myUFOCtrl.switchActionManager();
}
//每次发射之前清0分数
myStatusCtrl.resetScore();
myUFOCtrl.launchUFO();
}
最终效果
视频演示地址如下:https://www.bilibili.com/video/av22511301/
所有代码见github:https://github.com/CarolSum/Unity3d-Learning/tree/master/hw5