改进飞碟(Hit UFO)游戏
要求
- 按 adapter模式 设计图修改飞碟游戏
- 使它同时支持物理运动与运动学(变换)运动
实现
原项目:3D编程与游戏设计作业五
仅仅对其中的一些类进行改动就能实现。
飞碟预设
由于要求支持物理运动,因此飞碟的预设需要在原来的基础上加上刚体:
Adapter的实现
adapter是通过不同的状态选择不同的接口,在本作业中是选择不同的动作实现方式(物理/运动学),发现与之前的flyActionController的功能类似,因此把它改写成Adapter:
public class Adapter : SSActionManager {
public DiskFlyAction fly;
public PhysisFlyAction fly_;
public void DiskFly(GameObject disk, int mode, mes information) {
int leftOrRight = 1;
if (disk.transform.position.x > 0){
leftOrRight = -1;
}
if(mode == 2){
fly = DiskFlyAction.GetSSAction(leftOrRight, information.angle, information.speed);
this.StartAction(disk, fly);
}
else{
fly_ = PhysisFlyAction.GetSSAction(leftOrRight, information.speed);
this.StartAction(disk, fly_);
}
}
}
通过mode控制运动类型,然后分别调用DiskFlyAction和PhysisFlyAction,这里用到的information是自定义类型,用于存储相关信息。
public struct mes{
public float speed;
public float angle;
}
PhysisFlyAction && SSAction && DiskFlyAction
PhysisFlyAction类,代码如下:
public class PhysisFlyAction : SSAction
{
private bool start_position;
public float force;
public static PhysisFlyAction GetSSAction(int pos, float force_){
PhysisFlyAction action = CreateInstance<PhysisFlyAction>();
if(pos == 1){
action.start_position = true;
}
else{
action.start_position = false;
}
action.force = force_;
return action;
}
// Start is called before the first frame update
public override void Start()
{
Rigidbody disk = gameobject.GetComponent<Rigidbody>();
gameobject.GetComponent<Rigidbody>().useGravity = true;
if(gameobject.GetComponent<Rigidbody>().position.y <= 3){
if(start_position){
gameobject.GetComponent<Rigidbody>().AddForce(new Vector3(0.4f,0.2f,0)*force*15f, ForceMode.Impulse);
}
else{
gameobject.GetComponent<Rigidbody>().AddForce(new Vector3(-0.4f,0.2f,0)*force*15f, ForceMode.Impulse);
}
}
}
// Update is called once per frame
public override void Update()
{
}
public override void FixedUpdate() {
if (transform.position.y <= -10f) {
Debug.Log(transform.position.y);
gameobject.GetComponent<Rigidbody>().useGravity = false;
gameobject.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
this.enable = false;
}
}
}
总体与物理学运动实现类似,但是这里用到了FixedUpdate。
这个类设计的小细节有对重力的改变,在start中,开启了重力,在一个初始力和重力的作用下,飞碟进行抛体运动,当飞碟运动到我们摄像机视线之外(这里是FixedUpdate中提到的-10f)时,则关闭重力。因为如果不关闭重力,飞碟仍然会继续下落,然后等到DiskFactory回收该飞碟进行下一次使用的时候会具有很大的速度,影响游戏体验,如下图(可以看到第三次绿色飞碟出现在右下角的时候具有很大的竖直速度,一闪而过):
由于physic增加了FixedUpdate,因此SSAction、DiskFlyAction也增加了一个空的FixedUpdate:
public class SSAction : ScriptableObject {
……
public virtual void FixedUpdate() {
throw new System.NotImplementedException();
}
……
}
public class DiskFlyAction : SSAction {
……
public override void FixedUpdate() {
}
……
}
FirstController && Interfaces
FirstController的改动有:
增加了一个bool变量,用于记录是物理运动还是运动学变换运动,为了通过UserGUI改变这个变量,还增加了一个setPhysic函数,并且同时在Interfaces中加上方便UserGUI修改。
private bool physic = false;
……
public void setPhysic(bool physic_){
physic = physic_;
}
SSActionManager
增加FixedUpdate:
……
if (action.enable) {
action.Update();
action.FixedUpdate();
}
……
UserGUI
在第一个界面增加了两个按钮,用于选择是否是physic模式。
效果
physic模式:
原本运动学模式仍然正常运行:
源代码:
GitHub