本系列文章是根據(jù)官方視頻教程而寫下的學(xué)習(xí)筆記,原官方視頻教程網(wǎng)址:https://unity3d.com/cn/learn/tutorials/s/tanks-tutorial
系列其他筆記傳送門
Unity官方教程《Tanks》學(xué)習(xí)筆記(一)
Unity官方教程《Tanks》學(xué)習(xí)筆記(二)
Unity官方教程《Tanks》學(xué)習(xí)筆記(三)
Unity官方教程《Tanks》學(xué)習(xí)筆記(五)
創(chuàng)建子彈
本小節(jié)的目標是創(chuàng)建子彈井佑,完善子彈的爆炸禀忆、音效等效果朱巨,并且利用腳本對子彈進行控制呀潭。
首先械蹋,在models文件夾下俏竞,找到Shell模型绸硕,把它拖拽到Hierarchy根目錄下,我們對它進行編輯:
①創(chuàng)建Capsule Collider魂毁,勾選“Is Trigger”玻佩,把Direction選擇為Z-Axis;更改Center的坐標為(0,0,0.2)席楚;更改Radius為0.15以及Height為0.55咬崔。
Capsule Collider實際上是一個膠囊碰撞器,由一個圓柱體連接兩個半球體組成烦秩,在上面修改了該碰撞器的半徑以及高度后垮斯,我們可以觀察到子彈的碰撞邊界是這樣的:
②創(chuàng)建Rigidbody,為子彈添加剛體只祠,因為子彈要與坦克產(chǎn)生碰撞兜蠕,也就需要剛體。如果沒有剛體铆农,那么子彈就不會有物理效果牺氨。
③創(chuàng)建Light組件。
④在Prefabs文件夾下墩剖,找到ShellExplosion預(yù)制件猴凹,拖拽它到Shell中,成為Shell的子對象岭皂。選擇ShellExplosion郊霎,添加Audio Source,音效選擇為ShellExplosion爷绘,取消勾選Play On Awake书劝。
⑤在Scripts/Shell文件夾內(nèi)进倍,找到ShellExplosion腳本,把它拖拽到Shell下购对。該腳本控制了Shell的行為猾昆,雙擊打開該腳本,開始編輯:
using UnityEngine;
public class ShellExplosion : MonoBehaviour
{
public LayerMask m_TankMask; //Player的層級
public ParticleSystem m_ExplosionParticles; //爆炸的粒子系統(tǒng)
public AudioSource m_ExplosionAudio; //Audio
public float m_MaxDamage = 100f; //最大傷害
public float m_ExplosionForce = 1000f;
public float m_MaxLifeTime = 2f;
public float m_ExplosionRadius = 5f; //子彈爆炸半徑
private void Start()
{
Destroy(gameObject, m_MaxLifeTime); //在子彈的存活時間過后骡苞,自動銷毀
}
/**
* 當子彈與其他物體發(fā)生碰撞并且碰撞器的Is Trigger勾選的情況下垂蜗,會調(diào)用該函數(shù)
*/
private void OnTriggerEnter(Collider other)
{
// Find all the tanks in an area around the shell and damage them.
/**
* Physics.OverlapSphere(Vector3 position,float radius,int layerMask mask)
* @parameter position 球體的球心
* @parameter radius 球體的半徑
* @parameter mask 只有該層級與球體碰撞才會被選擇
* 該函數(shù)用于返回在球體范圍內(nèi)與球體產(chǎn)生碰撞的特定層級的碰撞器
*/
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腳本
TankHealth targetHealth = targetRigidbody.GetComponent<TankHealth>();
if(!targetHealth){
continue;
}
//計算傷害并扣除血量
float damage = CalculateDamage(targetRigidbody.position);
targetHealth.TakeDamage(damage);
}
//把粒子系統(tǒng)與Shell的關(guān)聯(lián)解除
m_ExplosionParticles.transform.parent = null;
//播放爆炸效果及音效
m_ExplosionParticles.Play();
m_ExplosionAudio.Play();
//粒子系統(tǒng)的爆炸效果播放完畢后,刪除該object
Destroy(m_ExplosionParticles.gameObject,m_ExplosionParticles.main.duration);
Destroy(gameObject); //回收Shell
}
private float CalculateDamage(Vector3 targetPosition)
{
// Calculate the amount of damage a target should take based on it's position.
//1解幽、創(chuàng)建一個向量贴见,由Shell指向目標
Vector3 explosionToTarget = targetPosition - transform.position;
//2、計算Shell與目標之間的距離
float explosionDistance = explosionToTarget.magnitude;
//3躲株、根據(jù)上一步的距離計算出傷害權(quán)重
float relativeDistance = (m_ExplosionRadius - explosionDistance) / m_ExplosionRadius;
//4片部、根據(jù)傷害權(quán)重計算出最終傷害
float damage = relativeDistance * m_MaxDamage;
//5、最低傷害為0霜定,這是因為第三步的數(shù)值有可能是負值档悠,這樣就相當于沒有傷害
damage = Mathf.Max(0f,damage);
return damage;
}
}
接著,我們初始化該腳本使用的公有變量:
這里要注意的是然爆,Tank Mask的選取必須是Players站粟,否則后面子彈的爆炸將不會作用于坦克黍图。
完成以上的步驟之后曾雕,把Shell拖拽到Prefabs文件夾下,成為預(yù)制件助被,然后刪除掉Hierarchy根目錄下的Shell剖张,并保存當前場景。
發(fā)射子彈
接下來就要實現(xiàn)子彈的發(fā)射功能揩环,并且子彈可以蓄能搔弄,蓄能越久射擊距離也就越長,因此也就需要有一個蓄能狀態(tài)的指示丰滑。
首先顾犹,選中Hierarchy層級下的Tank,為他新建一個子對象褒墨,Create Empty炫刷,命名為FireTransform。該對象主要是規(guī)定子彈的射出位置郁妈。把FireTransform的transform設(shè)置為如下:
接著浑玛,在Tank的Canvas下,新建一個Slider噩咪,命名為AimSlider镣屹。選定AimSlider署尤,對它的Slider組件進行一些調(diào)整:
①取消勾選Interactable
②Transition設(shè)置為None
③Direction設(shè)置為Bottom to Top
④Min Value設(shè)置為15
⑤Max Value設(shè)置為30
⑥Rect Transform屬性可以通過拖動改變形狀疗涉,也可以通過設(shè)置數(shù)值的形式指定,這里設(shè)置為(1筋搏,-9,-1,1,3)
如下圖所示:
下一步是展開AimSlider的子對象厕隧,把其中的Background和Handle Slide Area刪除拆又,只保留Fill Area。同時選中AimSlider和Fill Area栏账,點擊Anchor Presets帖族,按住Alt鍵以選中右下角的選項:
展開Fill Area,選中Fill挡爵,把Height設(shè)置為0竖般,Source Image選擇為Aim Arrow:
接下來就是利用腳本對坦克的射擊行為作出控制,在/Scripts/Tank文件夾下找到Tank Shooting腳本茶鹃,把它拖拽到Tank中涣雕,然后我們打開編輯它:
using UnityEngine;
using UnityEngine.UI;
public class TankShooting : MonoBehaviour
{
public int m_PlayerNumber = 1; //玩家序號
public Rigidbody m_Shell; //炮彈
public Transform m_FireTransform; //發(fā)射點位置
public Slider m_AimSlider; //蓄能條
public AudioSource m_ShootingAudio; //Audio
public AudioClip m_ChargingClip; //蓄能的音效
public AudioClip m_FireClip; //發(fā)射的音效
public float m_MinLaunchForce = 15f; //最小發(fā)射力量
public float m_MaxLaunchForce = 30f; //最大發(fā)射力量
public float m_MaxChargeTime = 0.75f; //最大充能時間
private string m_FireButton;
private float m_CurrentLaunchForce;
private float m_ChargeSpeed;
private bool m_Fired;
/**
* 初始化
*/
private void OnEnable()
{
m_CurrentLaunchForce = m_MinLaunchForce;
m_AimSlider.value = m_MinLaunchForce;
}
private void Start()
{
//保存當前player發(fā)射按鍵的字符串
m_FireButton = "Fire" + m_PlayerNumber;
//充能速度
m_ChargeSpeed = (m_MaxLaunchForce - m_MinLaunchForce) / m_MaxChargeTime;
}
private void Update()
{
// Track the current state of the fire button and make decisions based on the current launch force.
m_AimSlider.value = m_MinLaunchForce;
//如果充能超過最大充能并且還沒發(fā)射子彈
if(m_CurrentLaunchForce >= m_MaxLaunchForce && !m_Fired){
m_CurrentLaunchForce = m_MaxLaunchForce;
Fire();
}
//根據(jù)按鍵判斷是否按下了開火鍵
else if(Input.GetButtonDown(m_FireButton)){
m_Fired = false;
m_CurrentLaunchForce = m_MinLaunchForce; //從最小充能開始
m_ShootingAudio.clip = m_ChargingClip; //切換成充能音效
m_ShootingAudio.Play();
}
//持續(xù)按下開火鍵的過程中,不斷增加充能
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();
}
}
private void Fire()
{
// Instantiate and launch the shell.
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;
}
}
接著挣郭,就是對腳本的公有變量進行賦值:
完成初始化之后,點擊右上角的Apply疗韵,使得改動在預(yù)制件中生效兑障。
現(xiàn)在可以開始游戲測試一下了。測試完畢之后蕉汪,把Hierarchy層的Tank刪除掉流译,保存當前場景。