Unity2D游戲制作入門 | 12(之人物受傷和死亡的邏輯動畫)

上期鏈接:Unity2D游戲制作入門 | 11(之人物屬性及傷害計算)-CSDN博客

上期我們聊到了人物的自身屬性和受傷時的計算,我們先給人物和野豬掛上屬性和攻擊屬性的代碼,然后通過觸發器觸發受傷的事件。物體(人物也好敵人也行)受傷時通常是在被攻擊者的內部進行計算的(這是有好處的,比如使用人物更復雜的血量計算方式,我們在人物內部讓它自己自動計算就好了),我們使用關鍵詞this來將Attacker內部的變量的訪問權限賦給Character,然后我們又使用了計時器,讓被攻擊的物體在受到攻擊后可以有短暫的無敵時間,計時器的寫法你還知道嗎?先創建三個變量一個布爾二個浮點,創建新的能賦給人物無敵的函數,然后判斷人物如果不如那么人物的無敵狀態就是True,然后賦給無敵時間(一個浮點變量我們是在Unity窗口手動賦給的,另一個浮點變量是內部進行使用它,在函數判斷人物是否處在無敵時才用公共無敵時間賦給那個私有的浮點變量,這樣就在內部激活了人物的無敵時間),我們在update中計算人物無敵的倒計時,到點了就切換人物無敵狀態為flase,然后在人物的Character中的TakeDamage函數中,我們判斷人物如果不是無敵則進入扣血規則,然后如果人物的當前血量足夠扣除一次血量則正常減血(如果人物血量為2敵人攻擊為5,那么人物直接判斷血量歸零),不然人物死亡,而無敵狀體的賦給與否全在人物扣血那部分功能中執行,如果人物血量歸零那么將無法觸發無敵狀態。總的來說,上次就是多了兩份通用的代碼文件,分別是物體的屬性和攻擊(僅對需要這些的物體有用,如果是場景的死物一般不給屬性如血量,也可以給看你設定,攻擊應該是不要加上去的,除了陷阱啥的),雖然多了兩份代碼,我們還是要弄清兩份代碼之間的訪問和運行的邏輯,以及什么時候用它們。這期我們看看角色的 受傷和死亡的邏輯和動畫 。代碼先下方:

