UDN
Search public documentation:

UT3ModsJP
English Translation
中国翻译
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 ホーム > Mod HomeJP > Unreal Tournament 3 Mod ホーム > Unreal Tournament 3におけるMODのオーサリング

Unreal Tournament 3におけるMODのオーサリング


はじめに

Unreal エンジンの MOD の開発は、まさに「やりがいのある」仕事です。ゲーム業界の現況を眺めると、腕のあるプログラマーや意欲的なアーティストが、自分の技量を世界中に知らしめるチャンスが少しずつ開かれようとしています。このドキュメントの目的は、MOD に関心があるユーザーを対象に、Unreal エンジン ベースのゲーム制作の成功に不可欠の情報を提供することにあります。技術情報はもちろん、MOD 開発の指針も含まれています。一生懸命やれば、MOD のオーサリングを通して、「面白い」と感じるものに必ず出会えます。

始める前のアドバイス

MOD の開発は、小さなものから始めることをお勧めします。いきなり Total Conversion (TC) を書くなどというのは無謀です。最初からハードルを上げすぎると、そこに到達する途中で何度も苛立ちや失望を味わい、ビジョンを実現できずに終わってしまう可能性があります。それよりも段階的に小さな目標を立てて、それらを順々に達成していくのが良策です。まずは、大規模なゲームに展開できそうな簡単なアイデアから着手し、単独でリリースできる扱いやすい小さな量に分けて作業してください。大きなプロジェクトに取り組む場合は、搭載機能をリリーススケジュールに組み込みます。例えば、新しい武器を 5 つ提供する場合は、先に 2 つまたは 3 つでリリースし、それと並行して残りの武器の作業を続けます。マイペースで、長期的な展開を想定してください。

誰にでもアイデアがあります。「これこそ、他の誰も考えつかないような革新的な新しいゲームコンセプトだ」と思うものです。でも、クールな発想を持っている、というだけでは、ゲーム業界で頭角を現すことなど稀で、そのアイデアを実践するか、または役に立つスキルを提供することが出来なければなりません。これは MOD のオーサリングにも当てはまります。MOD 制作者として腕を磨き、名を知られるようになれば、実現してもらいたいアイデアを提供してくれる人たちも現れるでしょう。開発技術を持ち合わせていないアイデアマンまたはリーダーが先導するプロジェクトには、絶対参加してはいけません。Web デザイナーしかいないプロジェクトにも参加してはいけません。皆それぞれに独自のアイデアがあります。それらを小さなサイズに分けて慎重に取り組むことで、素晴らしいプロジェクトを開発できるのです。

MOD をリリースできなければ、それを開発する意味はほとんどない、ということを忘れないでください。迅速に何かをリリースできるようにタスク リストを調整し、MOD の成長に合わせて機能を追加または強化していきましょう。すべてが完璧になるまで MOD を出し惜しみしていると、何もリリースしないで終わりを迎えることになります。

アイデアが浮かんだら、どのようなタイプの MOD が自分に合っているかを選択する必要があります。それからすべてを準備し、ビジョンを現実に変えるタスクを開始します。

MOD プロジェクトの設定

さて、そろそろ始めましょうか。最初に、Unreal エンジン ゲームが通常どのようにインストールされているかを理解する必要があります。次に、このゲームのどこに MOD ゲームが組み込まれるか、さらに、Unreal エンジンによるコンテンツのハンドリングについて、元の方法と新しい方法をそれぞれ把握します。その後で開発アプローチに応じてすべてをセットアップし、MOD の作成を開始します。

ディレクトリ構造

デフォルトでは、Unreal Tournament 3 は次のディレクトリにインストールされます。

  <InstallDrive>:\Program Files\Unreal Tournament 3
  

ユーザー設定は次のディレクトリにユーザー単位で保存されます。

  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\
  

ゲームを起動するには、デスクトップ上のアイコンをクリックするか、[Start] (スタート) メニューを使用するか、または次のコマンドを実行します。

  UTGame
  

ゲーム エディタの起動も、[Start] メニューから実行するか、または次のコマンドを実行します。

  UTGame editor
  

パッケージ

次は、Unreal Tournament を設定してプロジェクトを作成します。まず、UnrealScript (Unreal スクリプト) でパッケージがどのように使用されているか理解する必要があります。

パッケージはゲーム リソースのコレクションです。さまざまなタイプのアセット (テクスチャ、モデル、アニメーションサウンド、音楽、UI シーン) で構成することができます。パッケージのフォーマットはすべてのリソースで同じで、複数のリソース タイプをパッケージに組み込むことができます。Unreal Tournament では作業環境を健全に保つために、パッケージをリソース単位で区分けし、Textures ディレクトリにはテクスチャを含むパッケージ、Sounds ディレクトリにはサウンドを含むパッケージ、のように格納しています。これらのパッケージに異なるタイプのコンテンツを格納することもできますが、同じファイル拡張子 (.upk) が付けられるので、同じタイプのファイルであると見なされます。

プログラマーは UnrealScript で、コンパイル済みのゲームのコードパッケージファイル (.u) を使って作業します。コードパッケージには、主にコンパイル済みの UnrealScript が含まれていますが、コードと依存関係にあるテクスチャやサウンドも含まれています。

詳細については Unreal パッケージ ページを参照してください。

プログラミング

作業を始めるにあたり、各自で徹底的な調査が必要になります。時間をかけてフレームワークと使用可能なコードに精通しなくては、堅実な UnrealScript (Unreal スクリプト) プログラマーにはなれません。MOD のデザイン目標に関連した問題をクリエイティブに解決する方法を習得し、入手可能なツールを最大限に利用できるように実力を養ってください。

UnrealScript

UnrealScript は、オブジェクト指向型 (OO) 言語です。OO に馴染みがないユーザーは、このチュートリアルを進める前に、www.orangesmoothie.org/tuts/GM-OOtutorial.html に掲載されているオブジェクト指向プログラミングのガイドを一読してください。このドキュメントは非常に古いものですが、今でもためになる資料です。

UnrealScript はオブジェクト指向型なので、元のソースファイルを編集することはありません。この点で他のゲームエンジンとは異なるかもしれません。Unreal では、必要に応じて Unreal Tournament と共に提供されたクラスのサブクラスを作成し、それらをオーバーライドしたり拡張します。

UnrealScript の完全な参考資料については、UnrealScript 言語リファレンス ページを参照してください。

UnrealScript ソース ファイル

