Unity3D课程学习笔记(五)

打飞碟游戏改进版----动作与物理分离版

本次作业主要是要添加一个管理物理动作的动作管理器CCPhysicsActionManager,并且通过添加按钮来决定选择哪一种创造飞碟的方式。因此在游戏的初始阶段有2中选择,一种是飞碟的运动将以运动的方式形成,另外一种是飞碟会以物理的方式形成,采用适配器模式,因此需要新建一个公共接口IActionManager,用来确定游戏开始的时候选择哪一种动作管理器。

游戏的初始接口效果图如下所示:


适配器模式的UML图的设计如下所示:


接下来是各个相关类修改后的方法,及其代码,因为代码和之前的设计有很多相似的地方,所以这里只分析修改过和新添加的代码,不做重复,相关可以参考上一次的作业:Unity3D课程学习笔记(四)

下面是一个公共的接口IActionManager,是CCActionManager和CCPhysicsActionManager需要实现的,在场景控制器中通过定义IActionManager和选择相应的按钮,可以选择使用运动学方式还是物理学方式:

public interface IActionManager
{
    int getDiskNumber();
    void setDiskNumber(int _diskNumber);
    void StartThrow(Queue<GameObject> diskQueue);
}

然后是CCActionManager的代码,基本上跟上次的没有什么改变,但是在这个类的代码里面添加了一个延迟执行Start的方法,因为我需要在开始的时候通过按钮来选择相应的模式,但是又不能在Update中时刻检测这个状态码的改变,所以只好采用这种方式,具体的代码如下所示:

public class CCActionManager : SSActionManager, ISSActionCallback, IActionManager
{
    public FirstSceneController sceneController;
    public List<CCFlyAction> Fly;
    private int DiskNumber = 0;
    //private bool isFirstEnter = true;

    private List<SSAction> Used = new List<SSAction>();
    private List<SSAction> Free = new List<SSAction>();

    public void setDiskNumber(int _diskNumber)
    {
        DiskNumber = _diskNumber;
    }

    public int getDiskNumber()
    {
        return DiskNumber;
    }

    //GetSSAction,首先从工厂里面找,如果没有的话就创造
    SSAction GetSSAction()
    {
        SSAction action = null;
        if (Free.Count > 0)
        {
            action = Free[0];
            Free.Remove(Free[0]);
        }
        else
        {
            action = ScriptableObject.Instantiate<CCFlyAction>(Fly[0]);
        }

        Used.Add(action);
        return action;
    }

    //FreeSSAction
    public void FreeSSAction(SSAction action)
    {
        SSAction temp = null;
        foreach (SSAction disk in Used)
        {
            if (action.GetInstanceID() == disk.GetInstanceID())
            {
                temp = disk;
            }
        }
        if (temp != null)
        {
            temp.reset();
            Free.Add(temp);
            Used.Remove(temp);
        }
    }

    protected new void Start()
    {
        StartCoroutine(PlayerAttack());
    }

    public void SSActionEvent(SSAction source,
        SSActionEventType events = SSActionEventType.Competeted,
        int Param = 0,
        string strParam = null,
        UnityEngine.Object objectParam = null)
    {
        if (source is CCFlyAction)
        {
            DiskNumber--;
            DiskFactory factory = Singleton<DiskFactory>.Instance;
            factory.FreeDisk(source.gameobject);
            FreeSSAction(source);
        }
    }

    public void StartThrow(Queue<GameObject> diskQueue)
    {
        foreach (GameObject temp in diskQueue)
        {
            //if (GetSSAction() != null)
            RunAction(temp, GetSSAction(), (ISSActionCallback)this);
        }
    }

    IEnumerator PlayerAttack()
    {
        yield return new WaitForSeconds(3.0f);
        Debug.Log("CCActionManager!");
        sceneController = (FirstSceneController)Director.getInstance().currentSceneController;
        if (sceneController.getActionState() == ActionState.MOVING)
        {
            Debug.Log("CCActionManager! Set actionManager!");
            sceneController.actionManager = this;
        }
        Fly.Add(CCFlyAction.GetSSAction());
    }
}

接着是CCPhysicsActionManager的代码,这个类跟CCActionManager的代码非常相似,只是我新建了一个CCPhysicsAction的基本动作来定义物理动作的生成,所以感觉有点冗余,但是这样做又是最方便的,所以就先采取这种方法。

