UDN
Search public documentation:

DevelopmentKitGemsCreatingActorSelectionBoxesOrBracketsJP
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

Unreal Development Kit ホーム > Unreal Development Kit Gems > アクタ選択ボックスまたはブラケットの作成
UE3 ホーム > ユーザーインターフェースと HUD > アクタ選択ボックスまたはブラケットの作成

アクタ選択ボックスまたはブラケットの作成


2011年3月、UDK について最終テスト実施済み
PC および iOS 対応

概要


ゲームのオブジェクトの中には、スクリーン上でよりビジュアルな情報を表示することによって、プレイヤーが判断しやすくなるものがあります。そのような判断には、アイテムの選択や、ターゲットへの攻撃、ある種の情報の取得などが含まれます。

GameInfo


アクタ選択のレンダリングは、HUD 内で行われます。独自のカスタム HUD を使用するには、新たな game info を作成します。この新たな game info は、UTDeathMatch を継承することによって、テストを容易にします。デフォルトでは、UTDeathMatch は新たな ScaleForm HUD を使用します。 bUseClassicHUD を TRUE にセットすることによって、game info が「クラシックな」 HUD を使用します。 HUDType を新たな HUD クラスに設定すると、この新たな game info が完了します。

ASIGameInfo.uc
class ASIGameInfo extends UTDeathMatch;

defaultproperties
{
  bUseClassicHUD=true
  HUDType=class'ASIHUD'
}

関連テーマ

HUDInterface


付加的なチェックしたり、アクタから付加的な情報を取得したりするには、空のインターフェースが使用されます。また、アクタをキャストすることによって、アクタが当該のインターフェースを実装しているか否かを簡単にテストすることができます。実装している場合は、アクタ選択のインターフェースをレンダリングします。このことを独自のサブクラスでのみ実行する場合に便利です。長大な型キャストのブロックを書く必要がなくなります。

ASIHUDInterface.uc
interface ASIHUDInterface;

たとえば、インターフェース実装メソッドがない場合は、次のようにしなければなりません。

if (PawnSubClass(Actor) != None || VehicleSubClass(Actor) != None || DroppedPickupSubClass(Actor) != None)
{
  RenderActorSelection(Actor);
}

ご覧のとおり、行が進むにつれて大量の型キャストを実行するため、たいへんな無駄が生じています。また、追加した新たなクラスを自動的に選択できないので非常に不便でもあります。

実装メソッドを使用することによって自動的に ASIHUDInterface を実装するクラスをすべてサポートできます。また、追加する可能性のある将来のためのクラスを含めることができます。

if (ASIHUDInterface(Actor) != None)
{
  RenderActorSelection(Actor, ASIHUDInterface(Actor));
}

関連テーマ

HUD


プレイヤーの前にあるアクタを見つけるには、trace (トレース) を使用します。trace actors を使用するのは、プレイヤーの前に不可視なブロック アクタが存在する場合があるからです。trace actor のイタレーションの各結果については、フィルターが適用されることによって、適切なアクタが選択され、アクタ選択のインターフェースがレンダリングされるようにします。

ASIHUD.uc
class ASIHUD extends UTHUD;

event PostRender()
{
  local Actor HitActor;
  local Vector HitLocation, HitNormal, EyeLocation;
  local Rotator EyeRotation;

  Super.PostRender();

  // Ensure the player owner is set
  if (PlayerOwner != None)
  {
    // Retrieve the player camera location and rotation
    PlayerOwner.GetPlayerViewPoint(EyeLocation, EyeRotation);

    // Perform a trace to find what the player is looking at
    // Use trace actors so that we can ignore unimportant objects
    ForEach TraceActors
    (
      class'Actor',
      HitActor,
      HitLocation,
      HitNormal,
      EyeLocation + Vector(EyeRotation) * PlayerOwner.InteractDistance,
      EyeLocation,
      Vect(1.f, 1.f, 1.f),,
      TRACEFLAG_Bullet
    )
    {
      // If the hit actor is the player owner, the player owner's pawn or the hit actor isn't visible
      if (HitActor == PlayerOwner || HitActor == PlayerOwner.Pawn || !FastTrace(HitActor.Location, EyeLocation))
      {
        // Ignore this hit actor
        continue;
      }

      // Render the actor selection here
    }
  }
}