UnrealScript の最新ソース ファイルは、http://udn.epicgames.com/Files/UT3/Mods/UT3ScriptSource_1.2.rar からダウンロードできます。

前のバージョンもあります:

パッチリリースのたびに、パッチアップデートに合わせてスクリプト ソースのアップデートも行われる点に留意してください。これらのアップデートは、パッチリリースの数日後に公開され、以前のバージョンはアーカイブされます。

作成する MOD プロジェクト用の UnrealScript のソースコードを、以下の場所に解凍します。

  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\Src\YourModName\Classes
  

注意: 場合によっては、Src\YourModName\Classes ディレクトリ構造を作成する必要があります。

UnrealScript ソースをコンパイルする前に、スクリプトの mod 名をエンジンに登録する必要があります。これには、UTEditor.ini を開いて [ModPackages] セクションの下に次の行を追加します。

  ModPackages=作成する Mod の名前
  

ゲームの UnrealScript コンパイラを実行するには、次のコマンドを使います。

  UTGame make
  

... 完全なリビルドの場合:

  UTGame make -full
  

注意: コア UT の UnrealScript クラスを絶対に変更しないでください。

コンパイルした UnrealScript パッケージは次の場所に置かれます。

  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\Unpublished\CookedPC\Script\YourModName.u
  

注意: 場合によっては Script ディレクトリの作成が必要です。

MOD パッケージ用の設定ファイルが自動的に作成され、次の場所に置かれます。

  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\Config\UTYourModName.ini
  

注意: 設定ファイルが自動生成されるときには、UT* クラスのサブクラスしか検出されません。この動作を制御する bExportMenuData フラグが、これらのサブクラスにしか存在しないためです。MOD の名前の接頭辞が UT でない場合、この接頭辞が付けられます。MOD に UT* クラスのサブクラスが含まれていない場合は、設定ファイルを手動で作成する必要があります。

