• 理解引导行为:路径跟踪


    路径跟踪是游戏开发中一个经常出现的问题。此教程涵盖引导行为的路径跟踪,这里的路径是提前根据点和线预设好的。

           注意:虽然此教程是用AS3和Flash实现的,你也可以在其他语言开发环境下使用这些类似的技巧和概念。当然前提是需要有基本的数学向量的知识。

           介绍

           路径跟踪可以用多种方式实现。Reynolds原型就是使用线来实现的,这里需要严格的按照线来实现。

           根据不同情况,准确度要求不同。角色可以根据线路运动,但是只是做一个参照而不是严格按照轨道来运行。

           此教程的路径跟踪是Reynolds原型的简化实现。运行效果不错,但是严重依靠数学的向量投影计算。

           设定路径

           路径可以是线连接的点的集合。即使曲线也可以用来描述路径,点和线处理处理得到相同的结果要简单的多。

     

     1 public class Path
     2 {
     3 private var nodes :Vector.<Vector3D>;
     4 
     5 public function Path() {
     6 this.nodes = new Vector.<Vector3D>();
     7 }
     8 
     9 public function addNode(node :Vector3D) :void {
    10 nodes.push(node);
    11 }
    12 
    13 public function getNodes() :Vector.<Vector3D> {
    14 return nodes;
    15 }
    16 }

     

     如果需要使用曲线,则可以将其简化为一些连接的点:

    曲线和直线

           Path类将用来描述路径。一般来说此类包含一个点向量和一些处理列表的方法:

           每个路径中的点都是一个三维空间中点的表示方式,角色的位置也是如此。

    逐个节点移动

           为了根据路径导航,角色从路线起始逐个节点移动直到到达路线末点。

           路径中的每个点都可以看做为一个对象,因此行为查看如下所示:

     

    挨个点查看

           角色会不断查看当前点,直到到达为止,然后路径中下一个点作为当前点。正如前面的碰撞避免教程中所述,每个行为的力都是在游戏更新时重新计算,因此从一个节点到另一个节点是圆滑的。

           Character类需要两个额外的属性来引导导航过程:当前节点和路径跟踪的引用。

           类如下所示:

     

     1 public class Boid
     2 {
     3 public var path :Path;
     4 public var currentNode :int;
     5 (...)
     6 
     7 private function pathFollowing() :Vector3D {
     8 var target :Vector3D = null;
     9 
    10 if (path != null) {
    11 var nodes :Vector.<Vector3D> = path.getNodes();
    12 
    13 target = nodes[currentNode];
    14 
    15 if (distance(position, target) <= 10) {
    16 currentNode += 1;
    17 
    18 if (currentNode >= nodes.length) {
    19 currentNode = nodes.length - 1;
    20 }
    21 }
    22 }
    23 
    24 return null;
    25 }
    26 
    27 private function distance(a :Object, b :Object) :Number {
    28 return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    29 }
    30 (...)
    31 }

     

    pathFollowing()函数用来产生路径跟踪方向,当前是没有的,但是它还是会选择合适的目标。Path!=null测试角色是否跟踪任何路径。如果是的话,就用当前节点作为当前目标。

           如果当前点和角色位置之间的目标数少于10,意味着角色已经到达当前节点,如果上述成立则将currentNode增加一,表示角色将在路径中寻找下一个点。整个过程循环运行,知道路径里没有点为止。

           计算和添加方向

           促使角色在路径中不断寻找节点的是寻找力。pathFollwing()函数以及选择了合适的节点,现在需要返回促使角色前进的的节点:

           路径追踪后会计算方向,然后加到角色速度向量里:

     

     1 private function pathFollowing() :Vector3D {
     2 var target :Vector3D = null;
     3 
     4 if (path != null) {
     5 var nodes :Vector.<Vector3D> = path.getNodes();
     6 
     7 target = nodes[currentNode];
     8 
     9 if (distance(position, target) <= 10) {
    10 currentNode += 1;
    11 
    12 if (currentNode >= nodes.length) {
    13 currentNode = nodes.length - 1;
    14 }
    15 }
    16 }
    17 
    18 return target != null ? seek(target) : new Vector3D();
    19 }

     

    路径引导方向跟追寻行为类似,角色不断根据目标调整方向。不同之处在于角色是在寻找一个不动的目标,这样就可以在角色逐渐靠近的时候忽略另一个。

           结果如下:

     

    1 steering = nothing(); // the null vector, meaning "zero force magnitude"
    2 steering = steering + pathFollowing();
    3 
    4 steering = truncate (steering, max_force)
    5 steering = steering / mass
    6 
    7 velocity = truncate (velocity + steering, max_speed)
    8 position = position + velocity

     

    实际中的路径跟踪。点击来查看方向。

           柔化轨迹

           当前的实现需要所有角色接触路径中的点来选择下一个目标。因此角色可能执非预期的动作模式,例如围绕一个点圆周运动直到到达。

           实际中,每个运动都遵循最优原则。例如一个人不可能总是在走廊中间行走。如果是一个拐弯,那么人会不断靠近墙,然后拐弯来缩短距离。

           上述的模式可以通过在路径中添加半径来不断重复。将半径应用到点,就可以看到路径的宽。这样就可以控制角色不断沿着路径走。

     

    半径对路径跟踪的影响

           如果角色和点之间的距离小于等于半径,那表示已经到达点。这样就可以根据线和点来做引导。

           利用半径进行路径跟踪。点击Force按钮来查看方向,点击+跟-按钮来动态调整半径尺寸。

           半径越大,路径越宽,角色拐弯的距离也就越大。半径的值可以用来产生不同的追踪模式。

           前进和后退

           有时候需要让角色不断移动,直到到达路径末尾。例如在巡逻模式中,角色需要在到达末尾后返回起点,追踪相同的点。

           我们可以在character类里添加pathDir属性。此属性是一个整型值,用来控制角色沿着路径的方向。如果pathDir是1,则表示向路径末尾运动,-1表示向起始点运动。

           pathFollowing()函数做如下改动:

     

     1 private function pathFollowing() :Vector3D {
     2 var target :Vector3D = null;
     3 
     4 if (path != null) {
     5 var nodes :Vector.<Vector3D> = path.getNodes();
     6 
     7 target = nodes[currentNode];
     8 
     9 if (distance(position, target) <= path.radius) {
    10 currentNode += pathDir;
    11 
    12 if (currentNode >= nodes.length || currentNode < 0) {
    13 pathDir *= -1;
    14 currentNode += pathDir;
    15 }
    16 }
    17 }
    18 
    19 return target != null ? seek(target) : new Vector3D();
    20 }

     

    跟之前版本不同,此处的pathDir添加到currentNode属性里。这样就允许角色选择基于当前位置的路径的下一个点了。

           然后通过一个测试来检测角色是否到达路径末尾。如果到达,就将pathDir乘以-1,也就是取相反值,来让角色反方向行走。

           结果是一个不断来回运动的模式:

           上述是利用半径的来回路径追踪模式。点击Force按钮来显示方向,点击+或者-来动态调整半径尺寸。

           总结

    路径追踪行为运行任何角色按照预先设定好的路径运动。路径是根据点来指引,可以调宽窄,产生不同运动模式来更贴近现实。

    此教程中涵盖的实现时给予Reynolds提出的路径追踪行为原型的,但是还是获得良好的效果。

     

    原文链接:理解引导行为:路径跟踪

     

    原文链接:http://gamedev.tutsplus.com/tutorials/implementation/understanding-steering-behaviors-path-following/

     

     

     

     

     

  • 相关阅读:
    PIC18F2455/2550/4455/4550之通用串行总线USB
    今天,一个新的起点
    WM_COPYDATA消息
    图片浏览(附带样式+效果)
    这条路,走远一点,再远一点
    html之table(10种表格)
    数据导出成Excel
    .net 附件下载
    .net Repeater嵌套的数据绑定问题
    AjaxPro.2.dll的使用方法,以实例讲解。
  • 原文地址:https://www.cnblogs.com/atong/p/3181985.html
Copyright © 2020-2023  润新知