プレイヤーが見ているアクタが検知されると、選択ボックスまたはブラケット (角カッコ) が描画されます。選択のレンダリング形式は HUD 内部で設定されますが、選択がどの形式としてレンダリングされるかを ASIHUDInterface に返させるのは些細な問題です。次のように、列挙型変数を使用して選択のレンダリング形式をセットします。

enum EActorBracketStyle
{
   EABS_2DActorBrackets,
   EABS_3DActorBrackets,
   EABS_2DBox,
   EABS_3DBox,
   EABS_3DCircle
};

var EActorBracketStyle ActorBracketStyle;

最後に、switch 文を使用して、ActorBracketStyle の値によって決定されるレンダリング形式をデリゲートします。(今振り返ってみると、deligate を使用することもできました)。

      // Render the actor selection here
      // Test what rendering style we want
      switch (ActorBracketStyle)
      {
      case EABS_2DActorBrackets:
   RenderTwoDeeActorBrackets(HitActor, HUDInterface);
   break;

      case EABS_3DActorBrackets:
   RenderThreeDeeActorBrackets(HitActor, HUDInterface);
   break;

      case EABS_2DBox:
   RenderTwoDeeBox(HitActor, HUDInterface);
   break;

      case EABS_3DBox:
   RenderThreeDeeBox(HitActor, HUDInterface);
   break;

      case EABS_3DCircle:
   RenderThreeDeeCircle(HitActor, HUDInterface);
   break;

      default:
   break;
      }

      break;

関連テーマ

2D 領域の計算


2D ボックスまたは 2D ブラケットの選択をレンダリングするには、アクタ コンポーネント バウンディングボックスの 2D 表現を計算する必要があります。そのためには、各ボックスの座標を投影して、各ボックスの座標空間を取得します。各 X、Y 座標の投影については、各座標の最小と最大が検知されます。

ASIHUD.uc
function Box GetTwoDeeActorBoundingBox(Actor Actor)
{
  local Box ComponentsBoundingBox, OutBox;
  local Vector BoundingBoxCoordinates[8];
  local int i;

  Actor.GetComponentsBoundingBox(ComponentsBoundingBox);

  // Z1
  // X1, Y1
  BoundingBoxCoordinates[0].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[0].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[0].Z = ComponentsBoundingBox.Min.Z;
  BoundingBoxCoordinates[0] = Canvas.Project(BoundingBoxCoordinates[0]);
  // X2, Y1
  BoundingBoxCoordinates[1].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[1].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[1].Z = ComponentsBoundingBox.Min.Z;
  BoundingBoxCoordinates[1] = Canvas.Project(BoundingBoxCoordinates[1]);
  // X1, Y2
  BoundingBoxCoordinates[2].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[2].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[2].Z = ComponentsBoundingBox.Min.Z;
  BoundingBoxCoordinates[2] = Canvas.Project(BoundingBoxCoordinates[2]);
  // X2, Y2
  BoundingBoxCoordinates[3].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[3].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[3].Z = ComponentsBoundingBox.Min.Z;
  BoundingBoxCoordinates[3] = Canvas.Project(BoundingBoxCoordinates[3]);

  // Z2
  // X1, Y1
  BoundingBoxCoordinates[4].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[4].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[4].Z = ComponentsBoundingBox.Max.Z;
  BoundingBoxCoordinates[4] = Canvas.Project(BoundingBoxCoordinates[4]);
  // X2, Y1
  BoundingBoxCoordinates[5].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[5].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[5].Z = ComponentsBoundingBox.Max.Z;
  BoundingBoxCoordinates[5] = Canvas.Project(BoundingBoxCoordinates[5]);
  // X1, Y2
  BoundingBoxCoordinates[6].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[6].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[6].Z = ComponentsBoundingBox.Max.Z;
  BoundingBoxCoordinates[6] = Canvas.Project(BoundingBoxCoordinates[6]);
  // X2, Y2
  BoundingBoxCoordinates[7].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[7].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[7].Z = ComponentsBoundingBox.Max.Z;
  BoundingBoxCoordinates[7] = Canvas.Project(BoundingBoxCoordinates[7]);

  // Find the left, top, right and bottom coordinates
  OutBox.Min.X = Canvas.ClipX;
  OutBox.Min.Y = Canvas.ClipY;
  OutBox.Max.X = 0;
  OutBox.Max.Y = 0;

  // Iterate though the bounding box coordinates
  for (i = 0; i < ArrayCount(BoundingBoxCoordinates); ++i)
  {
    // Detect the smallest X coordinate
    if (OutBox.Min.X > BoundingBoxCoordinates[i].X)
    {
      OutBox.Min.X = BoundingBoxCoordinates[i].X;
    }

    // Detect the smallest Y coordinate
    if (OutBox.Min.Y > BoundingBoxCoordinates[i].Y)
    {
      OutBox.Min.Y = BoundingBoxCoordinates[i].Y;
    }

    // Detect the largest X coordinate
    if (OutBox.Max.X < BoundingBoxCoordinates[i].X)
    {
      OutBox.Max.X = BoundingBoxCoordinates[i].X;
    }

    // Detect the largest Y coordinate
    if (OutBox.Max.Y < BoundingBoxCoordinates[i].Y)
    {
      OutBox.Max.Y = BoundingBoxCoordinates[i].Y;
    }
  }

  return OutBox;
}

