3D游戏编程5--打飞碟改进不完全版

作业要求

修改飞碟游戏:

  • 按设计图修改飞碟游戏
  • 使它同时支持物理运动与运动学(变换)运动

实现思路以及不如人意的结果

首先声明,这是一次失败的作业,打飞碟做成了“打地鼠”,等五一的时候再重新重构一下,因为每次将设计模式的时候,时间都很紧,导致学的不好,扩展的时候就做的很糟糕,甚至做不下去,这次选做题也没写,想要先好好学习一下设计模式。

上次作业一开始没用动作分离写,直接用了动力学,等我这周想改的时候,发现很难改。我想着还是写在一个类里面,至于怎么判断是动力学和应用学,加上条件就好。然后我重新做了一个prefab,叫做Disk2,并把以前的Disk改成Disk1.
disk2
它们的属性是不一样的,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函数中,还是要把设计模式学好,并不想每次都看师兄的代码写,因为我要不确定师兄的代码是否就是完美的,可能有的冗余,有的过度设计,总之每次看师兄代码都感觉被牵着走,自己没法思考,所以即使这次作业完成的不好,还是要写一篇博客纪念一下,为了以后更好的努力。

猜你喜欢

转载自blog.csdn.net/yaoxh6/article/details/80056686