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。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容