関連テーマ

2D 選択ボックス


2D 選択ボックスを使用して選択されたアクタ

ActorSelection2DBox.jpg

この形式でレンダリングするために、アクタ コンポーネント バウンディングボックスがキャンバス スペース上に投影されます。そこから、投影されたバウンディングボックスを表すボックスが簡単にレンダリングされます。

ASIHUD.uc
function RenderTwoDeeBox(Actor Actor, ASIHUDInterface HUDInterface)
{
  local Box ActorBoundingBox;

  if (Canvas == None || Actor == None)
  {
    return;
  }

  ActorBoundingBox = GetTwoDeeActorBoundingBox(Actor);

  // Draw the actor brackets
  Canvas.SetDrawColor(255, 255, 255);
  // Top left position
  Canvas.SetPos(ActorBoundingBox.Min.X, ActorBoundingBox.Min.Y);
  // Draw the box
  Canvas.DrawBox
  (
    (ActorBoundingBox.Max.X - ActorBoundingBox.Min.X),
    (ActorBoundingBox.Max.Y - ActorBoundingBox.Min.Y)
  );
}

2D 選択ブラケット


2D 選択ブラケットを使用して選択されたアクタ

ActorSelection2DBracket.jpg

この形式でレンダリングするために、アクタ コンポーネント バウンディングボックスがキャンバス スペース上に投影されます。そこから、ブラケットの各コーナーがレンダリングされます。

ASIHUD.uc
function RenderTwoDeeActorBrackets(Actor Actor, ASIHUDInterface HUDInterface)
{
  local Box ActorBoundingBox;
  local int ActualWidth, ActualHeight;

  if (Canvas == None || Actor == None)
  {
    return;
  }

  ActorBoundingBox = GetTwoDeeActorBoundingBox(Actor);

  // Calculate the width and height
  ActualWidth = (ActorBoundingBox.Max.X - ActorBoundingBox.Min.X) * 0.3f;
  ActualHeight = (ActorBoundingBox.Max.Y - ActorBoundingBox.Min.Y) * 0.3f;

  // Draw the actor brackets
  Canvas.SetDrawColor(255, 255, 255);

  // Top left
  Canvas.SetPos(ActorBoundingBox.Min.X, ActorBoundingBox.Min.Y);
  Canvas.DrawRect(ActualWidth, 2);
  Canvas.SetPos(ActorBoundingBox.Min.X, ActorBoundingBox.Min.Y);
  Canvas.DrawRect(2, ActualHeight);

  // Top right
  Canvas.SetPos(ActorBoundingBox.Max.X - ActualWidth - 2, ActorBoundingBox.Min.Y);
  Canvas.DrawRect(ActualWidth, 2);
  Canvas.SetPos(ActorBoundingBox.Max.X - 2, ActorBoundingBox.Min.Y);
  Canvas.DrawRect(2, ActualHeight);

  // Bottom left
  Canvas.SetPos(ActorBoundingBox.Min.X, ActorBoundingBox.Max.Y - 2);
  Canvas.DrawRect(ActualWidth, 2);
  Canvas.SetPos(ActorBoundingBox.Min.X, ActorBoundingBox.Max.Y - ActualHeight - 2);
  Canvas.DrawRect(2, Actualheight);

  // Bottom right
  Canvas.SetPos(ActorBoundingBox.Max.X - ActualWidth - 2, ActorBoundingBox.Max.Y - 2);
  Canvas.DrawRect(ActualWidth + 2, 2);
  Canvas.SetPos(ActorBoundingBox.Max.X - 2, ActorBoundingBox.Max.Y - ActualHeight - 2);
  Canvas.DrawRect(2, ActualHeight + 2);
}

