Photon Unity Networking基礎(chǔ)教程 5 Building the Player

本節(jié)將指導(dǎo)您從頭開始創(chuàng)建將在本教程中使用的Player Prefab,以便我們涵蓋創(chuàng)建過程的每一步馁痴。

這里介紹一個好的方法谊娇,首先嘗試和創(chuàng)建一個Player Prefab,可以在沒有PUN連接的情況下工作罗晕,所以它很容易快速測試济欢,調(diào)試,并確保在沒有任何網(wǎng)絡(luò)的時候正常工作小渊。然后法褥,您可以慢慢地建立和修改每個功能到網(wǎng)絡(luò)兼容的角色:通常,用戶輸入只應(yīng)該在玩家擁有的實(shí)例上激活酬屉,而不是在其他的玩家計算機(jī)上半等。 我們將在下面詳細(xì)介紹。

主要內(nèi)容

  • prefab基礎(chǔ)
  • CharacterController
  • 動畫設(shè)置
  • 用戶輸入
  • 相機(jī)設(shè)置
  • 光束設(shè)置
  • 健康設(shè)置

Prefab基礎(chǔ)

了解PUN的第一個重要約定是呐萨,對于一個要通過網(wǎng)絡(luò)實(shí)例化的Prefab杀饵,它需要保存在Resources文件夾中,否則不行谬擦。

在Resources中使用Prefabs的第二個重要的副作用切距,是你需要監(jiān)視他們的名字。在Assets Resources中不應(yīng)該有相同名字的Prefab惨远,因?yàn)閁nity會選擇它找到的第一個谜悟,因此請務(wù)必確保在您的項目資源中饵沧,Resources路徑中沒有兩個Prefab命名相同。

我們將使用Unity提供的Kyle Robot作為一個自由資產(chǎn)赌躺。它作為一個Fbx文件狼牺,它是由3d軟件生成的,例如3ds Max礼患,Maya是钥,cinema4d。使用這些軟件創(chuàng)建網(wǎng)格和動畫超出了本教程的范圍缅叠,但是對于創(chuàng)建自己的角色和動畫來說至關(guān)重要悄泥。這個機(jī)器人Kyle.fbx位于/Assets/Photon Unity Networking/Demos/Shared Assets/。

KyleRobotFbx.png

這里有一種方法開始使用Kyle Robot.fbx為你的玩家:

  • 在項目瀏覽器中肤粱,創(chuàng)建一個名為“Resources”的文件夾
  • 創(chuàng)建一個新的空場景弹囚,并保存為Kyle Test,放在這個文件夾/PunBasics_tutorial/Scenes/
  • 將Robot Kyle拖放到場景Hierarchy上领曼。
  • 將剛剛在Hierarchy中創(chuàng)建的GameObject重命名為My Robot Kyle
  • 將我的機(jī)器人Kyle拖放到/PunBasics_tutorial/Resources/

我們現(xiàn)在創(chuàng)建了一個基于Kyle Robot Fbx資產(chǎn)的Prefab卫玖,我們在您的場景Kyle Test的Hierarchy中有一個實(shí)例”涂担現(xiàn)在我們可以開始使用它钓账。

CharacterController

  1. 讓我們在層次結(jié)構(gòu)中添加一個CharacterController組件到我的Kyle Robot實(shí)例灌诅。你可以直接在Prefab本身上這樣做,但我們需要調(diào)整它单刁,所以這是更快的這種方式灸异。
  2. 雙擊My Robot Kyle讓場景視圖放大。注意Capsule Collider在腳中間; 我們需要Capsule Collider來正確匹配角色羔飞。
  3. 在Capsule Collider組件中把Center.y屬性改成1肺樟。
KyleRobotCCCenter.png
  1. 點(diǎn)擊Apply使改變對prefab生效。這不很重要逻淌,因?yàn)槲覀兙庉嬃薓y Kyle Robot prefab么伯,我們想要所有的實(shí)例都生效,不只是這一個恍风,所以點(diǎn)擊Apply蹦狂。
