Tanks!Tutorial 学习

Posted 志不强者智不达

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tanks!Tutorial 学习相关的知识,希望对你有一定的参考价值。

 

using UnityEngine;

namespace Complete
{
    public class CameraControl : MonoBehaviour
    {
        /// <summary>
        /// 相机重新聚焦的时间
        /// </summary>
        public float m_DampTime = 0.2f;                 
        /// <summary>
        /// 
        /// </summary>
        public float m_ScreenEdgeBuffer = 4f;           
        /// <summary>
        /// 正交模式吓的最小视口大小
        /// </summary>
        public float m_MinSize = 6.5f;                  
        /// <summary>
        /// 相机需要保卫的目标数组
        /// </summary>
        [HideInInspector] public Transform[] m_Targets; 

        /// <summary>
        /// 相机
        /// </summary>
        private Camera m_Camera;                        
        /// <summary>
        /// 变焦速度
        /// </summary>
        private float m_ZoomSpeed;                      
        /// <summary>
        /// 移动速度
        /// </summary>
        private Vector3 m_MoveVelocity;                 
        /// <summary>
        /// 目标位置
        /// </summary>
        private Vector3 m_DesiredPosition;                                   


        private void Awake ()
        {
            m_Camera = GetComponentInChildren<Camera> ();
        }


        private void FixedUpdate ()
        {
            Move ();
            Zoom ();
        }

        /// <summary>
        /// 移动
        /// </summary>
        private void Move ()
        {
            FindAveragePosition ();

            transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
        }

        /// <summary>
        /// 查找所有目标的中间位置
        /// </summary>
        private void FindAveragePosition ()
        {
            Vector3 averagePos = new Vector3 ();
            int numTargets = 0;

            for (int i = 0; i < m_Targets.Length; i++)
            {
                if (!m_Targets[i].gameObject.activeSelf)
                    continue;

                averagePos += m_Targets[i].position;
                numTargets++;
            }

            if (numTargets > 0)
                averagePos /= numTargets;

            averagePos.y = transform.position.y;
            m_DesiredPosition = averagePos;
        }

        /// <summary>
        /// 变焦
        /// </summary>
        private void Zoom ()
        {
            float requiredSize = FindRequiredSize();
            m_Camera.orthographicSize = Mathf.SmoothDamp (m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
        }

        /// <summary>
        /// 查找需要的视口大小
        /// </summary>
        /// <returns></returns>
        private float FindRequiredSize ()
        {

            Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);

            float size = 0f;

            for (int i = 0; i < m_Targets.Length; i++)
            {
                if (!m_Targets[i].gameObject.activeSelf)
                    continue;

                Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position);

                Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos;

                size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.y));

                size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.x) / m_Camera.aspect);
            }

            size += m_ScreenEdgeBuffer;

            size = Mathf.Max (size, m_MinSize);

            return size;
        }

        /// <summary>
        /// 设置相机的起始位置和大小
        /// </summary>
        public void SetStartPositionAndSize ()
        {
            FindAveragePosition ();

            transform.position = m_DesiredPosition;

            m_Camera.orthographicSize = FindRequiredSize ();
        }
    }
}
CameraControl

 

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

namespace Complete
{
    public class GameManager : MonoBehaviour
    {
        /// <summary>
        /// 要赢得游戏的局数
        /// </summary>
        public int m_NumRoundsToWin = 5;            
        /// <summary>
        /// 从回合准备转换到回合开始的时间
        /// </summary>
        public float m_StartDelay = 3f;             
        /// <summary>
        /// 从回合开始转换到回合结束的时间
        /// </summary>
        public float m_EndDelay = 3f;               
        /// <summary>
        /// 摄像机控制
        /// </summary>
        public CameraControl m_CameraControl;       
        /// <summary>
        /// 消息文本
        /// </summary>
        public Text m_MessageText;                  
        /// <summary>
        /// 坦克预设
        /// </summary>
        public GameObject m_TankPrefab;             
        /// <summary>
        /// 坦克管理数组
        /// </summary>
        public TankManager[] m_Tanks;               

        /// <summary>
        /// 当前回合数
        /// </summary>
        private int m_RoundNumber;                  
        /// <summary>
        /// 回合开始后的等待时间
        /// </summary>
        private WaitForSeconds m_StartWait;         
        /// <summary>
        /// 回合结束后的等待时间
        /// </summary>
        private WaitForSeconds m_EndWait;           
        /// <summary>
        /// 回合获胜者
        /// </summary>
        private TankManager m_RoundWinner;          
        /// <summary>
        /// 游戏获胜者
        /// </summary>
        private TankManager m_GameWinner;                                   


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

