UDN
Search public documentation:

DevelopmentKitGemsCreatingADynamicNavMeshObstacleCH
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 主页 > 虚幻开发工具包精华文章 > 创建动态导航网格物体障碍物
UE3主页 > AI & 导航 > 创建动态导航网格物体障碍物


创建动态导航网格物体障碍物


使用2011 年 6 月的UDK版本进行了最后测试
可以与 PC 和 iOS 兼容

概述


导航网格物体有很多有益的功能,这些功能使它远远优于以前的路径节点系统。其中一个最好的功能是它可以真正轻而易举地实时定义障碍物。

以前的路径节点系统通过关闭路径节点实现了这个功能,这样路径就不会使用它,因为这样做通常会产生更大的路径节点数,而关卡设计师需要牢记这个数字。而且它使用起来非常麻烦容易出错。

对于导航网格物体,它与将一个 2D 形状定义为障碍物并寄存它一样简单。

相关主题

动态导航网格物体障碍物


下面的脚本是一个可以扩展现有 NavMeshObstacle 类的辅助类。它可以帮助我们轻松创建我们想要的形状,通过为程序员提供一个使用界面 [SetAsSquare, SetAsRectangle, SetAsCircle] 的样本。

DynamicNavMeshObstacle.uc
class DynamicNavMeshObstacle extends NavMeshObstacle;

// 可以创建的形状列表
enum EShape
{
  EShape_None,
  EShape_Square,
  EShape_Rectangle,
  EShape_Circle
};

// 导航网格物体障碍物的形状
var PrivateWrite EShape ShapeType;
// 在 EShape_Square 中使用
var PrivateWrite float Width;
// 在 EShape_Square 和 EShape_Rectangle 中使用
var PrivateWrite float Height;
// 在 EShape_Circle 中使用
var PrivateWrite float Radius;
// 在 EShape_Circle 中使用
var PrivateWrite int Sides;
// 是否将障碍物与 actor 的旋转量对齐?
var bool AlignToRotation;

simulated function PostBeginPlay()
{
  // 忽略默认的 post begin play 函数
  Super(Actor).PostBeginPlay();
}

function SetAsSquare(float NewWidth)
{
  if (NewWidth > 0.f)
  {
    ShapeType = EShape_Square;
    Width = NewWidth;
  }
}

function SetAsRectangle(float NewWidth, float NewHeight)
{
  if (NewWidth > 0.f && NewHeight > 0.f)
  {
    ShapeType = EShape_Rectangle;
    Width = NewWidth;
    Height = NewHeight;
  }
}

function SetAsCircle(float NewRadius, float NewSides)
{
  if (NewRadius > 0.f && NewSides > 0)
  {
    ShapeType = EShape_Circle;
    Radius = NewRadius;
    Sides = NewSides;
  }
}

event bool GetObstacleBoudingShape(out array<vector> Shape)
{
  local Vector Offset;
  local int i, Angle;
  local Rotator R;

  if (ShapeType == EShape_Square)
  {
    if (AlignToRotation)
    {
      // 右上角
      Offset.X = Width;
      Offset.Y = Width;
      Shape.AddItem(Location + (Offset >> Rotation));
      // 右下角
      Offset.X = -Width;
      Offset.Y = Width;
      Shape.AddItem(Location + (Offset >> Rotation));
      // 左下角
      Offset.X = -Width;
      Offset.Y = -Width;
      Shape.AddItem(Location + (Offset >> Rotation));
      // 左上角
      Offset.X = Width;
      Offset.Y = -Width;
      Shape.AddItem(Location + (Offset >> Rotation));
    }
    else
    {
      // 右上角
      Offset.X = Width;
      Offset.Y = Width;
      Shape.AddItem(Location + Offset);
      // 右下角
      Offset.X = -Width;
      Offset.Y = Width;
      Shape.AddItem(Location + Offset);
      // 左下角
      Offset.X = -Width;
      Offset.Y = -Width;
      Shape.AddItem(Location + Offset);
      // 左上角
      Offset.X = Width;
      Offset.Y = -Width;
      Shape.AddItem(Location + Offset);
    }

    return true;
  }
  else if (ShapeType == EShape_Rectangle)
  {
    if (AlignToRotation)
    {
      // 右上角
      Offset.X = Width;
      Offset.Y = Height;
      Shape.AddItem(Location + (Offset >> Rotation));
      // 右下角
      Offset.X = -Width;
      Offset.Y = Height;
      Shape.AddItem(Location + (Offset >> Rotation));
      // 左下角
      Offset.X = -Width;
      Offset.Y = -Height;
      Shape.AddItem(Location + (Offset >> Rotation));
      // 左上角
      Offset.X = Width;
      Offset.Y = -Height;
      Shape.AddItem(Location + (Offset >> Rotation));
    }
    else
    {
      // 右上角
      Offset.X = Width;
      Offset.Y = Height;
      Shape.AddItem(Location + Offset);
      // 右下角
      Offset.X = -Width;
      Offset.Y = Height;
      Shape.AddItem(Location + Offset);
      // 左下角
      Offset.X = -Width;
      Offset.Y = -Height;
      Shape.AddItem(Location + Offset);
      // 左上角
      Offset.X = Width;
      Offset.Y = -Height;
      Shape.AddItem(Location + Offset);
    }

    return true;
  }
  else if (ShapeType == EShape_Circle && Sides > 0)
  {
    // 获取每个由面数定义的‘切片’的角度。
    Angle = 65536 / Sides;
    // 如果我们与旋转对齐,那么将旋转作为起点
    R = (AlignToRotation) ? Rotation : Rot(0, 0, 0);
    // 设置半径
    Offset.X = Radius;
    Offset.Y = 0.f;
    // 对于每个面...
    for (i = 0; i < Sides; ++i)
    {
      // 向左边的面添加点
      Shape.AddItem(Location + (Offset >> R));
      // 增加到相邻的面
      R.Yaw += Angle;
    }

    return true;
  }

  return false;
}

defaultproperties
{
}

使用 DynamicNavMeshObstacle


使用动态导航网格物体障碍物与在其中生成它一样简单,构建您需要的障碍物形状类型,然后寄存它。

YourClass.uc
var DynamicNavMeshObstacle PlacementObstacle;

function PostBeginPlay()
{
  Super.PostBeginPlay();
  PlacementObstacle = Spawn(class'DynamicNavMeshObstacle');
  PlacementObstacle.SetAsCircle(96, 8);
}

您还可以四处移动这个 DynamicNavMeshObstacle 创建一个可移动的导航网格物体障碍物。

function Tick(float DeltaTime)
{
  Super.Tick(DeltaTime);

  ForEach TraceActors(class'Actor', HitActor, HitLocation, HitNormal, CachedMouseWorldOrigin + CachedMouseWorldDirection * 65536.f, CachedMouseWorldOrigin,,, class'Actor'.const.TRACEFLAG_Bullet)
  {
    if (HitActor.bWorldGeometry)
    {
      PlacementObstacle.UnRegisterObstacle();
      PlacementObstacle.SetLocation(HitLocation);
      PlacementObstacle.RegisterObstacle();
      break;
    }
  }
}

DynamicNavMeshObstacleScreenShot.jpg