InstancePrefabApply.png

動畫設(shè)置

分配動畫控制器

Kyle Robot Fbx資源需要Animator Graph控制。我們這篇教程不會介紹這個Graph的創(chuàng)建朋贬,所以我們提供了一個控制器,在項目Assets中Photon Unity Networking/Demos/PunBasics/Animator/ 下面窜骄,叫做Kyle Robot锦募。

AnimatorController.png

要把這個Kyle Robot控制器分配給我們的Prefab,只需要把Animator組件的Controller屬性設(shè)置為Kyle Robot邻遏。

AssignAnimatorController.png

不要忘了糠亩,如果你修改的是My Kyle Robot實(shí)例虐骑,你需要點(diǎn)擊Prefab的Apply使改變生效。

嘗試控制器參數(shù)

理解Animator控制器的關(guān)鍵特性是動畫參數(shù)赎线,這些參數(shù)是我們?nèi)绾瓮ㄟ^腳本控制動畫廷没。在我們的例子中,有參數(shù)例如速度垂寥,方向颠黎,跳躍,Hi滞项。

Animator組件的一個重要功能是根據(jù)其動畫實(shí)際移動角色的能力狭归,這個功能稱為Root Motion,并且在Animator組件上有一個屬性Apply Root Motion文判,默認(rèn)情況下是true过椎。

所以,實(shí)際上戏仓,要讓人物走路疚宇,我們只需要將速度動畫參數(shù)設(shè)置為正值,它將開始行走和向前移動赏殃。 我們開工吧灰嫉!

Animator Manager Script

讓我們創(chuàng)建一個新的腳本,我們將基于用戶的輸入控制角色嗓奢。

  1. 創(chuàng)建新的腳本PlayerAnimatorManager

  2. 添加到My Robot Kyle這個Prefab 上

  3. 代碼如下

     using UnityEngine;
     using System.Collections;
     
     namespace Com.MyCompany.MyGame
     {
         public class PlayerAnimatorManager : MonoBehaviour
         {
             #region MONOBEHAVIOUR MESSAGES
     
             // Use this for initialization
             void Start()
             {
     
             }
     
             // Update is called once per frame
             void Update()
             {
     
             }
             #endregion
         }
     }
    
  4. 保存腳本

Animator Manager : 速度控制

我們要做的第一件事實(shí)獲得Animator組件讼撒,以便于控制它

  1. 確保你正在編輯PlayerAnimatorManager

  2. 創(chuàng)建一個Animator類型的私有變量animator

  3. 在Start()函數(shù)中保存Animator組件

     private Animator animator;
     // Use this for initialization
     void Start()
     {
         animator = GetComponent<Animator>();
         if (!animator)
         {
             Debug.LogError("PlayerAnimatorManager is Missing Animator Component", this);
         }
     }
    

注意,由于我們需要一個Animator組件股耽,如果我們沒有得到一個根盒,我們記錄一個錯誤,以便它不被忽視物蝙,并由開發(fā)人員直接解決炎滞。你應(yīng)該總是寫出來,如果它將被其他人使用的話:)它盡管單調(diào)乏味诬乞,但長遠(yuǎn)來看是值得的册赛。

  1. 讓我們監(jiān)聽用戶輸出,控制動畫的Speed參數(shù)

     // Update is called once per frame
     void Update()
     {
         if (!animator)
         {
             return;
         }
         float h = Input.GetAxis("Horizontal");
         float v = Input.GetAxis("Vertical");
         if (v < 0)
         {
             v = 0;
         }
         animator.SetFloat("Speed", h * h + v * v);
     }
    
  2. 保存腳本

讓我們看看這個腳本做了什么:

因?yàn)槲覀兊挠螒虿辉试S向后移動震嫉,所以我們確保v大于0.用戶按下向下鍵或's'鍵森瘪,我們不允許這樣做,并將值強(qiáng)制為0票堵。

