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 ();
            ;

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

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

            )
                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;

            ; 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>
        ;
        /// <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()
        {
            ; 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 + ;
                m_Tanks[i].Setup();
            }
        }

        /// <summary>
        /// 设置相机目标
        /// </summary>
        private void SetCameraTargets()
        {
            Transform[] targets = new Transform[m_Tanks.Length];

            ; 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 ();
            }
            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()
        {
            ;

            ; i < m_Tanks.Length; i++)
            {
                if (m_Tanks[i].m_Instance.activeSelf)
                    numTanksLeft++;
            }

            ;
        }

        /// <summary>
        /// 获取每局的胜者
        /// </summary>
        /// <returns></returns>
        private TankManager GetRoundWinner()
        {
            ; 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()
        {
            ; 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";

            ; 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()
        {
            ; i < m_Tanks.Length; i++)
            {
                m_Tanks[i].Reset();
            }
        }

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

        /// <summary>
        /// 关闭所有坦克的控制
        /// </summary>
        private void DisableTankControl()
        {
            ; 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> ();

            ; 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 ()
        {
            //设置死亡标志位 true
            m_Dead = true;

            //将爆炸粒子系统的位置移动到坦克的位置
            m_ExplosionParticles.transform.position = transform.position;
            m_ExplosionParticles.gameObject.SetActive (true);

            //播放爆炸粒子系统
            m_ExplosionParticles.Play ();

            //播放爆炸音效
            m_ExplosionAudio.Play();

            //禁用坦克
            gameObject.SetActive (false);
        }
    }
}

TankHealth

using UnityEngine;

namespace Complete
{
    /// <summary>
    /// 坦克移动
    /// </summary>
    public class TankMovement : MonoBehaviour
    {
        /// <summary>
        /// 玩家编号
        /// </summary>
        ;
        /// <summary>
        /// 坦克的移动速度
        /// </summary>
        public float m_Speed = 12f;
        /// <summary>
        /// 坦克的转向速度
        /// </summary>
        public float m_TurnSpeed = 180f;
        /// <summary>
        /// 移动声源
        /// </summary>
        public AudioSource m_MovementAudio;
        /// <summary>
        /// 空闲时的声音
        /// </summary>
        public AudioClip m_EngineIdling;
        /// <summary>
        /// 移动时的声音
        /// </summary>
        public AudioClip m_EngineDriving;
        /// <summary>
        /// 音高范围
        /// </summary>
        public float m_PitchRange = 0.2f;           

        /// <summary>
        /// 控制前后移动的轴名
        /// </summary>
        private string m_MovementAxisName;
        /// <summary>
        /// 控制
        /// </summary>
        private string m_TurnAxisName;
        /// <summary>
        /// 刚体
        /// </summary>
        private Rigidbody m_Rigidbody;              

        /// <summary>
        /// 移动输入
        /// </summary>
        private float m_MovementInputValue;
        /// <summary>
        /// 转向输入
        /// </summary>
        private float m_TurnInputValue;
        /// <summary>
        /// 原始音高
        /// </summary>
        private float m_OriginalPitch;                           

        private void Awake ()
        {
            m_Rigidbody = GetComponent<Rigidbody> ();
        }

        private void OnEnable ()
        {

            m_Rigidbody.isKinematic = false;

            m_MovementInputValue = 0f;
            m_TurnInputValue = 0f;
        }

        private void OnDisable ()
        {
            m_Rigidbody.isKinematic = true;
        }

        private void Start ()
        {
            //通过玩家编号获取输入轴
            m_MovementAxisName = "Vertical" + m_PlayerNumber;
            m_TurnAxisName = "Horizontal" + m_PlayerNumber;

            //存储原始音高
            m_OriginalPitch = m_MovementAudio.pitch;
        }

        private void Update ()
        {
            //获取输入轴的值
            m_MovementInputValue = Input.GetAxis (m_MovementAxisName);
            m_TurnInputValue = Input.GetAxis (m_TurnAxisName);

            EngineAudio ();
        }