エディタを開くと、UTEditor.ini の ModPackages リストに含まれる MOD パッケージがエディタの起動時に自動的にロードされ、[[ActorBrowserReference][Actor ブラウザ] には 配置可能な アクタ クラスが表示されます。この動作を抑制するには、=-nomodautoload フラグを指定してエディタを起動します。

ゲーム用の多量の UnrealScript のソースコードを読み込むだけでも相当の時間がかかる点に注意してください。実行パスをさかのぼり、各種クラス間のオーバーライドや相互作用の関係を確認してください。最初はかなり手ごわく見えますが、時間が経つにつれてそれらの内容や機能に関する豊富な知識が身につきます。怖がらずにオンラインに進出して、コミュニティメーリングリストやフォーラムで質問してください。学習に必要な時間をかければ、より大きく複雑なプロジェクトに挑戦できる力が身につきます。

コンテンツの作成

レベル

ゲーム エディタを使用すると、レベルは以下のディレクトリに保存されます。

  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\Unpublished\CookedPC\CustomMaps
  

ゲーム メニューにレベルが表示されるようにするには、CustomMaps のサブディレクトリに保存する必要があります。CustomMaps ディレクトリに直接保存したものは、すべて無視されます。制作する MOD の名前にふさわしい名前のディレクトリを作成することをお勧めします。

レベルを保存する際には、ゲームタイプの正しい接尾辞 (DM-、VCTF- など) を付けることを忘れないでください。

デフォルトでは、ゲームは Published ディレクトリ内でカスタムコンテンツを探しますが、ここで 2 つの選択肢があります。

  1. UT3.exe -useunpublished コマンドを実行し、_Unpublished_ ディレクトリの外に移動するように指図する。これは開発中のターンアラウンドタイム (所要時間) を短縮するのに最適な方法です。
  2. エディタの [Publish] (パブリッシュ) ボタンを使用する。これにより、Unpublished ディレクトリのコンテンツが Published にコピーされ、ゲームは自動的にコンテンツを検出します。

ゲームの初回起動時には、_CustomMaps_ フォルダのサブディレクトリを調べて、新しいレベルの存在を確認すると、レベル単位の設定 (.ini) ファイルを自動的に生成し、インゲーム UI を含むレベルを登録します。これらの設定ファイルを編集し、レベルの説明テキストなどを追加することができます。

Unreal Front End (Unreal フロントエンド) で MOD をクックする場合は、[Cook MOD] オプションが選択されていることを確認します。

パブリッシングとクッキング

CookedPC の命名規則は一見わかりにくいのですが、すべてを適切に設定してしまえば、実は比較的簡単なプロセスです。_Cooking_ (クッキング) とは、マップファイルから不要なコンテンツをベークアウト (排除) し、マップの適切なロードおよび実行に必要なシェーダーキャッシュ情報を作成し、パフォーマンスとロード時間の向上を図ることです。_Publishing_ (パブリッシング) とは、ファイルを配布する目的で用意し、適切なディレクトリにすべてを格納して、作成したゲームを他のユーザーがプレイできるようにすることです。

PublishedUnpublished の動作に関する注意: ゲームエディタで保存するコンテンツは、デフォルトでは Unpublished ディレクトリに書き込まれます。これは MOD 制作者の作業ディレクトリで、以下の場所にあります。

  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\UnPublished\CookedPC\
  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\UnPublished\CookedPC\Script\
  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\UnPublished\CookedPC\CustomMaps\
  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\UnPublished\CookedPC\CustomChars\
  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\UnPublished\CookedPC\Localization\<LANGUAGE>\
  

Published ディレクトリは次の場所にあります。

  …\Documents and Settings\<UserID>\My Documents\My Games\Unreal Tournament 3\UTGame\Published\CookedPC\
  

エディタでゲームを保存する際に UnPublished フォルダを作成し、ファイルをパブリッシュする際に Published フォルダを作成することになっています。いずれのフォルダも存在しない場合は、これらを手動で作成する必要があります。ダウンロードしたマップをプレイしたい場合は、これを Published フォルダに置きます。これによりゲームがマップを認識し、メニューにマップ名が表示されます。ファイルを適切なディレクトリに置かなければ、ゲームはこれを認識できず、適切にロードされることもメニューに表示されることもありません。

-useunpublished フラグを指定してゲームを起動しない限り、当然ゲームは Published ディレクトリのコンテンツを実行します。MOD の典型的なワークフローはスクリプトとマップの開発の繰り返しで、その間は -useunpublished を指定してゲームを起動します。MOD が準備できたら、最後の [Publish] (パブリッシュ) コマンドを実行し、_Published_ ディレクトリにコンテンツを書き込みます。配布には、ロード処理を最適化したこれらのファイルが使用されます。スクリプトファイルとローカライズしたテキスト ファイルは、手動でコピーする必要があります。

別の方法として、MOD 制作者はコンテンツを変更したときに、=-useunpublished= フラグを使わず [Publish] コマンドを実行してコンテンツを単独に実行することもできます。この方法では、MOD コンテンツはクックされずに Unpublished ディレクトリにコピーされ、ゲームは自動的にこれを認識します。最初の方法と同様に、MOD を配布する前に最後の [Publish] コマンドを実行することをお勧めします。

要約すると、=-useunpublished= フラグは作業中に MOD 開発者が何度もファイルをコピーしなくても済むためのショートカット、ということになります。

ローカライズ

MOD パッケージのローカライズ テキスト ファイルを作成したら、次のディレクトリに置く必要があります。

  <InstallDrive>:\Documents and Settings\<userID>\My Documents\My Games\Unreal Tournament 3\UTGame\UnPublished\CookedPC\Localization\<LANGUAGE>\YourModName.int
  

配布

以前は、mod のパッケージ化には Unreal Engine の master コマンドレットを使って MOD インストーラー ファイルを作成していました (UT では .umod、UT2003 と UT2004 では .ut2mod)。これが変更され、MOD は、WinRAR などのユーティリティを使用して圧縮アーカイブにパッケージ化されるようになりました。

命名規則

整合性および保全性上、何らかの命名規則やコーディング規格など、他のベストプラクティスをプロジェクトの開発初期に制定するのは非常によいことです。これにより、チーム メンバー全員が同じ規則のもとに作業できます。

プログラミングに関して、以下の命名規則が推奨されています。

  • UTMutator_ - UT3 Mutator クラス
  • UTGame_ - UT3 GameType クラス
  • UTGameRules_ - UT3 GameRules クラス (作成した Mutator または GameType が使用)
  • UTMod_ - 他の UT3 mod、パッケージや関連ディレクトリにも使用可能

Total Conversions については、UT Mod であると見なされるものの、そのプロジェクト名は UT と関連がなくても構わないので、上記規則から外れます。

パッケージと関連ディレクトリに名前を付けるときに、制作者のビジョンと一貫する命名規則を定めることを検討すべきですが、これをクラスファイルの名前だけに限定してしまう必要はありません。例えば、_Jailbreak_ という名前の新しい GameType を作成する場合、そのパッケージと関連ディレクトリに、コアの gametype クラスの名前 (多分 UTGame_Jailbreak) の代わりに、「UTMod_Jailbreak」または単に「Jailbreak」という名前を付けることができます。Mutator のコレクションを作成する場合は、パッケージと関連ディレクトリの名前として、「UTMod_MyMutators」または単純な「MyMutators」などを検討してください。

コンソール

PlayStation 3 の Mod サポート

PlayStation 3 コンソールのユーザー作成コンテンツ制作の詳細については、PS3 Mods ページを参照してください。

4 つの Mod タイプ

Mutators

Mutators (ミューテーター) は小型の mod で、Mutator クラスで定義されているとおり、機能が制限されています。Mutators は特定のルール (GameType により作成された規則) に従う必要があります。これらのルールに準拠できない場合、またはルールがあまりに制約的である場合は、GameType の MOD に取り組むことをお勧めします。

第一のルールは、Mutators は他のいかなる Mutator、特にゲーム付属の Mutator との連動が可能であることです。例えば、プレーヤーが撃った敵から命を抜き取ることができるという「Vampire (バンパイア)」 Mutator を記述するとします。この Mutator を Arena Mutators のいずれか、または No Powerups Mutator と組み合わせた場合にもうまく機能するようにします。これは Mutator システムの有益な特徴のひとつで、ミューテーターによってゲームプレイを多少変化 (または mutate (変異)) させて、面白いコンビネーション効果を生み出すことができます。

第二のルールは、Mutators によるゲームプレイの変化を軽度に抑えておくことです。あいまいな言い方ですが、Mutator の振る舞いを制限するように心がける必要があるということです。よく練り上げられたデザインは、他の mod との連携の可能性を拡大し、サポート労力を軽減します。

第三のルールは、他の Mutators とリソースを共有するようにすることです。作成する Mutator に ModifyPlayer 関数を実装する場合、この自作バージョンの関数の内側で NextMutator.ModifyPlayer を呼び出す必要があります。この方法により、Mutator リストで自作の mod の下に位置する Mutators も、必ず同じ関数呼び出しを処理することになります。このルールを破るのはお粗末なプログラミング スタイルで、コミュニティフレンドリーではありません。

GameTypes

GameTypes (ゲームタイプ) はかなり大型の MOD クラスで、Mutator で実行できない機能をすべて備え、さらに広範の機能へのアクセスも可能にしています。Mutator でアイデアを実現できない場合は GameType に取り組むことをお勧めします。

GameType の弱点は、他の GameTypes と組み合わせられないことです。例えば、「Capture the Flag」は Unreal Tournament の GameType のひとつで、Deathmatch (別の GameType) とまったく異なるゲームプレイスタイルです。

GameTypes は GameInfo クラスのゲーム固有のサブクラスとして実装されます。GameTypes には、クライアント・サーバー問題 (後述します) に注意すべき点を除き、固有のルールはありません。

Total Conversions

Total Conversions (TC) は、構築済みのゲームクラスを完全に逸脱し、エンジン コアから開始します。ゲーム固有のサブクラスを使用せず、TC はエンジンの基本クラスのサブクラス (GameInfo クラスなど) として実装されます。ゲーム界に存在しない Mod を作成する場合、他と完全に異なるものを試したい場合に取るべき道が TC です。すべてをゼロから始めなければならない点に注意してください。

カスタム コンテンツ

Mod の GameType によっては、AI や特殊アクタなどの多数の要素をゲームルール本体から切り離して作成しなければならない場合があります。あるいは、GameInfo または Mutator クラスを使用し、ゲームプレイをまったく変化させない Mod を作成することもできます。これらには、Player Plugin Models (PPM)、新しい武器やビークルが含まれます。

コードを書かずに新しいコンテンツを作成するには、レベルを使うのが最適な方法であることは言うまでもありません。新しいレベルを切り出し、ゲーム付属の既存のコンテンツ アセットを使って装飾します。または、独自のテクスチャやモデル (静的メッシュ) を作成することもできます。

マルチプレーヤー レベルのデザインに関するガイドラインの詳細は、Multiplayer Map Theory (マルチプレーヤー マップの理論) (UT3) ページを参照してください。

Mutator の作成方法

Mutators は、制限付きながらもエンジンの強力なサブセットにアクセスできるので、UnrealScript の修行を積むのに優れた場所です。前述したように、Mutators ではゲームコードに比較的微妙な変化をもたらすだけにしておくと、他の Mutators と組み合わせたときに適切に動作する可能性が増大します。(例えば、FatBoy、InstaGib No Powerups デスマッチをプレイできます。これは 3 つの Mutators の組み合わせです)

それでは、非常に簡単な Mutator mod を見てみましょう。

  class ExampleMutator extends Mutator;
  
  defaultproperties
  {
  }
  

設定

デフォルトでは、作成パッケージに対応する設定ファイルが作成され、このファイルに mutator への参照が含まれます。これには以下の情報が関与します。

  FriendlyName=Example Mutator
  Description=An Example Mutator
  

新しいミューテーターをメニューに適切に表示するために、設定の一部を変更する必要があります。

Instant Action および Multiplayer の両メニューは、UT クラスのサブクラスにあたるクラスのすべての設定ファイル内を検索します。パッケージのローカライズテキスト ファイルにこれらの行を追加すると、ミューテーター一覧に「ミューテーターサンプル」項目が表示されます。作成する MOD パッケージのローカライズテキスト ファイルで、次のようにテキストを指定します。

  ;///////////////
  ; ミューテーターの名前
  ;///////////////
  [ExampleMutator UIDataProvider_Mutator]
  FriendlyName=ミューテーターサンプル
  Description=ミューテーターのサンプル
  
  

MOD によってはゲーム メニュー内で構成できるものもあります。これには、UI シーンを作成してパッケージ内に保存し、=UIConfig= メンバー変数を使ってそのパッケージを参照する必要があり、この参照は Mutator クラスの defaultproperties で実行できます。

以下に例を示します。

  defaultproperties
  {
     UIConfigScene=UIScenes_Example.Menus.ExampleMutatorConfig
  }
  

簡単な Mutator を使って、Mutator で利用可能ないくつかのメソッドに注目してみましょう。

Mutator の構造 - 最初のステップ

簡単な UT MOD の記述を初体験したわけですが、もちろん、これだけではゲーム業界を揺さぶるどころか、仕事に就くにもまだまだです。Mutator 基本クラス内のメソッドを詳しく調べてみるのは価値のあることです。これらを使って何ができるか、その手掛かりを与えてくれるでしょう。ただし、これは氷山の一角を眺めるだけに過ぎません。ユーザーは多数の継承関数を使用できるうえに、他のオブジェクトとのやり取りも実現できるからです。

Mutate によって、プレーヤーがキーにバインドできる新規コマンドをミューテーターが定義することができます。例えば、プレーヤーが mutate givehealth をキーにバインドしてそのキーを使用すると、すべてのミューテーターは givehealth パラメータを指定して mutate 呼び出しを取得します。ミューテーターにこの文字列を探させ、メッセージを送信したプレーヤーの体力を補強することができます。

ModifyLogin

ModifyPlayer は Pawn が再度スポーンされるたびにゲームで呼び出されます。これを利用して、Pawn の変数を変更したり、Pawn を対象に何からのゲームロジックを実行することができます。この関数をオーバーライドするには Super.ModifyPlayer() を呼び出だし、この関数の親クラスバージョンを呼び出します。

AlwaysKeep を使って、ワールドに追加されることになっているオブジェクトを阻止することができます。登場したオブジェクトをオンザフライで別のオブジェクトに置き換えることができます。Unreal Tournament の Arena ミューテーターは、このメソッドの優れた使用例です。ゲーム内のすべての武器を受け取り、他の武器に変換します。ゲームに新しい武器を追加する予定がある場合は、これに Arena ミューテーターを追加することをお勧めします。

IsRelevant は、ゲームがワールドにオブジェクトを追加するときに呼び出されます。これを特別なコードでオーバーライドして、オブジェクトを受け入れる場合は true、拒否する場合は false を返すように指示することができます。ユーザーが False を指定すると、そのオブジェクトは破壊されます。

CheckRelevance

CheckReplacement

次のステップ: ゲームルール

Mutator クラスの根底を成すのは、変更可能な特定イベントのトラップとその調整です。もちろん、キルのスコアやダメージへの影響などの制限事項を同時に適用することができ、これが Game Rules (ゲームルール) の活躍する場です。GameInfo の各ゲームサブクラスには、GameRulesModifiers というゲームルールのリストがあります。GameRules のサブクラスを作成して、ゲームの特定のイベントの処理方法を制御することができます。

FindPlayerStart

HandleRestartGame

CheckEndGame

OverridePickupQuery

PreventDeath

ScoreObjective

ScoreKill

NetDamage

さらに詳しく調べていくと、ミューテーターが HUD に情報を提供できることも分かります。これは GameType から行う方がより柔軟に対応できるのですが、Mutator には制限付きの機能で十分なはずです。複製の Actor サブクラスを作成し、それを UTHud クラスの PostRenderedActors 配列に追加します。

この情報を使い、わずかな数のクラスで多数の変更を加えることができます。ミューテーターの能力を最大限に生かす方法を学ぶには、UT に付属のミューテーターのコードに目を通すのが一番です。

GameTypes 入門

Mutators でも結構素晴らしいことができる訳です。分かりやすく、特定のゲームイベントやルールとの相互作用により達成できることも少なくありません。色々組み合わせてもっと凄い効果を生み出すこともできます。でも、ミューテーターは強力ではありません。新しいゲームタイプ (例えば Jailbreak や Rocket Arena スタイルの MOD など) を作成したくとも、Mutators ではできません。ゲームルールを完全に制御する必要があるからです。そこで登場するのが GameInfo の一連のクラスです。

GameInfo は Engine に内在するクラスで、ゲーム エンジンにより作成され、ゲームプレイルールの中核を形成します。Unreal Tournament は UTGame パッケージに含まれる一連の GameInfo サブクラスを使用しています。UTGame クラスには Unreal Tournament のすべてのゲームタイプに共通するコードが含まれ、UTDeathmatch には標準のデスマッチを実行するためのコードが含まれています。UTTeamGame にはチームデスマッチ用のコードと、全般的なチーム管理コードが含まれています。UTCTFGame は UTTeamGame のサブクラスで、このゲームタイプを実装します。

新しいゲームタイプの記述における最初のステップは、サブクラス化する GameInfo クラスを決定することです。チームゲームを記述する場合は、UTTeamGame のサブクラス化が推奨されています。チーム編成なしのゲームの場合は UTDeathmatch を使用します。記述しようとするゲームが、既にスタイルが確立したゲームタイプと非常に異なる (ただし Unreal Tournament ゲーム内に存在する) 場合は、UTGame を使用します。サブクラス化によってかなりの恩恵が得られます。親クラス内のコードをすべて即座に継承し、デザイン目標に達するためにそれらを拡張またはオーバーライドできます。

もちろん、UT ゲームから完全に離れた Total Conversion (TC) を記述する場合は、GameInfo のサブクラス化が推奨されています。

それでは、非常に簡単な Game Type mod を見てみましょう。

  class ExampleGameType extends UTDeathMatch;
  defaultproperties
  {
     Acronym="EX"
     MapPrefixes[0]="EX"
     Description="GameType のサンプル"
  }
  

上記のコードを ExampleGameType.UC という名前のファイルに保存することで、新規 GameType の本体となります。唯一の相違点は、説明を「GameType のサンプル」に変更しただけです。この新しい名前は、Practice Session の選択ウィンドウや Scoreboard ヘッダーなど、多くの場所に登場します。このゲームを再生すると、新しい動作が実装されていないので他の Deathmatch ゲームとまったく同様に実行されます。

設定

Mutators の場合と同様に、パッケージの設定ファイルが作成され、作成するゲームタイプの参照が含まれます。これには以下の情報が関与します。

  FriendlyName=Example GameType
  Description=An Example GameType
  

Mutators と同様に、新しいゲームタイプをメニューに適切に表示するために、設定の一部を変更する必要があります。作成する MOD パッケージのローカライズテキスト ファイルで、次のようにテキストを指定します。

  ;///////////////
  ; ゲームモード
  ;///////////////
  [ExampleGameType]
  Description=GameType のサンプル
  GameName=ExampleGameType
  EndOfMatchRulesTemplateStr_Scoring=一位のプレーヤーが勝利!
  EndOfMatchRulesTemplateStr_Time=最多勝ち数!
  
  
  ;///////////////
  ; GameType の名前
  ;///////////////
  [ExampleGameType UIDataProvider_GameModeInfo]
  FriendlyName=GameType サンプル
  Description=GameType のサンプル
  
  

Instant Action と Start Multiplayer の両メニューは、パッケージのすべてのローカライズテキスト ファイル内で、文字列がローカライズされているクラスに関連するセクションの名前を探します。パッケージのローカライズテキスト ファイルにこれらの行を追加すると、ゲーム一覧に「GameType サンプル」項目が表示されます。この名前は GameInfo クラスの FriendlyName 変数から来ています。Description 行では、メニューに含まれるゲームタイプの説明テキストを提供しますが、今はこれについて心配する必要はおそらくありません。

簡単な GameType を使って、GameInfo で利用可能ないくつかのメソッドに注目してみましょう。

GameInfo の概要

Engine の GameInfo クラスは、基本的なゲームロジックが定義されているファイルです。このファイルの一番上に、変数宣言の長いリストがあるのが分かります。これらの変数の多数には、その目的を説明するコメントがあります。変数宣言の下に、作業を行う関数 (またはメソッド) があります。

最初に注目するのは Timer 関数です。GameInfo ではこれはかなり短く、UTDeathmatch では非常に長いです。=Timer= は特別な UnrealScript イベントで、=SetTimer(int Time, bool bLoop)= 関数を呼び出す場合に、当該 Actor で繰り返しタイマーを設定できます。Time パラメータは Timer 関数を呼び出すタイミングを示し、bLoop パラメータは Timer の最初の呼び出しの後に繰り返し呼び出すかどうかを示します。*すべての UTGame クラスは 1 秒間の Timer ループを使用します。* つまり、Timer 関数は毎秒呼び出されます。Timer 関数は、一定の時間に発生しなければならないイベントに使用することができます。秒数を合計する watch 変数を宣言し、1 秒の精度で任意の時間にイベントを実行します。UTDeathmatch ではこれを使用し、ゲームで TimeLimit に到達したかどうかを調べています。

もう 1 つ、覚えておくとよい時刻関数に Tick があります。Tick は GameInfo では使用されていませんが、任意の Actor がこれを使用できます。=Tick= は、=Tick(float DeltaTime)= のように宣言します。=Tick= はゲームの各フレームのすべてのアクタ上で呼び出されます。DeltaTime は、最後の Tick から経過した時間量を格納します。=Tick= を使い、1秒以下の精度で実行しなければならない動作を実行することができます。CPU への負担がかかる動作が Tick で呼び出されることがよくあるので、これを行わないよう注意してください。

GameInfo の下の方に Login 関数があります。この関数は、プレーヤーがゲームにログインするたびにエンジンにより呼び出されます。GameInfo バージョンでは、プレーヤーに名前、スキン、メッシュなどを割り当てるなど、重要な設定操作が行われています。さらに、最初のテレポート エフェクトをスポーンし、プレーヤーを貼り付けるスポーンポイントを見つけます。=Login= の次に Logout があります。プレーヤーがゲームを辞めると呼び出され、プレーヤーが終了した後にログアウトを使ってクリーンアップします。

AddDefaultInventory は、GameInfo のもうひとつの面白い関数です。この関数はプレーヤーに最初の武器や装備を割り当てます。UTDeathmatch では、プレーヤーに ImpactHammer と Enforcer を与えています。AddDefaultInventory を使って、MOD に参加したプレーヤーにカスタムインベントリ (例えば、手榴弾とお金を渡すなど) を追加することができます。

FindPlayerStart メソッドは、レベル内のアクタを調べてスポーンに適した NavigationPoint を探します。レベルデザイナーがレベルに追加する PlayerStart (プレーヤースタート地点) アクタは、これに該当する場所のひとつです。UTTeamGame では、=FindPlayerStart= はチームに応じてプレーヤーまたはボットをスポーンし、スポーンされる各 PlayerStart チームと Pawn チームを調べています。カスタムスポーンコードを記述するのに FindPlayerStart を使うことができます (例えば、一箇所で Opposing Forces、別の場所で Friendlies をスポーンしたい場合など)。

RestartPlayer メソッドは、プレーヤーが再スポーンするたびに呼び出されます。基本となる GameInfo バージョンでは、=FindPlayerStart= を呼び出して開始地点を見つけ、プレーヤーをその地点に移動してテレポートエフェクトを発生させます。さらに、プレーヤーの体力回復、プレーヤーの衝突の設定、デフォルト インベントリの提供を行います。

Killed メソッドはとても便利で、プレーヤーが他のプレーヤーを殺害するたびに呼び出されます。死に至る状況 (プレーヤが自殺したか、または殺害されたか) とダメージタイプを調べて、メッセージを出力します。最後に ScoreKill を呼び出します。

ScoreKill は殺害に対して得点を与えます。UTDeathmatch では殺害の場合にはフラグ (手榴弾の一種) が 1 つ渡され、自殺の場合には 1 つ没収されます。UTTeamGame ではさらに、Killer の TeamInfo に 1 点追加し、自殺の場合には減点します。

DiscardInventory は、プレーヤーが死亡するか、またはゲームから退場させられると呼び出されます。=DiscardInventory= は Pawn のインベントリを調べ、武器を捨て、他は適宜破壊します。バックパックやトラップを捨てさせたい場合には、この関数をオーバーライドできます。

最後に、=EndGame= 関数はゲームを終了するときにその理由を指定して呼び出します。ここで特別なログ記録またはクリーンアップを行うことをお勧めします。

以上、重要な GameInfo 関数をいくつか簡単に紹介しました。UTDeathmatch などの高度な GameInfo クラスは、ボットやシングルプレーヤーゲームを制御するための重要な動作を新たに追加するほか、GameInfo の各メソッドを特定のルールに合わせて調整します。

Mutator と同様、GameType の最大限に活用する方法を学ぶには UT 付属のゲームタイプに含まれるコードに目を通すのが最も効果的です。

ゲームルール

ヘッドアップ表示 (HUD)

スコアボード

AI

カスタム コンテンツの作成方法

キャラクター

詳細については、UT3 のカスタムキャラクターの作成 ページを参照してください。

レベル

ここでも同様に、新しいレベルをメニューに適切に表示するために、設定の一部を変更する必要があります。作成するレベルのローカライズテキスト ファイルで、次のようにテキストを指定します。

  [DM-Example UIDataProvider_MapInfo]
  FriendlyName=<Strings:UTGameUI.FriendlyMapNames.DM-Example>
  NumPlayers=4 人~8人のプレーヤー
  
  

ピックアップと武器

現在執筆中

ビークル

現在執筆中

注意点

Unreal Tournament の MOD を記述する際に、MOD 開発者が遭遇する主な「gotcha」(予期せぬ落とし穴) に関する情報を以下に提供します。この情報の多くは、エンジンでの作業経験を重ね上げるまでは無関係な話題かもしれません。新しいゲーム技術の習得は、とても素晴らしい経験であると同時に、思いどおりに進めずイライラするものです。その習得までの長い道のりの指針を以下に紹介します。

原則として、記述コードがパフォーマンスに及ぼす影響に常に注意を払うようにしてください。

Accessed Nones

遅かれ早かれ、このメッセージがログファイルに出没し始めます。UnrealScript では Accessed Nones を警告として扱いますが、開発者はこれらをエラーと見なすべきです。Accessed Nones は簡単に修正でき、常にコードのどこかが間違っていることを意味します。C++ または Java に精通したユーザーなら、Accessed None が何のことか簡単にお分かりだと思いますが、これらの言語に詳しくない方のために、以下に簡単に説明します。

UnrealScript は、オブジェクト指向型のプログラミング言語です。UnrealScript でプログラムを記述するときに、ゲーム内でこれらのオブジェクトが従う一連の動作と、オブジェクトの相互作用を定義します。オブジェクトには、プロパティのセット (メンバー変数とメンバー関数) があります。オブジェクトプロパティにアクセスするには、そのオブジェクトへの参照が必要です。

以下にサンプルコードを示します。

  class ExampleInfo extends Info;
  
  var PlayerReplicationInfo PlayerInfo;
  
  function PlayerReplicationInfo GetPlayerInfo()
  {
     return PlayerInfo;
  }
  

これは ExampleInfo という名前の、Info のサブクラスの簡単なオブジェクトです。PlayerInfo 変数と GetPlayerInfo() 関数の 2 つのプロパティがあります。作成する MOD の内部から、このオブジェクトとやり取りできるようにする必要があります。例えば、MOD 内に ExampleInfo オブジェクト参照があり、PlayerInfo プロパティ内から情報を取得したいので、次のようなコードを記述したとします。 class MyMod expands TournamentGameInfo;

  function string GetPlayerName()
  {
     local ExampleInfo TheInfo;
     local string PlayerName;
  
     TheInfo = GetMyObject();
     PlayerName = TheInfo.PlayerInfo.PlayerName;
     Log("The player's name is" @PlayerName);
  }
  

この例では、GetMyObject() という関数を呼び出して ExampleInfo 参照を取得します。次にこの参照にアクセスして PlayerInfo (TheInfo.PlayerInfo) を解決し、次に PlayerInfo 参照にアクセスして PlayerName (PlayerInfo.PlayerName) を解決します。しかし、ここで TheInfo が存在しなければ、または GetMyObject() のバグのために ExampleInfo を返せなければどうなるのでしょうか?そのような場合、この関数は None を返します。None は空の参照で、C++ の NULL ポインタと非常に似ています。

上記サンプルで、GetMyObject() が None を返した場合、変数 TheInfo には None が割り当てられます。次の行で、TheInfo にアクセスして PlayerInfo 参照の解決を試みます。しかし、TheInfo は None、つまり何も参照していません。アクセスできるものがないので、Unreal Engine は「コード中断」の警告をログに書き込みます。

  Accessed None in ExampleMod.GetPlayerName!
  

このようなバグを生じやすいコードの対策はとても簡単で、コードの数箇所にチェックを追加し、間違いがあった場合に実行される特別な動作を定義しておきます。

  class ExampleGameType extends UTGame;
  
  function string GetPlayerName()
  {
     local ExampleInfo TheInfo;
     local string PlayerName;
  
     TheInfo = GetMyObject();
     if ((TheInfo != None) && (TheInfo.PlayerInfo != None))
     {
        PlayerName = TheInfo.PlayerInfo.PlayerName;
     }
     else
     {
        PlayerName = "Unknown";
     }
  
     Log("The player's name is" @PlayerName);
  }
  

ここでは、TheInfo が None であるかどうかのチェックと、PlayerInfo 参照が None であるかどうかのチェックを行っています。UnrealScript の if ステートメントは短絡ロジックを使用し、=if= ステートメントを左から右に評価します。コードが If を否定するステートメントに遭遇すると、評価を中止します。これは、TheInfo が None ならば、コードは以降のステートメントを評価しないことを意味します。

  (TheInfo.PlayerInfo != None)
  

残りのステートメントの内容が何であれ、最初の部分が false なのでステートメント全体も false になります。

Accessed Nones は、特に Timer()Tick() などのタイムクリティカルな関数の場合に危険性が増します。コードが 1 秒間に 3000 ものエラーメッセージをダンプした場合、ログにこれらのエラーメッセージを書き込むだけでもかなりの時間を要し、パフォーマンスに (ディスクスペースにも) 深刻なダメージを与えかねません。

Iterators (反復子)

UnrealScript は、Iterators (反復子) という非常に便利な言語機能を備えています。反復子とはリストをカプセル化するデータ型です (UnrealScript ではリスト反復子のみサポートしています。同言語の将来のバージョンではユーザー定義の反復子がサポートされる可能性もあります)。反復子を取得してループ処理し、反復子内のすべてのオブジェクトに対して演算を実行することができます。以下に例を示します。

  local Ammo A;
  
  foreach AllActors(class'Ammo', A)
  {
     A.AmmoAmount = 999;
  }
  

この例では、=AllActors()= 関数を使用してアクタ リストの反復子を取得します。次に、AllActors 関数が返すすべてのオブジェクトについて、=foreach= 反復子ループを使って何かを実行します。=AllActors()= は目的の Actor タイプクラスと、それを格納する変数を取ります。=AllActors()= は現在のゲーム内のすべてのアクタを調べて、目的のオブジェクトを探します。次に、「_ゲーム内の各アクタの AmmoAmount を 999 に設定する_」と定めています。

これはいい考えのように聞こえますが、その二次的効果を考えて見ると、何百ものアクタのリストからわずかの数量を探しているので、必ずしも高速演算ではありません。

慎重に使いこなせば、反復子は強い味方になります。低速になりがちなので、1 秒間に数回以上もの高速反復処理は推奨されていません。=Tick()= の内側、または他のループの内側で AllActors() の反復処理を実行する理由はまず考えられません。後は皆さんのの判断にお任せます。

実際に扱うことになる AllActors() タイプの検索で最も一般的なのは、おそらく PlayerReplicationInfo アクタ全部を対象とする検索でしょう。PlayerReplicationInfo には、サーバーが各クライアントに送信する、重要な Players 情報が格納されています。この情報により、各クライアントは多量の情報を送信せずに他のプレーヤーのステータスを知ることができます。このアクタは、スコアボードのスコアや他の一般的な情報を表示するのに使われます。

通常、グローバルアクタリストに含まれる PlayerReplicationInfo アクタの数は少なく、その少しの結果を得るために、時間のかかる検索を行う意味はあまりありません。このようなよく行われる反復を簡単に処理するために、GameReplicationInfo クラスに PRI 配列が定義されています。PRIArray は 10 分の 1 秒ごとに更新され、現在の PlayerReplicationInfos のセットを格納します。そこで、=AllActors()= 呼び出しを実行せずに PRIArray の演算を書いて実行することができます。

他の反復子も使用できます。詳細は Actor クラスの定義を参照してください。その名前が示すとおりの振る舞いをします。=TouchingActors()= は接触しているアクタを返し、=RadiusActors()= は指定半径内のすべてのアクタを返します。これらの反復子を賢く使いこなして、コードの高速化を図ることができます。

トレーシング

Unreal Engine は potentially visible set (PVS、潜在的な可視集合) を使用しないので、空間感覚で何かをワールドで見つける場合は、トレースを実行する必要があります。大抵の場合はトレースの対象ははっきりしていて、知りたいのはその向こう側に何があるかです。その他の場合は、一連のトレースを使って対象オブジェクトを取り巻く環境を突き止めます。

最初のアドバイスは、出来るだけトレースを実行しないことです。トレースを使う目的をじっくり考え、それを別の方法でできないかどうか考えてみてください。トレースは、MOD の多少の減速を招く可能性があるコスト高の操作です。例えば、Tick のたびに複数のトレースを実行するプレーヤーを 1 つ用意するとします。テスト段階ではすべて順調に進むかもしれませんが、15 名以上が参加しオンラインプレイが始まるまでは、これらのトレースが雪だるま式に増えていくことに気が付かないものです。

トレースを実行しなければならない場合、そのサイズを制限してください。短いトレースの方が長いものより高速です。例えば、UT 用に新しいショットガンをデザインする場合、武器を発射するときに 12 のトレースを実行し、銃の散乱方向を割り出す必要があるかもしれません。12 のトレースは完璧に正当な数です。プレーヤーが 1 秒に 30 回ショットガンを発砲することはあり得ないからです。しかし、MOD が大きなオープンレベルを使用する場合は、この 12 のトレースのコストが上昇します。ショットガンが長距離の武器として効果的である可能性はまずないので、射程範囲を一定ポイントで切り上げた方がよいでしょう。エンジンがマップの端から端までトレースしなければならないような、最悪の状況を回避します。

トレースの使用は、最終的には各自の判断によるものです。深刻な問題が生じるのは、1 つのフレーム内で多数のトレースを実行した場合のみですが、それでもやはり、絶対に注意を要するものです。

複製 - その意味を解読する

複製について理解することは、Unreal Engine ゲーム制作を成功させる上で最も難しい点のひとつですが、マルチプレーヤーのゲームプレイを企画する場合にこれは避けて通れません。ほとんどのドキュメントは事実非常に専門的で、理解に苦しむものもあります。ここでは基礎の一部を紹介しておきます。そのうちに、複製に関する理解や評価が深まっていくことでしょう。

simulated 関数はクライアントとサーバーの両方で呼び出されますが、その呼び出し元は常にシミュレート関数です。関数呼び出しがシミュレーション チェーンを中断すると同時に、シミュレーションが停止します。シミュレーションの対象が何であるか、シミュレート関数で何を行うのかを十分に認識し、Unreal のソースコードのどこかで見かけたからという理由だけで、=simulated= のような関数修飾子を追加することは止めましょう。追加の理由、それが実行する内容を理解してください。自作のコードで何が行われているのか分からないのに高品質の MOD を書けるとは、まず期待できません。

シミュレート関数はクライアントとサーバーの両方で呼び出されるので、アクセスするデータの中身を特に意識する必要があります。サーバーで利用可能なオブジェクト参照が、クライアントでは利用できない可能性があります。例えば、すべてのアクタには現在のレベル参照だけでなく、現在所属するワールドの参照もあり、ワールド参照の内側に現在のゲームへの参照が存在します。次のようなコードを書いたとします。

  simulated function bool CheckTeamGame()
  {
     return World.Game.bTeamGame
  }
  

これは、現在のゲームが Team ゲームかどうかに応じて True または False を返す簡単なシミュレート関数で、そのために現在のレベルの GameInfo 参照の bTeamGame プロパティを調べます。しかし、何かがおかしいのです...

Level 参照の Game プロパティはサーバー上でのみ有効で、クライアントはサーバーのゲームオブジェクトのことは何も知りません。そのため、クライアントは Accessed None とログに書き込みます。

LevelInfo のスクリプトを開くと、以下のようなセクションがあるのが分かります。

  //-----------------------------------------------------------------------------
  // Network replication. (ネットワーク複製)
  
  replication
  {
     reliable if( Role==ROLE_Authority )
        Pauser, TimeDilation, bNoCheating, bAllowFOV;
  }
  

上記の replocation ブロックは、Unreal Engine にこのオブジェクトのプロパティの処理方法を指図する特別なステートメントです。詳しく見てみましょう。

最初に、=reliable if( Role = ROLE_Authority) の複製条件があります。この条件の最初の部分は、reliable または unreliable のいずれかになります。reliable と指定した場合、エンジンは複製した情報が各クライアントまで安全に到達することを確認します (UDP プロトコルの動作の仕組みにより、パケットが転送中に失われる可能性があります)。Unreliable と指定した場合、この複製ではパケットが安全に到着したかどうかの確認を行いません。unreliable の場合よりよりも reliable の複製の方がネットワークオーバーヘッドが多少高くなります。

条件の 2 番目の部分である (Role = ROLE_Authority)= は、データをいつ送信するかをエンジンに指示しています。この例では、現在の LevelInfo オブジェクトが Authority であるときに常にデータを送信することになります。この意味を真に理解するには、対象オブジェクト特有の役割を理解しなければなりません。サーバーは LevelInfo を使って、オブジェクトの正式な (authoritative) バージョンを管理します。レベルの振る舞いを伝えるのはサーバーからクライアントに対してであり、その逆ではありません。上記の replication ブロックの例に置き換えると、これはデータがサーバーから各クライアントに送信されることを意味します。

その他のよく使われる条件タイプに、=(Role < ROLE_Authority)= があります。これは、エンジンは現在のオブジェクトが authority でないときにデータを送信するという意味ですが、正確に言えば、クライアントがサーバーに現在の情報を伝えることを意味します。

最後に、条件の下に 4 つの 変数が並んでいます。これらはステートメントが適用される変数で、この例では「このオブジェクトがサーバーで、かつクライアントに Pauser、TimeDilation、bNoCheating および bAllowFOV 変数の期限切れコピーがある場合、クライアントにこれらの変数の新しい情報を送信し、データが安全に到着することを常に確認すること。」と述べています。

この複製ステートメントでは、LevelInfo の残りの変数には触れていません。これは次の 2 つのいずれか - a) クライアントが C++ で情報を提供する (TimeSeconds の場合)、または b) クライアントでは情報が更新されず、まったく信頼できない (Game の場合) - に解釈できます。