你會注意到扼睬,我們已經(jīng)平方了兩個輸入,為什么悴势? 所以它總是一個正的絕對值窗宇,以及增加一些緩和措伐。 這里是個微妙的技巧。你也可以使用Mathf.Abs()军俊,這將工作正常侥加。

我們還增加了兩個輸入來控制Speed,所以當(dāng)我們只是按下左邊的輸入粪躬,我們轉(zhuǎn)彎時仍然獲得一些速度担败。

當(dāng)然,所有這些都是非常具體的我們的角色設(shè)計短蜕,根據(jù)你的游戲邏輯氢架,你可能希望角色原地轉(zhuǎn),或有能力后退朋魔,所以動畫參數(shù)的控制總是針對具體的游戲 岖研。

測試,測試 1 2 3...

讓我們驗(yàn)證我們迄今為止做了什么警检。確保您已打開Kyle Test場景孙援。目前,在這個場景中扇雕,我們只有一個相機(jī)和Kyle Robot實(shí)例拓售,場景缺少地面機(jī)器人站立的地面,如果你現(xiàn)在運(yùn)行場景凱爾機(jī)器人會下降镶奉。 此外础淤,我們不會在現(xiàn)場照明或任何奇怪,我們想測試和驗(yàn)證我們的角色和腳本是否正常工作哨苛。

  1. 將Cube添加到場景鸽凶。因?yàn)橐粋€Cube默認(rèn)情況下是Box碰撞器,我們很好地使用它作為地板建峭。
  2. 把它放到0玻侥,-0.5,0,因?yàn)榱⒎襟w的高度是1.我們希望立方體的頂面是地板亿蒸。
  3. 將Cube縮放到30,1,30凑兰,以便我們有空間進(jìn)行實(shí)驗(yàn)
  4. 選擇相機(jī)并將其移開,以獲得良好的觀察視野边锁。一個很好的技巧是在Scene視圖中調(diào)整到您喜歡的視圖姑食,選擇相機(jī)并轉(zhuǎn)到菜單 "GameObject/Align With View",攝像機(jī)將匹配場景視圖砚蓬。
  5. 最后一步矢门,往y軸上方移動My Robot Kyle 0.1單位,否則碰撞在開始時被錯過灰蛙,角色通過地板祟剔,所以在碰撞者之間留下一些物理空間。
  6. 運(yùn)行場景摩梧,按向上箭頭鍵或'a'物延,角色正在走!您可以使用所有鍵進(jìn)行測試以驗(yàn)證仅父。

很好叛薯,但仍然很多工作在前頭,我們的相機(jī)需要跟隨笙纤,我們不能轉(zhuǎn)動...

如果你現(xiàn)在想在相機(jī)上工作耗溜,請轉(zhuǎn)到相機(jī)部分,本頁的其余部分將完成Animator控件并實(shí)現(xiàn)旋轉(zhuǎn)省容。

Animator Manager 腳本:方向控制

控制旋轉(zhuǎn)將稍微更復(fù)雜抖拴,我們不希望我們的角色因?yàn)榘醋笥益I突然旋轉(zhuǎn),我們希望溫柔平滑的旋轉(zhuǎn)腥椒。幸運(yùn)的是阿宅,動畫參數(shù)可以使用一些阻尼來設(shè)置。

  1. 確保您正在編輯腳本 PlayerAnimatorManager

  2. 在“PRIVATE PROPERTIES”區(qū)域上方的腳本的新區(qū)域“PUBLIC PROPERTIES”中創(chuàng)建公共float變量DirectionDampTime

     //#region PUBLIC PROPERTIES
     public float DirectionDampTime = .25f;
     //#endregion
    
  3. 在Update函數(shù)結(jié)尾處笼蛛,添加:

     animator.SetFloat( "Direction", h, DirectionDampTime, Time.deltaTime );
    

