D3D游戏编程系列(三):自己动手编写即时战略游戏之寻路
说起即时战略游戏,不得不提的一个问题是如何把一个物体从一个位置移动到另一个位置,当然,我说的不是瞬移,而是一个移动的过程,那么在这个移动的过程中我们如何来规划路线呢,这就不得不提到寻路了。
我所了解到的寻路算法有很多,当然我还是向大家推荐A*算法,这个应该是目前在八个方向上效率最高的寻路算法了吧,在这里,我不准备详细的去介绍这个算法的原理,给大家一个链接,http://www.cnblogs.com/technology/archive/2011/05/26/2058842.html,这是我在网上看到的我个人认为有关A*算法最好的讲解了。
好了,废话不多说,我给出在4个方向上的算法代码(上下左右,因为我的游戏里就是在四个方向上移动,八个方向类似)。
void MyWin::FindPath(sEleObj* Ele)
{
static sPathNode EleMem[1024*1024];
CPoint desPoint=Ele->DesPos;
if((m_MapInfo[desPoint.y][desPoint.x]<200 && m_MapInfo[desPoint.y][desPoint.x]!=Ele->ID) || (m_MapInfo[desPoint.y+Ele->CurPos.Height()-10][desPoint.x]<200 && m_MapInfo[desPoint.y+Ele->CurPos.Height()-10][desPoint.x]!=Ele->ID) || (m_MapInfo[desPoint.y][desPoint.x+Ele->CurPos.Width()-10]<200 && m_MapInfo[desPoint.y][desPoint.x+Ele->CurPos.Width()-10]!=Ele->ID) || (m_MapInfo[desPoint.y+Ele->CurPos.Height()-10][desPoint.x+Ele->CurPos.Width()-10]<200 && m_MapInfo[desPoint.y+Ele->CurPos.Height()-10][desPoint.x+Ele->CurPos.Width()-10]!=Ele->ID))
{
Ele->VecPath.clear();
m_FindPathEleList.remove(Ele);
m_DynamicFindPathEleList.remove(Ele);
m_DynamicFindPathEleList.push_back(Ele);
return;
}
sPathNode *node=new sPathNode;
node->Cur=Ele->CurPos.TopLeft();
node->F=abs(desPoint.x-node->Cur.x)+abs(desPoint.y-node->Cur.y);
node->Par=0;
m_OpenListSet.insert(node);
int count=0;
int pos=0;
set<DWORD> PointMap;
#define MAKEDWORD( wLow, wHigh ) ((LONG)(((WORD)(wLow)) | ((DWORD)((WORD)(wHigh))) << 16))
while(1)
{
if(++count==1000)
{
break;
}
if(m_OpenListSet.empty())
{
break;
}
sPathNode *MinNode=*m_OpenListSet.begin();
m_OpenListSet.erase(m_OpenListSet.begin());
m_CloseListSet.insert(MinNode);
//cout<<MinNode->Cur.x<<" "<<MinNode->Cur.y<<endl;
node=MinNode;
CPoint TopPoint;
TopPoint.x=node->Cur.x;
TopPoint.y=node->Cur.y-10;
if(TopPoint.y>=0)
{
CPoint TempPoint;
TempPoint.x=TopPoint.x+Ele->CurPos.Width()-10;
TempPoint.y=TopPoint.y;
if(m_MapInfo[TopPoint.y][TopPoint.x]==200 && m_MapInfo[TempPoint.y][TempPoint.x]==200)
{
sPathNode *NewNode=&EleMem[pos++];
NewNode->Cur=TopPoint;
NewNode->Par=node;
NewNode->F=abs(desPoint.x-NewNode->Cur.x)+abs(desPoint.y-NewNode->Cur.y);
if(PointMap.find(MAKEDWORD(NewNode->Cur.x,NewNode->Cur.y))==PointMap.end())
{
m_OpenListSet.insert(NewNode);
PointMap.insert(MAKEDWORD(NewNode->Cur.x,NewNode->Cur.y));
if(NewNode->F==0)
{
break;
}
}
}else if(TopPoint==desPoint)
{
break;
}
}
CPoint RightPoint;
RightPoint.x=node->Cur.x+10;
RightPoint.y=node->Cur.y;
if(RightPoint.x+Ele->CurPos.Width()<=1600)
{
CPoint TempPoint;
TempPoint.x=RightPoint.x+Ele->CurPos.Width()-10;
TempPoint.y=RightPoint.y+Ele->CurPos.Height()-10;
if(m_MapInfo[RightPoint.y][RightPoint.x+Ele->CurPos.Width()-10]==200 && m_MapInfo[TempPoint.y][TempPoint.x]==200)
{
sPathNode *NewNode=&EleMem[pos++];
NewNode->Cur=RightPoint;
NewNode->Par=node;
NewNode->F=abs(desPoint.x-NewNode->Cur.x)+abs(desPoint.y-NewNode->Cur.y);
if(PointMap.find(MAKEDWORD(NewNode->Cur.x,NewNode->Cur.y))==PointMap.end())
{
m_OpenListSet.insert(NewNode);
PointMap.insert(MAKEDWORD(NewNode->Cur.x,NewNode->Cur.y));
if(NewNode->F==0)
{
break;
}
}
}else if(RightPoint==desPoint)
{
break;
}
}
CPoint BottomPoint;
BottomPoint.x=node->Cur.x;
BottomPoint.y=node->Cur.y+10;
if(BottomPoint.y+Ele->CurPos.Height()<=1200)
{
CPoint TempPoint;
TempPoint.x=BottomPoint.x+Ele->CurPos.Width()-10;
TempPoint.y=BottomPoint.y+Ele->CurPos.Height()-10;
if(m_MapInfo[BottomPoint.y+Ele->CurPos.Height()-10][BottomPoint.x]==200 && m_MapInfo[TempPoint.y][TempPoint.x]==200)
{
sPathNode *NewNode=&EleMem[pos++];
NewNode->Cur=BottomPoint;
NewNode->Par=node;
NewNode->F=abs(desPoint.x-NewNode->Cur.x)+abs(desPoint.y-NewNode->Cur.y);
if(PointMap.find(MAKEDWORD(NewNode->Cur.x,NewNode->Cur.y))==PointMap.end())
{
m_OpenListSet.insert(NewNode);
PointMap.insert(MAKEDWORD(NewNode->Cur.x,NewNode->Cur.y));
if(NewNode->F==0)
{
break;
}
}
}else if(BottomPoint==desPoint)
{
break;
}
}
CPoint LeftPoint;
LeftPoint.x=node->Cur.x-10;
LeftPoint.y=node->Cur.y;
if(LeftPoint.x>=0)
{
CPoint TempPoint;
TempPoint.x=LeftPoint.x;
TempPoint.y=LeftPoint.y+Ele->CurPos.Height()-10;
if(m_MapInfo[LeftPoint.y][LeftPoint.x]==200 && m_MapInfo[TempPoint.y][TempPoint.x]==200)
{
sPathNode *NewNode=&EleMem[pos++];
NewNode->Cur=LeftPoint;
NewNode->Par=node;
NewNode->F=abs(desPoint.x-NewNode->Cur.x)+abs(desPoint.y-NewNode->Cur.y);
if(PointMap.find(MAKEDWORD(NewNode->Cur.x,NewNode->Cur.y))==PointMap.end())
{
m_OpenListSet.insert(NewNode);
PointMap.insert(MAKEDWORD(NewNode->Cur.x,NewNode->Cur.y));
if(NewNode->F==0)
{
break;
}
}
}else if(LeftPoint==desPoint)
{
break;
}
} }
if(count<1000)
{
if(!m_OpenListSet.empty())
{
node=*m_OpenListSet.begin();
while(node->Par!=0)
{
Ele->VecPath.push_front(node->Cur);
node=node->Par;
}
}else
{
if(m_VecSelectTank.size()>0)
{
Ele->VecPath.clear();
m_FindPathEleList.remove(Ele);
m_DynamicFindPathEleList.remove(Ele);
m_DynamicFindPathEleList.push_back(Ele);
} }
}
m_OpenListSet.clear();
m_CloseListSet.clear();
}
这里有用到二叉堆的数据结构,这样可以极大的提高效率,下面我给出相关的结构定义:
struct sPathNode;
class sort
{
public:
bool operator () (const sPathNode* b1,const sPathNode* b2) const{
return b1->F<b2->F;
}
};
struct sPathNode
{
CPoint Cur;
sPathNode *Par;
int F;
sPathNode(){}
sPathNode(int x,int y)
{
Cur.SetPoint(x,y);
}
};
struct sEleObj
{
IDirect3DTexture9* Sur;
CPoint DesPos;
CRect CurPos;
list<CPoint> VecPath;
bool bMove;
byte ID;
};
multiset<sPathNode*,sort> m_OpenListSet;
multiset<sPathNode*,sort> m_CloseListSet;
这样我们每次添加一个节点时,F值最小的节点便会在最开头的位置。在此我说下关于该算法的一些优化,我在函数的开头便定义了static sPathNode EleMem[1024*1024];这样的话我们每次就可以直接从这个数组里分配节点,而不用去new和delete一个新的节点,节约了操作内存的时间,并且,我在算法里用的容器都是Set,因为set内部是红黑二叉树实现的,所以在查找上速度十分快。还有一点是,千万不要同时为多个物体寻路,你应该把需要寻路的物体放在一个list里面,每一帧或者每过几帧(这根据你的需求)依次取出来做寻路,这样在速度上会大大提高,就算有几十到几百ms的延迟,用户也很难察觉。
还有我不得不提的是,动态碰撞怎么办,对,就是在你规划路径好了以后,在你的路径上出现了其他物体该怎么解决呢,那么我们就需要去做动态寻路,在我们遇到障碍物后,会根据当前物体的id,决定是否等待,如果等待,则障碍物如果是移动状态,则重新去寻路,规划一条新的路径,如果障碍物已经是停止状态,则当前物体重新寻路,规划出一条新的路径。
最后一点是,当我们操作多个物体移动到同一地点时,因为不可能重叠,所以这些物体不可能到达同一位置,这就是说,当物体的目的地不可到达时,我们该怎么处理呢?其实很简单,就是以目的地为中心向外搜索,找到一个物体可以到达的位置作为新的目的地,然后去寻路这个目的地就可以了。
说起来简单,但是这其中的代码量和繁琐程度还是很大的,大家可以参考一下我上传的代码,有什么问题一起交流下。
本文有不足之处,还望大家多多指正。
D3D游戏编程系列(三):自己动手编写即时战略游戏之寻路的更多相关文章
- D3D游戏编程系列(四):自己动手编写即时战略游戏之网络同步
说到网络同步,这真是一个网络游戏的重中之重,一个好的网络同步机制,可以让玩家的用户体验感飙升,至少,我玩过的魔兽争霸在网络同步方面做得非常好,即便是网络状况很不稳定,依然可以保证用户数据不会出现意想不 ...
- WCF编程系列(三)地址与绑定
WCF编程系列(三)地址与绑定 地址 地址指定了接收消息的位置,WCF中地址以统一资源标识符(URI)的形式指定.URI由通讯协议和位置路径两部分组成,如示例一中的: http://loc ...
- 022年9月12日 学习ASP.NET Core Blazor编程系列三——实体
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...
- OWIN系列之自己动手编写中间件
一.前言 1.基于OWIN的项目摆脱System.Web束缚脱颖而出,轻量级+跨平台,使得ASP.NET应用程序只需依赖这个抽象接口,不用关心所运行的Web服务器. 2.OWIN.dll介绍 使用反编 ...
- 异步编程系列第04章 编写Async方法
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- [Python] 文科生零基础学编程系列三——数据运算符的基本类别
上一篇:[Python] 文科生零基础学编程系列二--数据类型.变量.常量的基础概念 下一篇: ※ 程序的执行过程,就是对数据进行运算的过程. 不同的数据类型,可以进行不同的运算, 按照数据运算类型的 ...
- 【Visual C++】游戏编程学习笔记之九:回合制游戏demo(剑侠客VS巡游天神)
本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder 微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.com ...
- D3D游戏编程系列(六):自己动手编写第一人称射击游戏之第一人称视角的构建
说起第一人称射击游戏,不得不提第一人称视角啊,没有这个,那么这个第一就无从谈起啊,我作为一个观察者究竟如何在这个地图上顺利的移动和观察呢,那么,我们一起来研究下. 我们首先来看下CDXCamera类: ...
- D3D游戏编程系列(一):DXLib的介绍
这篇文章里我准备向大家介绍下我封装的一个基础D3D库:DXLib.有了这样一个类库,可以减少很多无用功以及繁琐的工作,使我们的效率大大提高. DXLib.h #define DIRECTINPUT_V ...
随机推荐
- Quartz Sheduler 入门
Quartz Sheduler 入门 原文地址:http://www.quartz-scheduler.org/generated/2.2.2/html/qtz-all/ 下载地址:http://qu ...
- 视频边下边播--缓存播放数据流-b
google搜索“iOS视频变下边播”,有好几篇博客写到了实现方法,其实只有一篇,其他都是copy的,不过他们都是使用的本地代理服务器的方式. 原理很简单,但是缺点也很明显,需要自己写一个本地代理服务 ...
- 常用javascript代码片段集锦
常用方法的封装 根据类名获取DOM元素 var $$ = function (className, element) { if (document.getElementsByClassName) { ...
- [JavaScript] 用html5 js实现浏览器全屏
项目中需要将后台浏览器的窗口全屏,也就是我们点击一个按钮要实现按F11全屏的 效果. 在HTML5中,W3C制定了关于全屏的API,就可以实现全屏幕的效果,也可以 让页面中的图片,视频等全屏目前只有g ...
- [转载]MongoDB C# 驱动教程
本教程基于C#驱动 v1.6.x . Api 文档见此处: http://api.mongodb.org/csharp/current/. 简介 本教程介绍由10gen支持的,用于MongoDB的C# ...
- matlab怎么同时显示imshow 两幅图片
matlab怎么同时显示imshow 两幅图片 matlab怎么同时显示imshow 两幅图片 方法一:subplot()函数 subplot(2,1,1); subplot(2,1,2); 分上下或 ...
- php多线程thread开发与应用的例子
Php多线程的使用,首先需要PHP5.3以上版本,并安装pthreads PHP扩展,可以使PHP真正的支持多线程,扩展如何安装请自行百度 PHP扩展下载:https://github.com/kra ...
- Codeforces Round #230 (Div. 2) C Blocked Points
题目链接 题意 : 给你一个半径为n的圆,圆里边还有圆上都有很多整点,让你找出与圆外的任意一个整点距离等于1的点. 思路 :这个题可以用枚举,画个图就发现了,比如说先数第一象限的,往下往右找,还可以找 ...
- JavaWeb学习总结(三十五)——使用JDBC处理Oracle大数据
一.Oracle中大数据处理 在Oracle中,LOB(Large Object,大型对象)类型的字段现在用得越来越多了.因为这种类型的字段,容量大(最多能容纳4GB的数据),且一个表中可以有多个这种 ...
- libvlc 双击,鼠标事件消息响应
基于vlc 2.1 动态库实现接收双击消息的接收,使双击vlc播放画面可以全屏显示. 需要其他版本的vlc可以与我联系(有偿进行修改) 下载地址:http://download.csdn.net/de ...