Unity 官方教程 Tanks (四)

GameManager

从这一章开始用markDown来编辑。
在场景里生成一个名为GameManager的空物体,挂载上GameManager.cs。


image.png

将对应的组件拖入其中,注意除了预制物外,其他组件都必须是场景里的。具体解释看GameManager:

 public int m_NumRoundsToWin = 5;        //总局数
    public float m_StartDelay = 3f;         //开始延迟
    public float m_EndDelay = 3f;           //结束延迟
    public CameraControl m_CameraControl;  //相机控制脚本  
    public Text m_MessageText;              //提示文本
    public GameObject m_TankPrefab;         //坦克预制物
    public TankManager[] m_Tanks;               //TankManager集合


    private int m_RoundNumber;              
    private WaitForSeconds m_StartWait;     
    private WaitForSeconds m_EndWait;       
/*    private TankManager m_RoundWinner;
    private TankManager m_GameWinner;       
*/

在Start()的第一个方法SwanAllTanks(),实例化所有的坦克,并编上号码:

 private void SpawnAllTanks()
    {
        for (int i = 0; i < m_Tanks.Length; i++)
        {
            m_Tanks[i].m_Instance =
                Instantiate(m_TankPrefab, m_Tanks[i].m_SpawnPoint.position, m_Tanks[i].m_SpawnPoint.rotation) as GameObject;//实例化
            m_Tanks[i].m_PlayerNumber = i + 1; //添加编号
            m_Tanks[i].Setup();
        }
    }

第二个方法,在将每个坦克的transform传给cameraControl.cs里的m_Targets,因为这里需要用到camaraControl里的公共变量,但是又不希望可以在组件里改变它,所以之前需要在m_Targets前加上[HideInspector]。

private void SetCameraTargets()
    {
        Transform[] targets = new Transform[m_Tanks.Length];

        for (int i = 0; i < targets.Length; i++)
        {
            targets[i] = m_Tanks[i].m_Instance.transform;
        }

        m_CameraControl.m_Targets = targets;
    }

完成上述内容后,我们现在来看将所有坦克重置、使用和禁用的方法,这些方法在TankManager.cs里已经实现了,在GameManager.cs中只要遍历一遍就行了

private void ResetAllTanks()  //重置
        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].Reset();
            }
        }

        private void EnableTankControl() //启用
        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].EnableControl();
            }
        }

        private void DisableTankControl() //禁用
        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].DisableControl();
            }
        }

接下来我们来执行每一小局的内容,这里用到协程。首先是每一小局开始需要做的工作,3s后开始游戏。

private IEnumerator RoundStarting () {
        ResetAllTanks (); //重置
        DisableTankControl (); //禁止
        m_CameraControl.SetStartPositionAndSize (); //重置摄像机
        m_RoundNumber++; //局数+1
        m_MessageText.text = "ROUND " + m_RoundNumber; //提示文本
        yield return m_StartWait; //等待3s
    }

其中的SetStartPositionAndSize ()方法我们要在CameraControl.cs中添加

 public void SetStartPositionAndSize () {
        FindAveragePosition ();  //找到多个坦克的中心点

        transform.position = m_DesiredPosition; //调整好相机位置和大小

        m_Camera.orthographicSize = FindRequiredSize ();
    }

然后是游戏中的协程

   private IEnumerator RoundPlaying () {
        EnableTankControl (); //启用
        m_MessageText.text = ""; 
        while (!OneTankLeft ()) { //没有超过1个留下,则循环结束
            yield return null;
        }
    }

在上面的方法中我们反复去判断是否只剩下不到2辆坦克了,如果是则结束协程,进入后面的内容。其中OneTankLeft()方法如下:

 private bool OneTankLeft () {
        int numTanksLeft = 0; //定义一个坦克数
        for (int i = 0; i < m_Tanks.Length; i++) { //遍历所有的坦克,根据是否显示来判断数量
            if (m_Tanks[i].m_Instance.activeSelf)
                numTanksLeft++;
        }
        return numTanksLeft <= 1; 
    }

接下来是结束的协程:
流程是1.得到小局获胜者 2.获胜者胜利局数+1 3.得到游戏胜利者,显示提示内容
给GameManager.cs添加成员变量


