有时候,影响计算寻路路径的不是时间,而是计算路径所需的上百个单元格所占的空间。寻路是需要内存来运行寻路算法,还需要额外内存来存储寻到的路径。运行寻路算法(A*,开集或闭集)所需的临时空间经常会比存储这些寻到的路径所需的空间更大。通过在同一时间内只进行一条路径计算来限制游戏中的计算量,可以将你需要的临时空间降到最少。另外,对开集闭集的数据结构的选择也会对减少你所需的临时内存产生很大的影响。在本章中将会转而关注通过生成的路径减少使用的空间。

位置vs方向

一条路径可以是一堆位置或者一堆方向,位置需要更多的空间,但是它的优势在于它很容易决定一条路径上的一个任意的位置点或者方向而不用遍历这条路径。当存储方向的时候,只需要这个方向就可以很容易的决定;而位置只能通过遵循某个方向经由整条路径才能决定,在传统的栅格化地图中,位置可能使用两个16位的整数来存储,这样的话,每一步存储都需要32字节。因为它有更少的方向所以需要的空间就更少。如果一个单元格只能在四个方向上移动,每一步只需要2字节;如果单元格可以在六个或者八个方向上移动,每一步就会需要3字节。这些存储在存储位置上的路径点在路径中是非常重要的。Hannu Kankaanpaa建议你可以通过存储绝对的方向(比如”向北”)而不是存储这些相对方向(比如”右转60度”)来进一步的减少存储所需的空间。一些相对方向可能让一些单元格难以理解。比如说如果你的单元格在想北方移动,那它下一步就不大可能向南移动。在一个六方向的游戏中,你只有五个有意义的方向。在一些地图中你可能只有3个方向(直走,左转60度,右转60度)有意义。但是在一些其他的地图中右转120度可能才是一个有效的移动(比如通过Z字形路线爬一座陡峭的山)。

路径压缩

一旦一个路径被找到,它将会通过某种方式被压缩。我们可以使用一个通用的压缩算法,但是我们不会在这篇文章中讨论这个算法。一个针对具体路径的压缩算法可以用来缩短基于位置的路径或者基于方向的路径。在做决定之前,考虑你游戏中的具体的典型路径来决定哪一种压缩算法最适合你所寻到的路径。同时 也要考虑在你游戏中实施(或者调试)的可行性,代码的体积还有这个压缩算法是否真的很重要。如果你有 个300单元格的限制,在同一时间只有50个单元格在移动,并且路径很短(只有100步),那么所需要的内存可能最多只有50k,那么你就不需要再考虑使用路径的压缩算法了。

位置点存储

在一张地图中如果障碍是寻路的主要影响因子而不是地形,那么就可以将路径分成很多条线段,如果是这种情况的话,那么一条路径只需要包括这些线段集合的各个终点位置(有时也被称为路径点)。运动就是由检查这条路径的下一个终点位置并沿着直线向终点移动组成。

方向存储

当方向被存储的时候,它可能是在一排中多次出现的方向,你可以利用那种常见的模式使用较少的空间去存储那条路径。

一种最好的存储路径方式是同时存储这个方向和指明单元格将在这个方向上移动多少次的数字。不同于位置存储的优化,当这个方向在这一排中并没有多次使用的时候这种优化可能会变得很糟。当然,对于很多直线路径的位置存储这种方式很有效,由于线可以不与的行走方向之一对齐,这种情况并不适用方向存储的压缩。当有多种可选方向时,你可以选择清除“一直直走”作为一个可行的方向。Hannu Kankaanpaa指出在一个八方向图中,你可以清除直走,后退还有135度左,右转(假设你的地图允许这样),然后你可以仅仅使用2字节去存储每个方向。

另一种存储路径的方法是使用可变长度的编码。这是指使用一个单字节去存储大部分的一般性步骤比如说:直走。使用数字1去标记转向,在跟上一个数字1使用一些字节去表示转向,在一个4向图中,你只可以左转或者右转,所以你可能需要使用10来表示左转11来表示右转。

可变长度编码更为通用,可能比游程编码工作起来更好,但是对于长直型的路径就不如混合编码了。这个(北向,六步直走,左转,直走三步,右转,直走5步,左转,直走六步)的序列被使用长编码的[(North,6),(WEST,3),(NORTH,5),(WEST,2)]所代替。如果每个方向占用2字节,美短距离占用8字节,这条路径需要40字节去存储。如果使用可变长度编码,你需要使用1个字节去存储各个步骤2个字节去存储每次转向-[NORTH 0 0 0 0 0 0 10 0 0 0 11 0 0 0 0 0 10 0 0]总共需要24字节。如果初始化的方向和每次转向代表一步,你可以每次转向省下一字节,这样你只需要20字节就可以存储这条路径。但是使用可变长度编码在遇到较长的路径可能需要使用更多的空间。如果使用游程编码这个序列(north,直走200步)是[(NORTH,200)]只需要10个字节,同样的序列如果使用可变长度编码就变成[NORTH 0 0...],总共需要202字节。

计算路径点

路径点是指一条路径上的所有点。寻路完成后处理步骤时,可以折叠多个步骤到一个单一的路径点钟,通常存储的是路径改变方向的点,或者像城市的主要位置点,而不是存储一路走来的每一步。然后使用算法在路径点之间沿着路径运动。

限制路径长度

考虑到地图条件或者指令可能会发生变化,存储一条长路径可能意义并不大,因为余下的路径点可能根本就不会被使用到。每个单元格可以在路径开始的时候存储一些合适的步骤数,然后在路径快要走完时在重新计算心的路径。这种方法可以控制每个单元格的数据量。