public class PlayerAnimations : MonoBehaviour
{private Animator anim;//創建好這個組件變量后,如果不知道如何通關代碼控制組件,可以去看代碼手冊private Rigidbody2D rb;//這個2D不能忽略,不然不報錯但是人物跑不起來。private Player_control playercon;//人物控制private physicsCheck physicsCheck;private void Awake(){physicsCheck = GetComponent<physicsCheck>();anim = GetComponent<Animator>();rb= GetComponent<Rigidbody2D>();playercon = GetComponent<Player_control>();}private void Update(){SetAnimatons();//每幀時時檢測,判斷是否需要切換動畫。}public void SetAnimatons()//需要做很多動畫的切換,我們用這個函數來執行所有的動畫切換。{anim.SetBool("isGround", physicsCheck.isGround);anim.SetFloat("velocityX",math.abs(rb.velocity.x));anim.SetFloat("velocityY",rb.velocity.y);anim.SetBool("shift", playercon.isShift);anim.SetBool("isDead", playercon.isDead);}public void PlayerHurt(){anim.SetTrigger("hurt");}}
public class Player_control : MonoBehaviour
{public PlayerInputControl inputControl;public Vector2 inputDirection;//public變量表示一個公開的方法,它代表我在Unity窗口中可以查看得到。private Rigidbody2D rb;private physicsCheck physicsCheck;//創建物理檢測變量private SpriteRenderer rbSprite;[Header("基本參數")]public float speed;public float walkSpeed;public float jumpForce;public float hurtForce;[Header("按鍵按下")]public bool isShift=false;[Header("狀態")]public bool isHurt;public bool isDead;private void Awake(){physicsCheck = GetComponent<physicsCheck>();rb= GetComponent<Rigidbody2D>();inputControl = new PlayerInputControl();inputControl.GamePlayer.Jump.started += Jump;//按下空格那一瞬間執行事件Jump//inputControl.GamePlayer.Walk.performed += Walk;rbSprite = GetComponent<SpriteRenderer>();}private void OnEnable(){inputControl.Enable();}private void OnDisable(){inputControl.Disable();}private void Update(){inputDirection = inputControl.GamePlayer.Move.ReadValue<Vector2>();isShift= Keyboard.current.shiftKey.isPressed;//檢測按鍵}private void FixedUpdate()//固定頻率運行,即0.02秒執行一次。跟物理有關的放在這執行{if (!isHurt){if (isShift && physicsCheck.isGround)Walk();elseMove();}}public void Move(){rb.velocity = new Vector2(inputDirection.x*speed*Time.deltaTime,rb.velocity.y);//人物翻轉if(inputDirection.x>0)rbSprite.flipX = false;if(inputDirection.x<0)rbSprite.flipX = true;}private void Jump(InputAction.CallbackContext obj){if (physicsCheck.isGround){rb.AddForce(jumpForce * transform.up, ForceMode2D.Impulse);//第一個參數表示給哪個方向施加力}}}private void Walk(){rb.velocity = new Vector2(inputDirection.x * walkSpeed * Time.deltaTime, rb.velocity.y);//人物翻轉if (inputDirection.x > 0)rbSprite.flipX = false;if (inputDirection.x < 0)rbSprite.flipX = true;}public void GetHurt(Transform attcker){isHurt = true;//受傷了//接下來執行反彈,不過前提是先把人物的速度停下來。rb.velocity = Vector2.zero;//表示物體的xy軸速度全設置為了。//接下來計算受傷的方向,然后ta要朝反方向彈射。Vector2 dir=new Vector2((transform.position.x-attcker.position.x),0).normalized;/*這里對上行代碼進行說明,dir是direction方向的簡寫。計算方向我們就用人物坐標減去野豬或是其他的attacker的坐標對于x軸來說,如果人物在敵人左邊那么它應該是負數,所以我們根據正負數作為它的方向乘上它的反沖力hurtForce(現實加速的效果)。dir算完后,我們需要不是數值的大小,而是方向值(我們按下鍵盤時dir有-1和1兩種數值)。如果人物離野豬很遠,那么x的值會非常大,乘反彈力會更大反而離得近數值會很小,所以我們要把數值歸一化,即用到normalized的方法。*/rb.AddForce(dir*hurtForce,ForceMode2D.Impulse);//添加瞬時的力反彈人物}public void PlayerDead(){isDead = true;inputControl.GamePlayer.Disable();}
}
public class Character : MonoBehaviour
{[Header("基本屬性")]public float maxHp;//最大血量public float currentHp;//當前血量[Header("受傷無敵")]public float invincibleTime;//無敵時間private float invincibleCounter;//一個計數器,內部計算即可,不需要在窗口可以看得到public bool invincible;//為了能看見無敵,我們創建一個布爾值public UnityEvent<Transform> Ontakedamage;public UnityEvent Ondie;private void Start()//開始游戲時,要滿血{currentHp = maxHp;}private void Update(){if(invincible){invincibleCounter-=Time.deltaTime;if(invincibleCounter <= 0){invincible = false;}}}//受到傷害public void TakeDamage(Attack attcker){if (invincible)return;//Debug.Log(attcker.damage);if (currentHp - attcker.damage > 0)//血量健康才能減血{currentHp -= attcker.damage;//如果學過python,你會知道這行代碼等于currentHp = currentHp - attcker.damage;TriggerInvincible();//觸發無敵//執行受傷Ontakedamage?.Invoke(attcker.transform);}else{currentHp=0;//觸發死亡Ondie?.Invoke();}}//受傷觸發無敵private void TriggerInvincible(){if(!invincible){invincible= true;invincibleCounter = invincibleTime;}}
}
public class HurtAninmation : StateMachineBehaviour
{override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){animator.GetComponent<Player_control>().isHurt = false;}
}

正文:

玩家如果受到傷害,那么應該有對應的受傷動畫,甚至血量歸零時人物播放死亡的動畫。找到我們之前的素材,我們可以先看看guid指導的動畫內容,找到受傷的內容。我們先點擊player,然后創建人物的動畫文件(一定放在人物動畫管理的文件下,這樣方便找),然后創建人物的hurt動畫,用右邊的那四張圖片(我們之前切割好的),然后Samples采樣率我們調整到合適的數值(14的話感覺還是有點快了所以我選了9)。
在這里插入圖片描述

死亡動畫編號為42-53。
在這里插入圖片描述

