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)建坦克以及控制坦克

首先凉敲,在Models文件夾內(nèi)找到Tank這個model票堵,把它拖拽到Hierarchy內(nèi)霸旗,我們在Tank的inspector視圖中颂跨,對其層級進行修改似炎,選擇Players,并僅對當(dāng)前對象修改掌呜。如下圖所示:


image.png

image.png

接著滓玖,我們選中Hierarchy中的Tank坪哄,為其添加若干個Component质蕉,分別是:Rigidbody、Box Collider翩肌、Audio Source模暗、Audio Source,并對這些部件進行設(shè)置如下:

Tank設(shè)置

然后念祭,我們把配置好的Tank從Hierarchy拖拽到Prefabs文件夾下担映,讓它成為一個預(yù)制件蛙紫,這樣以后我們可以重復(fù)利用該Tank秀鞭,而不用每次都重新配置兵琳。然后保存當(dāng)前場景。

因為整個游戲場景是在沙漠中的搜贤,所以坦克的行駛會有沙塵滾滾的效果,所以我們需要添加這一效果。在Prefabs文件夾內(nèi)濒旦,把DustTrail預(yù)制件拖拽到Hierarchy下的Tank內(nèi),讓其成為Tank的子對象再登,然后復(fù)制粘貼DustTrail尔邓,并分別重命名為LeftDustTrail和RightDustTrail,根據(jù)下面的官方教程锉矢,把兩個DustTrail的position進行調(diào)節(jié):


DustTrail

DustTrail設(shè)置

設(shè)置完畢后梯嗽,接下來就是對Tank的移動腳本進行設(shè)置。在/Assets/Scripts/Tank文件夾內(nèi)沽损,找到TankMoveMent.cs文件灯节,并把它拖拽到Hierarchy下的Tank內(nèi)。我們打開并編輯該腳本绵估,把里面的注釋符號去掉显晶,并添加邏輯如下:

using UnityEngine;

public class TankMovement : MonoBehaviour
{
    public int m_PlayerNumber = 1;         //游戲者的序號
    public float m_Speed = 12f;            //坦克移動速度
    public float m_TurnSpeed = 180f;       //坦克轉(zhuǎn)向的角速度
    public AudioSource m_MovementAudio;    
    public AudioClip m_EngineIdling;       //靜止的音效
    public AudioClip m_EngineDriving;      //移動的音效
    public float m_PitchRange = 0.2f;

    
    private string m_MovementAxisName;     
    private string m_TurnAxisName;         
    private Rigidbody m_Rigidbody;         
    private float m_MovementInputValue;    
    private float m_TurnInputValue;        
    private float m_OriginalPitch;         

    /**
     *  Scene加載的時候調(diào)用
     */
    private void Awake()
    {
        m_Rigidbody = GetComponent<Rigidbody>();
    }

    /**
     *  在Awake()之后,Update()之前調(diào)用
     */
    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()
    {
        // Store the player's input and make sure the audio for the engine is playing.
        m_MovementInputValue = Input.GetAxis(m_MovementAxisName);
        m_TurnInputValue = Input.GetAxis (m_TurnAxisName);

        EngineAudio ();
    }


    private void EngineAudio()
    {
        // Play the correct audio clip based on whether or not the tank is moving and what audio is currently playing.
        // 如果坦克處于靜止?fàn)顟B(tài)
        if (Mathf.Abs (m_MovementInputValue) < 0.1f && Mathf.Abs (m_TurnInputValue) < 0.1f)
        {
            //如果坦克播放的是行駛狀態(tài)的音效壹士,則替換
            if (m_MovementAudio.clip == m_EngineDriving)
            {
                // ... change the clip to idling and play it.
                m_MovementAudio.clip = m_EngineIdling;
                m_MovementAudio.pitch = Random.Range (m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                m_MovementAudio.Play ();
            }
        }
        else
        {
            // 如果坦克播放的是靜止?fàn)顟B(tài)的音效磷雇,則替換
            if (m_MovementAudio.clip == m_EngineIdling)
            {
                // ... change the clip to driving and play.
                m_MovementAudio.clip = m_EngineDriving;
                m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                m_MovementAudio.Play();
            }
        }
    }

    /**
     *  以固定的時間間隔調(diào)用,用于物理上的步驟躏救,比如行走唯笙、轉(zhuǎn)向
     */
    private void FixedUpdate()
    {
        // Move and turn the tank.
        Move ();
        Turn ();
    }


    private void Move()
    {
        // Adjust the position of the tank based on the player's input.
        Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;
        m_Rigidbody.MovePosition (m_Rigidbody.position + movement);
    }


    private void Turn()
    {
        // Adjust the rotation of the tank based on the player's input.
        float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;

        Quaternion turnRotation = Quaternion.Euler (0f,turn,0f);

        m_Rigidbody.MoveRotation (m_Rigidbody.rotation * turnRotation);
    }
}

修改完畢并保存文件,下一步我們需要初始化在腳本中聲明的幾個公有變量:Movement Audio盒使、Engine Idling崩掘、Engine Driving:


配置

二、控制攝像機

首先在Hierarchy的根目錄下創(chuàng)建一個空的GameObject少办,并重命名為“CameraRig”苞慢,修改其部分Transform數(shù)據(jù)如下:


CameraRig

接著,我們把Main Camera拖拽到CameraRig內(nèi)英妓,成為它的子對象挽放,并修改Main Camera的Transform數(shù)據(jù)如下:


Main Camera

接下來我們需要補充一些關(guān)于攝像機的知識:

1、perspective視圖和orthographic視圖
要想了解如何控制攝像機蔓纠,我們要首先知道攝像機的兩種不同視圖形式辑畦,上一章也有所提及:透視視圖和正交視圖,下面就用官方教程的一幅圖來直觀地解釋:

左側(cè)為透視視圖腿倚,右側(cè)為正交視圖

2纯出、正交攝像機的尺寸(Size)

正交攝像機的尺寸

調(diào)節(jié)Main Camera的size參數(shù),如果size變小,那么可視范圍變小且物體變大暂筝,有放大作用箩言。而size變大,可視范圍變大且物體變小焕襟,有縮小作用分扎。

3、攝像機的長寬比(aspect)

aspect

那么接下來胧洒,我們的攝像機應(yīng)該做些什么畏吓?
1、跟隨坦克卫漫。

Follow the tanks

找出兩輛坦克位置的中心點菲饼,把CameraRig移到該點。

2列赎、調(diào)整攝像機的尺寸以適應(yīng)坦克在屏幕上的位置宏悦。

攝像機視角

從上面補充的知識可以知道,正交攝像機的視圖的長為Size包吝,寬為Size * aspect饼煞。接著,在正交攝像機視角看來诗越,坦克的運動可以分解為x軸和y軸的運動砖瞧,這時,我們需要把坦克的坐標(biāo)切換成攝像機視角的本地坐標(biāo)嚷狞。
官方教程

官方教程

從上面兩幅圖我們可以知道块促,size的選擇有兩種情況,分別是沿y軸方向(size1 = y)床未;以及沿x軸方向竭翠,而x軸方向需要做一步計算,即size2 = x / aspect薇搁。接著比較這兩個size的大小斋扰,用大的size值決定攝像機的縮放。當(dāng)然了啃洋,這也需要考慮到另外一個tank的不同size值传货,總之,取最大的size值作為攝像機的縮放范圍裂允。

我們來看一下腳本是如何對攝像機進行控制的损离,打開/Assets/Scripts/Camera文件夾哥艇,選中CameraControl绝编,把它拖拽到CameraRig中,而不是Main Camera。

using UnityEngine;

public class CameraControl : MonoBehaviour
{
    public float m_DampTime = 0.2f;                 //移動Camera到目的position的時間
    public float m_ScreenEdgeBuffer = 4f;           //確保Tanks不會在屏幕邊界之外
    public float m_MinSize = 6.5f;                  //Camera的最小尺寸
    /*[HideInInspector]*/ public Transform[] m_Targets; //坦克十饥,先把[HideInInspector]注釋掉