所以我們馬上注意到animator.SetFloat()有不同的聲明洒放。我們用來控制速度是一個簡單的,但對于這一個需要兩個參數(shù)滨砍,一個是阻尼時間往湿,一個deltaTime。阻尼時間有意義:它達(dá)到所需的值需要多長時間惋戏,但deltaTime呢领追?它本質(zhì)上讓你編寫的幀速率獨(dú)立的代碼,因?yàn)閁pdate()取決于幀速率日川,我們需要通過使用deltaTime來考慮這種情況蔓腐。盡可能多的閱讀關(guān)于這個主題,當(dāng)你和在網(wǎng)上搜索的時候你會發(fā)現(xiàn)龄句。只有在你理解了這一概念之后回论,在動畫和隨時間變化對數(shù)值的一致性控制方面,你才能充分利用Unity的許多功能分歇。

  1. 保存腳本PlayerAnimatorManager
  2. 運(yùn)行你的場景傀蓉,并使用所有箭頭,看看你的角色是行走和轉(zhuǎn)身怎么樣
  3. 測試DirectionDampTime的效果:將其設(shè)為1职抡,例如葬燎,然后5,看到它需要達(dá)到最大轉(zhuǎn)向能力。你會看到轉(zhuǎn)彎半徑隨著DirectionDampTime增加谱净。

Animator Manager 腳本:跳躍

關(guān)于跳躍窑邦,我們需要多做一點(diǎn)工作,因?yàn)閮蓚€原因壕探。一是我們不想讓玩家在不跑動的情況下跳躍冈钦,二是我們不想跳躍循環(huán)。

  1. 確保正在編輯腳本PlayerAnimatorManager

  2. 在update方法中李请,捕捉用戶輸入之前瞧筛,插入下面代碼

     // deal with Jumping
     AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);          
     // only allow jumping if we are running.
     if (stateInfo.IsName("Base Layer.Run"))
     {
         // When using trigger parameter
         if (Input.GetButtonDown("Fire2")) animator.SetTrigger("Jump"); 
     }
    
  3. 保存腳本PlayerAnimatorManager

  4. 測試,開始跑動然后按下alt鍵导盅,Kyle會跳起來

要理解的第一件事情就是我們怎樣知道animator正在跑動较幌,通過使用stateInfo.IsName("Base Layer.Run"),我們詢問目前Animator的激活狀態(tài)是否是Run白翻。我們必須添加Base Layer因?yàn)镽un狀態(tài)是在Base Layer中的乍炉。

如果我們處于Run狀態(tài),然后我們監(jiān)聽Fire2輸入嘁字,然后調(diào)用Jump觸發(fā)器恩急。

到目前為止PlayerAnimatorManager腳本的完整版本:

    using UnityEngine;
    using System.Collections;
    
    namespace Com.MyCompany.MyGame
    {
        public class PlayerAnimatorManager : MonoBehaviour
        {   
            #region PUBLIC PROPERTIES
            public float DirectionDampTime = .25f;
            #endregion
    
            #region MONOBEHAVIOUR MESSAGES
            private Animator animator;
            // Use this for initialization
            void Start()
            {
                animator = GetComponent<Animator>();
                if (!animator)
                {
                    Debug.LogError("PlayerAnimatorManager is Missing Animator Component", this);
                }
            }
    
            // Update is called once per frame
            void Update()
            {
                if (!animator)
                {
                    return;
                }
    
                // deal with Jumping
                AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
                // only allow jumping if we are running.
                if (stateInfo.IsName("Base Layer.Run"))
                {
                    // When using trigger parameter
                    if (Input.GetButtonDown("Fire1"))
                    {
                        Debug.Log("jump");
                        animator.SetTrigger("Jump");
                    }                
                }
    
                float h = Input.GetAxis("Horizontal");
                float v = Input.GetAxis("Vertical");
                if (v < 0)
                {
                    v = 0;
                }
                animator.SetFloat("Speed", h * h + v * v);
                animator.SetFloat("Direction", h, DirectionDampTime, Time.deltaTime);
            }
            #endregion
        }
    }

