武器切り替え
ゲームの基本は競争であるため、どうしても敵と味方に分かれて争うゲームが多くなります。
そして戦いにバリエーションを持たせるため、キャラクタや武装の選択ができるゲームが非常に多いです。
シューターでもアクションでもRPGでも、プレイヤーが持つ武器を何らかの方法で切り替えられるようにしているゲームが多いです。
というわけで、今回はそんな武器切り替え手法を試してみます。
武器切り替えということで、今までのようにStaticMeshだけで実装するのはよろしくないでしょう。
そこで今回はあの方に登場していただくことになりました。
UnityにはUnityちゃんなる公式キャラが存在するようですが、UE4にも公式キャラが存在しています。
婦女子などという軟弱な存在ではなく、男臭さたっぷり、でも肌つやはとってもいい37歳(たぶん)の彼です!
ブルーマン先生の登場だぁぁぁぁぁぁ!
…はい、まあ、青人形です。
サードパーソンや横スクロールテンプレートを作成すると使用できるSkeletalMeshです。
私には残念ながらモーションを作る能力もキャラを作る能力もないのでテンプレートの彼を使用します。
攻撃モーションとかもありませんが、一応攻撃も可能なようにしてみます。
…見た目では攻撃しているように見えませんがね。
いつもはブランクプロジェクトを作成するところですが、今回はサードパーソンテンプレートを作成することにします。
適当な名前でBlueprintのサードパーソンテンプレートを作成してください。
まず最初に武器となるメッシュを作成します。
私はBrushをStaticMeshに変換して作成していますが、FBXを作成できるならそれをインポートしてもかまわないでしょう。
今回作成した武器となるStaticMeshは SM_Stick と SM_Axe の2つです。
これらと素手を切り替えられるようにします。
斧に見えない?Oh No.
ええと…次にブルーマン先生に武器を装備する場所を設定してあげる必要があります。
武器なので当然手に持つわけですが、手のどのあたりにくっつけるかを座標指定で細かく調整するのは面倒です。
何より、モーションに合わせて動かさなければならないので何らかの目印が必要になります。
これを実装するにはソケットを用いるのが最も簡単です。
コンテンツブラウザの "/Game/Character/HeroTPP" をダブルクリックし、SkeletalMeshのウィンドウを開きましょう。
左にSkeleton Treeという、SkeletalMeshの骨構造が表示されています。
この骨構造はFBXファイルをインポートしてきたものでしょうが、ここで何らかの座標や姿勢を提供するためのソケットを追加することが可能です。
コントロールポイントと呼ぶ人もいるでしょうけど、UE4ではソケットと呼ばれます。
このソケットは今回のように武器やアクセサリなどのアタッチ場所を指定する以外に、エフェクトの発生個所などにも使用できます。
現在のソケットの位置などはBlueprint上から取得可能なので、必要に応じてエフェクトを発生させるなどすることが可能です。
今回は手にソケットを追加したいので、"hand_l" と "hand_r" のボーンの子としてソケットを追加します。
それぞれのボーンを選択し、右クリックしてください。
コンテキストメニューから "Add Socket" を選択し、作成したソケットの名前を "weapon_l", "weapon_r" としておきましょう。
ソケットを追加すると親となっている各ボーンの位置にソケットが生成されるので、適当に平行移動で手のひらあたりに移動させてください。
また、回転方向の関係から、"weapon_l" のソケットはZ軸に180度回転させておきます(青い回転ウィジェットを利用する)。
こうしておかないと武器を逆手で持つようになってしまいます。
ソケットを追加したらキャラクタのBlueprintをいじって武器を装備できるようにしましょう。
"/Game/Blueprints/MyCharacter" をダブルクリックし、Blueprintを開きます。
武器を装備させる方法としては、StaticMeshをActorとして生成してソケットにアタッチする方法とStaticMeshComponentを作成してソケットにアタッチする方法があります。
今回は後者のコンポーネントを利用してみます。
まず、指定したメッシュを作成し、指定したソケットにアタッチする命令、CreateWeapon関数を作成しましょう。
(クリックで拡大)
この関数は今回のメインとなる関数なのできちんと解説してみます。
関数の最初は "Add StaticMeshComponent" と "Set Static Mesh" ですが、これは前回もやったとおりStaticMeshComponentを追加して、そこに引数で渡されたStaticMeshを設定しているだけです。
この次は第1のポイントです。
コンポーネントやアクターにはTagを追加することが可能です。
TagはName型で設定し、複数設定することも可能です。
このTagの主な用途は、特定用途のコンポーネントやアクターの検索です。
今回のサンプルでは、そのStaticMeshComponentが左手用武器なのか右手用武器なのかを検索するために利用しています。
また、この後に解説するCapsuleComponentが攻撃判定を持っていることを示すためにも利用しています。
Tagの追加は各コンポーネントの "Get Component Tags" でTagの配列を取得し、ここに "Add" 命令で指定名のTagを追加することができます。
わかりやすくするため、StaticMeshComponentに追加するTagはアタッチするソケット名と同じにしておきます。
これはあとで削除の際に検索しやすくするためです。
次の "Attach To" 命令が第2ポイントです。この命令こそ、コンポーネントをソケットにアタッチする命令です。
引数として設定するのは以下のものとなります。
Target:アタッチするコンポーネント(ここでは武器のStaticMeshComponent)
In Parent:アタッチ先コンポーネント(ここではキャラクタのSkeletalMeshComponent)
In Socket Name:ソケット名(Noneならどのソケットにもアタッチしない=根元にアタッチされる)
Attach Type:アタッチしたときにコンポーネントの姿勢をどうするか
Attach Typeは "Keep Relative Offset" にしておきます。
こうしておくと、コンポーネントのTransform情報がアタッチしたソケットに対してオフセットとして設定されます。
例えばZ方向にいくらか移動したTransformをコンポーネント生成時に指定していると、アタッチした先でもローカルZ軸方向に平行移動しているようになります。
今回はBrushからStaticMeshを生成している関係から、コンポーネント生成時のTransformを考慮しなければいけないため、Attach Typeはこのように設定しておく必要があります。
まあ、これがデフォルト値なので変更しなければいいってだけなんですがね。
ここまでで武器のStaticMeshのアタッチは出来ましたが、武器であるからには攻撃判定を持たなければなりません。
攻撃判定は球や箱、カプセルなどの単純形状を用いるのが一般的なので、今回は武器に対してカプセルを設定するようにします。
"Create Collision Capsule" とコメントされている部分がそれです。
CapsuleComponentを作成し、これを先に作成した武器のStaticMeshComponentにアタッチします。
そして削除用にソケット名をTagに追加、加えて攻撃判定を示すために "attack" というTagを追加しました。
さて、次は実際に武器をアタッチする "AttachWeapon" 関数です。
少々大きめなので2つの画像に分けました。
(クリックで拡大)
前半はまず現在の武器を削除する命令です。
"Get Root Component" でBlueprintのルートコンポーネントを取得し、そこから "Get Children Components" で子コンポーネントの配列を取得します。
この時、"Include All Descendants" にチェックを入れておきます。
このフラグは、子コンポーネントの子コンポーネントまで配列に含めるかを指定しています。
武器のStaticMeshComponentはSkeletalMeshComponentにアタッチされているので、このフラグをONにしないと削除したいコンポーネントが配列に加わりません。
このコンポーネント群を "ForEachLoop" 命令で1つ1つチェックします。
"Component Has Tag" 命令を使用すると、そのコンポーネントが指定のTagを持っているかどうか調べることができます。
そして、そのコンポーネントがソケット名と同じコンポーネントを持っているようであれば "Destroy Component" 命令で削除します。
これで、既に作成済みの武器と、その攻撃判定カプセルを削除することができます。
次の "Weapon Create" コメントで示された部分が武器の作成とアタッチの命令で、最終的には "CreateWeapon" 関数を呼んでいます。
"AttachWeapon"関数の引数である "Weapon Kind"、つまり武器の種類によって作成する武器を変更しているだけです。
なお、"Switch on Int" 命令の実行ピンに入ってきているのは、"ForEachLoop" の "Completed" からです。
各Transformはこちらで作成したメッシュに合わせて設定していますので、これをまねる人は各自の武器の大きさ等に合わせて調整を行ってください。
実際に装備をさせる前に武器を切り替えるためのキーバインドを行いましょう。
エディタメニューの [Edit] -> [Project Settings] でプロジェクト設定ウィンドウを開き、[Engine] -> [Input] の [Action Mappings] に以下のキーバインドを行います。
各武器変更と攻撃ですね。
次にMyCharacterに変数を2つ追加します。
どちらもInt型で、"RightWeaponKind" と "LeftWeaponKind" としておきます。
武器変更キーを押すとこの変数が 0 -> 1 -> 2 -> 0 -> …と変化していくようにします。
せっかくなので、デフォルトでも武器を持たせされるようにしてみましょう。
コンストラクションスクリプトを以下のように作成します。
(クリックで拡大)
こうしておくと、各変数のデフォルト値の変更によって、BlueprintウィンドウのComponentsで武器を装備した姿を見ることができるようになります。
メッシュやカプセルの位置はそこで調整するとよいでしょう。
武器切り替えボタンを押された場合のBlueprintは以下のようになります。
(クリックで拡大)
各変数を変更して、それに合わせて"AttachWeapon"を呼んでいるだけです。
ここまで作成したら実行してみましょう。
キーボードの1, 2キーを押すと右手、左手にそれぞれ武器を持つようになります。
やっぱり斧に見えない?Oh No.
最後は攻撃ですが、こちらはちょっとおまけって感じです。
実際のゲームならもっとしっかりやらないといけないでしょうけど、今回はサンプルなので。
(クリックで拡大)
まず、Blueprintが持つコンポーネントをすべてチェックして、"attack" というTagを持ったCapsuleComponentを探します。
見つかったら、"Get Overlapping Actors" 関数でCapsuleComponentと重なっているアクターをすべて列挙します。
そしてこれらのアクターすべてに "Apply Damage" 命令でダメージの指定を行います。
なお、この際に "Base Damage" 引数を0にしておくと、ダメージなしとなってダメージイベントが発行されないようですので注意してください。
あとは適当なStaticMeshを持ったBlueprintを作成し、"Any Damage" イベントを処理してやります。
まあ、"Print String" 命令で Ouch! とでも表示するようにしてみましょう。
このBPをレベルに配置し、ゲームを実行。
キャラクタの武器を変更して、重なり合った状態でマウス左クリックを行ってみましょう。
攻撃判定カプセルと被ダメージBPがきちんと重なっているなら Ouch! と表示されることでしょう。
本来のゲームではもちろん攻撃モーションが発行され、そのモーションの特定フレーム間だけ攻撃判定が発生するようにします。
また、その際の攻撃判定プリミティブは武器にアタッチせずにキャラの前方とかに発生する場合もあります。
この辺りをどのように処理するかはゲームに寄るのですが、少なくとも今回のように適当には処理しません。
実際のゲームを作成する場合はこの点に特に注意して作成しましょう。