首页 > 代码库 > Tanks!Tutorial 学习

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 =http://www.mamicode.com/ 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>
        public int m_PlayerNumber = 1;              
        /// <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 =http://www.mamicode.com/ 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>
        public int m_PlayerNumber = 1;              
        /// <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 =http://www.mamicode.com/ 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 =http://www.mamicode.com/ 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);

            //循环遍历碰撞体
            for (int i = 0; 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 学习