當(dāng)你考慮它在場景中實(shí)現(xiàn)的功能,對于這幾行代碼來說還不錯〖脱眩現(xiàn)在讓我們處理相機(jī)的工作衷恭,因?yàn)槲覀兡軌蛟谖覀兊氖澜缁顒樱覀冃枰粋€合適的相機(jī)行為跟隨纯续。

相機(jī)設(shè)置

在本節(jié)中随珠,我們將使用CameraWork腳本,以保持專注于Player Prefab整體創(chuàng)建過程猬错。如果你想從頭開始寫CameraWork窗看,請去下一部分,完成后回到這里倦炒。

  1. 將組件CameraWork添加到My Kyle Robot Prefab
  2. 打開屬性Follow on Start显沈,可以有效地使照相機(jī)即時跟隨角色。當(dāng)我們開始網(wǎng)絡(luò)實(shí)現(xiàn)時逢唤,我們將關(guān)閉它
  3. 設(shè)置屬性Center Offset為0,4,0拉讯,這使得相機(jī)看起來更高,從而給出了一個更好的視角的環(huán)境比鳖藕,如果相機(jī)直視玩家魔慷,我們會看到太多的地面什么都沒有。
  4. 運(yùn)行場景Kyle Test著恩,并移動角色院尔,以驗(yàn)證相機(jī)正確跟隨角色蜻展。

光束設(shè)置

我們的機(jī)器人角色還沒有武器,讓我們創(chuàng)造一些可以從它的眼睛中發(fā)出來的激光束邀摆。

添加光束模型

為了簡單起見纵顾,我們將使用簡單的立方體并將它們縮放為非常瘦長。有一些技巧來快速做到這一點(diǎn):不要直接添加一個Cube作為頭部節(jié)點(diǎn)的子節(jié)點(diǎn)隧熙,而是創(chuàng)建它移動它片挂,并放大幻林,然后將其附加到頭贞盯,這將防止猜測正確旋轉(zhuǎn)值讓你的光束與眼睛對齊。

另一個重要的技巧是沪饺,對兩個光束只使用一個碰撞器躏敢。這是為了讓物理引擎更好地工作,瘦的碰撞器從來不是一個好主意整葡,它不可靠件余,所以我們將制作一個大盒子碰撞器,以確痹饩樱可靠地?fù)糁心繕?biāo)啼器。

  1. 打開Kyle test場景
  2. 添加一個Cube,命名為Beam Left
  3. 把它修改成一個長的光束俱萍,放到左眼的位置
  4. 在Hierarchy中選中My Kyle Robot
  5. 選中Head子節(jié)點(diǎn)
KyleRobotHeadHierarchy.png
  1. 給Head對象添加一個空白對象端壳,命名為Beams
  2. 把Beam Left拖拽到Beams下面
  3. 復(fù)制Beams Left,命名為Beams Right
  4. 把它放到右眼的位置上
  5. 去掉Beams Right的碰撞體
  6. 調(diào)整Beams Right的碰撞體枪蘑,讓它包括兩個Beam對象
  7. 把Beams Left碰撞體的IsTrigger屬性設(shè)置為True损谦,我們只想知道光束接觸到的玩家,而不是碰撞體
  8. 撞見一個新的材質(zhì)岳颇,命名為Red Beam照捡,保存
  9. 把Red Beam賦值給兩個Beams
  10. 對prefab執(zhí)行Apply

你應(yīng)該像下面這樣的:

KyleRobotBeams.png
KyleRobotHeadHierarchyWithBeams.png

通過用戶輸入控制Beams

好了,既然我們有了激光束话侧,讓我們使用Fire鍵來觸發(fā)他們栗精。