3D 選択ボックス


3D 選択ボックスを使用して選択されたアクタ

ActorSelection3DBox.jpg

3D 選択ボックスをレンダリングするために、ここでは、HUD 内にある Draw3DLine 関数が使用されています。この関数は、1 ピクセル幅のラインだけしか描画できないという制限があります。この制限をなくすには、バウンディングボックスの座標それぞれをキャンバス空間に投影し、さらに 2D のラインを描画します。

ASIHUD.uc
function RenderThreeDeeBox(Actor Actor, ASIHUDInterface HUDInterface)
{
  local Box ComponentsBoundingBox;
  local Vector BoundingBoxCoordinates[8];
  local int i;

  if (Actor == None)
  {
    return;
  }

  Actor.GetComponentsBoundingBox(ComponentsBoundingBox);

  // Z1
  // X1, Y1
  BoundingBoxCoordinates[0].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[0].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[0].Z = ComponentsBoundingBox.Min.Z;
  // X2, Y1
  BoundingBoxCoordinates[1].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[1].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[1].Z = ComponentsBoundingBox.Min.Z;
  // X2, Y2
  BoundingBoxCoordinates[2].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[2].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[2].Z = ComponentsBoundingBox.Min.Z;
  // X1, Y2
  BoundingBoxCoordinates[3].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[3].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[3].Z = ComponentsBoundingBox.Min.Z;

  // Z2
  // X1, Y1
  BoundingBoxCoordinates[4].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[4].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[4].Z = ComponentsBoundingBox.Max.Z;
  // X2, Y1
  BoundingBoxCoordinates[5].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[5].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[5].Z = ComponentsBoundingBox.Max.Z;
  // X2, Y2
  BoundingBoxCoordinates[6].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[6].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[6].Z = ComponentsBoundingBox.Max.Z;
  // X1, Y2
  BoundingBoxCoordinates[7].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[7].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[7].Z = ComponentsBoundingBox.Max.Z;

  for (i = 0; i < 4; ++i)
  {
    Draw3DLine(BoundingBoxCoordinates[i], BoundingBoxCoordinates[(i == 3) ? 0 : i + 1], class'HUD'.default.WhiteColor);
  }

  for (i = 4; i < 8; ++i)
  {
    Draw3DLine(BoundingBoxCoordinates[i], BoundingBoxCoordinates[(i == 7) ? 4 : i + 1], class'HUD'.default.WhiteColor);
  }

  for (i = 0; i < 4; ++i)
  {
    Draw3DLine(BoundingBoxCoordinates[i], BoundingBoxCoordinates[i + 4], class'HUD'.default.WhiteColor);
  }
}
</pre>
</div>

---++ 3D 選択ブラケット
<div style="margin-top:-10px;" ><hr size="1" noshade="noshade"></div>
3D 選択ブラケットを使用して選択されたアクタ

<img src="%PUBURL%/%WEB%/DevelopmentKitGemsCreatingActorSelectionBoxesOrBrackets/ActorSelection3DBracket.jpg" alt="ActorSelection3DBracket.jpg" width='700' height='700' />

3D 選択ブラケットをレンダリングするために、HUD 内にある Draw3DLine が使用されました。繰り返しになりますが、この制限をなくすには、必要な座標すべてをスクリーン空間に投影し、さらに 2D のラインを描画します。この選択形式をレンダリングするためには、まず内部の座標を計算し、さらにラインを描画しました。