        /// <summary>
        /// 处理引擎的声音
        /// </summary>
        private void EngineAudio ()
        {
            //如果没有输入
            if (Mathf.Abs (m_MovementInputValue) < 0.1f && Mathf.Abs (m_TurnInputValue) < 0.1f)
            {
                //如果正在播放移动的声音
                if (m_MovementAudio.clip == m_EngineDriving)
                {
                    //播放闲置的声音
                    m_MovementAudio.clip = m_EngineIdling;
                    m_MovementAudio.pitch = Random.Range (m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                    m_MovementAudio.Play ();
                }
            }
            //如果有输入
            else
            {
                //如果正在播放闲置的声音
                if (m_MovementAudio.clip == m_EngineIdling)
                {
                    //播放移动的声音
                    m_MovementAudio.clip = m_EngineDriving;
                    m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                    m_MovementAudio.Play();
                }
            }
        }

        private void FixedUpdate ()
        {
            //移动
            Move ();
            //旋转
            Turn ();
        }

        /// <summary>
        /// 移动
        /// </summary>
        private void Move ()
        {
            //创建一个坦克的速度向量
            Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;

            //刚体移动
            m_Rigidbody.MovePosition(m_Rigidbody.position + movement);
        }

        /// <summary>
        /// 旋转
        /// </summary>
        private void Turn ()
        {
            //根据输入,旋转速度以及每帧的时间计算旋转的值
            float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;

            //创建y轴的四元数旋转
            Quaternion turnRotation = Quaternion.Euler (0f, turn, 0f);

            //刚体旋转
            m_Rigidbody.MoveRotation (m_Rigidbody.rotation * turnRotation);
        }
    }
}

TankMovement

using UnityEngine;
using UnityEngine.UI;

namespace Complete
{
    /// <summary>
    /// 坦克射击
    /// </summary>
    public class TankShooting : MonoBehaviour
    {
        /// <summary>
        /// 玩家编号
        /// </summary>
        ;
        /// <summary>
        /// 炮弹刚体
        /// </summary>
        public Rigidbody m_Shell;
        /// <summary>
        /// 射击的位置
        /// </summary>
        public Transform m_FireTransform;
        /// <summary>
        /// 射击的箭头滑动条
        /// </summary>
        public Slider m_AimSlider;
        /// <summary>
        /// 发射声音
        /// </summary>
        public AudioSource m_ShootingAudio;
        /// <summary>
        /// 充能声音
        /// </summary>
        public AudioClip m_ChargingClip;
        /// <summary>
        /// 开火声音
        /// </summary>
        public AudioClip m_FireClip;
        /// <summary>
        /// 发射炮弹最小的力
        /// </summary>
        public float m_MinLaunchForce = 15f;
        /// <summary>
        /// 发射炮弹最大的力
        /// </summary>
        public float m_MaxLaunchForce = 30f;
        /// <summary>
        /// 发射炮弹的最大充能时间
        /// </summary>
        public float m_MaxChargeTime = 0.75f;       

        /// <summary>
        /// 控制发射的轴名
        /// </summary>
        private string m_FireButton;
        /// <summary>
        /// 当前的发射力
        /// </summary>
        private float m_CurrentLaunchForce;
        /// <summary>
        /// 充能速度
        /// </summary>
        private float m_ChargeSpeed;
        /// <summary>
        /// 是否已发射
        /// </summary>
        private bool m_Fired;                         

        private void OnEnable()
        {
            //重置当前发射力和箭头滑动条的值
            m_CurrentLaunchForce = m_MinLaunchForce;
            m_AimSlider.value = m_MinLaunchForce;
        }

        private void Start ()
        {
            //根据玩家编号设置 发射的轴名
            m_FireButton = "Fire" + m_PlayerNumber;

            //计算发射充能
            m_ChargeSpeed = (m_MaxLaunchForce - m_MinLaunchForce) / m_MaxChargeTime;
        }

        private void Update ()
        {
            //设置箭头滑动条的值
            m_AimSlider.value = m_MinLaunchForce;

            //如果当前的发射力大于最大发射力,并且没有发射
            if (m_CurrentLaunchForce >= m_MaxLaunchForce && !m_Fired)
            {
                //用最大发射力发射
                m_CurrentLaunchForce = m_MaxLaunchForce;
                Fire ();
            }
            //如果按下了发射按钮
            else if (Input.GetButtonDown (m_FireButton))
            {
                //设置发射标志位为false
                m_Fired = false;
                //设置当前发射力为最小力
                m_CurrentLaunchForce = m_MinLaunchForce;

                //播放充能声音
                m_ShootingAudio.clip = m_ChargingClip;
                m_ShootingAudio.Play ();
            }
            //如果发射按钮被按住且炮弹并没有发射
            else if (Input.GetButton (m_FireButton) && !m_Fired)
            {
                //更新当前发射力
                m_CurrentLaunchForce += m_ChargeSpeed * Time.deltaTime;
                //更新箭头滑动条的值
                m_AimSlider.value = m_CurrentLaunchForce;
            }
            //如果发射键松开且炮弹没有发射
            else if (Input.GetButtonUp (m_FireButton) && !m_Fired)
            {
                //发射炮弹
                Fire ();
            }
        }

