作业要求
修改飞碟游戏:
- 按设计图修改飞碟游戏
- 使它同时支持物理运动与运动学(变换)运动
实现思路以及不如人意的结果
首先声明,这是一次失败的作业,打飞碟做成了“打地鼠”,等五一的时候再重新重构一下,因为每次将设计模式的时候,时间都很紧,导致学的不好,扩展的时候就做的很糟糕,甚至做不下去,这次选做题也没写,想要先好好学习一下设计模式。
上次作业一开始没用动作分离写,直接用了动力学,等我这周想改的时候,发现很难改。我想着还是写在一个类里面,至于怎么判断是动力学和应用学,加上条件就好。然后我重新做了一个prefab,叫做Disk2,并把以前的Disk改成Disk1.
它们的属性是不一样的,Disk2是运动学的,没有Rigidbody属性,而Disk1是动力学的,有Rigidbody属性,然后具体改代码的时候,就很悲剧了。
SceneController.cs的改动
- 加入
public enum ActionMode { PHYSIC, KINEMATIC, NOTSET }
,用来判断物体是动力学的,还是运动学的 GameInterface
里面加上两个函数ActionMode getMode();
和void setMode(ActionMode m);
SceneController
中加上private DiskFactoryController _diskFactoryController;
,因为物体初始化是在DiskFactoryController
中,所以引入这个类。- 在
SceneController
中实现setMode
方法。
public void setMode(ActionMode m)
{
if (m == ActionMode.KINEMATIC)
{
_diskFactoryController.kinematic();
mode = ActionMode.KINEMATIC;
}
else
{
_diskFactoryController.physic();
mode = ActionMode.PHYSIC;
}
}
- 也实现
_diskFactoryController
的初始化
internal DiskFactoryController GetDiskFactoryController()
{
return _diskFactoryController;
}
public void setDiskFactoryController(DiskFactoryController input)
{
_diskFactoryController = input;
}
DiskFactoryController.cs的改动
导入对应的prefab
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DiskFactoryController : MonoBehaviour
{
public GameObject disk;
private SceneController scene;
void Awake()
{
scene = SceneController.getInstance();
scene.setDiskFactoryController(this);
//DiskFactory.getInstance().disk = disk;
}
public void kinematic()
{
disk = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Disk2"));
DiskFactory.getInstance().disk = disk;
}
public void physic()
{
disk = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Disk1"));
DiskFactory.getInstance().disk = disk;
}
}
UserInterface.cs的改动
加入OnGUI函数,用来一开始显示按钮
public void OnGUI()
{
if (scene.getMode() == ActionMode.NOTSET)
{
if (GUI.Button(new Rect(150, 100, 90, 90), "KINEMATIC"))
{
scene.setMode(ActionMode.KINEMATIC);
}
if (GUI.Button(new Rect(300, 100, 90, 90), "PHYSIC"))
{
scene.setMode(ActionMode.PHYSIC);
}
}
}
update函数加入了很多判断。
void Update()
{
if(scene.getMode() != ActionMode.NOTSET)
{
if (Input.GetKeyDown("space") && isGameOver)
{
scene.setRound(0);
scene.nextRound();
isGameOver = false;
}
if (!isGameOver)
{
if (gameInterface.isCounting())
{
mainText.text = "Trial " + (gameInterface.getTrial() + 1).ToString();
}
else
{
gameInterface.MakeEmissionDiskable();
if (gameInterface.isShooting())
{
mainText.text = "";
}
if (gameInterface.isShooting() && Input.GetMouseButtonDown(0) && Time.time > nextFireTime)
{
nextFireTime = Time.time + fireRate;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//Debug.Log(Input.mousePosition);
bullet.GetComponent<Rigidbody>().velocity = Vector3.zero;
bullet.transform.position = transform.position;
Debug.Log(ray.direction);
bullet.GetComponent<Rigidbody>().AddForce(ray.direction * speed, ForceMode.Impulse);
RaycastHit hit;
if (Physics.Raycast(ray, out hit) && hit.collider.gameObject.tag == "Disk")
{
explosion.transform.position = hit.collider.gameObject.transform.position;
explosion.GetComponent<Renderer>().material.color = hit.collider.gameObject.GetComponent<Renderer>().material.color;
explosion.Play();
hit.collider.gameObject.SetActive(false);
}
}
}
roundText.text = "Round: " + gameInterface.getRound().ToString();
scoreText.text = "Score: " + gameInterface.getScore().ToString();
if (round != gameInterface.getRound())
{
round = gameInterface.getRound();
mainText.text = "Round " + round.ToString() + " !";
}
}
}
}
FirstController.cs的改动
- 这个类最后没有改动成功。
- 首先Awake函数中加入
scene.mode = ActionMode.NOTSET;
- 将以前的
emissionDisks
改成PemissionDisks
发射动力学和KemissionDisks
发射运动学 FixedUpdate
的改动,结果发现怎么改都没法改,没法改的原因,首先PemissionDisk
要在FixedUpdate
函数中实现,KemissionDisks要在Update
函数中实现,这就注定了这样的改动是不成功的,还有两个方法的shoot和time是不统一的,加了判断也不行,总之是很多问题,这都是一开始没分开写的后果。
void FixedUpdate()
{
if(timeToNext > 0)
{
timeToNext -= Time.deltaTime;
}
if (timeToNextEmission > 0)
{
isCounting = true;
timeToNextEmission -= Time.deltaTime;
}
else
{
isCounting = false;
if (isEmissionEnable)
{
if(scene.getMode() == ActionMode.PHYSIC)
{
PemissionDisks();
isEmissionEnable = false;
isShooting = true;
}
else
{
KemissionDisks();
isEmissionEnable = false;
isShooting = true;
if(timeToNext < 0)
{
for (int i = 0; i < disks.Count; i++)
{
freeADisk(i);
}
timeToNext = 3f;
isEmissionEnable = true;
isShooting = false;
}
}
}
}
}
DiskFactory.cs的改动
public void free(int id)
{
if (id > -1 && id < diskList.Count)
{
try
{
diskList[id].GetComponent<Rigidbody>().velocity = Vector3.zero;
}
catch
{
}
diskList[id].transform.localScale = disk.transform.localScale;
diskList[id].SetActive(false);
}
}
总结
总的来说,早知道改造是这样的结果,不如一开始重写,非要把动力学和运动学的物体运动写在一起实在不是很好的方法,算是一个失败的Apdater模式吧,最后卡在了FixedUpdate
函数中,还是要把设计模式学好,并不想每次都看师兄的代码写,因为我要不确定师兄的代码是否就是完美的,可能有的冗余,有的过度设计,总之每次看师兄代码都感觉被牵着走,自己没法思考,所以即使这次作业完成的不好,还是要写一篇博客纪念一下,为了以后更好的努力。