創(chuàng)建一個C#腳本,命名為PlayerManager瞻鹏。下面是該腳本第一個版本的完整內(nèi)容:

    using UnityEngine;
    using UnityEngine.EventSystems;
    using System.Collections;
    
    namespace Com.MyCompany.MyGame
    {
        /// <summary>
        /// Player manager. 
        /// Handles fire Input and Beams.
        /// </summary>
        public class PlayerManager : MonoBehaviour
        {
            #region Public Variables
    
            [Tooltip("The Beams GameObject to control")]
            public GameObject Beams;
    
            #endregion
    
            #region Private Variables
    
            //True, when the user is firing
            bool IsFiring;
    
            #endregion
    
            #region MonoBehaviour CallBacks
    
            /// <summary>
            /// MonoBehaviour method called on GameObject by Unity during early initialization phase.
            /// </summary>
            void Awake()
            {
                if (Beams == null)
                {
                    Debug.LogError("<Color=Red><a>Missing</a></Color> Beams Reference.", this);
                }
                else
                {
                    Beams.SetActive(false);
                }
            }
    
            /// <summary>
            /// MonoBehaviour method called on GameObject by Unity on every frame.
            /// </summary>
            void Update()
            {
                ProcessInputs();
    
                // trigger Beams active state 
                if (Beams != null && IsFiring != Beams.GetActive())
                {
                    Beams.SetActive(IsFiring);
                }
            }
    
            #endregion
    
            #region Custom
    
            /// <summary>
            /// Processes the inputs. Maintain a flag representing when the user is pressing Fire.
            /// </summary>
            void ProcessInputs()
            {
                if (Input.GetButtonDown("Fire1"))
                {
                    if (!IsFiring)
                    {
                        IsFiring = true;
                    }
                }
    
                if (Input.GetButtonUp("Fire1"))
                {
                    if (IsFiring)
                    {
                        IsFiring = false;
                    }
                }
            }
            #endregion
        }
    }

這個腳本在這個階段的要點(diǎn)是激活或停用激光束悲立。當(dāng)激活時,激光束將有效地觸發(fā)與其他模型發(fā)生碰撞乙漓,因此我們將在后面利用這些觸發(fā)器來影響每個角色的健康值级历。

我們還暴露了一個公共屬性Beams,它將讓我們在My Kyle Robot Prefab的層次結(jié)構(gòu)中引用確切的對象叭披。讓我們看看我們?nèi)绾喂ぷ鱽磉B接Beams寥殖,因?yàn)樵贏ssets瀏覽器中玩讳,Prefabs只暴露第一個子節(jié)點(diǎn),而不是所有子節(jié)點(diǎn)嚼贡,而且我們的Beams確實(shí)埋在Prefab層次結(jié)構(gòu)中熏纯,因此,我們需要從場景中的一個實(shí)例執(zhí)行此操作粤策,然后將其應(yīng)用回Prefab本身樟澜。

  1. 打開Kyle Test場景
  2. 在場景Hierachy中選擇我的Kyle Robot
  3. 將PlayerManager組件添加到My Kyle Robot
  4. 將My Kyle Robot/Root/Ribs/Neck/Head/Beams拖放到Inspector中的PlayerManager Beams屬性中
  5. 將實(shí)例中的更改應(yīng)用到Prefab

如果你點(diǎn)擊play,并按Fire1輸入(默認(rèn)情況下是左鼠標(biāo)或左ctrl鍵)叮盘,Beams將顯示秩贰,并立即隱藏時釋放時。

健康設(shè)置