C++ のソースコードへのアクセスはありませんが、オブジェクトのプロパティについていく通りかの推論を立てることで、ネイティブで更新される非複製プロパティがクラスに含まれているかどうかを判断できます。LevelInfo のクラス宣言を見てみましょう。

  class LevelInfo extends ZoneInfo
    native;
  

native は、「 このオブジェクトは C++ と UnrealScript で宣言されている 」という意味です。Native クラスには、おそらく見ることのできない C++ の動作があります。Native クラスは少数の特別クラスだけであり、これは通常パフォーマンス上の理由によるものです。

最後に、クラス宣言に nativereplication が含まれているクラスに注意してください。これは、UnrealScript の内側の replication ブロックは何も実行せず、複製はすべて C++ で定義されていることを意味します。ネットワーク負荷の高いオブジェクトの中には、ネットワークパフォーマンスを支援するために native 複製を使用するものがあります。

以上、複製変数とシミュレート関数に関する問題を回避する方法について学びました。次は、replicated 関数について考えて見ましょう。

replicated (複製される) 関数とは、クライアントまたはサーバーから呼び出され、呼び出し側の反対側で実行される関数です。=Say= 関数はこの関数の一例です。ゲーム中に T キーを押して誰かと話しをするときは、実際には Say 関数を実行してその会話内容を渡しているのです。クライアントはこの関数とパラメータを受け取り、実行してもらうためにサーバーに送信します。次にサーバーはメッセージを他のクライアントすべてに送信します。