<div class="codetitlebar">
ASIHUD.uc
</div>
<div class="codesnippet">
<verbatim>
function RenderThreeDeeActorBrackets(Actor Actor, ASIHUDInterface HUDInterface)
{
  local Box ComponentsBoundingBox;
  local Vector BoundingBoxCoordinates[8], InnerBoxCoordinates[8];
  local int i;
  local float f;

  if (Actor == None)
  {
    return;
  }

  Actor.GetComponentsBoundingBox(ComponentsBoundingBox);

  // Z1
  // X1, Y1
  BoundingBoxCoordinates[0].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[0].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[0].Z = ComponentsBoundingBox.Min.Z;
  // X2, Y1
  BoundingBoxCoordinates[1].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[1].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[1].Z = ComponentsBoundingBox.Min.Z;
  // X2, Y2
  BoundingBoxCoordinates[2].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[2].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[2].Z = ComponentsBoundingBox.Min.Z;
  // X1, Y2
  BoundingBoxCoordinates[3].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[3].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[3].Z = ComponentsBoundingBox.Min.Z;

  // Z2
  // X1, Y1
  BoundingBoxCoordinates[4].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[4].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[4].Z = ComponentsBoundingBox.Max.Z;
  // X2, Y1
  BoundingBoxCoordinates[5].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[5].Y = ComponentsBoundingBox.Min.Y;
  BoundingBoxCoordinates[5].Z = ComponentsBoundingBox.Max.Z;
  // X2, Y2
  BoundingBoxCoordinates[6].X = ComponentsBoundingBox.Max.X;
  BoundingBoxCoordinates[6].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[6].Z = ComponentsBoundingBox.Max.Z;
  // X1, Y2
  BoundingBoxCoordinates[7].X = ComponentsBoundingBox.Min.X;
  BoundingBoxCoordinates[7].Y = ComponentsBoundingBox.Max.Y;
  BoundingBoxCoordinates[7].Z = ComponentsBoundingBox.Max.Z;

  // Calc inner X
  f = VSize(BoundingBoxCoordinates[4] - BoundingBoxCoordinates[5]) * 0.3f;

  // Z1
  // X1, Y1
  InnerBoxCoordinates[0].X = ComponentsBoundingBox.Min.X + f;
  InnerBoxCoordinates[0].Y = ComponentsBoundingBox.Min.Y;
  InnerBoxCoordinates[0].Z = ComponentsBoundingBox.Min.Z;
  // X2, Y1
  InnerBoxCoordinates[1].X = ComponentsBoundingBox.Max.X - f;
  InnerBoxCoordinates[1].Y = ComponentsBoundingBox.Min.Y;
  InnerBoxCoordinates[1].Z = ComponentsBoundingBox.Min.Z;
  // X2, Y2
  InnerBoxCoordinates[2].X = ComponentsBoundingBox.Max.X - f;
  InnerBoxCoordinates[2].Y = ComponentsBoundingBox.Max.Y;
  InnerBoxCoordinates[2].Z = ComponentsBoundingBox.Min.Z;
  // X1, Y2
  InnerBoxCoordinates[3].X = ComponentsBoundingBox.Min.X + f;
  InnerBoxCoordinates[3].Y = ComponentsBoundingBox.Max.Y;
  InnerBoxCoordinates[3].Z = ComponentsBoundingBox.Min.Z;

  // Z2
  // X1, Y1
  InnerBoxCoordinates[4].X = ComponentsBoundingBox.Min.X + f;
  InnerBoxCoordinates[4].Y = ComponentsBoundingBox.Min.Y;
  InnerBoxCoordinates[4].Z = ComponentsBoundingBox.Max.Z;
  // X2, Y1
  InnerBoxCoordinates[5].X = ComponentsBoundingBox.Max.X - f;
  InnerBoxCoordinates[5].Y = ComponentsBoundingBox.Min.Y;
  InnerBoxCoordinates[5].Z = ComponentsBoundingBox.Max.Z;
  // X2, Y2
  InnerBoxCoordinates[6].X = ComponentsBoundingBox.Max.X - f;
  InnerBoxCoordinates[6].Y = ComponentsBoundingBox.Max.Y;
  InnerBoxCoordinates[6].Z = ComponentsBoundingBox.Max.Z;
  // X1, Y2
  InnerBoxCoordinates[7].X = ComponentsBoundingBox.Min.X + f;
  InnerBoxCoordinates[7].Y = ComponentsBoundingBox.Max.Y;
  InnerBoxCoordinates[7].Z = ComponentsBoundingBox.Max.Z;

  for (i = 0; i < 8; ++i)
  {
    Draw3DLine(BoundingBoxCoordinates[i], InnerBoxCoordinates[i], class'HUD'.default.WhiteColor);
  }

  // Calc inner Y
  f = VSize(BoundingBoxCoordinates[4] - BoundingBoxCoordinates[7]) * 0.3f;

  // Z1
  // X1, Y1
  InnerBoxCoordinates[0].X = ComponentsBoundingBox.Min.X;
  InnerBoxCoordinates[0].Y = ComponentsBoundingBox.Min.Y + f;
  InnerBoxCoordinates[0].Z = ComponentsBoundingBox.Min.Z;
  // X2, Y1
  InnerBoxCoordinates[1].X = ComponentsBoundingBox.Max.X;
  InnerBoxCoordinates[1].Y = ComponentsBoundingBox.Min.Y + f;
  InnerBoxCoordinates[1].Z = ComponentsBoundingBox.Min.Z;
  // X2, Y2
  InnerBoxCoordinates[2].X = ComponentsBoundingBox.Max.X;
  InnerBoxCoordinates[2].Y = ComponentsBoundingBox.Max.Y - f;
  InnerBoxCoordinates[2].Z = ComponentsBoundingBox.Min.Z;
  // X1, Y2
  InnerBoxCoordinates[3].X = ComponentsBoundingBox.Min.X;
  InnerBoxCoordinates[3].Y = ComponentsBoundingBox.Max.Y - f;
  InnerBoxCoordinates[3].Z = ComponentsBoundingBox.Min.Z;

  // Z2
  // X1, Y1
  InnerBoxCoordinates[4].X = ComponentsBoundingBox.Min.X;
  InnerBoxCoordinates[4].Y = ComponentsBoundingBox.Min.Y + f;
  InnerBoxCoordinates[4].Z = ComponentsBoundingBox.Max.Z;
  // X2, Y1
  InnerBoxCoordinates[5].X = ComponentsBoundingBox.Max.X;
  InnerBoxCoordinates[5].Y = ComponentsBoundingBox.Min.Y + f;
  InnerBoxCoordinates[5].Z = ComponentsBoundingBox.Max.Z;
  // X2, Y2
  InnerBoxCoordinates[6].X = ComponentsBoundingBox.Max.X;
  InnerBoxCoordinates[6].Y = ComponentsBoundingBox.Max.Y - f;
  InnerBoxCoordinates[6].Z = ComponentsBoundingBox.Max.Z;
  // X1, Y2
  InnerBoxCoordinates[7].X = ComponentsBoundingBox.Min.X;
  InnerBoxCoordinates[7].Y = ComponentsBoundingBox.Max.Y - f;
  InnerBoxCoordinates[7].Z = ComponentsBoundingBox.Max.Z;

  for (i = 0; i < 8; ++i)
  {
    Draw3DLine(BoundingBoxCoordinates[i], InnerBoxCoordinates[i], class'HUD'.default.WhiteColor);
  }

  // Calc inner Z
  f = VSize(BoundingBoxCoordinates[0] - BoundingBoxCoordinates[4]) * 0.3f;

  // Z1
  // X1, Y1
  InnerBoxCoordinates[0].X = ComponentsBoundingBox.Min.X;
  InnerBoxCoordinates[0].Y = ComponentsBoundingBox.Min.Y;
  InnerBoxCoordinates[0].Z = ComponentsBoundingBox.Min.Z + f;
  // X2, Y1
  InnerBoxCoordinates[1].X = ComponentsBoundingBox.Max.X;
  InnerBoxCoordinates[1].Y = ComponentsBoundingBox.Min.Y;
  InnerBoxCoordinates[1].Z = ComponentsBoundingBox.Min.Z + f;
  // X2, Y2
  InnerBoxCoordinates[2].X = ComponentsBoundingBox.Max.X;
  InnerBoxCoordinates[2].Y = ComponentsBoundingBox.Max.Y;
  InnerBoxCoordinates[2].Z = ComponentsBoundingBox.Min.Z + f;
  // X1, Y2
  InnerBoxCoordinates[3].X = ComponentsBoundingBox.Min.X;
  InnerBoxCoordinates[3].Y = ComponentsBoundingBox.Max.Y;
  InnerBoxCoordinates[3].Z = ComponentsBoundingBox.Min.Z + f;

  // Z2
  // X1, Y1
  InnerBoxCoordinates[4].X = ComponentsBoundingBox.Min.X;
  InnerBoxCoordinates[4].Y = ComponentsBoundingBox.Min.Y;
  InnerBoxCoordinates[4].Z = ComponentsBoundingBox.Max.Z - f;
  // X2, Y1
  InnerBoxCoordinates[5].X = ComponentsBoundingBox.Max.X;
  InnerBoxCoordinates[5].Y = ComponentsBoundingBox.Min.Y;
  InnerBoxCoordinates[5].Z = ComponentsBoundingBox.Max.Z - f;
  // X2, Y2
  InnerBoxCoordinates[6].X = ComponentsBoundingBox.Max.X;
  InnerBoxCoordinates[6].Y = ComponentsBoundingBox.Max.Y;
  InnerBoxCoordinates[6].Z = ComponentsBoundingBox.Max.Z - f;
  // X1, Y2
  InnerBoxCoordinates[7].X = ComponentsBoundingBox.Min.X;
  InnerBoxCoordinates[7].Y = ComponentsBoundingBox.Max.Y;
  InnerBoxCoordinates[7].Z = ComponentsBoundingBox.Max.Z - f;

  for (i = 0; i < 8; ++i)
  {
    Draw3DLine(BoundingBoxCoordinates[i], InnerBoxCoordinates[i], class'HUD'.default.WhiteColor);
  }
}
</verbatim>
</div>

