
1998年のリリースの時点で、Half-lifeはそのゲームデザインを温かく歓迎しました。これは、人工知能のおかげで可能になりました。 AIのこの影響はそれをもたらしました。 HL
が歴史上最も重要なゲームの 1つと呼んだもの。
そして20年後でも、そのコードを研究して、
シンプルだが効果的な AIシステムの作成について多くを学ぶことができます。 すべてのAIロジックはC ++でハードコーディングされており、オブジェクト指向ではありません。したがって、最近のエンジンよりも理解しやすい(拡張はそれほど簡単ではありませんが)。
この記事では、Half-Life 1のオープンSDKを見て、タスクスケジューラシステム、その実装(ステートマシンに類似)、センサーシステムなど、AIのさまざまな側面を分析します。 記事を読んだ後、これらの概念を使用する原理とゲームでの実装をより深く理解できます。
スクリーンショット1:ガードバーニーがモンスターの1人と戦っているHalf-Life SDKをダウンロード
Half-LifeのValve SDKのインストールは非常に簡単で(
FEARツールとは異なり
ます )、MODを開発する場合は元のゲームのみが必要です。 必要なものは次のとおりです。
- Half-Life SDKのバージョン2.3をダウンロードするか、リソースのないソースのみを ダウンロードするか、モデルを含む完全なSDKのコピーをダウンロードします。
- SDK modを使用して開発したい場合は、ファイルを任意のディレクトリ(できればゲームのあるフォルダー)に解凍します。 数秒かかります。その結果、モデルとソースコードを含む多数のカタログが作成されます。
スクリーンショット2:Half-Life SDKバージョン2.3のC ++ゲームコード。私たちはコードを扱います
コードベースは、FEARや
Quake 3ほど構造化されていません。 いくつかのサブディレクトリがありますが、ファイルにはあまり明確な名前がなく、C ++クラスの実装はいくつかのファイルに散らばっており、その名前からはほとんど何も理解できません。
- フルSDKには、コードを含む2つのフォルダーがあります:
Single-Player Source
およびMultiplayer Source
。 どちらも同様のディレクトリ構造を持っています。 - ほとんどのゲームロジックは
/dll/
サブディレクトリにあります。このサブディレクトリには、modフレームワークでもあるhl.dllをビルドするために必要なすべてのファイルが含まれています。 さらに、このディレクトリには、 *monster*.[h,cpp]
、 *ai*.[h,cpp]
などの名前を持つ多くのファイルに散在するAIコードが含まれています*ai*.[h,cpp]
- ソースコードを含むディレクトリには、他のディレクトリがあります。たとえば、
engine
には、メインの実行可能ファイルと(基本エンティティとして)対話するヘッダーファイルが含まれます。 common
ディレクトリには、エンジンとゲームコードで使用される同様の低レベルファイルも含まれています。
AIを学習または変更する場合、ゲーム内のさまざまなアクターの動作が含まれているため、ほとんどの時間を
/dll/
ディレクトリに費やします。
スクリーンショット3:科学者とのゲームのカットシーン。プランナーと目標システム
schedule.[h,cpp]
ファイルには、非常に単純な目標駆動型システムが含まれています。 これは、手続き的に組み合わせることができるいくつかのレベルのタスクで構成されています。
タスク
タスクは、特定の目的を持つ短い霧化された動作です。 たとえば、ほとんどの俳優ハーフライフは、次のタスクをサポート
TASK_WALK_PATH
、
TASK_CROUCH
、
TASK_STAND
、
TASK_GUARD
、
TASK_STEP_FORWARD
、
TASK_DODGE_RIGHT
、
TASK_FIND_COVER_FROM_ENEMY
、
TASK_EAT
、
TASK_STOP_MOVING
、
TASK_TURN_LEFT
、
TASK_REMEMBER
。 これらはヘッダーファイルの列挙として定義され、C ++メソッドとして実装されます。
条件
条件は、世界の俳優の状況を表現するために使用されます。 論理セットは堅固、条件が非常にコンパクトビットフィールドとして表現することができるが、その場合に条件はたとえばより32ではないかもしれないので、条件は
COND_NO_AMMO_LOADED
、
COND_SEE_HATE
、
COND_SEE_FEAR
、
COND_SEE_DISLIKE
、
COND_ENEMY_OCCLUDED
、
COND_ENEMY_TOOFAR
、
COND_HEAVY_DAMAGE
、
COND_CAN_MELEE_ATTACK2
、
COND_ENEMY_FACING_ME
。
計画
計画は一連のタスク(任意のパラメーター)で構成され、条件のビットフィールドを考慮して、計画が適用されない時期を判断します。 デバッグを容易にするために、プランオブジェクトには名前があります。
目標
目標はより高いレベルにあり、計画で構成されています。 目標のロジックは、必要に応じて、失敗したタスクと現在のコンテキストに基づいて計画を選択できます。 Half-Lifeの目標の例:
GOAL_ATTACK_ENEMY
、
GOAL_MOVE
、
GOAL_TAKE_COVER
、
GOAL_MOVE_TARGET
および
GOAL_EAT
Valveが使用するコードはQuakeエンジンから抽出されたものであり、C ++に変換されたという事実にもかかわらず、かなり明白です。 ファイルと構造体の名前は似ています。
スクリーンショット4:空tro部隊が研究センターで警報を発しました。ステートマシン
実際には、これらの計画とタスクはすべて、ステートマシンに似た構造で互いに接続されています。 最上位では、
monsterstate.cpp
の関数が呼び出されてAIが更新されます。
void CBaseMonster :: RunAI ( void );
次に、
MaintainSchedule()
最新計画の適用可能性を確認し
MaintainSchedule()
GetSchedule()
を使用して新しい計画を選択するオーバーロード関数を呼び出します。 生成されたクラスの助けを借りて、ニーズに応じて変更できます。たとえば、
barney.cpp
または
scientist.cpp
参照してください。
下位レベルでは、
StartTask()
および
RunTask()
関数は、
enum
構造で定義された各タスク識別子のロジックを実装します。 これらは
CBaseMonster
から継承されたクラスにも実装されています。 その結果、
switch
構造として実装されたステートマシンによく似ています。
void CScientist :: RunTask( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_RUN_PATH_SCARED: if ( MovementIsComplete() ) TaskComplete(); if ( RANDOM_LONG(0,31) < 8 ) Scream(); break; case TASK_MOVE_TO_TARGET_RANGE_SCARED: break; case TASK_HEAL: if ( m_fSequenceFinished ) { TaskComplete(); } else { if ( TargetDistance() > 90 ) TaskComplete(); pev->ideal_yaw = UTIL_VecToYaw( ); ChangeYaw( pev->yaw_speed ); } break; default: CTalkMonster::RunTask( pTask ); break; } }
より典型的なアプローチは、これらの各
case
ブロックを独自のクラスで実装することですが、既存の実装では、モジュール性を犠牲にして、必要に応じて別のオブジェクトのロジックを使用する方がはるかに簡単です。
また、AIには2つの状態が保存されることに注意してください。 したがって、ゲームコードを使用すると、アクターの目標を簡単に作成し、それらを達成するための最良の方法を見つけることができます。 これは、有限状態マシンと集中システムの興味深い組み合わせです。
スクリーンショット5:科学者とのゲームカットシーン。センサーシステムの実装
ベース
monster.[h,cpp]
には、すべての俳優に視覚、嗅覚、聴覚を与えるコードがあります。
void CBaseMonster :: Look ( int iDistance );
ビジョン関数は、
SF_MONSTER_PRISONER
や
SF_MONSTER_WAIT_TILL_SEEN
などのさまざまなフラグをチェックして、必要に応じて設計者に制御を提供します。 この式では、視界や視野角などのパラメーターも考慮されます。
CSound* CBaseMonster :: PBestSound ( void );
聴覚と嗅覚のコードは同様に機能し、サウンドイベントのみを使用します。 モンスターの注意を必要とするオブジェクトのリストが保存されており、センサーシステムはフォーカスに最適なオブジェクトを選択します。
まとめと補足資料
一般に、このシステムの背後にあるソースコードは、単純ではありますが非常に有益です。 人工知能による意思決定の簡単な実装を選択する場合は、このアプローチを選択する必要があります。 ただし、各タスクを独自のオブジェクトに実装する価値がある場合があります。最近では、商用ゲームは通常このソリューションを使用しています。
スクリーンショット6:Half-LifeのElemental分隊の動作。AI Half-Lifeコードには、他の興味深いアイデアも含まれています。
- ゲームコードは、ナビゲーションポイントを3Dベクトルと場所の種類のみの形式で表します! それらは下部ナビゲーションシステムに接続されていますが、モンスターが続く「パン粉」の古い学校のシステムでも使用できます。
- Half-Lifeは、ユニットの動作に多くの人を驚かせました。 ただし、ゲームにはこれらのユニットを制御する最上位のAIがありません。つまり、すべての動作は自然に現れます。
Half-Lifeの
モンスター以外の何かを再作成する場合は、ボットフレームワークを学習することをお勧めします。 マルチプレイヤーゲーム用のAIボットを作成し、サードパーティのHalf-life MODで使用できます。 ここにあります: