UDN
Search public documentation:

CameraTechnicalGuideJP
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 ホーム > ゲームプレイプログラミング > カメラの技術ガイド

カメラの技術ガイド


概観


「Unreal Engine 3」においてプレーヤーのためのカメラシステムは、3 つの主要となるクラスからできています。すなわち、 Camera(カメラ)、 Pawn(ポーン)、 PlayerControllerクラスです。これらのクラスは、相互に作用しながら、位置および回転、プレーヤーのカメラに適用されるべきその他の特別なエフェクトをプレー中に制御します。

PlayerController は、使用中の Camera への参照と制御中の Pawn への参照を保持します。 PlayerController は、プレーヤーからの入力を受け取り、それを利用して、制御の対象にしている Pawn の位置と回転を更新します。デフォルトでは、 Camera がその更新を Pawn に受け流し、転じて Pawn がカメラの位置と回転を更新します。

これらのクラスのうち 1 つ以上を修正し、相互作用のあり方を修正することによって、プレーヤーのカメラが、作成しているゲームの種類に合うパースペクティブを使用して、プレーヤーにワールドを表示するようにできます。デフォルトでは、プレーヤーのカメラは 1 人称のパースペクティブを使用します。任意で、3 人称の肩越しからのパースペクティブにトグルできます。これは、容易に修正して、トップダウンの(上からの)パースペクティブや等角投影法、横スクロールのパースペクティブ、その他、必要であればどのような視点からでも、ワールドを表示することができます。

Camera (カメラ)


カメラクラスは、ワールドを見るプレーヤーの視点を表わします。オンスクリーンで表示されるときにシーンがレンダリングされる視点は、プレーヤーカメラの位置と回転が決定します。 Camera クラスには、カメラを通したワールドの見え方を制御するプロパティも含まれています。このプロパティには、視界の設定やアスペクト比などがあります。カメラにはまた、適用される特殊エフェクトが含まれています。これには、ポストプロセス、レンズエフェクト、カメラモディファイア、カメラアニメーションなどがあります。

Camera Properties

  • General
    • PCOwner - このカメラを所有する PlayerController への参照。
    • CameraStyle - このカメラにおける現在のカメラモード。ビューターゲットによって視点がオーバーライドされていないときに、カメラのスタイル(たとえば、1 人称、3 人称、フリーなど)を決定するために使用します。
    • Target - カメラが"追跡する" Target のアクタです。
    • TViewTarget
      • Target - 理想的な視点を計算するために使用されるターゲットアクタです。
      • Controller - Target のコントローラです。(Pawn の場合)
        • POV - Target のための理想的な視点です。タイプは TPOV です。
          • TPOV
            • Location - 視点の位置です。
            • Rotation - 視点の回転です。
            • FOV - 視点のための視野角です。
          • AspectRatio - Target のために使用するアスペクト比です。
          • PRI - Pawn の遷移を通じて同一プレーヤーを追尾するために使用するプレーヤーの複製情報です。
  • FOV
    • DefaultFOV - カメラのためのデフォルトの視野角です。
    • bLockedFOV - True の場合は、カメラの視野角が LockedFOV の値にロックされます。
    • LockedFOV - FOV(視野角)がロックされたときに使用する視野角です。
  • Aspect Ratio
    • DefaultAspectRatio - カメラのためのデフォルトのアスペクト比です。
    • bConstrainAspectRatio - True の場合、カメラのアスペクト比が、 ConstrainedAspectRatio の値に制約されます。
    • ConstrainedAspectRatio - カメラのアスペクト比が制約されているときに使用するアスペクト比です。

Camera Functions

  • General
    • UpdateCamera [DeltaTime] - 1 フレームにつき 1 回呼び出されることによって、カメラの更新を実行します。
      • DeltaTime - 最後の更新が行われてから経過した時間です。
    • GetCameraViewPoint [OutCamLoc] [OutCamRot] - カメラの位置と回転を検索します。この関数を直接呼び出してはいけません。そのかわりに、 PCOwner の GetPlayerViewPoint() 関数を呼び出します。
      • OutCamLoc - カメラの位置を出力します。
      • OutCamRot - カメラの回転を出力します。
    • ProcessViewRotation [DeltaTime] [OutViewRotation] [OutDeltaRot] - 各カメラモディファイアに適用して、視界回転とデルタ回転の調整を可能にします。
      • DeltaTime - 最後の更新が行われてから経過した時間です。
      • OutViewRotation - 調整されたカメラの視点回転を出力します。
      • OutDeltaRot - 調整されたカメラのデルタ回転を出力します。
  • FOV
    • GetFOVAngle - カメラの現在の視野角を返します。
    • SetFOV [NewFOV] - カメラの視野角を NewFOV という値に設定します。
      • NewFOV - カメラの視野角として設定する値です。
  • View Target
    • SetViewTarget [NewViewTarget] [TransitionParams] - カメラのビューターゲットを設定します。
      • NewViewTarget - カメラのビューターゲットとして設定するアクタです。
      • TransitionParams - 新たなビューターゲットに遷移するときに使用するブレンドパラメータです。
    • UpdateViewTarget [OutVT] [DeltaTime] - カメラのビューターゲットにオーバーライドする機会を与えるあいだに、カメラのビューターゲットを設定します。
      • OutVT - ビューターゲットとカメラの視点を保持しているデータ構造体を出力します。
      • DeltaTime - 最後の更新が行われてから経過した時間です。

ポストプロセスエフェクト

ポストプロセスエフェクトとは、プレーヤーに表示される前のレンダリングされたシーンに対して適用するエフェクトのことです。カメラはそれぞれ自身のポストプロセス設定を適用することができます。この設定は、ワールドまたはボリューム、デフォルトのポストプロセスの設定をオーバーライドできます。

ポストプロセスエフェクトの詳細については、ポストプロセス エディタ ユーザガイドおよびポストプロセス テクニカルガイドポストプロセスによるマテリアル使用法をご覧ください。

Post Process Effects Properties

  • CameOverridePostProcessAlpha - ワールドおよびボリューム、デフォルトのポストプロセス設定に対して、カメラのポストプロセス設定がもつ影響度を設定します。値が 0.0 の場合は、ワールドおよびボリューム、デフォルトのポストプロセスが、完全な影響度をもちます。値が 1.0 の場合は、カメラのポストプロセスが、完全な影響度をもちます。
  • CamPostProcessSettings - カメラが、ワールドおよびボリューム、デフォルトのポストプロセスをオーバーライドしている時に使用するポストプロセスの設定です。
  • bEnableColorScaling - True の場合は、最終イメージ内のカラーチャンネルが、 ColorScale の値に基づいてスケーリングされます。
  • ColorScale -最終イメージ内の個々のカラーチャンネルをスケーリングするためのベクタです。
  • bEnableColorScaleInterp - True の場合、カメラは、新たなカラースケーリング値が SetDesiredColorScale() 関数を通じて設定される際に、カラースケーリング間で補間します。
  • bEnableFading - True の場合、カメラは、 FadeColor の FadeAmount をスクリーンに適用します。
  • FadeColor - カメラがフェードしつつあるときにスクリーンに適用するカラーです。
  • FadeAmount - 適用するフェード量です。基本的には、フェードのアルファです。

Post Process Effects Functions

  • SetDesiredColorScale [NewColorScale] [InterpTime] - 新たなカラースケーリング値を設定します。また、任意で、 bEnableColorScaleInterp の値に基づいて補間します。
    • NewColorScale - カラースケーリングのために使用する新たな値です。
    • InterpTime - 新たなカラースケーリング値に対して補間するのに必要となる時間です。

レンズエフェクト

レンズエフェクトとは、プレーヤーのカメラのレンズに適用するパーティクルエフェクトのことです。このレンズエフェクトを使用することによって、カメラレンズを滴り落ちる雨とか、レンズ上に飛び散る血や泥、ホコリといったものを作ることができます。カメラクラスには、これらのタイプのエフェクトを適用させる関数が含まれています。

パーティクルエフェクトの詳細については、パーティクル システムをご覧ください。

Lens Effects Properties

    • CameraLensEffects - カメラに現在適用されているすべてのパーティクルエフェクトの配列です。

Lens Effects Functions

  • FindCameraLensEffect [LensEffectEmitterClass] - 現在カメラに適用されているレンズエフェクトを検索し、合致するタイプのものをすべて返します。
    • LensEffectEmitterType - 検索するレンズエフェクトのクラスです。
  • AddCameraLensEffect [LensEffectEmitterClass] -指定された種類の新たなレンズエフェクトをカメラに適用します。
    • LensEffectEmitterClass - カメラに適用するレンズエフェクトのクラスです。
  • RemoveCameraLensEffect [Emitter] - カメラからレンズエフェクトを削除します。
    • Emitter - カメラから削除するレンズエフェクトです。
  • ClearCameraLensEffects - カメラに現在適用されているレンズエフェクトをすべて削除します。

カメラアニメーション

カメラアニメーションとは、 Matinee 内で作成されるアニメーションのことです。(任意で、外部のアニメーションエディタで作成、インポートすることができます)これは、アニメーションの平行移動および回転の情報を使用することによって、再生中にカメラをオフセットするとともに、通常 Matinee でアニメートが可能なカメラがもつ他のプロパティをアニメートできるようにします。これは、カメラ振動や手で支えられたカメラの上下動など、アニメーションエフェクトを作成する場合に、たいへん便利です。

カメラアニメーションの詳細については、カメラのセットアップをご覧ください。