            SpawnAllTanks();
            SetCameraTargets();

            //开启游戏主循环协程
            StartCoroutine (GameLoop ());
        }

        /// <summary>
        /// 孵化所有坦克
        /// </summary>
        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();
            }
        }

        /// <summary>
        /// 设置相机目标
        /// </summary>
        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;
        }


        /// <summary>
        /// 游戏循环协程
        /// </summary>
        /// <returns></returns>
        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 ());
            }
        }

        /// <summary>
        /// 回合准备协程
        /// </summary>
        /// <returns></returns>
        private IEnumerator RoundStarting ()
        {
            ResetAllTanks ();
            DisableTankControl ();

            m_CameraControl.SetStartPositionAndSize ();

            m_RoundNumber++;
            m_MessageText.text = "ROUND " + m_RoundNumber;

            yield return m_StartWait;
        }

        /// <summary>
        /// 回合开始协程
        /// </summary>
        /// <returns></returns>
        private IEnumerator RoundPlaying ()
        {
            EnableTankControl ();

            m_MessageText.text = string.Empty;

            while (!OneTankLeft())
            {
                yield return null;
            }
        }

        /// <summary>
        /// 游戏结束协程
        /// </summary>
        /// <returns></returns>
        private IEnumerator RoundEnding ()
        {
            DisableTankControl ();


            m_RoundWinner = null;

            m_RoundWinner = GetRoundWinner ();

            if (m_RoundWinner != null)
                m_RoundWinner.m_Wins++;

            m_GameWinner = GetGameWinner ();

            string message = EndMessage ();
            m_MessageText.text = message;

            yield return m_EndWait;
        }


        /// <summary>
        /// 检查激活的坦克数量是否小于等于1,用来设置这局游戏是否结束
        /// </summary>
        /// <returns></returns>
        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;
        }
        
        /// <summary>
        /// 获取每局的胜者
        /// </summary>
        /// <returns></returns>
        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;
        }


        /// <summary>
        /// 获取游戏的胜者
        /// </summary>
        /// <returns></returns>
        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;
        }


        /// <summary>
        /// 每回合结束或游戏结束的消息
        /// </summary>
        /// <returns></returns>
        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;
        }


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

        /// <summary>
        /// 开启所有坦克的控制
        /// </summary>
        private void EnableTankControl()
        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].EnableControl();
            }
        }

        /// <summary>
        /// 关闭所有坦克的控制
        /// </summary>
        private void DisableTankControl()
        {
            for (int i = 0; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].DisableControl();
            }
        }
    }
}
GameManager
using System;
using UnityEngine;

namespace Complete
{
    [Serializable]
    public class TankManager
    {
        /// <summary>
        /// 坦克颜色
        /// </summary>
        public Color m_PlayerColor;                             
        /// <summary>
        /// 坦克孵化点
        /// </summary>
        public Transform m_SpawnPoint;                          
        /// <summary>
        /// 玩家编号
        /// </summary>
        [HideInInspector] public int m_PlayerNumber;            
        /// <summary>
        /// 包含颜色的代表玩家的字符串
        /// </summary>
        [HideInInspector] public string m_ColoredPlayerText;    
        /// <summary>
        /// 坦克实例的引用
        /// </summary>
        [HideInInspector] public GameObject m_Instance;         
        /// <summary>
        /// 玩家已赢得的局数
        /// </summary>
        [HideInInspector] public int m_Wins;                    
        
        /// <summary>
        /// 坦克移动
        /// </summary>
        private TankMovement m_Movement;                        
        /// <summary>
        /// 坦克射击
        /// </summary>
        private TankShooting m_Shooting;                        
        /// <summary>
        /// 坦克游戏物体上的canvas
        /// </summary>
        private GameObject m_CanvasGameObject;                  

        /// <summary>
        /// 设置坦克
        /// </summary>
        public void Setup ()
        {

            m_Movement = m_Instance.GetComponent<TankMovement> ();
            m_Shooting = m_Instance.GetComponent<TankShooting> ();
            m_CanvasGameObject = m_Instance.GetComponentInChildren<Canvas> ().gameObject;

            m_Movement.m_PlayerNumber = m_PlayerNumber;
            m_Shooting.m_PlayerNumber = m_PlayerNumber;

            //设置带颜色的玩家名
            m_ColoredPlayerText = "<color=#" + ColorUtility.TohtmlStringRGB(m_PlayerColor) + ">PLAYER " + m_PlayerNumber + "</color>";

            //获取并设置坦克及子物体的颜色
            MeshRenderer[] renderers = m_Instance.GetComponentsInChildren<MeshRenderer> ();

            for (int i = 0; i < renderers.Length; i++)
            {
                renderers[i].material.color = m_PlayerColor;
            }
        }


        /// <summary>
        /// 关闭控制
        /// </summary>
        public void DisableControl ()
        {
            m_Movement.enabled = false;
            m_Shooting.enabled = false;

            m_CanvasGameObject.SetActive (false);
        }


        /// <summary>
        /// 开启控制
        /// </summary>
        public void EnableControl ()
        {
            m_Movement.enabled = true;
            m_Shooting.enabled = true;

            m_CanvasGameObject.SetActive (true);
        }


        /// <summary>
        /// 重置坦克状态
        /// </summary>
        public void Reset ()
        {
            m_Instance.transform.position = m_SpawnPoint.position;
            m_Instance.transform.rotation = m_SpawnPoint.rotation;

            m_Instance.SetActive (false);
            m_Instance.SetActive (true);
        }
    }
}
TankManager

 

using UnityEngine;
using UnityEngine.UI;

namespace Complete
{
    /// <summary>
    /// 坦克生命
    /// </summary>
    public class TankHealth : MonoBehaviour
    {
        /// <summary>
        /// 初始坦克生命
        /// </summary>
        public float m_StartingHealth = 100f;               
        /// <summary>
        /// 血量滑动条
        /// </summary>
        public Slider m_Slider;                             
        /// <summary>
        /// 血量滑动条的图片
        /// </summary>
        public Image m_FillImage;                           
        /// <summary>
        /// 坦克满血的滑动条颜色
        /// </summary>
        public Color m_FullHealthColor = Color.green;       
        /// <summary>
        /// 坦克没血的滑动条颜色
        /// </summary>
        public Color m_ZeroHealthColor = Color.red;         
        /// <summary>
        /// 坦克爆炸的预设
        /// </summary>
        public GameObject m_ExplosionPrefab;                
        
        /// <summary>
        /// 坦克爆炸的音效
        /// </summary>
        private Audiosource m_ExplosionAudio;               
        /// <summary>
        /// 坦克爆炸的粒子系统
        /// </summary>
        private ParticleSystem m_ExplosionParticles;        
        /// <summary>
        /// 坦克当前的血量
        /// </summary>
        private float m_CurrentHealth;                      
        /// <summary>
        /// 坦克是否死亡
        /// </summary>
        private bool m_Dead;                                             


        private void Awake ()
        {
            //实例化爆炸预设并获取爆炸粒子系统的引用
            m_ExplosionParticles = Instantiate (m_ExplosionPrefab).GetComponent<ParticleSystem> ();

            //获取爆炸的音效
            m_ExplosionAudio = m_ExplosionParticles.GetComponent<AudioSource> ();

            //禁用爆炸粒子系统
            m_ExplosionParticles.gameObject.SetActive (false);
        }


        private void OnEnable()
        {
            //设置当前血量为起始血量
            m_CurrentHealth = m_StartingHealth;
            //设置死亡标志位为false
            m_Dead = false;

            //修改血量UI
            SetHealthUI();
        }

        /// <summary>
        /// 坦克受到伤害
        /// </summary>
        /// <param name="amount"></param>
        public void TakeDamage (float amount)
        {
            //修改当前血量
            m_CurrentHealth -= amount;

            //修改血量UI
            SetHealthUI ();

            //如果死亡,当前血量<=0
            if (m_CurrentHealth <= 0f && !m_Dead)
            {
                OnDeath ();
            }
        }

        /// <summary>
        /// 设置坦克血量UI
        /// </summary>
        private void SetHealthUI ()
        {
            //设置滑动条的值为当前血量
            m_Slider.value = m_CurrentHealth;

            //根据当前血量和起始血量的比值设置坦克的滑动条血量的颜色
            m_FillImage.color = Color.Lerp (m_ZeroHealthColor, m_FullHealthColor, m_CurrentHealth / m_StartingHealth);
        }

        /// <summary>
        /// 坦克死亡
        /// </summary>
        private void OnDeath ()
        {
            以上是关于Tanks!Tutorial 学习的主要内容,如果未能解决你的问题,请参考以下文章

Slava and tanks 877C

unity 教程Tanks中的Transform.InverseTransformPoint理解

Azure 机器人微软Azure Bot 编辑器系列 : 机器人/用户提问回答模式,机器人从API获取响应并组织答案 (The Bot Framework Composer tutorial(代码片段

Tanks坦克大战

Codeforces 920D Tanks

Codeforces 877C Slava and tanks(思维)