近来买了一本讲游戏AI的入门书,在这里记录一下的自己的学习过程。不得不吐槽的是,对于游戏中的算法,相关解释给的很是简略而且不准确(或者说是不对,可能是翻译的锅!),而且游戏中给出的是算法的升级版!更坑爹的是,竟然是升级版的简单改造版!这就让读者的理解成本变高,很不友好啊。

今天讲讲追逐算法,最基础的方法莫过于下面的代码了:

if(predatorCol > preyCol)predatorCol--;
else if(predatorCol < preyCol)predatorCol++;
if(predatorRow > preyRow)predatorRow--;
else if(predatorRow < preyRow)predatorRow++;

这个方法有个问题,就是追逐着会首先按照对角线行走,然后按照直线的方向行走。这在玩家看来,无疑是很狗血的,这样会显得敌人十分愚蠢,因为我们都知道两点之间线段最短,敌人为什么不直接朝我走来呢?

基于此,我们有了接下来要讲的算法,Bresenham算法,这里是在砖块环境下的追逐,即追逐者和猎物的坐标都保存在一个整型的二维数组中。值得一提的是,Bresenham算法是计算机图形学领域使用最广泛的直线扫描转换方法。

这里假设直线的斜率k在0到1之间(如果k > 1, 则采取对应的算法),起点坐标x1,y1,终点坐标x2,y2。横轴间距Δx = x2 - x1 大于 纵轴间距Δy = y2 - y1。因此我们要在这两点这件画一条近似直线的路径,只需要考虑在追逐者“横行”时,需不需要“纵行”即可。假设当前坐标为(xi, yi),那么下一步的坐标可能为(xi + 1, yi)或者(xi + 1, yi + 1)。

上面橙线为起点到终点的直线,我们目前的问题是当追逐者走到横坐标为xi + 1, 纵坐标为yi 还是 yi + 1呢?Bresenham算法是要比较一下dy1与dy2的大小。如果dy1小,则上面的点距直线更近;反之则下面的点距直线更近。

图片来源于:https://blog.csdn.net/natsu1211/article/details/17004375

如果按照上面的方法选好了点,也就能够确定了追逐者的路径。总的来说,整个过程是这样的。误差d,由dy1和dy2转换而来,如图所示。只要d >= 0.5, 即选择上方的点;否则选下方点。初值为0,每横向走一步d = d + k(在坐标轴中,直线每次走的横向距离为单位距离1,纵坐标增加k,k = Δy / Δx),当d >= 0.5,则减去1。

这里呢,我们做个小改进,令e = d - 0.5。相应地,e初值为-0.5,每横向走一步e = e + k,当e >= 0,则减去1。这样的好处在于我们只需要判断e的正负即可,而不必与0.5做比较。

但我们如此就满足了吗!不!再审视一下这个式子,斜率用到了除法,相加用到了浮点运算,为了便于硬件运算和提高速度,我们令e' = e * 2 * Δx。那么e'初值为-Δx,每横向走一步e' = e' + 2 * Δy。当e' >= 0,则减去2 * Δx。

下面是我用C++的简单实现,与书中代码略有不同:

#include<iostream>
#include<cmath>using namespace std;int main(){int map[30][30], pathRow[30], pathCol[30];int i, j;int col = 20, row = 2;int endCol = 4, endRow = 24;int nextCol = col, nextRow = row;int deltaRow = endRow - row, deltaCol = endCol - col;int stepCol, stepRow, currentStep;int recordCol, recordRow;float d = 0, k, e;//初始路径设定for(i = 0; i < 30; i++){for(j = 0; j < 30; j++){map[i][j] = -1;}}for(currentStep = 0; currentStep < 900; currentStep++){pathRow[currentStep] = -1;pathCol[currentStep] = -1;}currentStep = 0;//路径方向计算if(deltaRow < 0) stepRow = -1; else stepRow = 1;if(deltaCol < 0) stepCol = -1; else stepCol = 1;recordCol = abs(deltaCol);recordRow = abs(deltaRow);deltaRow = abs(deltaRow * 2);deltaCol = abs(deltaCol * 2);pathRow[currentStep] = nextRow;pathCol[currentStep] = nextCol;currentStep++;//Bresenham算法if(deltaCol > deltaRow){e = -0.5;k = abs(deltaRow) * 1.0 / abs(deltaCol);while(nextCol != endCol){   //d = d + k;e = e + k;if(e > 0){nextRow = nextRow + stepRow;e -= 1;}nextCol = nextCol + stepCol;pathRow[currentStep] = nextRow;pathCol[currentStep] = nextCol;currentStep++;}}else{e = -0.5;k = abs(deltaCol) * 1.0 / abs(deltaRow);while(nextRow != endRow){e = e + k;if(e > 0){nextCol = nextCol + stepCol;e -= 1;}nextRow = nextRow + stepRow;pathRow[currentStep] = nextRow;pathCol[currentStep] = nextCol;currentStep++;}}//更改地图//起点为2, 终点为3 for(i = 0; i < currentStep; i++){if(pathRow[i] == row && pathCol[i] == col)map[pathRow[i]][pathCol[i]] = 2;else if(pathRow[i] == endRow && pathCol[i] == endCol)map[pathRow[i]][pathCol[i]] = 3;else map[pathRow[i]][pathCol[i]] = 1;} //打印for(i = 0; i < 30; i++){for(j = 0; j < 30; j++){if(map[i][j] == -1) cout << "■";else if(map[i][j] == 2) cout << "☆";else if(map[i][j] == 3) cout << "★";else cout << "□";}cout << '\n';}
}