public class CCPhysicsActionManager : SSActionManager, ISSActionCallback, IActionManager
{
    public FirstSceneController sceneController;
    public List<CCPhysicsFlyAction> Fly;
    private int DiskNumber = 0;

    private List<SSAction> Used = new List<SSAction>();
    private List<SSAction> Free = new List<SSAction>();

    public void setDiskNumber(int _diskNumber)
    {
        DiskNumber = _diskNumber;
    }

    public int getDiskNumber()
    {
        return DiskNumber;
    }

    //GetSSAction,首先从工厂里面找,如果没有的话就创造
    SSAction GetSSAction()
    {
        SSAction action = null;
        if (Free.Count > 0)
        {
            action = Free[0];
            Free.Remove(Free[0]);
        }
        else
        {
            action = ScriptableObject.Instantiate<CCPhysicsFlyAction>(Fly[0]);
        }

        Used.Add(action);
        return action;
    }
    //FreeSSAction
    public void FreeSSAction(SSAction action)
    {
        SSAction temp = null;
        foreach (SSAction disk in Used)
        {
            if (action.GetInstanceID() == disk.GetInstanceID())
            {
                temp = disk;
            }
        }
        if (temp != null)
        {
            temp.reset();
            Free.Add(temp);
            Used.Remove(temp);
        }
    }

    protected new void Start()
    {
        StartCoroutine(PlayerAttack());
    }

    public void SSActionEvent(SSAction source,
        SSActionEventType events = SSActionEventType.Competeted,
        int Param = 0,
        string strParam = null,
        UnityEngine.Object objectParam = null)
    {
        if (source is CCPhysicsFlyAction)
        {
            DiskNumber--;
            DiskFactory factory = Singleton<DiskFactory>.Instance;
            factory.FreeDisk(source.gameobject);
            FreeSSAction(source);
        }
    }

    public void StartThrow(Queue<GameObject> diskQueue)
    {
        foreach (GameObject temp in diskQueue)
        {
            //if (GetSSAction() != null)
            RunAction(temp, GetSSAction(), (ISSActionCallback)this);
        }
    }

    IEnumerator PlayerAttack()
    {
        //Start After 3 seconds.
        yield return new WaitForSeconds(3.0f);
        Debug.Log("CCActionManager!");
        sceneController = (FirstSceneController)Director.getInstance().currentSceneController;
        if (sceneController.getActionState() == ActionState.PHYSICS)
        {
            Debug.Log("PhysicsActionManager! Set actionManager!");
            sceneController.actionManager = this;
        }
        Fly.Add(CCPhysicsFlyAction.GetSSAction());
    }
}

在工厂中创造飞碟的时候,需要注意的是,如果选择的是物理状态,那么就需要给飞碟添加一个刚体属性,这样他的物理特性才能够体现出来,并且在CCPhysicsActionManager中应该要注意把相关的内容放在FixedUpdate中,一下是这两个类的代码

CCPhysicsActionManager

扫描二维码关注公众号,回复: 4580959 查看本文章
public class CCPhysicsFlyAction : SSAction
{
    //动作基本参数:加速度,垂直速度,边界,飞行时间,飞行方向
    public ScoreRecorder scoreRecorder { get; set; }
    private float acceleration = 3.0f;
    private float horizontalSpeed;
    private float lowerBound = -4;
    private float flyTime;
    private Vector3 direction;
    Rigidbody rigidbody;

    public override void Start()
    {
        enable = true;
        flyTime = 0;
        horizontalSpeed = gameobject.GetComponent<DiskData>().getDiskSpeed();
        direction = gameobject.GetComponent<DiskData>().getDiskDirection();
        scoreRecorder = Singleton<ScoreRecorder>.Instance;
        rigidbody = this.gameobject.GetComponent<Rigidbody>();
        if (rigidbody)
        {
            Debug.Log("AddForce");
            rigidbody.velocity = horizontalSpeed * direction * 3;
        }
    }

    public override void Update()
    {
        if (gameobject.activeSelf)
        {
            if (checkWhetherShouldRecycle())
            {
                scoreRecorder.MinRecord();
            }
        }
    }