先將Animator中出現的我們剛剛創建的兩個動畫刪去,我們注意到我們的人物在任何情況下都可能受傷,如我們跑步撞到野豬,在空中碰到敵人,這些都可能使人物受傷。如果人物受傷,應該凌駕在所有動畫之上(我們先前制作的所有動畫,如跳躍、閑置、跑步等),接下來我們創建新的方法。先不調用受傷動畫,來看一個有意思的方法(UP話)。玩家如果進行受傷的狀態, 那么玩家應該有閃爍的狀態來表示玩家在這個階段是受傷無敵的狀態。我們在下圖的這個地方創建新的動畫的Layer圖層注意這些圖層的名字下有一條線
在這里插入圖片描述

我們點擊動畫圖層右邊的齒輪可以發現,有一個名為Weight權重的東西,這個權重會影響當前的這一層的動畫的播放,你可以理解為:它的優先級是多少。下面的Blending為混合模式,Override是完全覆蓋的意思。我們先將HurtLayer動畫圖層的權重拉到1,然后混合模式切換成Additive(疊加)模式即當前層動畫不會覆蓋之前層(BaseLayer)的動畫,在之前層的基礎上為它進行添加。

在這里插入圖片描述

我們在這個新地方創建新的空的狀態,然后創建新的受傷動畫即bule_hurt2。在這里我們不調用任何的圖片,現在錄制我們的動畫片段。

在這里插入圖片描述

這個地方關鍵,我們去到人物的右邊的組件Sprite Renderer,看到Color我們修改它RGB的通道,也可以修改它的阿爾法值,怎么說呢就是修改物體的透明程度(1的話就顯示,0就隱身了),如果是改RGB中的值人物就會變色如變成紅色等。然后我們在動畫管理下的Add Property,找到對應組件的功能,即我們找到Sprite Renderer下的控制color的選項即可。
在這里插入圖片描述

我們先在BaseLayer中刪除我們創建的bule_hurt2動畫,然后添加到HurtLayer中去。對了,hutr2一個六幀,采樣率設置6即可,然后可以可以拖拽右邊的6個點到1:0的位置,然后再0:2、 0:4 、1:0的位置分別設置阿爾法值為0.5、1、0.5。弄好后鏈接一根線到bule_hurt2,再創建一個新的參數為trigger類型的名稱取hurt(你會注意到它右邊是圓形的圖案這是觸發器)。在觸發hurt2的條件中添加hurt參數這個條件(其他的條件如退出時間、轉換時間都弄為無或是0,和之前的那些動畫差不多就行),一旦hurt(左邊紅框的圓圈內)被勾選了即啟動了,那么會自動播放這個受傷的動畫。
在這里插入圖片描述

如果要由播放受傷的動畫播放完了,我們需要回到之間的動畫所以設置受傷播放完后回到初始的狀態,這里返回的條件就設置為無,即什么都不加。

在這里插入圖片描述

我們進入到代碼把它測試一下,我們打開代碼PlayerAnimations。trigger的方法我們不能在update中執行,它是單次執行的函數,所以創建一個新的函數。

....
public void PlayerHurt(){anim.SetTrigger("hurt");}

那么我們時候執行調用PlayerHurt()呢?應該在Character代碼中去執行:受傷我們需要播放人物的動畫,以及人物被彈走不能再往前走(當然,我們受傷被彈走一般是不允許進行鍵盤操作的),甚至我們需要播放受傷的聲音。這里又很關鍵了,試想一下,除了剛剛提到要被彈飛等事件,也可能還要調整一下我們ui的顯示,就在受傷后有很多事情需要去執行。想讓一次受傷去觸發其他各種各樣的代碼或以后做UI都要來執行對應的方法,我們需要使用Unity的事件的方式。