        /// <summary>
        /// 发射
        /// </summary>
        private void Fire ()
        {
            //设置发射标志位
            m_Fired = true;

            //获取炮弹刚体的引用
            Rigidbody shellInstance =
                Instantiate (m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;

            //设置刚体的速度
            shellInstance.velocity = m_CurrentLaunchForce * m_FireTransform.forward; 

            //播放发射声音
            m_ShootingAudio.clip = m_FireClip;
            m_ShootingAudio.Play ();

            //重置当前发射力为最小发射力
            m_CurrentLaunchForce = m_MinLaunchForce;
        }
    }
}

TankShooting

using UnityEngine;

namespace Complete
{
    /// <summary>
    /// 炮弹爆炸
    /// </summary>
    public class ShellExplosion : MonoBehaviour
    {
        /// <summary>
        /// 坦克层
        /// </summary>
        public LayerMask m_TankMask;
        public ParticleSystem m_ExplosionParticles;
        /// <summary>
        /// 爆炸声源
        /// </summary>
        public AudioSource m_ExplosionAudio;
        /// <summary>
        /// 最大伤害
        /// </summary>
        public float m_MaxDamage = 100f;
        /// <summary>
        /// 爆炸力
        /// </summary>
        public float m_ExplosionForce = 1000f;
        /// <summary>
        /// 炮弹的生命周期
        /// </summary>
        public float m_MaxLifeTime = 2f;
        /// <summary>
        /// 爆炸半径
        /// </summary>
        public float m_ExplosionRadius = 5f;                  

        private void Start ()
        {
            //如果炸弹没有被销毁,经过指定时间后自动销毁
            Destroy (gameObject, m_MaxLifeTime);
        }

        private void OnTriggerEnter (Collider other)
        {
            //以炮弹为中心,爆炸半径为半径发射相交球
            Collider[] colliders = Physics.OverlapSphere (transform.position, m_ExplosionRadius, m_TankMask);

            //循环遍历碰撞体
            ; i < colliders.Length; i++)
            {
                //获取目标刚体
                Rigidbody targetRigidbody = colliders[i].GetComponent<Rigidbody> ();

                //如果没有刚体,则继续检测下一个
                if (!targetRigidbody)
                    continue;

                //目标刚体添加爆炸力
                targetRigidbody.AddExplosionForce (m_ExplosionForce, transform.position, m_ExplosionRadius);

                //获取目标的血量
                TankHealth targetHealth = targetRigidbody.GetComponent<TankHealth> ();

                //如果没有,检测下一个
                if (!targetHealth)
                    continue;

                //根据目标位置计算伤害
                float damage = CalculateDamage (targetRigidbody.position);

                //目标受到伤害
                targetHealth.TakeDamage (damage);
            }

            m_ExplosionParticles.transform.parent = null;

            //播放爆炸粒子效果
            m_ExplosionParticles.Play();

            //播放爆炸声音
            m_ExplosionAudio.Play();

            //定时销毁粒子系统
            Destroy (m_ExplosionParticles.gameObject, m_ExplosionParticles.duration);

            //销毁炮弹
            Destroy (gameObject);
        }

        /// <summary>
        /// 计算伤害
        /// </summary>
        /// <param name="targetPosition">目标位置</param>
        /// <returns></returns>
        private float CalculateDamage (Vector3 targetPosition)
        {
            //创建一个从自身到目标的向量
            Vector3 explosionToTarget = targetPosition - transform.position;

            //计算这个向量的模
            float explosionDistance = explosionToTarget.magnitude;

            //计算相对距离
            float relativeDistance = (m_ExplosionRadius - explosionDistance) / m_ExplosionRadius;

            //根据距离比例和最大伤害计算伤害
            float damage = relativeDistance * m_MaxDamage;

            //确保最小伤害为0
            damage = Mathf.Max (0f, damage);

            return damage;
        }
    }
}

ShellExplosion

using UnityEngine;

namespace Complete
{
    /// <summary>
    /// UI朝向控制
    /// </summary>
    public class UIDirectionControl : MonoBehaviour
    {
        /// <summary>
        /// 是否使用相对旋转
        /// </summary>
        public bool m_UseRelativeRotation = true;       

        /// <summary>
        /// 局部旋转
        /// </summary>
        private Quaternion m_RelativeRotation;                        

        private void Start ()
        {
            //局部旋转为父对象的局部旋转
            m_RelativeRotation = transform.parent.localRotation;
        }

        private void Update ()
        {
            if (m_UseRelativeRotation)
                transform.rotation = m_RelativeRotation;
        }
    }
}

UIDirectionControl

视频:https://pan.baidu.com/s/1eRFbQYA

项目:https://pan.baidu.com/s/1midmmuc

Tanks!Tutorial 学习的更多相关文章