Camera Animation Functions

  • PlayCameraAnim [CameraAnim] [Rate] [Scale] [BlendInTime] [BlendOutTime] [bLoop] [bRandomStartTime] [Duration] [bSingleInstance] - カメラ上でカメラアニメーションを再生します。
    • CameraAnim - 再生するカメラアニメーションです。
    • Rate - 任意。カメラアニメーションを再生するスピードです。
    • Scale - 任意。カメラアニメーションの変形に適用する強度乗数です。
    • BlendInTime - 任意。カメラアニメーションにブレンドするのにかかる時間です。
    • BlendOutTime - 任意。カメラアニメーションからブレンドするのにかかる時間です。
    • bLoop - 任意。True の場合、カメラアニメーションは、明示的に停止されるまでループし続けます。
    • bRandomStartTime - 任意。True の場合、カメラアニメーションは、アニメーションのタイムライン内のランダムな時間に再生を開始します。
    • Duration - 任意。アニメーションを再生する時間です。これが設定されていない場合は、アニメーション全体が再生されます。
    • bSingleInstance - 任意。True の場合、カメラ振動のインスタンスが、1 度に 1 つだけ存在することが許されます。
  • StopAllCameraAnims [bImmediate] - 現在再生中のカメラアニメーションをすべて停止します。
    • bImmediate - 任意。True の場合、アニメーションは、設定されているブレンド時間を無視して、即座に停止します。
  • StopAllCameraAnimsByType [Anim] [bImmediate] - 特定のタイプのカメラアニメーションのインスタンスをすべて停止します。
    • Anim - 停止するカメラアニメーションのタイプです。
    • bImmediate - 任意。True の場合、アニメーションは、設定されているブレンド時間を無視して、即座に停止します。
  • StopCameraAnim [AnimInst] [bImmediate] - カメラアニメーションの特定のインスタンスを停止します。
    • AnimInst - 停止するカメラアニメーションです。
    • bImmediate - 任意。True の場合、アニメーションは、設定されているブレンド時間を無視して、即座に停止します。

カメラモディファイア

カメラモディファイアは、カメラに適用した場合に、そのカメラのプロパティを修正することができるオブジェクトです。 CameraModifier クラスは、これらのエフェクトのための基本クラスです。このクラスをサブクラス化し、中の関数をオーバーライドすることによって、完全にカスタム仕様のモディファイアを作成できます。 CameraModifier_CameraShake クラスは、カメラモディファイアを使用してできるものの良い例です。

Camera Modifier Properties

    • ModifierList - カメラに現在適用されているすべてのカメラモディファイアの配列です。
    • CameraShakeModClass - 円錐主導型カメラ振動(例: Kismet による非カメラのアニメーションスクリーン振動)のために使用するクラスです。

Camera Modifier Functions

  • PlayCameraShake [Shake] [Scale] [PlaySpace] [UserPlaySpaceRot] - カメラ振動エフェクトをカメラ上で再生します。
    • Shake - カメラ振動エフェクトのために使用する、 CamerShake の設定値です。
    • Scale - カメラ振動の設定値に掛け合わせるスケーリング係数です。
    • PlaySpace - 任意。カメラ振動のために使用する空間を再生します。
    • UserPlaySpaceRot - 任意。ユーザーによって定義された再生空間のために使用する回転です。
  • StopCameraShake [Shake] - カメラ上でカメラ振動エフェクトを再生するのを停止します。
    • Shake - 再生を停止するカメラ振動です。
  • CalcRadialCameraShake [Cam] [Epicenter] [InnerRadius] [OuterRadius] [Falloff] - ラジアル振動の特定カメラに関する強度を計算して返します。
    • Cam - 強度を計算するカメラです。
    • Epicenter - カメラ振動の発生源の位置です。
    • InnerRadius - フォールオフが始まる地点からの距離です。
    • OuterRadius - カメラ振動エフェクトの終わる地点からの距離です。
    • Falloff - 強度のフォールオフを計算するために使われる指数です。
  • PlayWorldCameraShake [Shake] [ShakeInstigator] [Epicenter] [InnerRadius] [OuterRadius] [Falloff] [bTrForceFeedback] [bOrientShakeTowardEpicenter] - 近くにある全カメラに影響を及ぼすインワールドのカメラ振動を再生します。
    • Shake - 再生するカメラ振動です。
    • ShakeInstigator - カメラ振動の原因となるアクタです。
    • Epicenter - カメラ振動の発生源の位置です。
    • InnerRadius - フォールオフが始まる地点からの距離です。
    • OuterRadius - カメラ振動エフェクトの終わる地点からの距離です。
    • Falloff - 強度のフォールオフを計算するために使われる指数です。
    • bTryForceFeedback - True の場合は、影響を受けているあらゆるコントローラーに対して、力フィードバックの適用が試みられます。
    • bOrientShakeTowardEpicenter - 任意。True の場合、カメラ振動内のあらゆるオフセットが、発生地点に向き合うことに関連して適用されます。その場合、正の X 軸は、発生地点に向かっています。
  • ClearAllCameraShakes - カメラに現在適用されているカメラ振動をすべて削除します。

プレーヤーコントローラー


PlayerController は、次のようなアクションを扱います。すなわち、 Pawn の移動ならびに回転、カメラの制御(Pawn を介して行われる)といったアクションです。新たなカメラパースペクティブを作成する場合、 PlayerController クラス内の機能を更新またはオーバーライドしなければならない場合があります。理由は、プレーヤーの入力が Pawn の移動や方向に変換される際に、その方法がカメラの種類毎によって異なる場合があるからです。移動およびカメラに関するプロパティならびに関数のうちいくつかのものは、次のように記述されます。

Player Controller Properties

  • PlayerCamera - プレーヤーのカメラへの参照です。
  • CameraClass - プレーヤーのために使用されるカメラのクラスです。
  • ViewTarget - プレーヤーのカメラがもつ現在のビューターゲットです。
  • RealViewTarget - プレーヤーのカメラがもつビューターゲットのプレーヤー複製情報です。
  • FOVangle - プレーヤーのカメラの視野角です。
  • DefaultFOV - プレーヤーのカメラのために使用されるデフォルトの視野角です。

Player Controller Functions

  • GetPlayerViewPoint [out_Location] [out_Rotation] - Controller が所有する Pawn の視点を返します。人プレーヤーにとっては、カメラの視点になります。AI に制御されるプレーヤーにとっては、 Pawn の目から見た視点になります。基本的な実装では、単に Controller 自体の位置と回転に相当します。
    • out_Location - プレーヤーの視点の位置を出力します。
    • out_Rotation - プレーヤーの視点の回転を出力します。
  • GetActorEyesViewPoint [out_Location] [out_Rotation] - Controller またはその Pawn が存在している場合、その視点を返します。基本的には、プレーヤーがどの方向をどこから見ているかという情報を返します。
    • out_Location - プレーヤーの目の位置を出力します。
    • out_Rotation - プレーヤーの目の回転を出力します。
  • UpdateRotation [DeltaTime] - プレーヤーの入力に基づいて、 Controller の回転および Controller が所有する Pawn の回転を更新します。
    • DeltaTime - 最後の更新が行われてから経過した時間です。
  • ProcessViewRotation [DeltaTime] [out_ViewRotation] [DeltaRot] - プレーヤーの入力に基づいて、プレーヤーの視点の回転を処理するとともに、その結果得られる回転を出力します。この関数は、 UpdateRotation() によって呼び出されます。
    • DeltaTime - 最後の更新が行われてから経過した時間です。
    • out_ViewRotation - プレーヤーの視点回転を出力します。
    • DeltaRot - プレーヤーの入力による回転の変更です。
  • PlayerMove [DeltaTime] - 現在の移動のために新たな加速値と回転値を計算します。その後、 ProcessMove()(プレーヤーが1人の場合またはリッスンサーバーの場合)、または、 ReplicateMove()(ネットワーククライアントの場合)のいずれかを呼び出します。基本 PlayerController クラスにおいては、この関数はスタブにすぎませんが、 PlayerWalking ステートなどのような移動に関係する何らかのステート内においては、オーバーライドされます。この関数は、 PlayerTick() 関数によって毎サイクルごとに呼び出されます。
  • ProcessMove [DeltaTime] [newAccel] [DoubleClickMove] [DeltaRot] - クライアント上で現在の移動を処理します。この関数は、移動のために特別な機能が必要となるある種のステート内で、オーバーライドされます。

Pawn (ポーン)


Pawn は、ワールドにおけるプレーヤーの物理的な象徴であるだけではなく、プレーヤーのカメラの位置および回転も表わします。 Pawn が含む関数は、オーバーライドすることによって、まったく新しいカメラパースペクティブを作成することができます。カメラ関係の関数について、いくつか以下で解説します。