public void TakeDamage(Attack attcker){if (invincible)return;//Debug.Log(attcker.damage);if (currentHp - attcker.damage > 0)//血量健康才能減血{currentHp -= attcker.damage;//如果學過python,你會知道這行代碼等于currentHp = currentHp - attcker.damage;TriggerInvincible();//執行受傷}else{currentHp=0;//觸發死亡}}

接上面的內容,我們需要調用Unity的命名空間,接下來創建這些事件,我們先創建一個類型為UnityEvent的變量(現在要先弄受傷的事件),然后再public UnityEvent<>的尖括號中,我們可以傳入一些參數,例如在受傷時希望每次受傷都能按受傷的這個方向的反方向被擊退,無論敵人還是人物都應該是這樣的。傳遞方向進去,其實也就是坐標,那么我們Transform類型的組件傳進去。

using UnityEngine.Events;
public UnityEvent<Transform> Ontakedamage;

可能上面代碼看得不是很懂,返回unity窗口就能直觀地看到了(記得先保存寫完的代碼):Character組件就多了事情的內容了。這個東西是unity自帶的,它的好處是以后我們學習UI時,點擊的時候也會有這種事件的處理方式。在這個事件當中,我們可以點擊加號來添加各種各樣的函數方法,各種各樣的功能。那么在一個事件觸發時候,這里可以執行所有你添加進去的方法。如我們之前提到的人物受傷,如果觸發了很可能我們要調用ui、播放音樂、執行方法,播放動畫,所有的內容都可以放在這里。
在這里插入圖片描述

應用舉例,我們把playerAnimations拖拽下去,我們找到代碼中的playerHurt的函數方法,然后可以選擇在何時運行它,如在游戲運行或是編輯器里時,這里我們選擇只在游戲運行時執行。

在這里插入圖片描述

接下來我們會到代碼文件Character中,回看這行代碼public UnityEvent<Transform> Ontakedamage;,**這個關于事件Ontakedamage,剛才的加號是代表我們把各種各樣的方法注冊到這個事件當中,接下來我們需要把這個事件啟動起來,它其實有一個固定的寫法。**注意新寫入的代碼Ontakedamage?.Invoke(attcker.transform);問號代表判斷一下有沒有任何方法添加進來,很可能之前的列表是空的,那我們就可能報錯了,所以加上問號。**后面接點Invoke表示啟動當前事件的內容(不要忘記打上括號)。**然后因為剛剛我們創建時有設置了參數,所以需要傳一個transform進去,誰攻擊我我就朝反方向移動,那么我們就要獲得attcker它的transform了。這樣,我們就實現了該函數(TakeDamage(Attack attcker))受傷數值減少、觸發無敵,然后執行所以注冊過來的受傷的函數方法。(目前我們只注冊了受傷時播放閃爍的動畫)

public void TakeDamage(Attack attcker){if (invincible)return;//Debug.Log(attcker.damage);if (currentHp - attcker.damage > 0)//血量健康才能減血{currentHp -= attcker.damage;//如果學過python,你會知道這行代碼等于currentHp = currentHp - attcker.damage;//觸發無敵TriggerInvincible();//執行受傷Ontakedamage?.Invoke(attcker.transform);}

運行游戲,如果人物經過野豬會有一個人物閃爍的效果,**我經過測試發現:如果把野豬的Is trigger給關掉或膠囊觸發器關閉不使用,那么人物經過野豬,不管是頂著它走還是穿過它都不能能觸發受傷閃爍的效果。**這樣我們就學習了如何觸發事件來執行一些方法。接下來我們給人物受傷切換回我們之前想要的受傷動畫,然后按照我們之前給沒有素材的動畫添加受傷會變紅閃爍的效果即可,然后這樣我們就有了紅色受傷的動畫,那么我們還需要讓人物反彈回去。
在這里插入圖片描述

我們受傷被擊退的事件應該在人物控制的代碼中被執行,因為控制人物的方向要被打斷,如果一直向前跑但是受傷后需要被彈開。所以我們在player_control里面創建新的方法,來執行一個人物反彈的效果。我們需要設置一下玩家的狀態,受傷就要阻止我們其他的移動,也要反彈一段距離。所以需要創建是否受傷的布爾值類型的變量isHurt。然后反彈的時候希望有一個力把它彈開一段距離。

	public bool isHurt;public float hurtForce;
....private void FixedUpdate()//固定頻率運行,即0.02秒執行一次。跟物理有關的放在這執行{if (!isHurt)//沒有進入受傷狀態才能走動{if (isShift && physicsCheck.isGround)Walk();elseMove();}}
.....public void GetHurt(Transform attcker){isHurt = true;//受傷了//接下來執行反彈,不過前提是先把人物的速度停下來。rb.velocity = Vector2.zero;//表示物體的xy軸速度全設置為了。//接下來計算受傷的方向,然后ta要朝反方向彈射。Vector2 dir=new Vector2((transform.position.x-attcker.position.x),0).normalized;/*這里對上行代碼進行說明,dir是direction方向的簡寫。計算方向我們就用人物坐標減去野豬或是其他的attacker的坐標對于x軸來說,如果人物在敵人左邊那么它應該是負數,所以我們根據正負數作為它的方向乘上它的反沖力hurtForce(現實加速的效果)。dir算完后,我們需要不是數值的大小,而是方向值(我們按下鍵盤時dir有-1和1兩種數值)。如果人物離野豬很遠,那么x		  的值會非常大,乘反彈力會更大,反而離得近數值會很小,所以我們要把數值歸一化,即用到normalized的		  方法。         */rb.AddForce(dir*hurtForce,ForceMode2D.Impulse);//添加瞬時的力反彈人物}

保存上面寫好的代碼會回到unity的窗口,我們需要把我們寫好的人物受傷的函數方法添加到Ontakedamage這個事件中去,然后我們給人物被攻擊的力改成8,我們發現人物被彈走后停不下來,原因是isHurt一直沒用變回flase。
在這里插入圖片描述

我們留意到animator中,我們看到受傷動畫狀態的右邊,即我們可以添加一個代碼,在這個動畫執行的過程中,做一些代碼的變化,我們先添加一個叫HurtAninmation的代碼。輸入完名稱后,按下回車鍵,然后它會為你創建這個新的代碼,不過代碼被放在了我們project下的Assets下了,和一些文件目錄同級了。

在這里插入圖片描述
在這里插入圖片描述

雙擊打開代碼,我們可以看到這是一個unity自動為我們寫好的模板,我們可以直接拿來用。它繼承了**StateMachineBehaviour,也就是狀態機的行為,**在做敵人我們也會單獨來寫。取消方法前面的注釋就可以用了。第一方法是,當進去這個狀態時執行,第二方法是當在執行這個動畫的過程中我執行函數方法(如果這個狀態也可稱為動畫時間比較久那么函數一直執行),第三個是當狀態退出后,我們執行某某方法。So,當我們受傷播完并退出后,我們更改我們的人物isHurt的狀態為flase即可。
在這里插入圖片描述

override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){animator.GetComponent<Player_control>().isHurt = false;}

注意我們用Ontakedamage事件的這個方法,我們即播放了動畫,又可以播放腳本里的函數的邏輯。最后一個我們要做的就是人物的死亡,在任何狀態下我們的人物都會死亡,所以我們到動畫控制器中添加死亡的動畫,然后HurtLayer的動畫圖層我們把混合的模式改為Override覆蓋。我們在Parameter中添加死亡參數進行判斷isDead(布爾值)。然后給Any State連一根線到死亡動畫中去,條件為isDead為true時,其他要么無要么為0。

在這里插入圖片描述

注意一下,我們的人物是否會一直進入死亡狀態呢?不一定,如果我們重新開始游戲,那么人物要刷新狀態并退出死亡的動畫(退出的條件大家應該都熟練了,isDead為flse其他要么無要么為0)。
在這里插入圖片描述

接下來把死亡動畫鏈接到函數,我們需要在Character代碼中添加死亡的事件方法。因為在人物死亡時,可能也要執行很多的事情,比如跳出UI的面板,除了通知你Game Over,還要通知你很多的信息,比如通知你的敵人不要繼續攻擊,人物不要再移動了。但是這次我們不需要傳遞任何參數,就是人物只是死亡。

//#Characte.cspublic UnityEvent Ondie;//新加入,對應代碼第22行
..........
public void TakeDamage(Attack attcker){if (invincible)return;//Debug.Log(attcker.damage);if (currentHp - attcker.damage > 0)//血量健康才能減血{currentHp -= attcker.damage;//如果學過python,你會知道這行代碼等于currentHp = currentHp - attcker.damage;TriggerInvincible();//觸發無敵//執行受傷Ontakedamage?.Invoke(attcker.transform);}else{currentHp=0;//觸發死亡Ondie?.Invoke();}}

那么人物的死亡是一個布爾值,所以它不是單次執行的,沒有必要單獨去寫,我們直接把狀態連接到Animation當中即可,并通過人物控制停止我們所有的人物操作如移動。

//#Player_control.cs
public bool isDead;
...
public void PlayerDead(){isDead = true;inputControl.GamePlayer.Disable();//我們之前輸入系統的人物操作相關的內容。我們只關閉人物的操作,正常的ui操作還要保留的。}

然后在PlaterAnimation中把狀態連接起來。

public void SetAnimatons()//需要做很多動畫的切換,我們用這個函數來執行所有的動畫切換。{........anim.SetBool("isDead", playercon.isDead);}

在這里插入圖片描述

然后設置人物的血量為6進行死亡測試,不過你會發現人物會反復死亡,這是因為人物的死亡動畫沒有設置為只播放一次。把下圖人物死亡的動畫的循環關去即可,讓它單次執行。一般來說很多動畫都需要單次播放的,如果不連接到Any State中,它都不會有這樣的問題,如果你鏈接了Any State且只希望播放一次,一定要取消勾選Loop Time。
在這里插入圖片描述

總結:

? 添加事件的方式特別的方便,它能幫助我們添加各種函數去執行一些事件,我們雖然只做了兩個動畫,即人物的受傷和死亡卻操作了很久說明做游戲也不是很容易的。這節可能沒那么好理解,記得多多操作并理解這些步驟是為什么要這么做的,就連我自己都要反復看才能理出一點頭緒。

? 為了能記下Unity一些的特殊用法,還是一些來稍微回味一下這期的內容吧。在創建人物受傷和死亡的動畫之前,我們先是創建了人物被觸發后能夠閃爍的動畫,這樣的動畫我們是通過組件Sprite Renderer里面的color功能區實現的。我們創建了一個新的動畫圖層,修改它顯示的權重并用于疊加到我們之前的動畫上。觸發受傷的動畫是通過觸發器來實現的,所以只需要單次執行,我們不會把它放入到Update函數中去,我們將在PlayerAnimations類中的函數PlayerHurt()放到Character代碼中去執行,因為人物檢測到血量減少后應該就執行人物受傷的動畫,這很符合直覺。然后因為如果我們的人物受傷了,我們需要做很多的事情,如播放音樂、播放受傷動畫等,所以我們使用了命名空間UnityEngine.Events,來給物體添加一些事件的功能,而且我們在Unity窗口的物體的組件上也能看到在對應的代碼多出了添加一些注冊事件的功能,然后我們需要在代碼的對應位置啟動某某事件固定格式為:事件名稱.Invoke(參數)Ontakedamage?.Invoke(attcker.transform);

? 運行游戲后發現觸發人物的受傷動畫是正常的,接下來我們需要人物在進去受傷動畫時,人物不應該能執行一些操作,如果移動跑步等,并且受傷被擊退的事件應該在人物控制的代碼中被執行,即現在我們需要確定的事件就是,人物受傷不能操作,且要被擊退,而播放動畫是在人物屬性的代碼中執行的,因為一旦扣血我們才播放受傷動畫。在人物控制的代碼文件中,我們創建了新的函數方法為GetHurt(Transform attcker),然后我們創建一個布爾值變量判斷受傷,和一個受傷應該能彈飛人物的力的變量。然后該事件函數(人物被彈飛,且不能操作)的調用我們放入到剛剛Character的代碼中去注冊到事件Ontakedamege中去,這個地方就是如果在Character代碼中如果事件Ontakedamage被啟動了,相應的人物動畫代碼中的觸發的參數hurt將被激活,然后執行人物受傷的動畫,再接下來就是人物控制代碼中的函數GetHurt(Transform attcker)被調用了,這是直接更新人物的受傷狀態isHurt為true,那么,人物進入不能操作且被擊飛的狀態,這個持續的時間是是無限時間,因為沒有設定何時把isHurt改為flase,在人物控制的FixedUpdate()函數中isHurt還是true,達不到我們能操作的條件,所以我們在受傷動畫退出的時間即受傷動畫播放完后,我們通過在受傷的State中創建新的代碼來在退出動畫時更新我們人物受傷的狀態,該代碼文件的關鍵代碼為:animator.GetComponent<Player_control>().isHurt = false;,即我們獲取了人物控制的代碼,在動畫完全退出后我們把isHurt的狀態改為flase,這樣在我們人物被擊飛后我們又獲得了人物操作的控制權(是的,人物在受傷獲得操控權后又飄了…)。然后就是注入人物死亡的動畫,當人物的狀態isDead為true時,我們讓人物進入死亡并且所有操作都要停止,但是也只是限制人物的操作,像其他的如UI的操作我們沒有停止,因為那是結算界面。我們在人物控制的代碼文件中創建新的函數為PlayerDead(),人物死亡則isDead為true,而且關閉人物相關操作,并在人物動畫中時時檢測人物死亡因為重開游戲人物會滿血達不到死亡的條件。

? 大致的流程就是這樣了,不知道我有沒有說清楚?唉這個部分就是比較混亂的,多看多想吧。

未盡事宜以后可能會補充。

-------------------------結束線

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/24631.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/24631.shtml
英文地址,請注明出處:http://en.pswp.cn/web/24631.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

思考、學習、創造、越來越有趣

程序員應該有什么職業素養&#xff1f; 對于程序員而言&#xff0c;把復雜的事情變簡單是最重要的能力&#xff01; 方向一&#xff1a;專業精神 程序的本質是算法&#xff0c;無論復雜或不復雜&#xff1b;程序員就是幫助使用者把重復的工作交給代碼。所以程序員最本質的能力…

2024 IDEA最新永久使用碼教程(2099版)

本篇文章我就來分享一下2024年當前最新版 IntelliJ IDEA 最新注冊碼&#xff0c;教程如下&#xff0c;可免費永久&#xff0c;親測有效&#xff0c;適合Windows和Mac。 本教程適用于 J B 全系列產品&#xff0c;包括 Pycharm、IDEA、WebStorm、Phpstorm、Datagrip、RubyMine、…

Vue基礎知識:插槽——默認插槽,插槽的后備內容,具名插槽,作用域插槽的認識與使用。(slot,#default,row的認識)

1.插槽的基本認識&#xff1a; 作用&#xff1a;讓組件內部的一些結構支持自定義 插槽的分類&#xff1a; 1.默認插槽&#xff08;組件內只能定制一處結構&#xff09; 2.具名插槽&#xff08;組件內可以定制多次結構&#xff09; 簡單而言&#xff1a;就是你希望封裝一個…

09-數組的含義以及零長數組變長數組與多維數組

09-數組的含義以及零長數組變長數組與多維數組 文章目錄 09-數組的含義以及零長數組變長數組與多維數組一、數組名的含義1.1 表示整個數組的首地址1.2 表示整個數組首元素的首地址 二、數組下標字符串常量 三、零長數組3.1 示例 四、變長數組4.1 示例 五、多維數組5.1 定義與初…

nodejs---fs模塊,文件讀寫操作詳解,自定義一個文件寫入方法

fs模塊導入 Node.js 同時支持 CommonJS 和 ES 模塊系統&#xff08;自 Node.js v12 以來&#xff09; // 兩種模塊導入方式 import * as fs from fs;// Es6:這種方式需要在package.json中配置"type": "module" const fs require(fs);// commonJs:如果你…

golang協程工作池處理多任務示例

1. 工作方法實現 // 工作線程 // id : 線程號 // jobs : 任務通道 (chan) // results: 完成結果通道 (chan) func worker(id int, jobs <-chan int, results chan<- int) {//遍歷任務for j : range jobs {fmt.Println("工作協程: ", id, "啟動任務: &quo…

oracle中如何查詢特定日期?

1. select last_day(to_date(20230101,YYYYMMDD)) from dual; select last_day(to_date(V_END_DATE,YYYYMMDD)) from dual; --查詢任意一天 當月的最后一天 2. select to_char(to_date(20230101,YYYYMMDD)-1,YYYYMMDD) INTO V_START_DATE FROM DUAL; select to_char(to_dat…

vscode輸出控制臺中文顯示亂碼最有效解決辦法

當VSCode的輸出控制臺中文顯示亂碼時&#xff0c;一個有效的解決辦法是通過設置環境變量來確保編碼的正確性。以下是解決方式&#xff1a; 首先&#xff0c;設置環境變量以修正亂碼問題&#xff1a; 如果上述方法沒有解決亂碼問題&#xff0c;請繼續以下步驟&#xff1a; 右鍵…

技術革命的十年:計算機、互聯網、大數據、云計算與AI

近10年來&#xff0c;計算機、互聯網、大數據、云計算和人工智能等技術領域發展迅速&#xff0c;帶來了巨大的變革和創新。以下是各個領域的發展歷史、現狀、問題瓶頸、未來趨勢以及可能的奇點。 計算機技術&#xff1a; 發展歷史&#xff1a; 過去&#xff1a;過去十年間&am…

HTML5表單元素:重塑數據收集的藝術

HTML5為網頁表單帶來了革命性的變化&#xff0c;不僅增強了用戶體驗&#xff0c;也為開發者提供了更加強大和靈活的工具來收集和驗證數據。本文將深入解析HTML5中新增和改進的表單元素&#xff0c;通過實例展示它們如何提升表單功能和交互性。 1. 新增表單元素 <input>…

SVN中trunk,branch,tag

SVN trunk(主線) branch(分支) tag(標記) 用法詳解和詳細操作步驟_svn 分支-CSDN博客 場景: 項目的1.0版本已經完成開發,測試,并上線了. 接到了新需求,要修改多個文件的代碼. 你寫了一段時間的時候,用戶或測試人員反饋, 1.0版本有重大bug要修復,修復好后立刻上線. 此時應該怎么…

RocketMQ的安裝

首先到RocketMQ官網下載頁面下載 | RocketMQ (apache.org)&#xff0c;本機解壓縮&#xff0c;作者在這里用的是最新的5.2.0版本。按照如下步驟安裝。 1、環境變量配置rocket mq地址 ROCKETMQ_HOME D:\rocketmq-all-5.2.0-bin-release 在變量path中添加”%ROCKETMQ_HOME%\bi…

免費數據庫同步軟件

在信息化日益發展的今天&#xff0c;數據同步成為了企業和個人用戶不可或缺的一部分。數據庫同步軟件作為數據同步的重要工具&#xff0c;能夠幫助我們實現不同數據庫系統之間的數據復制和同步&#xff0c;確保數據的一致性和完整性。本文將介紹幾款免費數據庫同步軟件&#xf…

ES5/ES6 的繼承除了寫法以外還有什么區別?

一、主要區別 ES5 的繼承實質上是先創建子類的實例對象&#xff0c; 然后再將父類的方法添加 到 this 上&#xff08;Parent.apply(this)&#xff09; . ES6 的繼承機制完全不同&#xff0c; 實質上是先創建父類的實例對象 this&#xff08;所以必 須先調用父類的 super()方法…

C#根據反射生成sql語句(Update語句)

今天有人問我Update語句怎么搞&#xff0c;想了一下大致思路就是用特性去標識一下&#xff0c;主鍵&#xff0c;然后再去用反射的方式拼sql語句。 在C#中&#xff0c;我們可以使用特性&#xff08;Attributes&#xff09;來標識一個類的屬性作為該類的主鍵&#xff08;Primary…

旅游卡系統開發搭建

旅游卡系統的開發搭建是一個涉及多個步驟和關鍵因素的復雜過程。以下是關于旅游卡系統開發搭建的詳細步驟和要點&#xff1a; 一、需求分析 目標用戶調研&#xff1a;深入調研目標用戶&#xff0c;了解他們的需求和痛點&#xff0c;從而確定系統的功能和特點。功能確定&#…

數據分析必備:一步步教你如何用Pandas做數據分析(20)

1、Pandas 分類數據 Pandas 分類數據的操作實例 數據通常實時包含重復的文本列。性別&#xff0c;國家/地區和代碼等功能始終是重復的。這些是分類數據的示例。 分類變量只能采用有限的且通常是固定數量的可能值。除固定長度外&#xff0c;分類數據可能還具有順序&#xff0c;…

elasticsearch安裝與使用(1)-使用docker安裝Elasticsearch

ES的優點&#xff1a; 1、分布式準實時2、提供REST風格的API接口&#xff0c;是用戶可解借助任何語言使用https對ES執行請求來完成搜索任務&#xff1b;3、提供聚合功能 1、Elasticsearch安裝 docker network create elastic docker pull docker.elastic.co/elasticsearch/e…

MySQL入門學習-聚合和分組.計數(COUNT()函數)

在 MySQL 中&#xff0c;聚合和分組是用于對數據進行匯總和分析的強大功能。聚合函數可以計算數據的總和、平均值、最小值、最大值等統計信息&#xff0c;而分組則可以將數據按照特定的字段進行分組&#xff0c;然后對每個分組進行聚合計算。計數&#xff08;COUNT() 函數&…

【MYSQL系列】mysql中text,longtext,mediumtext區別

【MYSQL系列】mysql中text,longtext,mediumtext區別 在MySQL數據庫中&#xff0c;TEXT、LONGTEXT和MEDIUMTEXT都是用于存儲大量文本數據的字段類型。它們之間的主要區別在于可存儲的數據大小和性能方面的差異。本文將探討這些字段類型的特點、使用場景和一些最佳實踐。 TEXT類…