运行结果如下图:

Bresenham整数追逐算法相关推荐

  1. 图形学--(中点画线法+Bresenham画线算法)

    编程环境:codeblocks+EGE库 用到的函数:putpixel(int x1,int y1,int color)  用某种颜色打亮一个坐标点. 这俩种算法都是用来在计算机上画一条直线的,那么我 ...

  2. Bresenham画线算法笔记

    目录 一.DDA算法和中点画线算法的回顾 二.Bresenham画线算法 一.DDA算法和中点画线算法的回顾 1.DDA算法(Digtal Differential Analyzer) 假设两个端点坐 ...

  3. Bresenham画线算法的推导

    转自:https://www.cnblogs.com/soroman/archive/2006/07/27/509602.html 以前看到Bresenham画线算法,直接拿来用,没有去推导它,近日, ...

  4. 【计算机图形学】扫面转换算法(DDA算法 中点画线算法 Bresenham画线算法)

    模块1 扫描转换算法 一 实验目的 编写直线.弧线的光栅扫描转换算法,并对线宽与线形的算法加以探讨 用DDA算法.中点画线算法.Bresenham画线算法绘制直线(如果键盘输入数据,给出数据值:如果绘 ...

  5. openGL实现中点画线算法、DDA画线算法,Bresenham画线算法,并进行鼠标键盘的交互

    首先设置变量用于进行鼠标交互和键盘交互: int m = 0; GLdouble m1 =0, m2 = 0; 1.实验入口主函数: //主函数 int main(int argc, char** a ...

  6. java bresenham画直线_OpenGL中点Bresenham绘制直线算法

    本文实例为大家分享了OpenGL中点Bresenham绘制直线算法,供大家参考,具体内容如下 环境 macos xcode编译器 代码 #include #include #include #incl ...

  7. 追逐算法之--牛鞭的子弹是怎样练成的(2)--简单追逐

    那是8岁的一个夏天,我刚刚完成了一天的工作,赚了50块钱,那个时候赚钱之后,唯一的消费场所当然就是游戏机厅了,从家里往游戏机室冲的感觉真是美好.乐极生悲,那天可能过于兴奋,穿着一双拖鞋,往游戏机室跳奔 ...

  8. C++找出数组中的第一个非重复整数的算法(附完整源码)

    C++找出数组中的第一个非重复整数的算法 C++找出数组中的第一个非重复整数的算法完整源码(定义,实现,main函数测试) C++找出数组中的第一个非重复整数的算法完整源码(定义,实现,main函数测 ...

  9. 子集和与一个整数相等算法_背包问题的一个变体:如何解决Java中的分区相等子集和问题...

    子集和与一个整数相等算法 by Fabian Terh 由Fabian Terh Previously, I wrote about solving the Knapsack Problem (KP) ...

最新文章

  1. HMM 前向 后向 Viterbi算法讲解通透的
  2. 源泉书签,助您管理海量收藏。www.yuanquanshuqian.com 今日更新:支持了导入url为js代码的书签...
  3. 160 - 14 bjanes.1
  4. flutter listview 滚动到底部_??一个高颜值Flutter版WanAndroid客户端
  5. c++ new delete
  6. linux源码acl,Linux自主访问控制机制模块详细分析之posix_acl.c核心代码注释与acl.c文件介绍...
  7. 智能优化算法:足球联赛竞争算法-附代码
  8. python读取xps文件_Python操作PDF-文本和图片提取(使用PyPDF2和PyMuPDF)
  9. 52单片机C语言如何用间接寻址,单片机要如何寻址?
  10. python中计算结果保留两位小数
  11. 计算两样本间的相关系数和P
  12. Bigben vlc sdl 播放视频可随窗口改变大小
  13. 如何让鼠标拖动时变成直线
  14. 时间复杂度和空间复杂度及多道例题讲解
  15. 『最小表示法 Necklace』
  16. python爬虫成长之路(一):抓取证券之星的股票数据
  17. iPhone/iPad/iTouch配置Bash/C/C++/OC/Java/Theos/MySQL/Python开发环境! 让我告诉你iOS的魅力~
  18. vs2012 access数据库 crystalreport
  19. phpcms-前台模板调用和后台模板调用
  20. 大屏---适配比例缩放--视频播放完路由自动切换

热门文章

  1. tsconfig.json
  2. Prometheus运维二 安装部署Prometheus及使用PromQL查询监控数据
  3. 你知道菩薩為什麼靈驗,香火不絕嗎?(主管必讀)
  4. CSS的圆角边框以及阴影
  5. CentOS安装gnome dask to dock插件
  6. ipython console_Python 安装IPython以及qtconsole
  7. Web自动化测试二:selenium打开和登录浏览器(火狐、IE、chrome)
  8. 经验教训 软件开发_软件可靠性的教训
  9. 结构化查询语言(SQL)简介
  10. win7怎么修改计算机皮肤,win7系统修改UC浏览器皮肤的方法【图文】