Pawn Functions

  • CalcCamera [DeltaTime] [out_CamLoc] [out_CamRot] [out_FOV] - Pawn から眺めた時のカメラの視点を計算します。これがプレーヤーのための主となるカメラ計算となります。
    • DeltaTime - 最後の更新が行われてから経過した時間です。
    • out_CamLoc - カメラの位置を出力します。
    • out_CamRot - カメラの回転を出力します。
    • out_FOV - カメラの視野角を出力します。
  • GetDefaultCameraMode [RequestedBy] - この Pawn のために使用されるべきデフォルトのカメラモードを名前として返します。この関数は、 Pawn を所有する時にコントローラーによって呼び出されます。
    • RequestedBy - デフォルトのカメラモードを必要とするコントローラーです。
  • ProcessViewRotation [deltaTime] [out_ViewRotation] [out_DeltaRot] - プレーヤーの視点の回転を処理するとともに、 out_ViewRotation パラメータとして最終的な視点の回転を返します。この関数は、 PlayerController の UpdateRotation() 関数から呼び出されます。
    • deltaTime - 最後に更新が行われてから経過した時間です。
    • out_ViewRotation - Pawn の視点の回転を出力します。
    • out_DeltaRot - デルタ回転を出力します。
  • SetViewRotation [NewRotation] - Controller が存在する場合は、その回転を設定します。 Controller が存在しない場合は、 Pawn 自体の回転を設定します。
    • NewRotation - Pawn の視点に設定する新しい回転です。
  • GetActorEyesViewPoint [out_Location] [out_Rotation] - Pawn の目、すなわち、プレーヤーの視点の位置と志向性を返します。第 1 の人のパースペクティブについては、カメラの位置および志向性と同一です。これは、大多数のトレースが実行される際の起点となる視点ともなります。
    • out_Location - Pawn の目の位置を出力します。
    • out_Rotation - Pawn の目の回転を出力します。

カメラの動作をカスタマイズする


カスタム仕様のカメラを実装する主な方法には2つあります。ビューターゲットの Pawn クラスが CalcCamera() を実装することができます。あるいは、 Camera クラスを拡張したカスタムクラスを作成します。

Pawn.CalcCamera() を実装すると、カメラモードが単純かつ容易になるので便利です。ただし、このメソッドを使用すると、フルに使用することができない機能があるため、トレードオフとなります。その機能には、ポストプロセスエフェクトやカメラアニメーションなどが該当します。

カスタムカメラクラスを作成すると、起動するのにオーバーヘッドか多少余計に必要となりますが、機能はフルで使用できます。 GameFramework.GamePlayerCamera は、この方法の1例です。


以下の基本的な例では、プレーヤーがもつカメラのパースペクティブを修正しています。また、プレーヤーが入力したものを処理する方法を修正している例もあります。これらは、カメラが必要とする完全なプラグまたはプレーソリューションとして意図されたものではありません。意図したことは、どのようにして自分のカメラを設定すればよいか、みなさんが理解するきっかけになればということです。

カメラタイプを公表、採用できるレベルにするには、修正できることや修正しなければならないことが、他にも多くあることは明らかです。一人称モード以外のモードで、プレーヤーからカメラの距離をマウスホイールを使って調整できる機能を実装しなければならない場合もあるでしょう。ある種のモードでは、カメラがワールドのジオメトリ上で侵入するのを防ぐために、コードを追加すると良い場合があります。特に、設計するレベルがこの種のことを避けたい場合に有効となります。また、ある種のモードでは、照準(クロスヘア)の描画方法を完全に削除するのではなく変更することによって、有効な追加となることがあります。

UDNGame.uc

class UDNGame extends UTDeathMatch;

defaultproperties
{
   DefaultPawnClass=class'UDNExamples.UDNPawn'
   PlayerControllerClass=class'UDNExamples.UDNPlayerController'
   MapPrefixes[0]="UDN"
}

また、DefaultGame.ini を編集して、エンジンが新たなゲームタイプをデフォルトとして使用するようにしなければなりません。

DefaultGame.ini

[Engine.GameInfo]
DefaultGame=UDNExamples.UDNGame
DefaultServerGame=UDNExamples.UDNGame

注意 : 新たなゲームタイプが使用されるようにするには、マップに正しいプレイフィックスをつけるようにしなければなりません。私たちのゲームタイプにおいては、プレイフィックスを UDN に設定しているので、すべてのマップが UDN- から始まるように命名する必要があります。エディタ内でどのようなマップであっても新たなゲームタイプを素早くテストすることができます。そのためには、マップのためのワールド プロパティ内にある Game Type PIE プロパティを、新たなゲームタイプにセットします。

一人称カメラの例

一人称のパースペクティブは、 UTPawn を拡張した Pawn クラスのためのデフォルトのカメラタイプです。例は、関連するクラスそれぞれから、カメラタイプを構成する中心部分を抜粋し、新しいサブクラスに配置したものです。これによって、基本的な一人称カメラを作成する際に関連するプロセスについて、効果的に説明することができます。

camera_first.jpg

UDNPawn.uc

class UDNPawn extends UTPawn;

simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   // Calculate first person camera position and rotation
   GetActorEyesViewPoint( out_CamLoc, out_CamRot );

   return true;
}

defaultproperties
{
}

UDNPlayerController.uc

Class UDNPlayerController extends UTPlayerController;

state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;

   function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
   {
      if( Pawn == None )
      {
         return;
      }

      if (Role == ROLE_Authority)
      {
         // Update ViewPitch for remote clients
         Pawn.SetRemoteViewPitch( Rotation.Pitch );
      }

      Pawn.Acceleration = NewAccel;

      CheckJumpOrDuck();
   }
}

function UpdateRotation( float DeltaTime )
{
   local Rotator   DeltaRot, newRotation, ViewRotation;

   ViewRotation = Rotation;
   if (Pawn!=none)
   {
      Pawn.SetDesiredRotation(ViewRotation);
   }

   // Calculate Delta to be applied on ViewRotation
   DeltaRot.Yaw   = PlayerInput.aTurn;
   DeltaRot.Pitch   = PlayerInput.aLookUp;

   ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
   SetRotation(ViewRotation);

   NewRotation = ViewRotation;
   NewRotation.Roll = Rotation.Roll;

   if ( Pawn != None )
      Pawn.FaceRotation(NewRotation, deltatime);
}

defaultproperties
{
}

三人称カメラの例

UTPawn から派生するすべてのサブクラスのための代替カメラタイプとして、三人称カメラの設定も含まれています。例では、中心部分を抜粋し、デフォルトのカメラをオーバーライドすることによって、三人称カメラにしています。

camera_third.jpg

UDNPawn.uc

class UDNPawn extends UTPawn;

//override to make player mesh visible by default
simulated event BecomeViewTarget( PlayerController PC )
{
   local UTPlayerController UTPC;

   Super.BecomeViewTarget(PC);

   if (LocalPlayer(PC.Player) != None)
   {
      UTPC = UTPlayerController(PC);
      if (UTPC != None)
      {
         //set player controller to behind view and make mesh visible
         UTPC.SetBehindView(true);
         SetMeshVisibility(UTPC.bBehindView);
      }
   }
}

simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )

{
   local vector CamStart, HitLocation, HitNormal, CamDirX, CamDirY, CamDirZ, CurrentCamOffset;
   local float DesiredCameraZOffset;

   CamStart = Location;
   CurrentCamOffset = CamOffset;

   DesiredCameraZOffset = (Health > 0) ? 1.2 * GetCollisionHeight() + Mesh.Translation.Z : 0.f;
   CameraZOffset = (fDeltaTime < 0.2) ? DesiredCameraZOffset * 5 * fDeltaTime + (1 - 5*fDeltaTime) * CameraZOffset : DesiredCameraZOffset;

   if ( Health <= 0 )
   {
      CurrentCamOffset = vect(0,0,0);
      CurrentCamOffset.X = GetCollisionRadius();
   }

   CamStart.Z += CameraZOffset;
   GetAxes(out_CamRot, CamDirX, CamDirY, CamDirZ);
   CamDirX *= CurrentCameraScale;

   if ( (Health <= 0) || bFeigningDeath )
   {
      // adjust camera position to make sure it's not clipping into world
      // @todo fixmesteve.  Note that you can still get clipping if FindSpot fails (happens rarely)
      FindSpot(GetCollisionExtent(),CamStart);
   }
   if (CurrentCameraScale < CameraScale)
   {
      CurrentCameraScale = FMin(CameraScale, CurrentCameraScale + 5 * FMax(CameraScale - CurrentCameraScale, 0.3)*fDeltaTime);
   }
   else if (CurrentCameraScale > CameraScale)
   {
      CurrentCameraScale = FMax(CameraScale, CurrentCameraScale - 5 * FMax(CameraScale - CurrentCameraScale, 0.3)*fDeltaTime);
   }

   if (CamDirX.Z > GetCollisionHeight())
   {
      CamDirX *= square(cos(out_CamRot.Pitch * 0.0000958738)); // 0.0000958738 = 2*PI/65536
   }

   out_CamLoc = CamStart - CamDirX*CurrentCamOffset.X + CurrentCamOffset.Y*CamDirY + CurrentCamOffset.Z*CamDirZ;

   if (Trace(HitLocation, HitNormal, out_CamLoc, CamStart, false, vect(12,12,12)) != None)
   {
      out_CamLoc = HitLocation;
   }

   return true;
}

defaultproperties
{
}

UDNPlayerController.uc

Class UDNPlayerController extends UTPlayerController;

state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;

   function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
   {
      if( Pawn == None )
      {
         return;
      }

      if (Role == ROLE_Authority)
      {
         // Update ViewPitch for remote clients
         Pawn.SetRemoteViewPitch( Rotation.Pitch );
      }

      Pawn.Acceleration = NewAccel;
   }
}

function UpdateRotation( float DeltaTime )
{
   local Rotator   DeltaRot, newRotation, ViewRotation;

   ViewRotation = Rotation;
   if (Pawn!=none)
   {
      Pawn.SetDesiredRotation(ViewRotation);
   }

   // Calculate Delta to be applied on ViewRotation
   DeltaRot.Yaw   = PlayerInput.aTurn;
   DeltaRot.Pitch   = PlayerInput.aLookUp;

   ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
   SetRotation(ViewRotation);

   NewRotation = ViewRotation;
   NewRotation.Roll = Rotation.Roll;

   if ( Pawn != None )
      Pawn.FaceRotation(NewRotation, deltatime);
}

