美文网首页游戏开发案例系列教程
《Unity入门案例-Tanks坦克大战》11-游戏流程控制

《Unity入门案例-Tanks坦克大战》11-游戏流程控制

作者: 杜增强 | 来源:发表于2018-10-20 09:16 被阅读0次

    11 游戏流程控制

    使用协程来控制游戏流程

    11.1 添加MessageText

    首先添加一个Text来显示文字

    image

    设置GameMgr

    image

    11.2 游戏整体流程

    image207.png

    下面GameMgr.cs最终代码预览,后面我们逐个讲解.

    using UnityEngine;

    using UnityEngine.UI;

    using System.Collections;

    public class GameMgr : MonoBehaviour

    {

    private int roundNumber = 0;  // 轮次.
    
    public Text messageText; // ui text
    
    private bool gameOver = false; // 本轮游戏是否已结束
    
    // Use this for initialization
    
    void Start ()
    
    {
    
        StartCoroutine ( GameLoop ());
    
    }
    
    private IEnumerator GameLoop () // 游戏主循环逻辑
    
    {
    
        yield return StartCoroutine (RoundStart ()); // 开始本轮游戏.
    
        yield return StartCoroutine (RoundPlay ()); // 游戏进行中.
    
        yield return StartCoroutine (RoundEnd ()); // 本轮游戏结束.
    
        StartCoroutine (GameLoop ()); // 开始下一轮游戏
    
    }
    
    private IEnumerator RoundStart ()
    
    {
    
        roundNumber++; // 累计轮数
    
        messageText.text = "ROUND " + roundNumber;
    
        yield return new WaitForSeconds (2f);// 等待2s继续
    
    }
    
    private IEnumerator RoundPlay ()
    
    {
    
        messageText.text = string.Empty; // 清空 "GamePlaying";//
    
        while (!gameOver) // 游戏结束才跳出
    
        {
    
            yield return null;
    
        }
    
    }
    
    private IEnumerator RoundEnd ()
    
    {
    
        string message = "GameEnd"; // 显示分数
    
        messageText.text = message;
    
        yield return new WaitForSeconds (2f);// 等待2s继续
    
    }
    

    }

    11.3 开始本轮游戏 RoundStart()

    开始新一轮游戏是需要做三件事情

    ResetTanks (); // 重置坦克

    DisableTanksControl (); // 禁用坦克操作

    camera.SetStartPositionAndSize ();// 重置相机

    为了方便对坦克进行操作,我们写了TankMgr来实现对于坦克的控制。

    image

    TankMgr.cs

    using UnityEngine;

    using System.Collections;

    public class TankMgr : MonoBehaviour {

    public Transform spawnPoint; // 出生点
    
    public void Reset(){// 重置坦克
    
        transform.position = spawnPoint.position;//坐标
    
        transform.rotation = spawnPoint.rotation;//旋转角度
    
        GetComponent<Health> ().blood = 100;//血值
    
    }
    
    public void EnableControl(){// 启用控制
    
        GetComponent<TankMove> ().enabled = true;
    
        GetComponent<TankShoot> ().enabled = true;
    
    }
    
    public void DisableControl(){ // 禁用控制
    
        GetComponent<TankMove> ().enabled = false;
    
        GetComponent<TankShoot> ().enabled = false;
    
    }
    

    }

    还需要设置两个GameObject作为SpawnPosition

    image image

    TankMgr是直接挂载到Tank上面的

    image

    最终RoundStart()函数里面是这样的

    private IEnumerator RoundStart ()// 开始本轮游戏.

    {
    
        ResetTanks (); // 重置坦克
    
        DisableTanksControl (); // 禁用坦克操作
    

    camera.SetStartPositionAndSize ();// 重置相机

        roundNumber++; // 累计轮数
    
        messageText.text = "ROUND " + roundNumber;
    
        yield return new WaitForSeconds (2f);// 等待2s继续
    
    }
    

    因为要控制所有坦克,所以需要一个数组保存所有坦克。

    public TankMgr[] tanks; // 所有坦克

    private void ResetTanks(){ // 重置坦克状态

    foreach( TankMgr tm in tanks)
    
        tm.Reset();
    

    }

    private void DisableTanksControl(){ // 禁用坦克操作

    foreach( TankMgr tm in tanks)
    
        tm.DisableControl();
    

    }

    然后当游戏开始的时候重新起来坦克控制

    IEnumerator RoundPlay(){

        foreach( TankMgr t in tanks){
    
            t.EnableControls ();
    
        }
    
        messageText.text = "Playing";
    
        while( true ){// 一直运行,直到有一个坦克挂掉
    
            yield return null;
    
        }
    
    }
    

    这是游戏处理运行过程,我们需要判断什么时候有坦克已经挂掉.

    这时候我们发现按照之前在Health.cs里面的处理,坦克是直接被Destroy掉的.所以这个地方我们做一些调整.当坦克挂掉之后,我们把它SetActive(false)

    public void TakeDamage( float damage){

        currentBlood -= damage; // 掉血
    
        slider.value = currentBlood; // 更新血槽显示
    
        if (currentBlood <= 0) {
    
            // die
    
            //ps.transform.parent = null;
    
            ps.Play ();
    
            audioSource.clip = explosionAudio;
    
            audioSource.Play ();
    
            //Destroy (ps.gameObject, ps.duration);
    
            //Destroy (gameObject);
    
            gameObject.SetActive ( false );
    
        }
    
    }
    

    这样当坦克挂掉之后并不是真的把它销毁了,我们可以使用gameObject.activeSelf来判断坦克是否已经挂掉

    bool OneTankLeft(){ // 判断是否有坦克挂掉

        foreach( TankMgr t in tanks){
    
            if (t.gameObject.activeSelf == false)
    
                return true;
    
        }
    
        return false;
    
    }
    

    这样我们就可以终止RoundPlay里面的while语句了

    IEnumerator RoundPlay(){

        foreach( TankMgr t in tanks){
    
            t.EnableControls (); // 启用坦克控制
    
        }
    
        messageText.text = "";
    
        while( !OneTankLeft() ){// 一直运行,直到有一个坦克挂掉
    
            yield return null;
    
        }
    
    }
    

    这样程序就可以执行到下一个阶段,就是RoundEnd函数里面了.

    在游戏结束的时候我们需要知道玩家到底是谁,所以我们什么一个winner来保持赢家

    private int winner; // 赢家

    int GetWinner(){ // 谁是赢家

        for(int i=0;i<tanks.Length;i++){
    
            if (tanks [i].gameObject.activeSelf == true)
    
                return i;
    
        }
    
        return 0;
    
    }
    

    这个方法在如果有一个坦克挂掉的时候就返回此坦克在Tanks数组中的索引.如果两个坦克都挂掉了(是有这种可能的),现在返回的仍然是0,可以返回一个-1,单独处理,这个我们在这就不讲了,大家下去自己实现一些.

    IEnumerator RoundEnd(){ // 本轮游戏结束

        winner = GetWinner ();
    
        messageText.text = "Player "+(winner+1)+" wins!";// 显示赢家
    
        yield return new WaitForSeconds (2f);
    
    }
    

    这样游戏就可以一轮一轮的进行下去了,如果我们想在某一轮后结束游戏,可以判断roundNum来实现.

    相关文章

      网友评论

        本文标题:《Unity入门案例-Tanks坦克大战》11-游戏流程控制

        本文链接:https://www.haomeiwen.com/subject/zoppzftx.html