【Unity】キャラクター操作その5 – レーザーソードで攻撃する
概要
前回(RobotKyleでいろい~その4~)ではRobotKyleにレーザーソードを持たせてソードをON/OFFさせるところまで実現しました。
今回はさらにRobotKyleにレーザーソードで攻撃する動作を付け加えていきたいと思います。
完成イメージ
Step1 : 攻撃Animationの調達
Unity Asset Storeにはソード系の攻撃Animationが沢山ありますが、今回はこのAssetを使用させて頂くことにしました。
https://assetstore.unity.com/packages/3d/animations/sword-and-shield-animations-pack-164596#reviews
RobotKyleにシールドは持たせてないですが、斬撃のアニメーションがダイナミックでカッコいいのでこれに決めました。Asset Storeからダウンロードし、PackageManagerからImportします。
Step2 : Animationの設定
Step1でインポートしたSword and Shield PackのFBXフォルダに入っているFBXのうち、Attack01とIdleをCtrl+Dで複製します。
複製されたファイル名はそのままでも構いませんが、後で見つけやすくするためにF2ボタンでSwordAttack、SwordIdleに名前を変更しておきます。
なお、このSword and Shield Packのアニメーションはインポートした時点でデフォルトでRigがHumanoidに設定されていますが、もし他のパッケージの攻撃アニメーションを使用する場合は複製する前にAnimation ClipのRigでAnimation TypeをHumanoidに設定しておいてください。
Step3 : SimpleAnimationへの紐づけ
今回もAnimationの再生はSimpleAnimationを使用してスクリプトで制御していきます。まずはInspectorでSimpleAnimationのスクリプトのSizeを6にした上でSwordAttackとSwordIdleを追加します。アニメーションクリップはStep2で準備したものを指定しておきます。
Step4 : 制御スクリプトの作成
ここでは前々回、前回で作成したキーボード操作による移動とソードON/OFFのスクリプトを統合しつつさらに攻撃アニメーションを制御するスクリプトを作成していきます。
具体的には以下の仕様を満たすコードにします。
- 攻撃はレーザーソードをONにしてる時だけしか行えない制限をかける
- レーザーソードをONしているときはSwordIdleでIdleし、OFFしているときは通常のIdleになるようにする
- 移動中、ダッシュ中、ジャンプ中もソードONできるようにする
- 移動中、ダッシュ中、ジャンプ中も攻撃できるようにする
次のようなコードになります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCon : MonoBehaviour
{
// Start is called before the first frame update
//Status
[SerializeField] public bool onGround = true; //地面接地フラグ
[SerializeField] public bool inJumping = false;//ジャンプ中フラグ
[SerializeField] public bool inAttacking = false;//攻撃中フラグ
[SerializeField] public bool withSwordsOn = false;//ソードONフラグ
[SerializeField] public bool toSwordsOn = false;//ソードONにするフラグ
[SerializeField] public bool inIdle = false;//Idle状態フラグ
[SerializeField] public bool inRunning = false;//移動中フラグ
[SerializeField] public bool inRotating = false;//移動中フラグ
[SerializeField] public bool inSprinting = false;//ダッシュ中フラグ
[SerializeField] public bool inSwordIdle = false;//ソードONのIdleフラグ
[SerializeField] public bool inPushedSwordKey = false;//ソード有効化キー押下済みフラグ
[SerializeField] public bool inPushedAttackKey = false;//ソード有効化キー押下済みフラグ
//rb Variable
Rigidbody rb;
//Run speed
float speed = 0.06f;
//Sprint speed
float sprintspeed = 0.09f;
//Angle change speed
float angleSpeed = 2;
//variable
float v;
float h;
//Defining SimpleAnimation
SimpleAnimation simpleAnimation;
//LaserSword
GameObject laserswordObj;
void Start()
{
//Rigidbodyコンポーネントの取得
rb = this.GetComponent<Rigidbody>();
//プレイヤーの回転抑止
rb.constraints = RigidbodyConstraints.FreezeRotation;
//シンプルアニメーションコンポーネントの取得
simpleAnimation = GetComponent<SimpleAnimation>();
//LaserSwordオブジェクトの取得
laserswordObj = GameObject.Find("LaserSwordPrefab");
}
// Update is called once per frame
void Update()
{
/*
* フラグ初期化
*/
inRunning = false;
inSprinting = false;
inRotating = false;
/*
*基本動作制御部
*/
//左シフトキーでダッシュスピード、それ以外はふつうのスピードを定義
if (!inAttacking && !inJumping)
{
if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.LeftShift))
{
transform.position += transform.forward * sprintspeed;
inSprinting = true;
}
else if (Input.GetKey(KeyCode.DownArrow) && Input.GetKey(KeyCode.LeftShift))
{
transform.position += transform.forward * -sprintspeed / 2;
inSprinting = true;
}
else if (Input.GetKey(KeyCode.UpArrow))
{
transform.position += transform.forward * speed;
inRunning = true;
}
else if (Input.GetKey(KeyCode.DownArrow))
{
transform.position += transform.forward * -speed / 2;
inRunning = true;
}
}
//旋回動作
if (Input.GetKey(KeyCode.RightArrow))
{
transform.Rotate(Vector3.up * angleSpeed);
inRotating = true;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
transform.Rotate(Vector3.up * -angleSpeed);
inRotating = true;
}
//ジャンプ動作
//スペースキーが押されて、地面に設定しているとき
if (Input.GetKey(KeyCode.Space) && onGround)
{
//速度を一旦0に初期化
rb.velocity = new Vector3(0, 0, 0);
//上(ジャンプで上がる方向)に力を発生
rb.AddForce(transform.up * 600);
//移動中にジャンプボタンを押した場合は斜めにジャンプさせるため前方方向へもそれぞれ力を発生
//ダッシュ中とふつうの移動で発生させる力を変える
if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.LeftShift))
{
rb.AddForce(transform.forward * 250);
}
else if (Input.GetKey(KeyCode.UpArrow))
{
rb.AddForce(transform.forward * 180);
}
else if (Input.GetKey(KeyCode.DownArrow))
{
rb.AddForce(transform.forward * -100);
}
//地面接地フラグをfalseに
onGround = false;
//ジャンプフラグをtrueに
inJumping = true;
}
if (Input.GetKeyDown(KeyCode.C))
{
inPushedSwordKey = true;
}
if (Input.GetKeyDown(KeyCode.Z))
{
inPushedAttackKey = true;
}
/*
*アニメーション制御部
*/
//LaserSwordのスクリプト取得
DigitalRuby.LaserSword.LaserSwordScript laserSwordScript = laserswordObj.GetComponent<DigitalRuby.LaserSword.LaserSwordScript>();
//攻撃動作の最中(80%完了まで)は攻撃中フラグを保持するようにする
if (simpleAnimation.GetState("SwordAttack").normalizedTime >= 0.8)
{
inAttacking = false;
}
//①ここからは前方後方移動中の場合のアニメーションの制御
//前方後方移動キーが押されたとき
if (inPushedSwordKey)
{
if (!withSwordsOn)//現在ソードOFF状態のとき
{
toSwordsOn = true;//ソードONフラグをtrueに
}
else if (withSwordsOn)//現在ソードON状態のとき
{
toSwordsOn = false;//ソードONフラグをfalseに
}
}
//ソードがONで攻撃ボタンが押されたとき
if (withSwordsOn && inPushedAttackKey)
{
//攻撃アニメーションを再生
simpleAnimation.CrossFade("SwordAttack", 0.1f);
//攻撃キー押下済みフラグをfalseに
inPushedAttackKey = false;
//攻撃中フラグをtrueに
inAttacking = true;
}
//移動中フラグもしくはダッシュ中フラグが中のとき
else if (inRunning || inSprinting)
{
//ジャンプ中フラグがtrueのとき
if (inJumping)
{
//ジャンプアニメーションを再生
simpleAnimation.CrossFade("Jump", 0.1f);
}
else if (inAttacking) { }//攻撃中の場合は特に何もせず(攻撃アニメーションを優先)
else if (inSprinting)
{
//スプリントアニメーションを再生
simpleAnimation.CrossFade("Sprint", 0.1f);
}
else//通常移動の場合
{
//移動アニメーションを再生
simpleAnimation.CrossFade("Run", 0.1f);
}
}
//ジャンプ中で攻撃中でないとき
else if (inJumping && !inAttacking)
{
//ジャンプアニメーションを再生
simpleAnimation.CrossFade("Jump", 0.1f);
}
else
{
if (inAttacking) { }//攻撃中は攻撃アニメーションを継続
else if (inJumping) { }//ジャンプ中はジャンプアニメーションを継続
else if (inPushedSwordKey) { }//ソードON/OFFキー押下中も今のアニメーションを継続
else//それ以外
{
//ソードをONしているとき
if (withSwordsOn)
{
//SwordIdlwを再生
simpleAnimation.CrossFade("SwordIdle", 0.1f);
}
else
{
//ふつうのIdleを再生
simpleAnimation.CrossFade("Default", 0.1f);
}
}
}
/*
* ここからソードのON/OFF制御
*/
//ソードON/OFFキーが押下され、攻撃モーション中でない場合
if (inPushedSwordKey && !inAttacking)
{
//ソードONフラグがtrueなら
if (toSwordsOn)
{
//レーザーソードをAcfivate
laserSwordScript.Activate();
//ソードON中フラグをtrueに
withSwordsOn = true;
//ソードON/OFFキーフラグをfalseに
inPushedSwordKey = false;
//ソードON予定フラグをfalseに
toSwordsOn = false;
}
else//ソードONフラグがfalseなら
{
//レーザーソードをDeactivate
laserSwordScript.Deactivate();
//ソードON/OFFキーフラグをfalseに
withSwordsOn = false;
//ソードON/OFFキーフラグをfalseに
inPushedSwordKey = false;
}
}
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "Ground")
{
onGround = true;
inJumping = false;
simpleAnimation.Stop("Jump");
}
}
上記スクリプトをRobotKyleにアタッチしてGameを実行すると冒頭のgifのような動作ができます。
以上
Unityを一から学ぶのにおすすめの本はコチラ