defaultproperties
{
}

トップダウン(上からの)カメラの例

トップダウンカメラは、修正を加えることによって作成できます。三人称カメラの設定と似ていますが、 Pawn の回転が制限されます。特に、ピッチが制限されます。これは、上下に照準を向けることができないためです。

camera_top.jpg

UDNPawn.uc

class UDNPawn extends UTPawn;

var float CamOffsetDistance; //distance to offset the camera above the player
var bool bFollowPlayerRotation; //If true, camera rotates with player

//override to make player mesh visible by default
simulated event BecomeViewTarget( PlayerController PC )
{
   local UTPlayerController UTPC;

   Super.BecomeViewTarget(PC);

   if (LocalPlayer(PC.Player) != None)
   {
      UTPC = UTPlayerController(PC);
      if (UTPC != None)
      {
         //set player controller to behind view and make mesh visible
         UTPC.SetBehindView(true);
         SetMeshVisibility(UTPC.bBehindView);
         UTPC.bNoCrosshair = true;
      }
   }
}

simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   out_CamLoc = Location;
   out_CamLoc.Z += CamOffsetDistance;

   if(!bFollowPlayerRotation)
   {
      out_CamRot.Pitch = -16384;
      out_CamRot.Yaw = 0;
      out_CamRot.Roll = 0;
   }
   else
   {
      out_CamRot.Pitch = -16384;
      out_CamRot.Yaw = Rotation.Yaw;
      out_CamRot.Roll = 0;
   }

   return true;
}

simulated singular event Rotator GetBaseAimRotation()
{
   local rotator   POVRot, tempRot;

   tempRot = Rotation;
   tempRot.Pitch = 0;
   SetRotation(tempRot);
   POVRot = Rotation;
   POVRot.Pitch = 0;

   return POVRot;
}

defaultproperties
{
   bFollowPlayerRotation = false;
   CamOffsetDistance=384.0
}

UDNPlayerController.uc

Class UDNPlayerController extends UTPlayerController;

state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;

   function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
   {
      if( Pawn == None )
      {
         return;
      }

      if (Role == ROLE_Authority)
      {
         // Update ViewPitch for remote clients
         Pawn.SetRemoteViewPitch( Rotation.Pitch );
      }

      Pawn.Acceleration = NewAccel;

      CheckJumpOrDuck();
   }
}

function UpdateRotation( float DeltaTime )
{
   local Rotator   DeltaRot, newRotation, ViewRotation;

   ViewRotation = Rotation;
   if (Pawn!=none)
   {
      Pawn.SetDesiredRotation(ViewRotation);
   }

   // Calculate Delta to be applied on ViewRotation
   DeltaRot.Yaw   = PlayerInput.aTurn;
   DeltaRot.Pitch   = 0;

   ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
   SetRotation(ViewRotation);

   NewRotation = ViewRotation;
   NewRotation.Roll = Rotation.Roll;

   if ( Pawn != None )
      Pawn.FaceRotation(NewRotation, deltatime);
}

defaultproperties
{
}

等角投影法カメラの例

単純な等角投影法型のカメラは、先に解説したトップダウンカメラの例にかなり類似しています。カメラは、X 軸とZ 軸 2 つの軸に沿ったオフセットで、ピッチは、下に回転してプレーヤーにフォーカスします。

camera_iso.jpg

UDNPawn.uc

class UDNPawn extends UTPawn;

var float CamOffsetDistance; //distance to offset the camera from the player
var int IsoCamAngle; //pitch angle of the camera

//override to make player mesh visible by default
simulated event BecomeViewTarget( PlayerController PC )
{
   local UTPlayerController UTPC;

   Super.BecomeViewTarget(PC);

   if (LocalPlayer(PC.Player) != None)
   {
      UTPC = UTPlayerController(PC);
      if (UTPC != None)
      {
         //set player controller to behind view and make mesh visible
         UTPC.SetBehindView(true);
         SetMeshVisibility(UTPC.bBehindView);
         UTPC.bNoCrosshair = true;
      }
   }
}

simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   out_CamLoc = Location;
   out_CamLoc.X -= Cos(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;
   out_CamLoc.Z += Sin(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;

   out_CamRot.Pitch = -1 * IsoCamAngle;
   out_CamRot.Yaw = 0;
   out_CamRot.Roll = 0;

   return true;
}

simulated singular event Rotator GetBaseAimRotation()
{
   local rotator   POVRot, tempRot;

   tempRot = Rotation;
   tempRot.Pitch = 0;
   SetRotation(tempRot);
   POVRot = Rotation;
   POVRot.Pitch = 0;

   return POVRot;
}

defaultproperties
{
   IsoCamAngle=6420 //35.264 degrees
   CamOffsetDistance=384.0
}

UDNPlayerController.uc

Class UDNPlayerController extends UTPlayerController;

state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;

   function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
   {
      if( Pawn == None )
      {
         return;
      }

      if (Role == ROLE_Authority)
      {
         // Update ViewPitch for remote clients
         Pawn.SetRemoteViewPitch( Rotation.Pitch );
      }

      Pawn.Acceleration = NewAccel;

      CheckJumpOrDuck();
   }
}

function UpdateRotation( float DeltaTime )
{
   local Rotator   DeltaRot, newRotation, ViewRotation;

   ViewRotation = Rotation;
   if (Pawn!=none)
   {
      Pawn.SetDesiredRotation(ViewRotation);
   }

   // Calculate Delta to be applied on ViewRotation
   DeltaRot.Yaw   = PlayerInput.aTurn;
   DeltaRot.Pitch   = 0;

   ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
   SetRotation(ViewRotation);

   NewRotation = ViewRotation;
   NewRotation.Roll = Rotation.Roll;

   if ( Pawn != None )
      Pawn.FaceRotation(NewRotation, deltatime);
}

defaultproperties
{
}

横スクロールカメラの例

横スクロールカメラでは、カメラの視点を制御する必要があるだけでなく、プレーヤーによる入力の処理の仕方を修正する必要があります。プレーヤーは、スクリーン上で左右の移動しか許可されず、常に移動する方向に面しているように強いられます。入力は、A のキーと D のキーによってプレーヤーが前後に移動するようにしなければなりません。

camera_side.jpg

UDNPawn.uc

class UDNPawn extends UTPawn;

var float CamOffsetDistance; //Position on Y-axis to lock camera to

//override to make player mesh visible by default
simulated event BecomeViewTarget( PlayerController PC )
{
   local UTPlayerController UTPC;

   Super.BecomeViewTarget(PC);

   if (LocalPlayer(PC.Player) != None)
   {
      UTPC = UTPlayerController(PC);
      if (UTPC != None)
      {
         //set player controller to behind view and make mesh visible
         UTPC.SetBehindView(true);
         SetMeshVisibility(UTPC.bBehindView);
         UTPC.bNoCrosshair = true;
      }
   }
}

simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   out_CamLoc = Location;
   out_CamLoc.Y = CamOffsetDistance;

   out_CamRot.Pitch = 0;
   out_CamRot.Yaw = 16384;
   out_CamRot.Roll = 0;
   return true;
}

simulated singular event Rotator GetBaseAimRotation()
{
   local vector   POVLoc;


   POVRot = Rotation;
   if( (Rotation.Yaw % 65535 > 16384 && Rotation.Yaw % 65535 < 49560) ||
      (Rotation.Yaw % 65535 < -16384 && Rotation.Yaw % 65535 > -49560) )
   {
      POVRot.Yaw = 32768;
   }
   else
   {
      POVRot.Yaw = 0;
   }

   if( POVRot.Pitch == 0 )
   {
      POVRot.Pitch = RemoteViewPitch << 8;
   }

   return POVRot;
}

defaultproperties
{
   CamOffsetDistance=0.0
}

UDNPlayerController.uc

Class UDNPlayerController extends UTPlayerController;

state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;

   function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
   {
      local Rotator tempRot;

      if( Pawn == None )
      {
         return;
      }

      if (Role == ROLE_Authority)
      {
         // Update ViewPitch for remote clients
         Pawn.SetRemoteViewPitch( Rotation.Pitch );
      }

      Pawn.Acceleration.X = -1 * PlayerInput.aStrafe * DeltaTime * 100 * PlayerInput.MoveForwardSpeed;
      Pawn.Acceleration.Y = 0;
      Pawn.Acceleration.Z = 0;

      tempRot.Pitch = Pawn.Rotation.Pitch;
      tempRot.Roll = 0;
      if(Normal(Pawn.Acceleration) Dot Vect(1,0,0) > 0)
      {
         tempRot.Yaw = 0;
         Pawn.SetRotation(tempRot);
      }
      else if(Normal(Pawn.Acceleration) Dot Vect(1,0,0) < 0)
      {
         tempRot.Yaw = 32768;
          Pawn.SetRotation(tempRot);

      }

      CheckJumpOrDuck();

   }
}

function UpdateRotation( float DeltaTime )
{
   local Rotator   DeltaRot, newRotation, ViewRotation;

   ViewRotation = Rotation;

   // Calculate Delta to be applied on ViewRotation
   DeltaRot.Yaw = Pawn.Rotation.Yaw;
   DeltaRot.Pitch   = PlayerInput.aLookUp;

   ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
   SetRotation(ViewRotation);

}

defaultproperties
{
}

オールインワンカメラの例

この例では、他のすべての例を、単一の実装にまとめたものです。それによって、プレーヤーが、いずれかのカメラタイプに切り替えることができ、実行関数を通じてそれらを調節することができます。