    private Camera m_Camera;                        
    private float m_ZoomSpeed;                      
    private Vector3 m_MoveVelocity;                 
    private Vector3 m_DesiredPosition;              //需要移動到的位置


    private void Awake()
    {
        m_Camera = GetComponentInChildren<Camera>();
    }


    private void FixedUpdate()
    {
        Move();
        Zoom();
    }


    private void Move()
    {
        FindAveragePosition();

        /**
         * function Vector3.SmoothDamp(Vector3 current,Vector3 target
         *                 ,ref Vector3 currentVelocity,float smoothTime)
         *  @parameters
         *  current:當(dāng)前的位置
         *  target:試圖接近的位置
         *  currentVelocity:當(dāng)前速度窟勃,這個值由你每次調(diào)用這個函數(shù)時修改
         *  smoothTime:到達目標(biāo)的大約時間,較小的值將快速到達目標(biāo)
         */ 
        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++)
        {
            //判斷當(dāng)前坦克是否已經(jīng)不是激活狀態(tài)(死亡)逗堵,如果未激活秉氧,
            //則不需要跟隨該坦克
            if (!m_Targets[i].gameObject.activeSelf)
                continue;

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

        if (numTargets > 0)
            averagePos /= numTargets;

        //CameraRig的Y position不會被改變
        averagePos.y = transform.position.y;

        m_DesiredPosition = averagePos;
    }


    private void Zoom()
    {
        //根據(jù)目標(biāo)位置來計算合適的Size
        float requiredSize = FindRequiredSize();
        m_Camera.orthographicSize = Mathf.SmoothDamp(m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
    }


    private float FindRequiredSize()
    {   
        //把目標(biāo)位置的世界坐標(biāo)轉(zhuǎn)換成本地坐標(biāo)
        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;

            //把坦克所在的位置轉(zhuǎn)換成CameraRig的本地坐標(biāo)
            Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position);

            //在CameraRig的本地坐標(biāo)下,求出坦克與CameraRig的目標(biāo)位置的距離
            Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos;

            size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.y));

            size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.x) / m_Camera.aspect);
        }
        //加上ScreenEdgeBuffer值蜒秤,即坦克與屏幕邊界的距離
        size += m_ScreenEdgeBuffer;

        size = Mathf.Max(size, m_MinSize);

        return size;
    }


    public void SetStartPositionAndSize()
    {
        FindAveragePosition();

        transform.position = m_DesiredPosition;

        m_Camera.orthographicSize = FindRequiredSize();
    }
}

然后汁咏,我們返回Unity,把Tank拖拽到如下位置:


拖拽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é)果婚禮上弦叶,老公的妹妹穿的比我還像新娘俊犯。我一直安慰自己,他們只是感情好伤哺,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布燕侠。 她就那樣靜靜地躺著者祖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绢彤。 梳的紋絲不亂的頭發(fā)上七问,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音茫舶,去河邊找鬼械巡。 笑死,一個胖子當(dāng)著我的面吹牛饶氏,可吹牛的內(nèi)容都是我干的讥耗。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼疹启,長吁一口氣:“原來是場噩夢啊……” “哼葛账!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起皮仁,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤籍琳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贷祈,有當(dāng)?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
  • 正文 我出身青樓占调,卻偏偏與公主長得像,于是被迫代替她去往敵國和親移剪。 傳聞我的和親對象是個殘疾皇子究珊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容