讓我們實(shí)現(xiàn)一個非常簡單的健康系統(tǒng)柔吼,當(dāng)光束擊中玩家時會減少生命毒费。由于它不是子彈,而是一個恒定的能量流愈魏,我們需要以兩種方式考慮健康損害觅玻,當(dāng)我們受到光束撞擊時,以及在整個時間射束撞擊我們培漏。

  1. 打開PlayerManager腳本

  2. 為了暴露PhotonView組件溪厘,把PlayerManager改變成Photon.PunBehaviour的子對象,

     public class PlayerManager : Photon.PunBehaviour {
    
  3. 在Public Variables區(qū)塊添加一個公共的Health屬性

     [Tooltip("The current Health of our player")]
     public float Health = 1f;
    
  4. 在MonoBehaviour CallBacks區(qū)塊中添加下面兩個方法

     /// <summary>
     /// MonoBehaviour method called when the Collider 'other' enters the trigger.
     /// Affect Health of the Player if the collider is a beam
     /// Note: when jumping and firing at the same, you'll find that the player's own beam intersects with itself
     /// One could move the collider further away to prevent this or check if the beam belongs to the player.
     /// </summary>
     void OnTriggerEnter(Collider other)
     {
         if (!photonView.isMine)
         {
             return;
         }
         // We are only interested in Beamers
         // we should be using tags but for the sake of distribution, let's simply check by name.
         if (!other.name.Contains("Beam"))
         {
             return;
         }
         Health -= 0.1f;
     }
    
     /// <summary>
     /// MonoBehaviour method called once per frame for every Collider 'other' that is touching the trigger.
     /// We're going to affect health while the beams are touching the player
     /// </summary>
     /// <param name="other">Other.</param>
     void OnTriggerStay(Collider other)
     {
         // we dont' do anything if we are not the local player.
         if (!photonView.isMine)
         {
             return;
         }
         // We are only interested in Beamers
         // we should be using tags but for the sake of distribution, let's simply check by name.
         if (!other.name.Contains("Beam"))
         {
             return;
         }
         // we slowly affect health when beam is constantly hitting us, so player has to move to prevent death.
         Health -= 0.1f * Time.deltaTime;
     }
    
  5. 保存PlayerManager腳本

首先牌柄,這兩種方法幾乎是相同的畸悬,唯一的區(qū)別是,我們在TriggerStay期間使用Deltatime減少健康友鼻,減量的速度不取決于幀速率傻昙。這是一個重要的概念,通常適用于動畫彩扔,但在這里妆档,我們也需要這樣,我們希望Health在所有設(shè)備上以可預(yù)測的方式減少虫碉,在更快的計算機(jī)上這是不公平的贾惦,你的健康下降更快:) Deltatime在這里是為了保證一致性。如果您有問題敦捧,并通過搜索Unity社區(qū)了解DeltaTime须板,直到您完全吸收這個概念,然后回來兢卵,這是至關(guān)重要的习瑰。

第二個重要的方面,現(xiàn)在應(yīng)該明白秽荤,我們只影響本地玩家的健康甜奄,這就是為什么我們前面退出方法的條件PhotonView不是Mine柠横。

最后,如果擊中我們的對象是一個Beam课兄,我們只想影響健康牍氛,所以我們使用標(biāo)簽“Beam”檢查這點(diǎn),這是我們?yōu)楹螛?biāo)記我們的Beam對象烟阐。

為了便于調(diào)試搬俊,我們使Health float作為一個公共浮動,以便在等待UI構(gòu)建時輕松檢查其值蜒茄。

好吧唉擂,這看起來一切正確嗎?健康系統(tǒng)是不完整的扩淀,當(dāng)健康是0時楔敌,沒有考慮到玩家的游戲結(jié)束狀態(tài),讓我們現(xiàn)在做到這一點(diǎn)驻谆。

游戲結(jié)束健康檢查