image.png
    private IEnumerator RoundEnding () {
        DisableTankControl ();
        m_RoundWinner = null;
        m_RoundWinner = GetRoundWinner (); //.得到小局获胜者
        if (m_RoundWinner != null) { //获胜者胜利局数+1
            m_RoundWinner.m_Wins++;
        }
        m_GameWinner = GetGameWinner (); // 3.得到游戏胜利者
        string message = EndMessage (); //显示提示内容
        m_MessageText.text = message;

        yield return m_EndWait;
    }

获取小局胜利者,用到的方法和OneTankLeft()相同

 private TankManager GetRoundWinner () {
        for (int i = 0; i < m_Tanks.Length; i++) {
            if (m_Tanks[i].m_Instance.activeSelf)
                return m_Tanks[i];
        }

        return null;
    }

获取游戏胜利者,通过判断Wins数是否达到胜利数

private TankManager GetGameWinner () {
        for (int i = 0; i < m_Tanks.Length; i++) {
            if (m_Tanks[i].m_Wins == m_NumRoundsToWin)
                return m_Tanks[i];
        }

        return null;
    }

提示信息
提示信息里包含当前小局谁获胜,每个人赢了几局和谁赢得了游戏,(如果有的话)。

 private string EndMessage () {
        string message = "DRAW!";

        if (m_RoundWinner != null)
            message = m_RoundWinner.m_ColoredPlayerText + " WINS THE ROUND!";

        message += "\n\n\n\n";

        for (int i = 0; i < m_Tanks.Length; i++) {
            message += m_Tanks[i].m_ColoredPlayerText + ": " + m_Tanks[i].m_Wins + " WINS\n";
        }

        if (m_GameWinner != null)
            message = m_GameWinner.m_ColoredPlayerText + " WINS THE GAME!";

        return message;
    }

现在游戏前,游戏中,游戏后的协程都完成了,我们把它放在一个总协程里

 private IEnumerator GameLoop () {
        yield return StartCoroutine (RoundStarting ()); //游戏前
        yield return StartCoroutine (RoundPlaying ()); //游戏中
        yield return StartCoroutine (RoundEnding ()); //游戏后

        if (m_GameWinner != null) {
            SceneManager.LoadScene (0); //重新加载场景
        } else {
            StartCoroutine (GameLoop ()); 
        }

    }

再在Start()里开启它

private void Start () {
        m_StartWait = new WaitForSeconds (m_StartDelay);
        m_EndWait = new WaitForSeconds (m_EndDelay);

        SpawnAllTanks ();
        SetCameraTargets ();

        StartCoroutine (GameLoop ());
    }

音效

测试一下呗。至此代码部分都完成,现在我们添加一下音效
新建一个AudioMixer文件夹,在其中新建一个Audio Mixer。重命名为MainMix,双击打开它


image.png

确保选中的是这个MainMix,(因为还有一个教程制作好的),在Group下新建三个子类,分别命名为如下所示:


image.png

1.将Music的Attenuation 设为-12,并添加一个DuckVolume


image.png

2.SFX添加一个Send


image.png

3.Driving Attenuation设为-25


image.png

4.把Tank的prefab点开,打开第一个audio Source,其中的outPut设为Driving


image.png

5.第二个Audio Source 的output设为SFX。
6.同理 Shell


image.png

7.TankExplosion的的outPut设为SFX;
8.给场景里的GameManager添加一个Audio Source,做如下设置:
image.png

优化

至此所有官方内容都已完成了,测试一下,感觉坦克的移动不是很理想,例如我们希望按下左键和下键坦克能够往左后方移动,实际上它往右后方移动了,因为在代码中“左”是让坦克的的整体朝向向左,而不是轮胎的方向向左。我们打开TankMovement.cs,在Trun()里加上一小段

 private void Turn () { // Adjust the rotation of the tank based on the player's input.
        if (m_MovementInputValue < 0) {  //后退时,左右方向取反
            m_TurnInputValue = -m_TurnInputValue;
        }
        float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;
        Quaternion turnRotation = Quaternion.Euler (0f, turn, 0f);
        m_Rigidbody.MoveRotation (m_Rigidbody.rotation * turnRotation);
    }

再测试一下就跟我们想要的一样了。Nice。

你可能感兴趣的:(Unity 官方教程 Tanks (四))