//TankManager.cs
using System;
using UnityEngine;
[Serializable]
public class TankManager
{
public Color m_PlayerColor;
public Transform m_SpawnPoint;
[HideInInspector] public int m_PlayerNumber;
[HideInInspector] public string m_ColoredPlayerText;
[HideInInspector] public GameObject m_Instance;
[HideInInspector] public int m_Wins;
private MyTankMovement m_Movement;
private MyTankShooting m_Shooting;
private GameObject m_CanvasGameObject;
public void Setup()
{
m_Movement = m_Instance.GetComponent<MyTankMovement>();
m_Shooting = m_Instance.GetComponent<MyTankShooting>();
m_CanvasGameObject = m_Instance.GetComponentInChildren<Canvas>().gameObject;
m_Movement.PlayerNumber = m_PlayerNumber;
m_Shooting.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;
}
}
public void DisableControl()
{
m_Movement.enabled = false;
m_Shooting.enabled = false;
m_CanvasGameObject.SetActive(false);
}
public void EnableControl()
{
m_Movement.enabled = true;
m_Shooting.enabled = true;
m_CanvasGameObject.SetActive(true);
}
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);
}
}
//GameManagers.cs
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
//public class TankManager123
//{
// public GameObject Tank;
// public MyTankShooting my;
// public MyTankMovement mymove;
// public int m_RoundNumber;
//}
public class GameManager : MonoBehaviour
{
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;
//private TankManager123 tk123;
private int m_RoundNumber;
private WaitForSeconds m_StartWait;
private WaitForSeconds m_EndWait;
private TankManager m_RoundWinner;
private TankManager m_GameWinner;
private void Start()
{
//tk123.m_RoundNumber = 123321;
m_StartWait = new WaitForSeconds(m_StartDelay);
m_EndWait = new WaitForSeconds(m_EndDelay);
SpawnAllTanks();
SetCameraTargets();
StartCoroutine(GameLoop());//协程
}
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();
}
}
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;
}
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());
}
}
private IEnumerator RoundStarting()
{
ResetAllTanks();//?这是什么方法?
DisableTankControl();//?
m_CameraControl.SetStartPositionAndSize();//?
m_RoundNumber++;//?
m_MessageText.text = "ROUND_ "+m_RoundNumber ;
yield return m_StartWait;//协程返回写yield,return
}
private IEnumerator RoundPlaying()
{
EnableTankControl();//?
m_MessageText.text = " ";
while (!OneTankLeft ())//?
{
yield return null;
}
}
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;
}
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;
}
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;
}
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 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();
}
}
}
//CameraContral.cs
using UnityEngine;
public class CameraControl : MonoBehaviour
{
//m_DampTime就是过度时间,断定他是过渡时间是看SmoothDamp的传参
public float m_DampTime = 0.2f;
public float m_ScreenEdgeBuffer = 4f;
public float m_MinSize = 6.5f;
[HideInInspector] public Transform[] m_Targets; //HideInInspector的作用是暂时将public的代码隐藏,就无法再unity检查器中看到
//Targets是一个transform类型的数组,这里Targets作用是定义所有坦克对象的数组
private Camera m_Camera;
private float m_ZoomSpeed;
private Vector3 m_MoveVelocity;
//两个坦克中心点(多个坦克中心点)
private Vector3 m_DesiredPosition;
private void Awake()
{
m_Camera = GetComponentInChildren<Camera>();//GetComponent作用是获取物体组件,GetComponentInChildren的作用是在子物体中获取组件
}
private void FixedUpdate()
{
Move();
Zoom();
}
private void Move()//Move就是遍历所有的坦克求出他们的平均点,然后将平均点给到CameraRig的position
{
FindAveragePosition();
transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
}
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)//sctiveSelf这个属性表示当前物体的Active状态
continue;
averagePos += m_Targets[i].position;
numTargets++;
}
if (numTargets > 0)
averagePos /= numTargets;
averagePos.y = transform.position.y;
m_DesiredPosition = averagePos;
}
private void Zoom()
{
float requiredSize = FindRequiredSize();
m_Camera.orthographicSize = Mathf.SmoothDamp(m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
}
private float FindRequiredSize()
{
Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);//这个方法InverseTransformPoint用来计算本地空间
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;
}
public void SetStartPositionAndSize()
{
FindAveragePosition();
transform.position = m_DesiredPosition;
m_Camera.orthographicSize = FindRequiredSize();
}
}
//MyShellExplosion.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static UnityEngine.GraphicsBuffer;
public class MyShellExplosion : MonoBehaviour
{
public LayerMask TankMask;
public ParticleSystem ExplosionParticles;//接收粒子特效
public AudioSource ExplosionAudio;
public float MaxDamage = 100f;
public float ExplisionForce = 1000f;
public float MaxLifeTime = 2f;
public float ExplosionRadius = 5f;//爆炸范围半径
// Start is called before the first frame update
void Start()
{
Destroy(transform.gameObject,MaxLifeTime );//重载就是两个方法,名字一样参数不一样(相当于一个行为的不同版本)
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
//获取到半径为R的一个球型里面的所有物体
Collider [] targetCollider= Physics.OverlapSphere(transform.position, ExplosionRadius, TankMask);
for(int i = 0; i<targetCollider .Length;i ++)
{
//获取刚体组件
Rigidbody target = targetCollider[i].GetComponent<Rigidbody>();
if (target == null)
continue;
//调用刚体组件下方的爆炸方法
target.AddExplosionForce(ExplisionForce, transform.position, ExplosionRadius);
//扣血
TankHealth targetTankHealth=targetCollider[i].GetComponent<TankHealth>();
//计算坦克与爆炸的距离
float damage = CalculateDamage(target .gameObject .transform.position );
targetTankHealth.TakeDamage(damage);
}
//TankHealth tankHealth= other.gameObject.GetComponent<TankHealth>();//通过坦克自身的Cokkider组件(other.gameObject),再通过gameObject来获取GetComponent来获取TankHealth。炮弹跟坦克发生碰撞之后,立马通过box collider来Getocmponent的血量组件
//if(tankHealth !=null )
//tankHealth.TakeDamage(20);//这句话就会使CurrentHealth血量减去20
//other.gameObject.SetActive(true );//gameObject下有一个setActive方法设置true是启用,设置false是不启用,设置true和false时候会调用onenable方法
//Debug.Log("触发了一个物体");
//播放爆炸特效
ExplosionParticles.transform.parent = null;
ExplosionParticles.Play();
//播放爆炸声音
//void OnTriggerEnter(Collider other)
//{
// // 检查音频源是否启用
// if (!ExplosionAudio .enabled)
// {
// // 如果未启用,则启用音频源
// ExplosionAudio.enabled = true;
// }
// // 播放音频
// // ExplosionAudio.Play();
//}
ExplosionAudio.Play();
//销毁爆炸的特效
Destroy(ExplosionParticles.gameObject,ExplosionParticles .main .duration );//main.duration获取粒子特效持续时间
//销毁炮弹
Destroy(gameObject );
}
/// <summary>
/// 计算爆炸伤害
/// </summary>
/// <param name="targetPosition">爆炸的中心点</param>
/// <returns></returns>
private float CalculateDamage(Vector3 targetPosition)
{
//计算坦克与爆炸点的距离
Vector3 v3 = targetPosition - transform.position;//计算两点间距离
float distance = v3.magnitude;//获得它距离的具体的float值
float damage = ((ExplosionRadius - distance) / ExplosionRadius) * MaxDamage;//通过float值和半径(distance)来计算出占比
damage = Mathf.Max(0, damage);
return damage;
}
}
//TankHealth.cs
using UnityEngine;
using UnityEngine.UI;
public class TankHealth : MonoBehaviour
{
public float m_StartingHealth = 100f; //坦克初始血量
public Slider m_Slider; //UI控件
public Image m_FillImage; //UI控件
public Color m_FullHealthColor = Color.green; //ui控件
public Color m_ZeroHealthColor = Color.red;
public GameObject m_ExplosionPrefab;//爆炸的预制体
private AudioSource m_ExplosionAudio;//爆炸音效
private ParticleSystem m_ExplosionParticles;//坦克爆炸的ParticleSystem粒子特效,
//坦克当前血量
private float m_CurrentHealth;
private bool m_Dead;//表示坦克是否死亡,true是死亡,false是生存
private void Awake()
{
//从爆炸预制体中获取爆炸粒子特效
m_ExplosionParticles = Instantiate(m_ExplosionPrefab).GetComponent<ParticleSystem>();//Instantiate是实体化,Instantiate(m_ExplosionPrefab)初始化这样一个预制体。调用GetComponent<ParticleSystem>,从前面的预制体里面获取组件,获取OarticleSystem组件,并赋值给ExplosionParticles
m_ExplosionAudio = m_ExplosionParticles.GetComponent<AudioSource>();//从ExplosionParticles这个粒子特效中,获取GetComponent的AudioSource声音播放组件
m_ExplosionParticles.gameObject.SetActive(false);//坦克不会一场就爆炸,所有需要先将报纸粒子特效置为不可用
}
private void OnEnable()//物体可用时调用OnEnable方法
{
m_CurrentHealth = m_StartingHealth;//当前血量设置为初始血量
m_Dead = false;
SetHealthUI();//用来更新UI界面,血量实时显示在画面当中
}
public void TakeDamage(float amount)
{
m_CurrentHealth -= amount;
SetHealthUI();
if (m_CurrentHealth<=0f&&!m_Dead )
{
OnDeath();
}
Debug.Log(m_CurrentHealth);
// Adjust the tank's current health, update the UI based on the new health and check whether or not the tank is dead.
}
private void SetHealthUI()
{
//将当前的血量展示在UI界面中
m_Slider.value = m_CurrentHealth;
m_FillImage.color = Color.Lerp(m_ZeroHealthColor, m_FullHealthColor, m_CurrentHealth / m_StartingHealth); //颜色差值计算.解释(m_CureenHealth/m_StartingHealth是用来计算现有血量占总血量的比例,如果大于百分之50,则偏向于m_FullHealthColor绿色,小于百分之50偏向于m_ZeroHealthColor红色)
//if (m_CurrentHealth > 40)//设置血量颜色,当大于40的时候是绿色,反之为红色
// m_FillImage.color = m_FullHealthColor;
//else
// m_FillImage.color = m_ZeroHealthColor;
// Adjust the value and colour of the slider.
}
private void OnDeath()
{
m_Dead = true;
//播放粒子特效
m_ExplosionParticles.transform.position = transform.position;
m_ExplosionParticles.gameObject.SetActive(true);
m_ExplosionParticles.Play();
//播放声音
m_ExplosionAudio.Play();
gameObject.SetActive(false);// Play the effects for the death of the tank and deactivate it.
}
}
//MyTankShooting.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MyTankShooting : MonoBehaviour
{
public int PlayerNumber = 1;
public GameObject FireTransform;
public GameObject Shell;
public Slider AimSlider;
public AudioSource ShootingAudio;
public AudioClip ChargingClip;
public AudioClip FireClip;
public float MinLaunchForce = 15f;
public float MaxLunchForce = 30f;
public float ChargeTime = 0.75f;
// Start is called before the first frame update
private string FireButton;
private float ChargeSpeed;
private float CurrentLaunchForce;
private bool Fired;
void Start()
{
FireButton = "Fire" + PlayerNumber;
ChargeSpeed = (MaxLunchForce - MinLaunchForce) / ChargeTime;
}
// Update is called once per frame
void Update()
{
//if (Input.GetButtonDown(FireButton ))
//{
// GameObject gameObjectInstance = Instantiate(Shell, FireTransform.transform.position, FireTransform.transform.rotation);
// Rigidbody rigidbody = gameObjectInstance.GetComponent<Rigidbody>();
// rigidbody.velocity = FireTransform.transform.forward * 15;
//}
if (Input .GetButtonDown(FireButton))
{
CurrentLaunchForce = MinLaunchForce;
ShootingAudio.clip = ChargingClip;
ShootingAudio.Play();
Fired = false;
}
else if (Input .GetButton (FireButton )&&!Fired )
{
CurrentLaunchForce += ChargeSpeed * Time.deltaTime;
//if (ShootingAudio.clip == FireClip)
//{
// ShootingAudio.clip = ChargingClip;
// ShootingAudio.Play();
//}
AimSlider.value = CurrentLaunchForce;
if (CurrentLaunchForce >=MaxLunchForce )
{
CurrentLaunchForce = MaxLunchForce;
Fire();
}
}
else if (Input .GetButtonUp(FireButton )&&!Fired )
{
Fire();
}
}
void Fire()
{
AimSlider.value = MinLaunchForce ;
Fired = true;
GameObject gameObjectInstance = Instantiate(Shell, FireTransform.transform.position, FireTransform.transform.rotation);
Rigidbody rigidbody = gameObjectInstance.GetComponent<Rigidbody>();
rigidbody.velocity = FireTransform.transform.forward * CurrentLaunchForce;
CurrentLaunchForce = MinLaunchForce;
ShootingAudio.clip = FireClip;
ShootingAudio.Play();
}
}
//MyTankMovement.cs
using UnityEngine;
public class MyTankMovement : MonoBehaviour
{
public int PlayerNumber = 1;
public float Speed = 12;
public float TurnSpeed = 180;
public AudioSource MovementAudio;
public AudioClip EngineIdling;
public AudioClip EngineDriving;
public float PichRage = 0.2f;
private Rigidbody rb;
private string MovementAxisName;
private string TurnAxisName;
private float MovementInputValue;
private float TurnInputValue;
private float OriginalPitch;
// Start is called before the first frame update
public void Awake()
{
rb = GetComponent<Rigidbody>();
}
void Start()
{
MovementAxisName = "Horizontal"+PlayerNumber ;
TurnAxisName = "Vertical"+PlayerNumber ;
OriginalPitch = MovementAudio.pitch;
}
// Update is called once per frame
void Update()//所有信息都可以获取
{
MovementInputValue = Input.GetAxis(TurnAxisName);
TurnInputValue = Input.GetAxis(MovementAxisName);
Debug.Log(MovementInputValue);
//调用播放声音方法
if (Mathf.Abs(MovementInputValue) < 0.1f &&Mathf.Abs(TurnInputValue) < 0.1)
{
if (MovementAudio .clip ==EngineDriving )
{
MovementAudio.clip = EngineIdling;
MovementAudio.pitch =Random .Range(OriginalPitch - PichRage , OriginalPitch + PichRage );
MovementAudio.Play();
}
}
else
{
if (MovementAudio.clip == EngineIdling )
{
MovementAudio.clip = EngineDriving ;
MovementAudio.pitch = Random.Range(OriginalPitch - PichRage, OriginalPitch + PichRage);
MovementAudio.Play();
}
}
}
private void FixedUpdate()//fixedupdate是固定帧率,间隔一段时间才会出发一次
{
Move();
Turn();
}
void Move()
{
Vector3 movementV3 = transform.forward * MovementInputValue * Speed * Time.deltaTime;
rb.MovePosition(rb.position + movementV3);
}
void Turn()
{
float turn = TurnInputValue * TurnSpeed * Time.deltaTime;
Quaternion quaternion = Quaternion.Euler(0, turn, 0);
rb.MoveRotation(rb.rotation * quaternion);//位置用加减法,旋转用惩罚,后面乘的是四元数
}
}
标签:C#,void,float,transform,private,unity,position,public,3D
From: https://blog.csdn.net/m0_74031997/article/details/142140916