UDN
Search public documentation:

DevelopmentKitGemsCreatingActorSelectionBoxesOrBracketsCH
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

虚幻开发工具包 > 虚幻开发工具包精华文章 > 创建 actor 选择框
UE3 主页 > 用户界面 & HUD > 创建 actor 选择框

创建 actor 选择方框


最后一次测试是在2011年3月份的UDK版本上进行的。
可以与 PC 和 iOS 兼容

概述


某些游戏对象需要画面上更多直观的信息,它们可以帮助玩家进行决策。这些决策的范围可以从选取一个物品到袭击目标或获取一些其他种类的信息。

GameInfo


在 HUD 内对 actor 选项进行渲染。为了使用我们自己定义的 HUD,需要创建一个新的游戏 info 类。这个新的游戏 info 类可以扩展 UTDeathMatch,使其更易于进行测试。默认情况下,UTDeathMatch 将会使用较新的 ScaleForm HUD。将 bUseClassicHUD 设置为 true 将强制游戏 info 类使用‘典型’HUD。将 HUDType 设置为新的 HUD 类并完成这个新的游戏 info 类。

ASIGameInfo.uc
class ASIGameInfo extends UTDeathMatch;

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

相关主题

HUDInterface


可以使用空白界面进行多余的检查或检索 actor 中多余的信息。投射 actor 测试他们是否可以执行这个界面相对来说也会更简单,如果他们可以执行,那么您可以渲染 actor 选择界面。它在您只想要在您自己的子类上执行这个界面的情况下有效。这样做可以阻止大型投射块。

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


为了找到玩家前面的 actor,需要使用跟踪。使用跟踪 actor 的原因是偶尔不可见的阻塞 actor 可能会在玩家前面。对于跟踪 actor 迭代的每个结果,采用过滤器可以确保在 actor 选择界面上选择了合适的 actor 进行渲染。

ASIHUD.uc
class ASIHUD extends UTHUD;

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

  Super.PostRender();

  // 确保对玩家所有者进行设置
  if (PlayerOwner != None)
  {
    // 获取玩家相机位置和旋转量
    PlayerOwner.GetPlayerViewPoint(EyeLocation, EyeRotation);

    // 执行跟踪找出这个玩家查看的地方
    // 使用跟踪 actor,这样我们可以忽略不重要的对象
    ForEach TraceActors
    (
      class'Actor',
      HitActor,
      HitLocation,
      HitNormal,
      EyeLocation + Vector(EyeRotation) * PlayerOwner.InteractDistance,
      EyeLocation,
      Vect(1.f, 1.f, 1.f),,
      TRACEFLAG_Bullet
    )
    {
      // 如果点击 actor 是玩家所有者,那么这个玩家所有者的 pawn 或点击 actor 不可见
      if (HitActor == PlayerOwner || HitActor == PlayerOwner.Pawn || !FastTrace(HitActor.Location, EyeLocation))
      {
        // 忽略这个点击 actor
        continue;
      }

      // 在这里渲染这个 actor 选择
    }
  }
}

只要检测到玩家正在观看的 actor 后,就会马上出现选择方框。选择渲染类型要在 HUD 中进行设置,但是可以轻而易举地使 ASIHUDInterface 返回选择物渲染的类型。在这里,使用一个枚举变量设置选择物渲染类型。

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

var EActorBracketStyle ActorBracketStyle;

最后,使用一个开关代表由 ActorBracketStyle 值确定的渲染类型。(补充说明,同时还使用了代理)。

// 在这里渲染这个 actor 选择
// 测试我们想要使用的渲染类型
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;
}

相关主题

2D 边界计算


要渲染 2D 方框选择物,必须计算 actor 组件边界盒的 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]);

  // 找出左方、顶部、右方和底部坐标
  OutBox.Min.X = Canvas.ClipX;
  OutBox.Min.Y = Canvas.ClipY;
  OutBox.Max.X = 0;
  OutBox.Max.Y = 0;

  // 遍历边界盒坐标
  for (i = 0; i < ArrayCount(BoundingBoxCoordinates); ++i)
  {
    // 检测最小的 X 坐标
    if (OutBox.Min.X > BoundingBoxCoordinates[i].X)
    {
      OutBox.Min.X = BoundingBoxCoordinates[i].X;
    }

    // 检测最小的 Y 坐标
    if (OutBox.Min.Y > BoundingBoxCoordinates[i].Y)
    {
      OutBox.Min.Y = BoundingBoxCoordinates[i].Y;
    }

    // 检测最大的 X 坐标
    if (OutBox.Max.X < BoundingBoxCoordinates[i].X)
    {
      OutBox.Max.X = BoundingBoxCoordinates[i].X;
    }

    // 检测最大的 Y 坐标
    if (OutBox.Max.Y < BoundingBoxCoordinates[i].Y)
    {
      OutBox.Max.Y = BoundingBoxCoordinates[i].Y;
    }
  }

  return OutBox;
}