总结

路径在游戏中可能占用很多空间,尤其是当路径很长,并且这个路径上有很多游戏单元的时候。路径压缩、路径点还有信标(beacon)都会在一定程度上减少在一小块数据里存储很多行路步骤的空间。在一条直线路径上加入需要存储路径点的话,只需要存储末尾点就可以了,信标是依靠在地图上特意标明的地方之间事先计算好的路径上使用。如果路径仍然需要占用很大的空间,就要限制路径的长度了,在经典的实时路径计算中是这样做的:为了节省空间,消息可以被忽略并且延迟计算。

关于寻路算法的一些思考(6):预先计算好的路径的所用空间相关推荐

  1. 游戏中常用的寻路算法(5)预先计算好的路径的所用空间

    有时候,影响计算寻路路径的不是时间,而是计算路径所需的上百个单元格所占的空间.寻路是需要内存来运行寻路算法,还需要额外内存来存储寻到的路径.运行寻路算法(A*,开集或闭集)所需的临时空间经常会比存储这 ...

  2. [转]关于寻路算法的一些思考

    关于寻路算法的一些思考(1):A*算法介绍 物体的移动算法似乎显得很简单,然而寻路规划问题却十分复杂.考虑下面这个例子: 这个单位的初始位置在地图的下方,想要到达地图的顶部.如果物体所能侦测到的地方( ...

  3. 关于寻路算法的一些思考(3):A*算法的实现

    概述 剥除代码,A* 算法非常简单.算法维护两个集合:OPEN 集和 CLOSED 集.OPEN 集包含待检测节点.初始状态,OPEN集仅包含一个元素:开始位置.CLOSED集包含已检测节点.初始状态 ...

  4. 关于寻路算法的一些思考(2):Heuristics 函数

    启发式函数h(n)告诉A*从任何结点n到目标结点的最小代价评估值.因此选择一个好的启发式函数很重要. 启发式函数在A* 中的作用 启发式函数可以用来控制A*的行为. 一种极端情况,如果h(n)是0,则 ...

  5. 关于寻路算法的一些思考(5):处理移动中的障碍物

    一个寻路算法会计算出一条绕过静止障碍物的路径,但如果障碍物会移动呢?当一个单位移动到达某特定点时,原来的障碍物可能不在那点了,或者在那点上出现了新的障碍物.如果路线可以绕过典型的障碍物,那么只要使用单 ...

  6. 关于寻路算法的一些思考(1):A*算法介绍

    物体的移动算法似乎显得很简单,然而寻路规划问题却十分复杂.考虑下面这个例子: 这个单位的初始位置在地图的下方,想要到达地图的顶部.如果物体所能侦测到的地方(粉色部分所示)并没有障碍,那么物体就会直接向 ...

  7. 关于寻路算法的一些思考(4):A* 算法的变体

    定向搜索 在A*算法的循环中,OPEN集合用来保存所有用于寻找路径的被搜索节点.定向搜索是在A*算法基础上,通过对OPEN集合大小设置约束条件而得到的变体算法.当集合太大的时候,最不可能出现在最优路径 ...

  8. 关于寻路算法的一些思考(8):长期和短期目标

     我已经集中讲过了从一个地方到另一个地方寻找路径的任务.然而,一个与之同等重要的问题是:一旦我有一个路径,我该怎样沿着它移动?最明显的答案是从一个位置到另一个的位置的直线移动.然而,你可能想在曲线 ...

  9. 盘点即时战略游戏中高实用性寻路算法

    编者按:在即时战略(RTS)游戏中,寻路系统可谓其核心要素之一,但它的算法也是较难攻克的内容之一.在这篇文章中,来自iSamurai工作室的伍一峰为广大游戏开发者带来了他对即时战略游戏寻路算法的深入思 ...

最新文章

  1. AWS ML deploy platform
  2. 一个简单的配置管理器(SettingManager)
  3. TensorRT学习笔记6 - IPlugin
  4. php orm 链式,关于php:雄辩的ORM中的交叉和分页
  5. java excel 操作方式_Java读写Excel基本操作
  6. 数据结构与算法——图解平衡二叉树及代码实现
  7. linux chmod 命令理解
  8. android 类似按键精灵脚本_android软件。按键精灵或者脚本精灵都可以,录制脚本可以设置播放次数的最好了。...
  9. Windows 域基础环境搭建-Win_Server_2003
  10. C# WinForm菜单和工具栏控件
  11. [一步一步MVC]第四回:漫谈ActionLink,有时“胡搅蛮缠”
  12. 反射--成员属性:Feild
  13. 从txt中读取float数据C++
  14. linux airplay 客户端,iOS/MAC OSX airplay 使用教程 (更新macosx下的正确使用方式)
  15. selenium的工作原理
  16. OCR-文本检测后的文字纠正
  17. 输入关键字的爬虫方法(运行环境python3)
  18. 聊聊benchmark测试
  19. URL中参数中的加号
  20. 菜鸟学习Mybatis 01

热门文章

  1. 循环结构_for循环
  2. C语言烧写C51单片机的线,51单片机烧写程序过程以及详细说明【图文】
  3. python实例化类执行顺序_Python实例化class的执行顺序
  4. html动画效果放大,一个CSS+jQuery实现的放大缩小动画效果
  5. 端口号属于协议还是进程
  6. 构建增强现实移动应用程序的六款顶级工具
  7. 13.1-13.3 设置更改root密码,连接MySQL,MySQL常用命令
  8. Android基础控件ProgressBar进度条的使用
  9. TYVJ P1051 选课 Label:多叉转二叉树形dp(虐心♥)
  10. C#使用post提交http请求