為了保持簡單,當(dāng)玩家的健康達(dá)到0時庆聘,我們就離開房間胜臊。如果你還記得,我們已經(jīng)在GameManager Script中創(chuàng)建了一個離開房間的方法伙判。如果我們可以重用這個方法而不是重寫一遍象对,這是不錯的主意。 相同結(jié)果的重復(fù)代碼是你應(yīng)該盡一切代價避免的宴抚。這也將是一個好時機(jī)勒魔,介紹一個非常方便的編程概念,“Singleton”菇曲。 雖然這個主題本身可以寫滿幾個教程冠绢,我們將只實(shí)現(xiàn)極小的“單例”。了解Singleton常潮,它們在Unity上下文中的變體以及它們?nèi)绾螏椭鷦?chuàng)建強(qiáng)大的功能是非常重要的弟胀,并將為您節(jié)省很多麻煩。所以喊式,不要猶豫孵户,把時間放在這個教程來了解更多。

  1. 打開GameManager腳本

  2. 在Public Properties區(qū)塊添加這個變量

    static public GameManager Instance;

  3. 在Start函數(shù)中添加這行代碼

    Instance = this;

  4. 保存GameManager腳本

注意岔留,我們使用[static]關(guān)鍵字修飾了Instance變量夏哭,這意味著,不必持有一個指向GameManager實(shí)例的指針献联,就可以使用這個變量竖配,所以你可以在代碼中的任何地方做一個簡單的GameManager.instance.xxx()厕吉。這是非常實(shí)用的!讓我們看看如何用于我們的游戲結(jié)束邏輯管理械念。

  1. 打開PlayerManager腳本

  2. 在Update函數(shù)中头朱,ProcessInput之后,加入這些代碼

     if ( Health <= 0f)
     {
         GameManager.Instance.LeaveRoom();
     }
    
  3. 保存PlayerManager腳本

  • 注意龄减,我們考慮到健康可能是負(fù)面的项钮,因?yàn)榧す馐斐傻膿p害在強(qiáng)度上是不同的。
  • 注意希停,我們調(diào)用了GameManager實(shí)例的LeaveRoom()公共方法烁巫,而實(shí)際上不需要獲取組件或任何東西,我們僅僅依賴于我們假設(shè)GameManager組件在當(dāng)前場景中某個GameObject上的事實(shí)宠能。

好了亚隙,下面我們要處理網(wǎng)絡(luò)部分。

原文

http://doc.photonengine.com/en-us/pun/current/tutorials/pun-basics-tutorial/player-prefab#cam_setup

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末违崇,一起剝皮案震驚了整個濱河市阿弃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌羞延,老刑警劉巖渣淳,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伴箩,居然都是意外死亡入愧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門嗤谚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棺蛛,“玉大人,你說我怎么就攤上這事巩步∨陨蓿” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵渗钉,是天一觀的道長彤恶。 經(jīng)常有香客問我,道長鳄橘,這世上最難降的妖魔是什么声离? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮瘫怜,結(jié)果婚禮上术徊,老公的妹妹穿的比我還像新娘。我一直安慰自己鲸湃,他們只是感情好赠涮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布子寓。 她就那樣靜靜地躺著,像睡著了一般笋除。 火紅的嫁衣襯著肌膚如雪斜友。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天垃它,我揣著相機(jī)與錄音鲜屏,去河邊找鬼。 笑死国拇,一個胖子當(dāng)著我的面吹牛洛史,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酱吝,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼也殖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了务热?” 一聲冷哼從身側(cè)響起忆嗜,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎陕习,沒想到半個月后霎褐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡该镣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了响谓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片损合。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖娘纷,靈堂內(nèi)的尸體忽然破棺而出嫁审,到底是詐尸還是另有隱情,我是刑警寧澤赖晶,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布律适,位于F島的核電站,受9級特大地震影響遏插,放射性物質(zhì)發(fā)生泄漏捂贿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一胳嘲、第九天 我趴在偏房一處隱蔽的房頂上張望厂僧。 院中可真熱鬧,春花似錦了牛、人聲如沸颜屠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甫窟。三九已至密浑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粗井,已是汗流浹背尔破。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留背传,地道東北人呆瞻。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像径玖,于是被迫代替她去往敵國和親痴脾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

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