UDNPawn.uc

class UDNPawn extends UTPawn;

Enum CameraPerspective
{
   CAM_FirstPerson,
   CAM_ThirdPerson,
   CAM_TopDown,
   CAM_SideScroller,
   CAM_Isometric
};

var bool bFollowPlayerRotation;
var CameraPerspective CameraType;
var float CamOffsetDistance;
var int IsoCamAngle;

exec function CameraMode(CameraPerspective mode)
{
   local UTPlayerController UTPC;

   CameraType = mode;

   UTPC = UTPlayerController(Controller);
   if (UTPC != None)
   {
      if(CameraType != CAM_FirstPerson)
      {
         UTPC.SetBehindView(true);
         if(CameraType != CAM_ThirdPerson)
         {
            UTPC.bNoCrosshair = true;
         }
         else
         {
            UTPC.bNoCrosshair = false;
         }
      }
      else
      {
         UTPC.bNoCrosshair = false;

         UTPC.SetBehindView(false);
      }
      SetMeshVisibility(UTPC.bBehindView);
   }
}

exec function IsoAngle(int angle)
{
   IsoCamAngle = angle;
}

/* BecomeViewTarget
   Called by Camera when this actor becomes its ViewTarget */
simulated event BecomeViewTarget( PlayerController PC )
{
   local UTPlayerController UTPC;

   Super.BecomeViewTarget(PC);

   if (LocalPlayer(PC.Player) != None)
   {
      UTPC = UTPlayerController(PC);
      if (UTPC != None)
      {
         if(CameraType != CAM_FirstPerson)
         {
            UTPC.SetBehindView(true);
            if(CameraType != CAM_ThirdPerson)
            {
               UTPC.bNoCrosshair = true;
            }
            else
            {
               UTPC.bNoCrosshair = false;
            }
         }
         else
         {
            UTPC.bNoCrosshair = false;

            UTPC.SetBehindView(false);
         }
         SetMeshVisibility(UTPC.bBehindView);
      }
   }
}

