2014-5-21

UE4 におけるダメージ機能

作成 Jeff Farris

「人に危害を加えざるを得ない場合は、報復の恐れが必要ないくらい徹底的にやるべきである」- マキャベリ

「ダメージ」はゲームでは一般的なコンセプトです。そこで今回は、UE4 のゲームフレームワークに含まれているダメージ機能について簡単に解説したいと思います。

ダメージは、ベースの Actor クラスの機能であるため幅広く使用できます。結果が早くほしい場合は、一般的な機能に簡単にアクセスできます。必要に応じて独自のダメージモデルをカスタマイズできる拡張性もあります。また、ダメージに対する反応のしかたは想定されていません。だから、エンジンには「ヒットポイント」とか「戦闘不能」という概念がありません。これらの概念は、普通、ゲームそれぞれで固有のものであるからです。それらを一般化しても、かえって苦労をかけることになると考えたのです。

基本的なダメージのコンセプト

ダメージには、よく使われるコンセプトがいくつかありますので、簡単に紹介してみましょう。

DamageType

その名の通り DamageType は、ダメージ源とは無関係にダメージの「型」を記述できるオブジェクトです。これが役立つのは、ダメージのソースが多数あり、それらに共通の機能を持たせたい場合です。

簡単な例を使って説明しましょう。火のダメージがあるとします。キャラクターがそのダメージを受けると、「あっちー」と叫んで、近くの水のあるところまで駆け込ませるようします。その場合、キャラクターにやけどをさせることができるあらゆるアクタ (または、やけどを負う可能性があるあらゆる型のアクタ) にこのコードをコピーするよりも、火のためにダメージ型 (UDamageTypeFire) を定義して、そこに何らかの HandleDamagedCharacter() 関数を備え、適宜 TakeDamage() の呼び出しチェーンからその関数を呼び出すようにするのがよいでしょう。

Instigator

Instigator とは、ダメージを引き起こすです。普通は、PlayerController や AIController が Instigator となります。火のダメージの場合は、プレイヤーか、火をつける AI がこれになるでしょう。

DamageCauser

causer とは、普通、ダメージを引き起こすのことです。たとえば、ACampFire アクタの上を歩くと、それが causer となります。

C++ におけるダメージ

まず、ネーティブコードがダメージにどのように対応しているか見て行上できましょう。

この例の場合は、アクタにダメージを与えるのは簡単です。そのアクタ上で TakeDamage() を呼び出すだけです。

virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, class AActor* DamageCauser);

また、ダメージに対して反応させるためには、ダメージを受けたアクタ上で TakeDamage() をオーバライドして、カスタムの操作を挿入するだけです。簡単ですよね!

ご覧のとおり、TakeDamage() のコールでは、引数として DamageEvent が渡されていますね。この FDamageEvent データ構造体には、ダメージを発生させるイベントの特定の状況に関するデータが含まれています。それによって、反応のためのコードが適切に対応できるようになります。UE4 には、次のような 3 種類の味のダメージ イベントがビルトインされています。

FPointDamageEvent

「その方向からうたれたため、顔のここが痛い」

ポイント ダメージ イベントは、被害者の特定の点に加えられたダメージ (弾丸やパンチなど) を具現化しています。このイベントには、攻撃が到来した方向と、サーフェスのインパクトを記述する FHitResult が含まれています。

FRadialDamageEvent

「あの大きな爆発のせいで、左半身全体が痛い」

ラジアル ダメージ イベントは、ある 1 点を源とする放射状のダメージを具現化したものです。代表的な例としては、爆発からダメージがあります。このダメージには、爆心地、および、空間におけるダメージの減衰を記述するためのデータ、影響を受けるコンポーネントのリストが含まれています。

FDamageEvent

「あ痛っ」

もっとも汎用的なダメージ モデルです。含まれているものは、オプションの DamageTypeClass だけです。

これらのビルトインされているイベントの型が、求めているものではない場合は、独自の構造体を FDamageEvent から派生させ、必要なデータを格納することができます。

ブループリントにおけるダメージ

ブループリントでダメージを扱う場合も同様です。ただし、ダメージの適用とダメージへの反応が、イベントの型によって用意されている点が異なります。ダメージを与える場合は、グローバルにアクセスできるノードが利用できます。ApplyDamage、ApplyPointDamage、ApplyRadialDamage などがそれです。ダメージ イベントに反応するためには、同様の took damage (ダメージを受けた) イベント群が用意されています。これらはアクタ クラスとレベル内のアクタ インスタンス両方のためのものです。

ご自分のプロジェクトのためにカスタムのダメージ イベントを定義した場合は、おそらく、ブループリントで使用するために、同様の関数およびデリゲートの集まりをエクスポーズする必要が出てくるでしょう。

さあ、ダメージを楽しんでください!そして、ダメージに関する質問や体験談などがありましたら、フォーラムをお訪ねください!

最近の投稿

最新技術を先取りチェック:間もなく実現、アンリアルのリアルタイム レイトレーシング

「リアルタイム」と「レイトレーシング」はかつて相反する言葉でした。しかしNVIDIA RTX 技術の登場により、アンリアル エンジンでのリアルタイム ...

西部劇風ビジュアルの大乱闘 FPS、『Sky Noon』の制作背景

ニュージーランドを拠点とするインディー デベロッパー チームであり、Unreal Dev Grant を受賞した Lunar Rooster が、ユニ...

GitHub アカウントと Epic Games アカウントの紐付けの認証プロセスのアップデート

ユーザー エクスペリエンスとセキュリティの向上のために、GitHub アカウントと Epic Games アカウントの紐付けプロセスに OAuth 機...