    public override void FixedUpdate()
    {
        Debug.Log("Physics!");
        if (gameobject.activeSelf)
        {
            if (checkWhetherShouldRecycle())
            {
                scoreRecorder.MinRecord();
            }
        }
    }

    //如果飞碟的高度低于最低限度,则回收该飞碟
    private bool checkWhetherShouldRecycle()
    {
        if (this.transform.position.y < lowerBound)
        {
            this.destroy = true;
            this.enable = false;
            this.callback.SSActionEvent(this);
            return true;
        }
        return false;
    }

    public static CCPhysicsFlyAction GetSSAction()
    {
        CCPhysicsFlyAction action = ScriptableObject.CreateInstance<CCPhysicsFlyAction>();
        return action;
    }
}

DiskFactory类

public class DiskFactory : MonoBehaviour
{
    public GameObject Disk_Product;
    public FirstSceneController sceneController;

    //Used用来保存被激活的飞碟,Free用来保存空闲的飞碟
    private List<DiskData> Used = new List<DiskData>();
    private List<DiskData> Free = new List<DiskData>();

    //Awake
    private void Awake()
    {
        sceneController = (FirstSceneController)Director.getInstance().currentSceneController;
        Disk_Product = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/DiskModel"),
            Vector3.zero, Quaternion.identity);
        Disk_Product.SetActive(false);
    }

    //GetDisk
    public GameObject GetDisk(int Game_Round)
    {
        GameObject NewDiskProduct = null;
        if (Free.Count > 0)
        {
            NewDiskProduct = Free[0].gameObject;
            Free.Remove(Free[0]);
        }
        else
        {
            NewDiskProduct = GameObject.Instantiate<GameObject>(Disk_Product, Vector3.zero,
                Quaternion.identity);
            NewDiskProduct.AddComponent<DiskData>();
        }

        //控制飞碟产生的频率
        int From = 0;
        if (Game_Round == 1)
        {
            From = 100;
        }
        if (Game_Round == 2)
        {
            From = 250;
        }
        int TheDiskColor = Random.Range(From, Game_Round * 499);

        if (TheDiskColor > 500)
        {
            Game_Round = 2;
        }
        else if (TheDiskColor > 300)
        {
            Game_Round = 1;
        }
        else
        {
            Game_Round = 0;
        }

        //根据回合控制生成飞碟的属性
        if (Game_Round == 0)
        {
            setDiskProp(NewDiskProduct, Color.yellow, 2.0f);
        }
        else if (Game_Round == 1)
        {
            setDiskProp(NewDiskProduct, Color.red, 3.0f);
        }
        else if (Game_Round == 2)
        {
            setDiskProp(NewDiskProduct, Color.black, 4.0f);
        }
        Debug.Log("Produce!");
        if (sceneController.getActionState() == ActionState.PHYSICS)
        {
            Debug.Log("Check!");
            NewDiskProduct.AddComponent<Rigidbody>();
        }

        Used.Add(NewDiskProduct.GetComponent<DiskData>());
        NewDiskProduct.name = NewDiskProduct.GetInstanceID().ToString();
        return NewDiskProduct;
    }

    //setDiskProp.
    public void setDiskProp(GameObject Disk, Color _Color, float _Speed)
    {
        Disk.GetComponent<DiskData>().setDiskColor(_Color);
        Disk.GetComponent<DiskData>().setDiskSpeed(_Speed);
        float RanX = UnityEngine.Random.Range(-1.0f, 1.0f) < 0 ? -1 : 1;
        Disk.GetComponent<DiskData>().setDiskDirection(new Vector3(RanX, 1, 0));
        Disk.GetComponent<Renderer>().material.color = _Color;
    }

    //FreeDisk.
    public void FreeDisk(GameObject Disk)
    {
        DiskData temp = null;
        foreach (DiskData disk in Used)
        {
            if (Disk.GetInstanceID() == disk.gameObject.GetInstanceID())
            {
                temp = disk;
            }
        }
        if (temp != null)
        {
            temp.gameObject.SetActive(false);
            Free.Add(temp);
            Used.Remove(temp);
        }
    }
}

至于其他的类,都和上次作业差不多,在这里就不再多叙述了,如果想查看相应的代码,可以到我的Github

最后附上一张效果图:


猜你喜欢

转载自blog.csdn.net/Alva112358/article/details/80069558