---++ 3D 選択サークル
<div style="margin-top:-10px;" ><hr size="1" noshade="noshade"></div>
3D 選択サークルを使用して選択されたアクタ

<img src="%PUBURL%/%WEB%/DevelopmentKitGemsCreatingActorSelectionBoxesOrBrackets/ActorSelection3DCircle.jpg" alt="ActorSelection3DCircle.jpg" width='700' height='700' />

この選択形式では、HUD 内にある Draw3DLine 関数を使用します。繰り返しますが、オフセットのすべてをキャンバス空間座標に投影し、さらに 2D のラインを描画することが可能です。オフセットすべては、ベクターの Z 成分を増加させることによって調整されています。これによってサークルが上方に移動できるようになります。ベクターのオフセットを他に追加することによって、サークルの位置を変更することが可能です。サークル内部にある点の数を増加させるには、計算されている点の数を調整しなければなりません。それには、Unreal の回転単位で、ヨーのインクリメントの値を増加 / 減少させます。(現在の値は 4096 です)。また、オフセット配列のサイズを増加させることによって、ヨーのインクリメントの値に合致するようにします。(現在は、16, 65536/4096 です)。

<div class="codetitlebar">
ASIHUD.uc
</div>
<div class="codesnippet">
<verbatim>
  local Rotator Angle;
  local Vector Radius, Offsets[16];
  local Box ComponentsBoundingBox;
  local float Width, Height;
  local int i;

  if (Actor == None)
  {
    return;
  }

  Actor.GetComponentsBoundingBox(ComponentsBoundingBox);

  Width = ComponentsBoundingBox.Max.X - ComponentsBoundingBox.Min.X;
  Height = ComponentsBoundingBox.Max.Y - ComponentsBoundingBox.Min.Y;

  Radius.X = (Width > Height) ? Width : Height;
  i = 0;

  for (Angle.Yaw = 0; Angle.Yaw < 65536; Angle.Yaw += 4096)
  {
    // Calculate the offset
    Offsets[i] = Actor.Location + (Radius >> Angle) + Vect(0.f, 0.f, 16.f);
    i++;
  }

  // Draw all of the lines
  for (i = 0; i < ArrayCount(Offsets); ++i)
  {
    if (i == ArrayCount(Offsets) - 1)
    {
      Draw3DLine(Offsets[i], Offsets[0], class'HUD'.default.WhiteColor);
    }
    else
    {
      Draw3DLine(Offsets[i], Offsets[i + 1], class'HUD'.default.WhiteColor);
    }
  }
}
</verbatim>
</div>

---++ テスト
<div style="margin-top:-10px;" ><hr size="1" noshade="noshade"></div>
この機能をテストするには、DM-Deck をロードし、PIE game type を ASIGameInfo に設定します。保存してプレイします。

---+++ 関連テーマ
   * [[PlayInEditorJP][Play In Editor]]

---++ ダウンロード
<div style="margin-top:-10px;" ><hr size="1" noshade="noshade"></div>
   * UnrealScript のコードは、 [[%PUBURL%/%WEB%/DevelopmentKitGemsCreatingActorSelectionBoxesOrBrackets/ActorSelectionInterface.zip][ここから]] ダウンロードすることができます。  (ActorSelectionInterface.zip)

</noautolink>