/**
 *   Calculate camera view point, when viewing this pawn.
 *
 * @param   fDeltaTime   delta time seconds since last update
 * @param   out_CamLoc   Camera Location
 * @param   out_CamRot   Camera Rotation
 * @param   out_FOV      Field of View
 *
 * @return   true if Pawn should provide the camera point of view.
 */
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   // Handle the fixed camera

   if (bFixedView)
   {
      out_CamLoc = FixedViewLoc;
      out_CamRot = FixedViewRot;
   }
   else
   {
      if ( CameraType == CAM_ThirdPerson )   // Handle BehindView
      {
         CalcThirdPersonCam(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
      }
      else if ( CameraType == CAM_TopDown )   // Handle BehindView
      {
         CalcTopDownCam(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
      }
      else if ( CameraType == CAM_SideScroller )   // Handle BehindView
      {
         CalcSideScrollerCam(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
      }
      else if ( CameraType == CAM_Isometric )   // Handle BehindView
      {
         CalcIsometricCam(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
      }
      else
      {
         // By default, we view through the Pawn's eyes..
         GetActorEyesViewPoint( out_CamLoc, out_CamRot );
      }

      if ( UTWeapon(Weapon) != none)
      {
         UTWeapon(Weapon).WeaponCalcCamera(fDeltaTime, out_CamLoc, out_CamRot);
      }
   }

   return true;
}

simulated function bool CalcTopDownCam( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   out_CamLoc = Location;
   out_CamLoc.Z += CamOffsetDistance;

   if(!bFollowPlayerRotation)
   {
      out_CamRot.Pitch = -16384;
      out_CamRot.Yaw = 0;
      out_CamRot.Roll = 0;
   }
   else
   {
      out_CamRot.Pitch = -16384;
      out_CamRot.Yaw = Rotation.Yaw;
      out_CamRot.Roll = 0;
   }

   return true;
}

simulated function bool CalcSideScrollerCam( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   out_CamLoc = Location;
   out_CamLoc.Y = CamOffsetDistance;

   out_CamRot.Pitch = 0;
   out_CamRot.Yaw = 16384;
   out_CamRot.Roll = 0;

   return true;
}

simulated function bool CalcIsometricCam( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   out_CamLoc = Location;
   out_CamLoc.X -= Cos(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;
   out_CamLoc.Z += Sin(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;

   out_CamRot.Pitch = -1 * IsoCamAngle;
   out_CamRot.Yaw = 0;
   out_CamRot.Roll = 0;

   return true;
}

/**
 * returns base Aim Rotation without any adjustment (no aim error, no autolock, no adhesion.. just clean initial aim rotation!)
 *
 * @return   base Aim rotation.
 */
simulated singular event Rotator GetBaseAimRotation()
{
   local vector   POVLoc;
   local rotator   POVRot, tempRot;

   if(CameraType == CAM_TopDown || CameraType == CAM_Isometric)
   {
      tempRot = Rotation;
      tempRot.Pitch = 0;
      SetRotation(tempRot);
      POVRot = Rotation;
      POVRot.Pitch = 0;
   }
   else if(CameraType == CAM_SideScroller)
   {
      POVRot = Rotation;
      if( (Rotation.Yaw % 65535 > 16384 && Rotation.Yaw % 65535 < 49560) ||
          (Rotation.Yaw % 65535 < -16384 && Rotation.Yaw % 65535 > -49560) )
      {
         POVRot.Yaw = 32768;
      }
      else
      {
         POVRot.Yaw = 0;
      }

      if( POVRot.Pitch == 0 )
      {
         POVRot.Pitch = RemoteViewPitch << 8;
      }
   }
   else
   {
      if( Controller != None && !InFreeCam() )
      {
         Controller.GetPlayerViewPoint(POVLoc, POVRot);
         return POVRot;
      }
      else
      {
         POVRot = Rotation;

         if( POVRot.Pitch == 0 )
         {
            POVRot.Pitch = RemoteViewPitch << 8;
         }
      }
   }

   return POVRot;
}


defaultproperties
{
   CameraType=CAM_FirstPerson;
   bFollowPlayerRotation = false;
   CamOffsetDistance=384.0
   IsoCamAngle=6420 //35.264 degrees
}

UDNPlayerController.uc

class UDNPlayerController extends UTPlayerController;

state PlayerWalking
{
   function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
   {
      local UDNPawn P;
      local Rotator tempRot;

          if( (Pawn != None) )
      {
         P = UDNPawn(Pawn);
         if(P != none)
         {
            if(P.CameraType == CAM_SideScroller)
            {
               Pawn.Acceleration.X = -1 * PlayerInput.aStrafe * DeltaTime * 100 * PlayerInput.MoveForwardSpeed;
               Pawn.Acceleration.Y = 0;
               Pawn.Acceleration.Z = 0;

               tempRot.Pitch = P.Rotation.Pitch;
               tempRot.Roll = 0;
               if(Normal(Pawn.Acceleration) Dot Vect(1,0,0) > 0)
               {
                  tempRot.Yaw = 0;
                  P.SetRotation(tempRot);
               }
               else if(Normal(Pawn.Acceleration) Dot Vect(1,0,0) < 0)
               {
                  tempRot.Yaw = 32768;
                  P.SetRotation(tempRot);
               }
            }
            else
            {

               if ( (DoubleClickMove == DCLICK_Active) && (Pawn.Physics == PHYS_Falling) )
                  DoubleClickDir = DCLICK_Active;
               else if ( (DoubleClickMove != DCLICK_None) && (DoubleClickMove < DCLICK_Active) )
               {
                  if ( UTPawn(Pawn).Dodge(DoubleClickMove) )
                     DoubleClickDir = DCLICK_Active;
               }

               Pawn.Acceleration = newAccel;
            }

            if (Role == ROLE_Authority)
            {
               // Update ViewPitch for remote clients
               Pawn.SetRemoteViewPitch( Rotation.Pitch );
            }
         }

         CheckJumpOrDuck();
      }
   }
}

function UpdateRotation( float DeltaTime )
{
   local UDNPawn P;
   local Rotator   DeltaRot, newRotation, ViewRotation;

   P = UDNPawn(Pawn);

   ViewRotation = Rotation;
   if (p != none && P.CameraType != CAM_SideScroller)
   {
      Pawn.SetDesiredRotation(ViewRotation);
   }

   // Calculate Delta to be applied on ViewRotation
   if( P != none && P.CameraType == CAM_SideScroller )
   {
      DeltaRot.Yaw = Pawn.Rotation.Yaw;
   }
   else
   {
      DeltaRot.Yaw = PlayerInput.aTurn;
   }
   DeltaRot.Pitch = PlayerInput.aLookUp;

   ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
   SetRotation(ViewRotation);

   ViewShake( deltaTime );

   NewRotation = ViewRotation;
   NewRotation.Roll = Rotation.Roll;

   if (P != None && P.CameraType != CAM_SideScroller )
      Pawn.FaceRotation(NewRotation, deltatime);
}

defaultproperties
{
}

カスタムのカメラの例


この例では、これまでのものとは異なるアプローチを取ります。これまではすべて、Pawn (ポーン) クラスにある CalcCamera() 関数を利用してカメラを変更していました。この例では、カスタムのカメラ フレームワークを作成して、さまざまなカメラモジュールに簡単にプラグインすることによって、素早くカメラのビヘイビアを変更できるようにします。また、これは同じくらい重要なことですが、カメラの機能すべてに完全にアクセスすることができます。その機能には、ポストプロセス エフェクト、カメラ アニメーションおよびエフェクトなどがあります。さらに、プレイヤーの Controller クラスによって、プレイヤーのコントロール モジュールを使用する機能が追加され、プレイヤーの動きおよび照準における特定の要素をオーバーライドできるようになります。

この例の構成は、他の例と同様、いくつかの関数を割と簡単にオーバーライドする場合に比べて若干複雑になっています。この例では、これまでの例で取り上げられてきた関数の多くをオーバーライドする必要があります。ただし、これらの関数に直接機能を追加したり変更を加えたりはしません。単にカスタムのカメラおよびコントロール システムに依存することによって、通常実現する機能を提供することになります。

本質的に、新たな Camera クラスはカメラモジュールへのインターフェースとして機能します。これには、新たなカメラ モジュールを作成する関数、および、プレイヤーの Pawn とは異なるビューターゲットをカメラがもつ場合を処理するための関数がいくつか含まれます。 それ以外の役割としては、さまざまな Engine クラスからの関数呼び出しを、処理すべき現在のカメラ モジュールに渡すということがあります。同様に、新たな PlayerController クラスは、依存するコントロール モジュールを参照して、PlayerController および Pawn クラスの特定の動きと照準の関数を処理します。これによって、カメラおよびコントロール タイプに固有な機能が、すべて、コンパクトで自己完結したクラスに含まれることになります。これらのクラスは自由に置き換えることができるため、素早く簡単に新たなカメラタイプを実装することができます。

ベースとなるカメラ モジュール

ベースとなるカメラ モジュールのクラスは、Object クラスを拡張したもので、すべてのカメラ モジュールに共通するプロパティとビヘイビアを定義します。プロパティの中には、このクラスを所有しているカメラへの参照があります。初期化および初期化解除の関数が定義されているものの、このクラスでメインとなる機能は、UpdateCamera() 関数によって実行されます。この関数は、プレイヤーのカメラの新たな位置と回転を計算するとともに、他の必要なエフェクトまたは変更を適用することができます。

このクラスの定義には config(Camera) 指定子を使用します。これによって、特定のカメラ モジュールにおいて設定可能であるか永続的でなければならないあらゆるプロパティが Camera.ini ファイルに置かれることになります。また、このクラスは abstract として定義されるため、実際に使用することはできません。それ自体実際に使用されるクラスではなく、特定のカメラ モジュールをビルドする際に基となるテンプレートと言うべきものです。

UDNCameraModule.uc

class UDNCameraModule extends Object
   abstract
   config(Camera);

//owning camera
var transient UDNPlayerCamera   PlayerCamera;

//mode-specific initialization
function Init();

/** Called when the camera becomes active */
function OnBecomeActive( UDNCameraModule OldCamera );
/** Called when the camera becomes inactive */
function OnBecomeInActive( UDNCameraModule NewCamera );

//Calculate new camera location and rotation
function UpdateCamera(Pawn P, UDNPlayerCamera CameraActor, float DeltaTime, out TViewTarget OutVT);

//initialize new view target
simulated function BecomeViewTarget( UDNPlayerController PC );

//handle zooming in
function ZoomIn();

//handle zooming in
function ZoomOut();

defaultproperties
{
}

カスタムの Camera

新たな Camera クラスは、ベースとなる Camera クラスを拡張したもので、関数をオーバーライドし、カメラ モジュールを処理する新たな機能を追加しています。このシステムにおける Camera の主な仕事は、計算の大部分を処理するため、カメラ モジュールの仲介者として振る舞うことです。

UDNPlayerCamera.uc

class UDNPlayerCamera extends Camera
   config(Camera);

var UDNPlayerController PlayerOwner; //player controller owning this camera
var UDNCameraModule CurrentCamera; //Current camera mode in use
var config string DefaultCameraClass; //class for default camera mdoe

function PostBeginPlay()
{
   local class<UDNCameraModule> NewClass;

   Super.PostBeginPlay();

   // Setup camera mode
   if ( (CurrentCamera == None) && (DefaultCameraClass != "") )
   {
      //get the default camera class to use
      NewClass = class<UDNCameraModule>( DynamicLoadObject( DefaultCameraClass, class'Class' ) );

      //create default camera
      CurrentCamera = CreateCamera(NewClass);
   }
}

//Initialize the PlayerCamera for the owning PlayerController
function InitializeFor(PlayerController PC)
{
   //do parent initialization
   Super.InitializeFor(PC);

   //set PlayerOwner to player controller
   PlayerOwner = UDNPlayerController(PC);
}

/**
 * Internal. Creates and initializes a new camera of the specified class, returns the object ref.
 */
function UDNCameraModule CreateCamera(class<UDNCameraModule> CameraClass)
{
   local UDNCameraModule NewCam;

   //create new camera and initialize
   NewCam = new(Outer) CameraClass;
   NewCam.PlayerCamera = self;
   NewCam.Init();

   //call active/inactive functions on new/old cameras
   if(CurrentCamera != none)
   {
      CurrentCamera.OnBecomeInactive(NewCam);
      NewCam.OnBecomeActive(CurrentCamera);
   }
   else
   {
      NewCam.OnBecomeActive(None);
   }

   //set new camera as current
   CurrentCamera = NewCam;

   return NewCam;
}

/**
 * Query ViewTarget and outputs Point Of View.
 *
 * @param   OutVT      ViewTarget to use.
 * @param   DeltaTime   Delta Time since last camera update (in seconds).
 */
function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
{
   local CameraActor   CamActor;
   local TPOV OrigPOV;
   local Vector Loc, Pos, HitLocation, HitNormal;
   local Rotator Rot;
   local Actor HitActor;

   // Don't update outgoing viewtarget during an interpolation
   if( PendingViewTarget.Target != None && OutVT == ViewTarget && BlendParams.bLockOutgoing )
   {
      return;
   }

   OrigPOV = OutVT.POV;

   // Default FOV on viewtarget
   OutVT.POV.FOV = DefaultFOV;

   // Viewing through a camera actor.
   CamActor = CameraActor(OutVT.Target);
   if( CamActor != None )
   {
      CamActor.GetCameraView(DeltaTime, OutVT.POV);

      // Grab aspect ratio from the CameraActor.
      bConstrainAspectRatio   = bConstrainAspectRatio || CamActor.bConstrainAspectRatio;
      OutVT.AspectRatio      = CamActor.AspectRatio;

      // See if the CameraActor wants to override the PostProcess settings used.
      CamOverridePostProcessAlpha = CamActor.CamOverridePostProcessAlpha;
      CamPostProcessSettings = CamActor.CamOverridePostProcess;
   }
   else
   {
      // Give Pawn Viewtarget a chance to dictate the camera position.
      // If Pawn doesn't override the camera view, then we proceed with our own defaults
      if( Pawn(OutVT.Target) == None ||
         !Pawn(OutVT.Target).CalcCamera(DeltaTime, OutVT.POV.Location, OutVT.POV.Rotation, OutVT.POV.FOV) )
      {
         //Pawn didn't want control and we have a custom mode
         if(CurrentCamera != none)
         {
            //allow mode to handle camera update
            CurrentCamera.UpdateCamera(Pawn(OutVT.Target), self, DeltaTime, OutVT);
         }
         //no custom mode - use default camera styles
         else
         {
            switch( CameraStyle )
            {
               case 'Fixed'      :   // do not update, keep previous camera position by restoring
                                 // saved POV, in case CalcCamera changes it but still returns false
                                 OutVT.POV = OrigPOV;
                                 break;

               case 'ThirdPerson'   : // Simple third person view implementation
               case 'FreeCam'      :
               case 'FreeCam_Default':
                                 Loc = OutVT.Target.Location;
                                 Rot = OutVT.Target.Rotation;

                                 //OutVT.Target.GetActorEyesViewPoint(Loc, Rot);
                                 if( CameraStyle == 'FreeCam' || CameraStyle == 'FreeCam_Default' )
                                 {
                                    Rot = PCOwner.Rotation;
                                 }
                                 Loc += FreeCamOffset >> Rot;

                                 Pos = Loc - Vector(Rot) * FreeCamDistance;
                                 // @fixme, respect BlockingVolume.bBlockCamera=false
                                 HitActor = Trace(HitLocation, HitNormal, Pos, Loc, FALSE, vect(12,12,12));
                                 OutVT.POV.Location = (HitActor == None) ? Pos : HitLocation;
                                 OutVT.POV.Rotation = Rot;
                                 break;

               case 'FirstPerson'   : // Simple first person, view through viewtarget's 'eyes'
               default            :   OutVT.Target.GetActorEyesViewPoint(OutVT.POV.Location, OutVT.POV.Rotation);
                                 break;

            }
         }
      }
   }

   ApplyCameraModifiers(DeltaTime, OutVT.POV);

   // set camera's location and rotation, to handle cases where we are not locked to view target
   SetRotation(OutVT.POV.Rotation);
   SetLocation(OutVT.POV.Location);
}

//pass view target initialization through to camera mode
simulated function BecomeViewTarget( PlayerController PC )
{
   CurrentCamera.BecomeViewTarget(UDNPlayerController(PC));
}

//pass zoom in through to camera mode
function ZoomIn()
{
   CurrentCamera.ZoomIn();
}

//pass zoom out through to camera mode
function ZoomOut()
{
   CurrentCamera.ZoomOut();
}

defaultproperties
{
}

ベースとなるコントロール モジュール

ベースとなるコントロール モジュール クラスは、Object クラスを拡張したのもので、全コントロール モジュールに共通するプロパティおよびビヘイビアをすべて定義します。このクラスは、このクラスを所有しているコントローラーへの参照を含むとともに、現在のマウスカーソルの位置を保持します。ベースとなるカメラ モジュールと同様、タイプ固有の構成または必要となるクリーンアップを可能にする初期化および初期化解除の関数が定義されています。このクラスの残りは、プレイヤーの動きおよび照準を処理する関数から構成されています。

このクラスの定義には config(Control) 指定子を使用します。これによって、特定のカメラ モジュールにおいて設定可能であるか永続的でなければならないあらゆるプロパティが Camera.ini ファイルに置かれることになります。また、このクラスは abstract として定義されるため、実際に使用することはできません。このクラスは、それ自体実際に使用されるものではなく、特定のカメラ モジュールをビルドする際に基となるテンプレートにすぎません。

UDNControlModule.uc

class UDNControlModule extends Object
   abstract
   config(Control);

//reference to the owning controller
var UDNPlayerController Controller;

//mode-specific initialization
function Init();

/** Called when the camera becomes active */
function OnBecomeActive( UDNControlModule OldModule );
/** Called when the camera becomes inactive */
function OnBecomeInActive( UDNControlModule NewModule );

//Calculate Pawn aim rotation
simulated singular function Rotator GetBaseAimRotation();

//Handle custom player movement
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot);

//Calculate controller rotation
function UpdateRotation(float DeltaTime);

defaultproperties
{
}

エンジンクラスのオーバーライド

いくつかのエンジンクラスを拡張することによって、新たなカメラシステムおよびコントロールシステム (主に PlayerController 、Pawn 、HUD クラス) のインターフェースとなるようにする必要があります。新たなゲームタイプも作成し、これらの新たなクラスを利用できるようにします。

PlayerController

新たな PlayerController クラスは、使用されているカメラ モジュールのタイプを変更する実行関数、および、ズームインまたはズームアウトするための実行関数を追加します。(ズームのための関数の機能のしかたは、それらの関数を現在のカメラ モジュールがどのように実装するかということに依存します)。 PlayerWalking ステートの ProcessMove() 関数、および、 UpdateRotation() 関数がオーバーライドされることによって、関数呼び出しがコントロール モジュールに追加されます。最後に GetPlayerViewPoint() 関数がオーバーライドおよび変更されることによって、カメラが破壊されないようにし、新たなカスタムのカメラがある場合は PlayerController にそのカメラを使用させるようにします。

UDNPlayerController.uc

class UDNPlayerController extends UTPlayerController;

var UDNControlModule ControlModule; //player control module to use
var config string DefaultControlModuleClass; //default class for player control module

//exec function for switching to a different camera by class
exec function ChangeControls( string ClassName )
{
   local class<UDNControlModule> ControlClass;
   local UDNControlModule NewControlModule;

   ControlClass = class<UDNControlModule>( DynamicLoadObject( DefaultControlModuleClass, class'Class' ) );

   if(ControlClass != none)
   {
      // Associate module with PlayerController
      NewControlModule = new(Outer) ControlClass;
      NewControlModule.Controller = self;
      NewControlModule.Init();

      //call active/inactive functions on new/old modules
      if(ControlModule != none)
      {
         ControlModule.OnBecomeInactive(NewControlModule);
         NewControlModule.OnBecomeActive(ControlModule);
      }
      else
      {
         NewControlModule.OnBecomeActive(None);
      }

      ControlModule = NewControlModule;
   }
   else
   {
      `log("Couldn't get control module class!");
      // not having a Control Class is fine.  PlayerController will use default controls.
   }
}

//exec function for switching to a different camera by class
exec function ChangeCamera( string ClassName )
{
   local class<UDNCameraModule> NewClass;

   NewClass = class<UDNCameraModule>( DynamicLoadObject( ClassName, class'Class' ) );

   if(NewClass != none && UDNPlayerCamera(PlayerCamera) != none)
   {
      UDNPlayerCamera(PlayerCamera).CreateCamera(NewClass);
   }
}

//zoom in exec
exec function ZoomIn()
{
   if(UDNPlayerCamera(PlayerCamera) != none)
   {
      UDNPlayerCamera(PlayerCamera).ZoomIn();
   }
}

//zoom out exec
exec function ZoomOut()
{
   if(UDNPlayerCamera(PlayerCamera) != none)
   {
      UDNPlayerCamera(PlayerCamera).ZoomOut();
   }
}

simulated function PostBeginPlay()
{
   local class<UDNControlModule> ControlClass;
   local UDNControlModule NewControlModule;

   Super.PostBeginPlay();

   ControlClass = class<UDNControlModule>( DynamicLoadObject( DefaultControlModuleClass, class'Class' ) );

   if(ControlClass != none)
   {
      // Associate module with PlayerController
      NewControlModule = new(Outer) ControlClass;
      NewControlModule.Controller = self;
      NewControlModule.Init();

      //call active/inactive functions on new/old modules
      if(ControlModule != none)
      {
         ControlModule.OnBecomeInactive(NewControlModule);
         NewControlModule.OnBecomeActive(ControlModule);
      }
      else
      {
         NewControlModule.OnBecomeActive(None);
      }

      ControlModule = NewControlModule;
   }
   else
   {
      `log("Couldn't get control module class!");
      // not having a Control Class is fine.  PlayerController will use default controls.
   }
}

state PlayerWalking
{
   function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
   {
      //Controller has a UDNPlayerCamera
      if(ControlModule != none)
      {
         //allow custom camera to override player movement
         ControlModule.ProcessMove(DeltaTime, NewAccel, DoubleClickMove, DeltaRot);
      }
        else
        {
         Super.ProcessMove(DeltaTime, NewAccel, DoubleClickMove, DeltaRot);
        }
      }
}

function UpdateRotation( float DeltaTime )
{
   //Controller has a UDNPlayerCamera
   if(ControlModule != none)
   {
      //allow custom camera to update our rotation
      ControlModule.UpdateRotation(DeltaTime);
   }
    else
    {
         Super.UpdateRotation(DeltaTime);
   }
}


/* GetPlayerViewPoint: Returns Player's Point of View
   For the AI this means the Pawn's Eyes ViewPoint
   For a Human player, this means the Camera's ViewPoint */
simulated event GetPlayerViewPoint( out vector POVLocation, out Rotator POVRotation )
{
   local float DeltaTime;
   local UTPawn P;

   P = IsLocalPlayerController() ? UTPawn(CalcViewActor) : None;

   if (LastCameraTimeStamp == WorldInfo.TimeSeconds
      && CalcViewActor == ViewTarget
      && CalcViewActor != None
      && CalcViewActor.Location == CalcViewActorLocation
      && CalcViewActor.Rotation == CalcViewActorRotation
      )
   {
      if ( (P == None) || ((P.EyeHeight == CalcEyeHeight) && (P.WalkBob == CalcWalkBob)) )
      {
         // use cached result
         POVLocation = CalcViewLocation;
         POVRotation = CalcViewRotation;
         return;
      }
   }

   DeltaTime = WorldInfo.TimeSeconds - LastCameraTimeStamp;
   LastCameraTimeStamp = WorldInfo.TimeSeconds;

   // support for using CameraActor views
   if ( CameraActor(ViewTarget) != None )
   {
      if ( PlayerCamera == None )
      {
         super.ResetCameraMode();
         SpawnCamera();
      }
      super.GetPlayerViewPoint( POVLocation, POVRotation );
   }
   else
   {
      //do not destroy our camera!!!
      /* if ( PlayerCamera != None )
      {
         PlayerCamera.Destroy();
         PlayerCamera = None;
      } */

      //no camera, we have view target - let view target be in control
      if ( PlayerCamera == None && ViewTarget != None )
      {
         POVRotation = Rotation;
         if ( (PlayerReplicationInfo != None) && PlayerReplicationInfo.bOnlySpectator && (UTVehicle(ViewTarget) != None) )
         {
            UTVehicle(ViewTarget).bSpectatedView = true;
            ViewTarget.CalcCamera( DeltaTime, POVLocation, POVRotation, FOVAngle );
            UTVehicle(ViewTarget).bSpectatedView = false;
         }
         else
         {
            ViewTarget.CalcCamera( DeltaTime, POVLocation, POVRotation, FOVAngle );
         }

         if ( bFreeCamera )
         {
            POVRotation = Rotation;
         }
      }
      //no camera, no view target - we are in control
      else if(PlayerCamera == None)
      {
         CalcCamera( DeltaTime, POVLocation, POVRotation, FOVAngle );
         return;
      }
      //we have a camera - let camera be in control
      else
      {
         POVLocation = PlayerCamera.ViewTarget.POV.Location;
         POVRotation = PlayerCamera.ViewTarget.POV.Rotation;
         FOVAngle = PlayerCamera.ViewTarget.POV.FOV;
      }
   }

   // apply view shake
   POVRotation = Normalize(POVRotation + ShakeRot);
   POVLocation += ShakeOffset >> Rotation;

   if( CameraEffect != none )
   {
      CameraEffect.UpdateLocation(POVLocation, POVRotation, GetFOVAngle());
   }


   // cache result
   CalcViewActor = ViewTarget;
   CalcViewActorLocation = ViewTarget.Location;
   CalcViewActorRotation = ViewTarget.Rotation;
   CalcViewLocation = POVLocation;
   CalcViewRotation = POVRotation;

   if ( P != None )
   {
      CalcEyeHeight = P.EyeHeight;
      CalcWalkBob = P.WalkBob;
   }
}

defaultproperties
{
   CameraClass=class'UDNExamples.UDNPlayerCamera'
   MatineeCameraClass=class'UDNExamples.UDNPlayerCamera'
}

Pawn クラス

新たな Pawn クラスは、 CalcCamera() 関数をオーバーライドすることによって単に FALSE を返すようにし、新たなカメラシステムが常にカメラの位置と回転を制御できるようにします。 BecomeViewTarget() および GetBaseAimRotation() 関数は、オーバーライドされることによって、それらの機能の処理をそれぞれ、カメラシステムとコントロールシステムに渡します。

UDNPawn.uc

class UDNPawn extends UTPawn;

/* BecomeViewTarget
   Called by Camera when this actor becomes its ViewTarget */
simulated event BecomeViewTarget( PlayerController PC )
{
   local UDNPlayerController UDNPC;

   UDNPC = UDNPlayerController(PC);

   //Pawn is controlled by a UDNPlayerController and has a UDNPlayerCamera
      if(UDNPC != none && UDNPlayerCamera(UDNPC.PlayerCamera) != none)
      {
      //allow custom camera to control mesh visibility, etc.
      UDNPlayerCamera(UDNPC.PlayerCamera).BecomeViewTarget(UDNPC);
      }
      else
      {
      Super.BecomeViewTarget(PC);
   }
}

/**
 *   Calculate camera view point, when viewing this pawn.
 *
 * @param   fDeltaTime   delta time seconds since last update
 * @param   out_CamLoc   Camera Location
 * @param   out_CamRot   Camera Rotation
 * @param   out_FOV      Field of View
 *
 * @return   true if Pawn should provide the camera point of view.
 */
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
   //return false to allow custom camera to control its location and rotation
      return false;
}

/**
 * returns base Aim Rotation without any adjustment (no aim error, no autolock, no adhesion.. just clean initial aim rotation!)
 *
 * @return   base Aim rotation.
 */
simulated singular event Rotator GetBaseAimRotation()
{
      local vector   POVLoc;
      local rotator   POVRot;
      local UDNPlayerController PC;

   PC = UDNPlayerController(Controller);

   //Pawn is controlled by a UDNPlayerController and has a UDNPlayerCamera
      if(PC != none && PC.ControlModule != none)
      {
      //allow custom camera to control aim rotation
      return PC.ControlModule.GetBaseAimRotation();
      }
      else
      {
         if( Controller != None && !InFreeCam() )
         {
            Controller.GetPlayerViewPoint(POVLoc, POVRot);
            return POVRot;
         }
         else
         {
            POVRot = Rotation;

            if( POVRot.Pitch == 0 )
            {
               POVRot.Pitch = RemoteViewPitch << 8;
            }

            return POVRot;
         }
      }
}


defaultproperties
{
}

GameInfo クラス

新たなゲームタイプ クラスは、UTDeathMatch クラスを拡張したベースとなるクラスであり、使用する新たな HUD 、Pawn 、PlayerController クラスを設定します。また、このクラスは、 bUseClassicHUD を TRUE にセットすることによって、UTGFxHUDWrapper (この bool 型がセットされていない場合に使用されるようにハードコード化されています) の代わりに、ここで指定される HUD クラスが使用されるようにします。

UDNGame.uc

class UDNGame extends UTDeathMatch;

defaultproperties
{
   DefaultPawnClass=class'UDNExamples.UDNPawn'
   PlayerControllerClass=class'UDNExamples.UDNPlayerController'
   MapPrefixes[0]="UDN"
}

カメラ モジュールの例

新たなカメラのフレームワーク例として、トップダウン (上方からの) カメラを構成します。新たなカメラ モジュールを作成するということは、およそ、ベースとなるカメラ モジュール クラスで定義されている関数を実装することに他なりません。上記 CalcCamera() 例をご覧になっている場合は、その多くが見慣れたものであるはずです。

UDNCameraModule_TopDown.uc

class UDNCameraModule_TopDown extends UDNCameraModule;

var float CamAltitude; //actual camera height offset from player
var float DesiredCamAltitude; //new height offset to move camera to
var float MaxCamAltitude; //maximum offset from player camera can be
var float MinCamAltitude; //minimum offset from player camera can be
var float CamZoomIncrement; //how many units to zoom with each click of mousewheel

//Calculate new camera location and rotation
function UpdateCamera(Pawn P, UDNPlayerCamera CameraActor, float DeltaTime, out TViewTarget OutVT)
{
   //interpolate to new camera offest if not there
   if(CamAltitude != DesiredCamAltitude)
   {
      CamAltitude += (DesiredCamAltitude - CamAltitude) * DeltaTime * 3;
   }

   //align camera to player with height (Z) offset
   OutVT.POV.Location = OutVT.Target.Location;
   OutVT.POV.Location.Z += CamAltitude;

   //set camera rotation - face down
   OutVT.POV.Rotation.Pitch = -16384;
   OutVT.POV.Rotation.Yaw = 0;
   OutVT.POV.Rotation.Roll = 0;
}

//initialize new view target
simulated function BecomeViewTarget( UDNPlayerController PC )
{
   if (LocalPlayer(PC.Player) != None)
      {
      //Set player mesh visible
        PC.SetBehindView(true);
        UDNPawn(PC.Pawn).SetMeshVisibility(PC.bBehindView);
        PC.bNoCrosshair = true;
      }
}

function ZoomIn()
{
   //decrease camera height
   DesiredCamAltitude -= CamZoomIncrement;

   //lock camera height to limits
   DesiredCamAltitude = FMin(MaxCamAltitude, FMax(MinCamAltitude, DesiredCamAltitude));
}

function ZoomOut()
{
   //increase camera height
   DesiredCamAltitude += CamZoomIncrement;

   //lock camera height to limits
   DesiredCamAltitude = FMin(MaxCamAltitude, FMax(MinCamAltitude, DesiredCamAltitude));
}

defaultproperties
{
   CamAltitude=384.0
   DesiredCamAltitude=384.0
   MaxCamAltitude=1024.0
   MinCamAltitude=160.0
   CamZoomIncrement=96.0
}

コントロール モジュールの例

UDNControlModule_TopDown.uc

class UDNControlModule_TopDown extends UDNControlModule;

//Calculate Pawn aim rotation
simulated singular function Rotator GetBaseAimRotation()
{
   local rotator   POVRot;

   //aim where Pawn is facing - lock pitch
      POVRot = Controller.Pawn.Rotation;
      POVRot.Pitch = 0;

      return POVRot;
}

//Handle custom player movement
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
   if( Controller.Pawn == None )
    {
       return;
    }

    if (Controller.Role == ROLE_Authority)
    {
       // Update ViewPitch for remote clients
        Controller.Pawn.SetRemoteViewPitch( Controller.Rotation.Pitch );
    }

    Controller.Pawn.Acceleration = NewAccel;


   Controller.CheckJumpOrDuck();
}

//Calculate controller rotation
function UpdateRotation(float DeltaTime)
{
   local Rotator   DeltaRot, NewRotation, ViewRotation;

      ViewRotation = Controller.Rotation;

   //rotate pawn to face cursor
      if (Controller.Pawn!=none)
      Controller.Pawn.SetDesiredRotation(ViewRotation);

      DeltaRot.Yaw   = Controller.PlayerInput.aTurn;
      DeltaRot.Pitch   = 0;

      Controller.ProcessViewRotation( DeltaTime, ViewRotation, DeltaRot );
      Controller.SetRotation(ViewRotation);

      NewRotation = ViewRotation;
      NewRotation.Roll = Controller.Rotation.Roll;

      if ( Controller.Pawn != None )
         Controller.Pawn.FaceRotation(NewRotation, DeltaTime);
}

defaultproperties
{
}

Config ファイル

以下のファイルはすべて、UDKgame/Config ディレクトリに置かれなければなりません。そのうちいくつかのファイルは新たに追加されるものなので、作成する必要があります。他のファイルは、新たなコンフィギュレーション設定項目を含むように修正するだけです。

DefaultCamera.ini ファイルは、新たなカメラクラスにあるconfig 変数の値で満たす必要があります。この例では、デフォルトのカメラ モジュール クラスをセットするだけです。

DefaultCamera.ini

[UDNExamples.UDNPlayerCamera]
DefaultCameraClass=UDNExamples.UDNCameraModule_TopDown

DefaultGame.ini ファイルでは、 [Engine.GameInfo] セクションを変更して、新たなゲームタイプを指すようにしなければなりません。また、最下部にセクションを追加して、使用すべきデフォルトのコントロール モジュール クラスを指定する必要があります。

DefaultGame.ini


...

[Engine.GameInfo]
DefaultGame=UDNExamples.UDNGame
DefaultServerGame=UDNExamples.UDNGame

...

[UDNExamples.UDNPlayerController]
DefaultControlModuleClass=UDNExamples.UDNControlModule_TopDown

これらが作成されるか、あるいは、望ましいコンフィギュレーション設定項目で満たされるか変更されるかすると、ゲームまたはエディタが次回起動したときに、新たな UDKCamera.ini ファイルと UDKGame.ini ファイルが作成されることになります。

注意 : 新たなゲームタイプが使用されるようにするには、マップに正しいプレイフィックスをつけるようにしなければなりません。 私たちのゲームタイプにおいては、プレイフィックスを UDN に設定しているので、すべてのマップが UDN- から始まるように命名する必要があります。エディタ内でどのようなマップであっても新たなゲームタイプを素早くテストすることができます。そのためには、マップのためのワールド プロパティ内にある Game Type PIE プロパティを、新たなゲームタイプにセットします。