  1. Python Tutorial 学习(八)--Errors and Exceptions

    Python Tutorial 学习(八)--Errors and Exceptions恢复 Errors and Exceptions 错误与异常 此前,我们还没有开始着眼于错误信息.不过如果你是一 ...

  2. Django 1.7 Tutorial 学习笔记

    官方教程在这里 : Here 写在前面的废话:)) 以前学习新东西,第一想到的是找本入门教程,按照书上做一遍.现在看了各种网上的入门教程后,我觉得还是看官方Tutorial靠谱.书的弊端一说一大推 本 ...

  3. 深度学习 Deep Learning UFLDL 最新 Tutorial 学习笔记 1:Linear Regression

    1 前言 Andrew Ng的UFLDL在2014年9月底更新了. 对于開始研究Deep Learning的童鞋们来说这真的是极大的好消息! 新的Tutorial相比旧的Tutorial添加了Conv ...

  4. SQL Expression Language Tutorial 学习笔记一

    http://docs.sqlalchemy.org/en/latest/core/tutorial.html Google 翻译了一下 SQLAlchemy Expression Language, ...

  5. FFmpeg的tutorial 学习

    一.前言: 这是一个学习 FFmpeg 的 tutorial 系列. 这个是一个对初学者比较友好的FFmpeg学习教程,作者一步步引导我们实现了一个音视频同步的播放器. 参考链接: 原文地址: htt ...

  6. Python Tutorial 学习(六)--Modules

    6. Modules 当你退出Python的shell模式然后又重新进入的时候,之前定义的变量,函数等都会没有了. 因此, 推荐的做法是将这些东西写入文件,并在适当的时候调用获取他们. 这就是为人所知 ...

  7. Python Tutorial 学习(四)--More Control Flow Tools

    4.1 if 表达式 作为最为人熟知的if.你肯定对这样的一些表达式不感到陌生: >>> x = int(raw_input("Please enter an intege ...

  8. Python Tutorial 学习(一)--Whetting Your Appetite

    Whetting Your Appetite [吊你的胃口]... 这里就直接原文奉上了... If you do much work on computers, eventually you fin ...

  9. 深度学习 Deep Learning UFLDL 最新Tutorial 学习笔记 5:Softmax Regression

    Softmax Regression Tutorial地址:http://ufldl.stanford.edu/tutorial/supervised/SoftmaxRegression/ 从本节開始 ...

随机推荐

  1. Bluedroid: 音频数据的传输流程

    一. UIPC:   Audio Flinger获取到a2dp的hw module,然后蓝牙协议栈有专用于发送和接收media数据的线程,名称:btif_media_task.   蓝牙与Audio的 ...

  2. DevExpress WinForms使用教程:WinForms Fluent Design和Acrylic Effects

    在先前的版本发布中,宣布支持Fluent Design Form和Acrylic effects——旨在复制Microsoft下一代UI metaphor的新功能.本文主要介绍如何实现此功能,并明确说 ...

  3. Spring异步调用注解@Async的使用

    1.pom依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spri ...

  4. java 移动开发获取多级下拉框json数据的类和mobile-select-area插件

    我这里以行政区划做例子 //这个类是把数据库中的行政区划转化为json格式的data @SuppressWarnings("rawtypes")public class XzqhL ...

  5. api中locale或language字段,传送客户端地域信息,一般为下划线

    在请求新闻的分类信息和新闻内容时,需要在api地址中传入local参数,根据用户地区不同返回不同的新闻和分类. local参数,通过navigator.languages[0]获取, 但是,问题来了: ...

  6. L313 珊瑚裸鼠灭绝

    This week the Australian government declared the extinction of a tiny rodent called Bramble Cay melo ...

  7. ios九宫格算法

    - (void)viewDidLoad { [super viewDidLoad]; //1.总列数(一行最多3列) ; CGFloat appW=; CGFloat appH=; //2.间隙=(控 ...

  8. java学习笔记18(基本类型包装类,system类)

    基本类型包装类 定义:程序界面用户输入的数据都是以字符串类型存储的,如果需要操作这些字符串进行运算,需要转成基本数据类型,这时就要用到基本类型包装类,例: public class Demo { pu ...

  9. Java NIO系列教程

    http://ifeve.com/overview/ http://tutorials.jenkov.com/java-nio/nio-vs-io.html

  10. SpringBoot2静态资料访问

    在SpringBoot2内要继承WebMvcConfigurationSupport并重写addResourceHandlers方法才能访问到静态资料. @Configuration public c ...