Unity官方教程《Tanks》學(xué)習(xí)筆記(四)

本系列文章是根據(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

Capsule Collider實際上是一個膠囊碰撞器,由一個圓柱體連接兩個半球體組成烦秩,在上面修改了該碰撞器的半徑以及高度后垮斯,我們可以觀察到子彈的碰撞邊界是這樣的:


綠色邊界為碰撞邊界

②創(chuàng)建Rigidbody,為子彈添加剛體只祠,因為子彈要與坦克產(chǎn)生碰撞兜蠕,也就需要剛體。如果沒有剛體铆农,那么子彈就不會有物理效果牺氨。
③創(chuàng)建Light組件。
④在Prefabs文件夾下墩剖,找到ShellExplosion預(yù)制件猴凹,拖拽它到Shell中,成為Shell的子對象岭皂。選擇ShellExplosion郊霎,添加Audio Source,音效選擇為ShellExplosion爷绘,取消勾選Play On Awake书劝。

ShellExplosion

在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;
    }
}

接著,我們初始化該腳本使用的公有變量:

Shell Script

這里要注意的是然爆,Tank Mask的選取必須是Players站粟,否則后面子彈的爆炸將不會作用于坦克黍图。

完成以上的步驟之后曾雕,把Shell拖拽到Prefabs文件夾下,成為預(yù)制件助被,然后刪除掉Hierarchy根目錄下的Shell剖张,并保存當前場景。

發(fā)射子彈

接下來就要實現(xiàn)子彈的發(fā)射功能揩环,并且子彈可以蓄能搔弄,蓄能越久射擊距離也就越長,因此也就需要有一個蓄能狀態(tài)的指示丰滑。

首先顾犹,選中Hierarchy層級下的Tank,為他新建一個子對象褒墨,Create Empty炫刷,命名為FireTransform。該對象主要是規(guī)定子彈的射出位置郁妈。把FireTransform的transform設(shè)置為如下:


FireTransform

接著浑玛,在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)
如下圖所示:


Rect Transform
AimSlider

下一步是展開AimSlider的子對象厕隧,把其中的Background和Handle Slide Area刪除拆又,只保留Fill Area。同時選中AimSlider和Fill Area栏账,點擊Anchor Presets帖族,按住Alt鍵以選中右下角的選項:


Anchor Preset

展開Fill Area,選中Fill挡爵,把Height設(shè)置為0竖般,Source Image選擇為Aim Arrow:


Fill

接下來就是利用腳本對坦克的射擊行為作出控制,在/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刪除掉流译,保存當前場景。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末者疤,一起剝皮案震驚了整個濱河市福澡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驹马,老刑警劉巖革砸,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異糯累,居然都是意外死亡算利,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門寇蚊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笔时,“玉大人,你說我怎么就攤上這事仗岸≡使ⅲ” “怎么了借笙?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長较锡。 經(jīng)常有香客問我业稼,道長,這世上最難降的妖魔是什么蚂蕴? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任低散,我火速辦了婚禮,結(jié)果婚禮上骡楼,老公的妹妹穿的比我還像新娘熔号。我一直安慰自己,他們只是感情好鸟整,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布引镊。 她就那樣靜靜地躺著,像睡著了一般篮条。 火紅的嫁衣襯著肌膚如雪弟头。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天涉茧,我揣著相機與錄音赴恨,去河邊找鬼。 笑死伴栓,一個胖子當著我的面吹牛伦连,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挣饥,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼除师,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了扔枫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤锹安,失蹤者是張志新(化名)和其女友劉穎短荐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叹哭,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡忍宋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了风罩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糠排。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖超升,靈堂內(nèi)的尸體忽然破棺而出入宦,到底是詐尸還是另有隱情哺徊,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布乾闰,位于F島的核電站落追,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏涯肩。R本人自食惡果不足惜轿钠,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望病苗。 院中可真熱鬧疗垛,春花似錦、人聲如沸硫朦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阵幸。三九已至花履,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挚赊,已是汗流浹背诡壁。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留荠割,地道東北人妹卿。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像蔑鹦,于是被迫代替她去往敵國和親夺克。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361