相关主题

2D 选择框(实线框)


使用 2D 选择方框选中的 Actor

ActorSelection2DBox.jpg

为了渲染这种类型,需要将 actor 组件边界盒投影到画布空间。在这里,只渲染可以表示投影的边界盒的方框。

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

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

  ActorBoundingBox = GetTwoDeeActorBoundingBox(Actor);

  // 绘制 actor 框
  Canvas.SetDrawColor(255, 255, 255);
  // 左上方位置
  Canvas.SetPos(ActorBoundingBox.Min.X, ActorBoundingBox.Min.Y);
  // 绘制这个方框
  Canvas.DrawBox
  (
    (ActorBoundingBox.Max.X - ActorBoundingBox.Min.X),
    (ActorBoundingBox.Max.Y - ActorBoundingBox.Min.Y)
  );
}

2D 选择框(虚线框)


使用 2D 选择框选中的 Actor

ActorSelection2DBracket.jpg

为了渲染这种类型,需要将 actor 组件边界盒投影到画布空间。在这里会渲染框的每个角。

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

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

  ActorBoundingBox = GetTwoDeeActorBoundingBox(Actor);

  // 计算宽度和高度
  ActualWidth = (ActorBoundingBox.Max.X - ActorBoundingBox.Min.X) * 0.3f;
  ActualHeight = (ActorBoundingBox.Max.Y - ActorBoundingBox.Min.Y) * 0.3f;

  // 绘制 actor 框
  Canvas.SetDrawColor(255, 255, 255);

  // 左上方
  Canvas.SetPos(ActorBoundingBox.Min.X, ActorBoundingBox.Min.Y);
  Canvas.DrawRect(ActualWidth, 2);
  Canvas.SetPos(ActorBoundingBox.Min.X, ActorBoundingBox.Min.Y);
  Canvas.DrawRect(2, ActualHeight);

  // 右上方
  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);

  // 左下方
  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);

  // 右下方
  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 选择方框选中的 Actor

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);
  }
}

3D 选择框(虚线框)


使用 3D 选择框选中的 Actor

ActorSelection3DBracket.jpg

要渲染 3D 框选择框,请在这里 HUD 中使用 Draw3DLine 函数。其次,您可以通过将所有必需的坐标投影到屏幕空间然后绘制 2D 线来解决这个局限性问题。要渲染这种选择类型,必须首先计算内层坐标,然后绘制线。

ASIHUD.uc
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;

  // 计算内层 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);
  }

  // 计算内层 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);
  }

  // 计算内层 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);
  }
}

3D 选择圆圈


使用 3D 选择圆圈选中的 Actor

ActorSelection3DCircle.jpg

这种选择类型可以使用 HUD 中的 Draw3DLine 函数。此外,还可以将所有偏移投影到画布空间坐标中,然后绘制 2D 线。通过增加这个向量的 Z 分量调整了所有偏移。它可以帮助向上移动圆圈。通过添加其他向量偏移,您可以转换圆圈的位置。要则增加圆圈内的点数,您需要调整进行计算的点数。可以通过增加或减少相片旋角增量值(虚幻旋转单位,当前为 4096)进行这项操作。您还需要增加偏移数组的大小,以匹配相片旋角增量值(当前为 16, 65536/4096)。

ASIHUD.uc
function RenderThreeDeeCircle(Actor Actor, ASIHUDInterface HUDInterface)
{
  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)
  {
    // 计算偏移
    Offsets[i] = Actor.Location + (Radius >> Angle) + Vect(0.f, 0.f, 16.f);
    i++;
  }

  // 描画所有线
  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);
    }
  }
}

测试


要测试这项功能,请加载 DM-Deck 并将 PIE 游戏类型设置为 ASIGameInfo。保存并播放。

相关主题

下载


  • 下载 unrealscript 代码。(ActorSelectionInterface.zip)