replicated 関数とは、ポイントを 1 つ覚えておけば非常に使いやすい関数です。それは、「値を返すことができない」です。この関数はネットワーク上で反対側に転送され、それに時間を要します (ping とほぼ等しい長さです)。replicated 関数がブロックされた場合 (つまり、戻り値を待っていた場合)、ネットワーク通信は中断されます。

これは考えれば当たり前のことですが、MOD の制作に没頭しているときには考える余裕がないかもしれません。replicated 関数は即座に戻るので、クライアントで何かの動作 (特別なエフェクトなど) またはメッセージ (サーバーへの武器の発砲メッセージなど) をトリガするのにこの関数を利用できます。

最後に、replicated 関数の使用はわずかのクラスに制限されています。アクタでの関数呼び出しは、そのアクタを所有するプレーヤーにのみ複製されます。関数呼び出しは 1 つのアクタ (それを所有するプレーヤー) にしか複製されず、マルチキャストはできません。作成した武器やインベントリアイテムで (アイテムを所有するプレーヤーに関数を複製する場合に)、この関数を使うことをお勧めします。

それが、複製の基礎を理解する上で役に立つでしょう。

サンプル

Mutator

ゲームルール

Overlay

GameType

ゲームルール

HUD

スコアボード

AI

Deathmatch レベル

CTF レベル

カスタム キャラクター

Unreal Tournament 3 用のカスタム キャラクターの作成開始を支援するために、以下のキャラクターの骨組みを参考用に用意しました。

さらに、参考のために次の主観視点の骨組みも用意しました。

注意: Biped リグが含まれている骨組みがあります。Biped リグは、動きを付けやすくした付加的な骨組みです。アニメーション編集作業が終了するとそれを元の骨組みの上にベークし、biped リグを削除してからアニメーションをエクスポートします。

詳細については、 カスタム キャラクター ページを参照してください。