Unity2019.2.2f1
Windows10
□
【UnityC#講座】3D人型モデルを三人称視点で動かす操作を改良
今回はこの記事の続きとしてユニティちゃんにパンチをさせます。
そして次回は操作するユニティちゃんとNavMeshAgentで動くユニティちゃんで殴り合いをさせるのでその準備もします。
目次 [非表示]
■AnimatorControllerの設定をする
アニメーションクリップ
攻撃モーションとダメージモーションを追加します。
ダメージモーションは今回使いませんが、次回使うのでついでに設定しておきます。
ユニティちゃんのフォルダの中からPOSE30とDAMAGED00をアニメーションクリップを見つけてAnimatorControllerにドラッグしてください。
攻撃モーション
Project > Assets > unity-chan! > Unity-chan > Art > Animation > unitychan_ARpose2 Impo > POSE30
ダメージモーション
Project > Assets > unity-chan! > Unity-chan > Art > Animation > unitychan_DAMAGED00 In > DAMAGED00
そうすると長方形のアイコン、StateができるのでInspectorから名前をAttackとDamageに替えます。
Transition
そしてStateを左クリックで選択してから右クリック、Make Transitonをし、他のStateを左クリックすることでつなげます。
画像のようにしてください。
Blend Tree ←→Attack
Blend Tree ←→Damage
Attack → Damage
Blend TreeはAttackとDamageの両方と互いにTransition(矢印付きの線)を張り、AttackからDamageは一方通行です。
Parameters
次はParametersを設定しましょう。
AnimatorControllerの左上のParametersを選択、そして+ボタンをクリックし、Boolを選択します。
それでまたAttackとDamageの2つを作ってください。
Transitionの設定
次はTransitionの設定です。
Transitionをクリックし、HasExitTimeのチェックを外し、Conditionsの設定をします。
Conditionsの+ボタンを押し、それからそれぞれ以下のようにします。
Blend Tree → Attack Attack/True
Blend Tree ← Attack Attack/False
Blend Tree → Damage Damage/True
Blend Tree ← Damage Damage/False
Attack → Damage Damage/True
Blend Treeから行くのがTrueで戻るのがFalseです。
AttackからDamageに行くのは攻撃中に攻撃を受けた時のためです。
■アニメーションイベントの設定をする
アニメーションイベントはアニメーション中の特定のタイミングでメソッドを呼び出したりできる機能です。
まずはPOSE30のアイコンをクリックし、InspectorからEdit、Eventsとたどり設定します。
StateのMotion欄のPOSE30をクリックするとすぐにPOSE30にたどりつけます。
Eventsという文字の下のアイコンをクリックし、出てきた棒をメソッドを呼びたい時間に置きますが、後で調整できるので適当でいいです。
そしてFunctionの欄にAttackEndと入れてください。
最後にApplyをクリックして完了です。
Damageも同じように設定しDamageEndと入れてください。
■攻撃判定のオブジェクトを設置する
次は攻撃が相手に当たったことを判定するオブジェクトを設置します。
これもパンチさせるだけならいらないのですが、次回の殴り合いのために作っておきましょう。
まずの空のオブジェクトを出し名前をAttackPointにします。
Hierarchy > Create > Create Empty
次はTagを設定します。
InspectorのTagからPlayerAttackとEnemyAttackを作ります。
Tag > Add Tag > Tags > +
+ボタンを押してTagの名前を付けてください。
そして戻ってPlayerAttackを選びます。
EnemyAttackは次回使います。
次はそれをユニティちゃんの右手のアーマチュア(アニメーションするための骨組み)の子オブジェクトにします。
混み入っていて面倒ですが頑張りましょう!
Hierarchy > unithchan > Charaster1_Reference > Charaster1_Spine > Character1_Spine2 > Charaster1_RightShoulder > Character1_RightArm > Character1_RightHand
ちなみにCreate横の検索欄に名前をコピペすれば簡単にたどりつけます。
次はAddComponentでSphereColliderを入れます。
位置はXYZのPositionがすべて0で良いです。
円の大きさ、Radiusは0.2にしましたが別に何でもいいです。
そしてIsTriggerにチェックを入れることを忘れないでください。
スポンサーリンク
■スクリプトを設定する
最後はスクリプトを書いてアタッチし、そのInspectorを設定すれば出来上がりです。
前回書いたPlayerスクリプトに追加します。
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[RequireComponent(typeof(CapsuleCollider))] | |
[RequireComponent(typeof(Rigidbody))] | |
public class Player : MonoBehaviour | |
{ | |
[SerializeField] float speed = 4f; | |
private Animator animator; | |
Transform cam; | |
Rigidbody rb; | |
CapsuleCollider caps; | |
//列挙型、Actionの部分は自分で名前つける | |
enum Action | |
{ | |
Move, | |
Attack, | |
Damage | |
} | |
//列挙型の名前を型にして変数を宣言する | |
[SerializeField] Action action = Action.Move; | |
//攻撃判定のオブジェクトを入れる | |
[SerializeField]GameObject attackObj; | |
void Start() | |
{ | |
animator = GetComponent<Animator>(); | |
rb = GetComponent<Rigidbody>(); | |
rb.constraints = RigidbodyConstraints.FreezeRotation; | |
cam = Camera.main.transform; | |
caps = GetComponent<CapsuleCollider>(); | |
caps.center = new Vector3(0, 0.76f, 0); | |
caps.radius = 0.23f; | |
caps.height = 1.6f; | |
//攻撃判定のオブジェクトをしまっておく | |
attackObj.SetActive(false); | |
} | |
void Update() | |
{ | |
//Action.Moveの時だけ移動できるようにする | |
if (action == Action.Move) | |
{ | |
float x = Input.GetAxisRaw("Horizontal") * Time.deltaTime * speed; | |
float z = Input.GetAxisRaw("Vertical") * Time.deltaTime * speed; | |
animator.SetFloat("X", x * 50); | |
animator.SetFloat("Y", z * 50); | |
if (z > 0) | |
{ | |
transform.rotation = Quaternion.Euler(new Vector3(transform.rotation.x, | |
cam.eulerAngles.y, transform.rotation.z)); | |
} | |
else if (z < 0) | |
{ | |
z = z / 1.5f; | |
} | |
transform.position += transform.forward * z + transform.right * x; | |
//マウスの左クリックでAction.Attackに変更する | |
if (Input.GetMouseButtonDown(0)) | |
{ | |
action = Action.Attack; | |
} | |
} | |
//Action.Attackの時だけ攻撃をする | |
else if (action == Action.Attack) | |
{ | |
//パンチのアニメーションを出す | |
animator.SetBool("Attack", true); | |
//攻撃判定のオブジェクトを出す | |
attackObj.SetActive(true); | |
} | |
//Action.Damageの時だけダメージのアニメーションを出す | |
else if (action == Action.Damage) | |
{ | |
animator.SetBool("Damage", true); | |
} | |
} | |
//TagがEenmyAttackのオブジェクトに当たるとAction.Damageになる | |
//Action.Damageの時に当たるとreturnでそれ以降何も起きない | |
private void OnTriggerEnter(Collider other) | |
{ | |
if (other.gameObject.tag == "EnemyAttack") | |
{ | |
if (action == Action.Damage) | |
{ | |
return; | |
} | |
else | |
{ | |
action = Action.Damage; | |
} | |
} | |
} | |
//POSE30のアニメーションイベントで呼ばれる | |
//Invokeで指定した秒数の後にAttackEndAnimが呼ばれる | |
public void AttackEnd() | |
{ | |
Invoke("AttackEndAnim", 0.5f); | |
} | |
//Action.Moveに戻す | |
//パンチアニメーションから移動アニメーションへ | |
//攻撃判定のオブジェクトをしまう | |
void AttackEndAnim() | |
{ | |
action = Action.Move; | |
animator.SetBool("Attack", false); | |
attackObj.SetActive(false); | |
} | |
//DAMAGED00のアニメーションイベントで呼ばれる | |
//Action.Moveに戻す | |
//ダメージアニメーションから移動アニメーションへ | |
void DamageEnd() | |
{ | |
action = Action.Move; | |
animator.SetBool("Damage", false); | |
} | |
} |
列挙型(Enum)で移動、攻撃、ダメージの行動を分けるようにしました。
OnTriggerEnterでEnemyAttackのTagに当たるとダメージモードに切り替わるようにしています。
POSE30はアニメーションと言うよりも単なるポーズのようなのでInvokeで0.5秒後にAttackEndAnimメソッドを呼び攻撃モードを終えるようにしました。
仕上げはユニティちゃんにスクリプトをアタッチしていなければし、そしてInspectorからAttackPointを設定して出来上がりです。
さて、無事にパンチできたでしょうか?
ユニティちゃんにパンチさせる#unity pic.twitter.com/e4C19wIVfW
— イシゲー@UnityとBlender (@ishidahanta) November 17, 2019
今回はこれで終わります。
続きはこちらです。
【UnityC#講座】ユニティちゃんに殴り合いをさせる【NavMeshAgent】
■関連記事
【UnityC#講座】無料アセットでユニティちゃんに剣を振らせる
【UnityC#講座】無料アセットで一人称視点に剣を振らせる
この作品はユニティちゃんライセンス条項の元に提供されています
スポンサーリンク