基本介绍
本次需要根据课上所学内容为对象添加运动模式从而实现一个包含运动学模式和动力学模式的打飞碟小游戏。
代码地址:代码地址
视频展示
Unity打飞碟
游戏设计介绍
基础概述
本次游戏编写采用与上次相同的MVC模式进行开发,故而相似部分不再阐述。下面解释新增或主要改动的部分:飞碟工厂、两种运动模式的实现。
飞碟工厂
游戏过程中需要不断生成和销毁飞碟对象,如果按照一般的做法常规进行对象生成销毁,会导致大量计算资源的浪费,故而在代码中引入飞碟工厂模块,其中包含正在使用的飞碟对象和空闲的飞碟对象。每当需要产生一个飞碟时,优先看是否有空闲的,没有再新生成一个;当需要销毁一个飞碟时,不是真的销毁,而只是将其设置为disable,方便下次直接调用。
- 飞碟预设(包含刚体组件)
飞碟的参数类
public class DiskData : MonoBehaviour
{
public float speed; //水平速度
public int points; //得分(红1,绿2,蓝3)
public Vector3 direction; //初始方向
}
飞碟工厂类
public class DiskFactory : MonoBehaviour
{
public GameObject disk_prefab; //飞碟预制
private List<DiskData> used; //已使用的飞碟
private List<DiskData> free; //空闲的飞碟
void Start(){
used = new List<DiskData>();
free = new List<DiskData>();
disk_prefab = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/UFO"), Vector3.zero, Quaternion.identity);
disk_prefab.SetActive(false); //刚生成的对象点击无效
}
//获取
public GameObject GetDisk(int round){
GameObject disk;
//如果有空闲的飞碟,则直接使用。否则生成新的飞碟
if (free.Count > 0)
{
disk = free[0].gameObject;
free.Remove(free[0]);
}
else
{
disk = GameObject.Instantiate<GameObject>(disk_prefab, Vector3.zero, Quaternion.identity);
disk.AddComponent<DiskData>();
}
disk.gameObject.name = "Disk";
//生成飞碟的规则
//注意:位置的生成不由这个类管理
float base_speed = 3 + round * 0.8f; //根据round决定速度基数的大小
Vector3 base_scale = new Vector3(8,1,8); //颜色和大小有关
float rand_y = Random.Range(-0.5f, 0.5f); //速度垂直方向随机生成
int side = Random.Range(0,2); //速度水平方向(左或右)
if(side == 0){
side = -1;
}
int rand_color = Random.Range(1,4); //颜色和速度有关
if(rand_color == 1){
disk.GetComponent<DiskData>().points = 1;
disk.GetComponent<DiskData>().speed = 0.6f * base_speed;
disk.GetComponent<DiskData>().direction = new Vector3(side, rand_y, 0);
disk.GetComponent<Renderer>().material.color = Color.yellow;
disk.GetComponent<Transform>().localScale = 1.2f * base_scale;
}
else if(rand_color == 2){
disk.GetComponent<DiskData>().points = 2;
disk.GetComponent<DiskData>().speed = 1.2f * base_speed;
disk.GetComponent<DiskData>().direction = new Vector3(side, rand_y, 0);
disk.GetComponent<Renderer>().material.color = Color.green;
disk.GetComponent<Transform>().localScale = base_scale;
}
else{
disk.GetComponent<DiskData>().points = 3;
disk.GetComponent<DiskData>().speed = 1.8f * base_speed;
disk.GetComponent<DiskData>().direction = new Vector3(side, rand_y, 0);
disk.GetComponent<Renderer>().material.color = Color.blue;
disk.GetComponent<Transform>().localScale = 0.8f * base_scale;
}
//将这一对象的DiskData属性添加到列表中
used.Add(disk.GetComponent<DiskData>());
return disk;
}
//释放
public void FreeDisk(GameObject disk){
foreach(DiskData d in used){
if(d.gameObject.GetInstanceID() == disk.GetInstanceID()){
disk.SetActive(false); //一定要先灭活
used.Remove(d);
free.Add(d); //重新放回到对象池中
break;
}
}
}
//由于重新开始和切换模式的需要,应当销毁所有对象
public void Clear(){
foreach(DiskData d in used){
//由于某些对象可能还被FlyAction绑定,因此需要先让FlyAction结束并回调,再销毁对象。
d.gameObject.transform.position = new Vector3(0, -20, 0);
Destroy(d.gameObject);
}
foreach(DiskData d in free){
d.gameObject.transform.position = new Vector3(0, -20, 0);
Destroy(d.gameObject);
}
//由于对象被销毁了,因此这些数据列表也应当删除。
used.Clear();
free.Clear();
}
}
运动学模式实现
通过游戏开始页面的菜单选择游戏模式
代码中包含有关动作的两个基类,以及一个接口,CC开头的类实现相关函数,完成运动学相关的动作;Physical开头的类实现相关函数,完成动力学相关的动作。
运动学模式
CCFlyAction
public class CCFlyAction : SSAction
{
float speed;
Vector3 direction;
public static CCFlyAction GetSSAction(Vector3 dir, float speed){
CCFlyAction ret = ScriptableObject.CreateInstance<CCFlyAction>();
ret.speed = speed;
ret.direction = dir;
return ret;
}
// Update is called once per frame
public override void Update()
{
//动作运行
transform.Translate(direction * speed * Time.deltaTime);
//判断动作是否结束,结束则进行回调。(注意,由于不存在重力,这里出屏幕外就算结束)
if(this.transform.position.y < -10 || this.transform.position.y > 20 || this.transform.position.x < -35 || this.transform.position.x > 35){
this.destroy = true;
this.enable = false;
this.callback.SSActionEvent(this);
}
}
public override void Start() {
gameobject.GetComponent<Rigidbody>().isKinematic = true;
}
}
CCActionManager
public class CCActionManager : SSAcCCActionManagertionManager, ISSActionCallback, IActionManager
{
public CCFlyAction flyAction;
public FirstController controller;
public void Start()
{
controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
}
//对外接口
public void Fly(GameObject disk, float speed, Vector3 direction){
flyAction = CCFlyAction.GetSSAction(direction, speed);
RunAction(disk, flyAction, this);
}
//回调函数
public void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Competed,
int intParam = 0,
string strParam = null,
Object objectParam = null)
{
controller.diskFactory.FreeDisk(source.gameobject);//动作结束,交给工厂来释放资源
}
}
动力学模式
PhysicalAction
public class PhysicalAction : SSAction
{
float speed;
Vector3 direction;
public static PhysicalAction GetSSAction(Vector3 dir, float speed){
PhysicalAction ret = ScriptableObject.CreateInstance<PhysicalAction>();
ret.speed = speed;
ret.direction = dir;
return ret;
}
// Update is called once per frame
public override void Update()
{
//动作运行
transform.Translate(direction * speed * Time.deltaTime);
//实现上下飞行效果
if(this.transform.position.y>10){
gameobject.GetComponent<Rigidbody>().AddForce(Vector3.down * 9.8f * gameobject.GetComponent<Rigidbody>().mass);
}
if(this.transform.position.y<-5){
gameobject.GetComponent<Rigidbody>().AddForce(Vector3.up * 9.8f * gameobject.GetComponent<Rigidbody>().mass);
}
//判断动作是否结束,结束则进行回调。
if(this.transform.position.y < -10 || this.transform.position.x < -35 || this.transform.position.x > 35){
this.destroy = true;
this.enable = false;
this.callback.SSActionEvent(this);
}
}
public override void Start() {
gameobject.GetComponent<Rigidbody>().isKinematic = false;
//为物体增加水平初速度,否则会由于受到重力严重影响运动状态。
gameobject.GetComponent<Rigidbody>().velocity = speed * direction;
}
}
PhysicalActionManager
public class PhysicalActionManager : SSActionManager, ISSActionCallback, IActionManager
{
public PhysicalAction flyAction;
public FirstController controller;
public void Start()
{
controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
}
//对外接口
public void Fly(GameObject disk, float speed, Vector3 direction){
flyAction = PhysicalAction.GetSSAction(direction, speed);
RunAction(disk, flyAction, this);
}
//回调函数
public void SSActionEvent(SSAction source,
SSActionEventType events = SSActionEventType.Competed,
int intParam = 0,
string strParam = null,
Object objectParam = null)
{
controller.diskFactory.FreeDisk(source.gameobject);//动作结束,交给工厂来释放资源
}
}
结尾
本博客参考实现 博客