关于即时战略的讨论

jackmay 2003-05-21 09:17:37
这里先讨论游戏单位的问题
我列出的单位class:
java伪代码

class unit extends base implements 行走,攻击
{
public 行走(){};
public 寻找路径(){};
public 攻击(){};
public 生命值增加(){};
public 生命值减少(){};
public 特殊技能(){};
private int 生命值;
private int 攻击力;
private 自定义地点类型 目的地路径[];
privete 自定义地点类型 目的地;
private 自定义地点类型 当前地点;
}
interface 行走
{
public void 行走()
{};
}
interface 攻击
{
public void 攻击()
{};
}


这个框架可以吗?
初学者
什么都不懂
如果有什么地方不对
大家请指出来

谢谢
...全文
51 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
jackmay 2003-05-29
  • 打赏
  • 举报
回复
举个例子来说,游戏中有某种魔法可以使一个陆地unit拥有短暂的水上能力,那么考虑它的寻径问题就非常复杂(注意还有时效问题),难道你把这些都放在map的寻径中吗。}

这个应该不是问题
我前面说过
只要给地图注明是陆地寻径还是水上寻径就可以
当陆地unit短暂拥有水上活动能力时
只需它同时对标注为水的部分有一种包容策略就可以了

map是属于数据层的对象,它可以提供两点间的最短路径,但不应该考虑unit的属性。}
我这里没有考虑unit的属性
只是说对地图上各部分都有相同性质的地图元素(如陆地、海洋)
都存在一种可抵达的路径列表
至于unit是什么东西
是陆地的还是海洋的亦或是水陆两栖的
只需各取所需
陆地的找陆地的列表
海洋的找海洋的列表
水陆两栖的两个都包括在内即可

我还是在校生
不知道商业开发会采用什么样的策略
只是一点想法而已
天堂里的死神 2003-05-29
  • 打赏
  • 举报
回复
我觉得可以先做一个简简单单的小模型,可以用鼠标控制他的移动:其实这已经要求一个比较完善的框架了。
然后再不断重构。
最好先去找找一些开源的,比较“名牌”的游戏,看看他们的抽象,然后就会有思路了。
libi 2003-05-29
  • 打赏
  • 举报
回复
如果参照商业软件的三层结构,采用什么样的寻径策略,那是逻辑层的东西,而map是属于数据层的对象,它可以提供两点间的最短路径,但不应该考虑unit的属性。如果你为了提高效率,把寻径做到map里,那么就相当于把逻辑规则固化到map中去了,如果说你的规则简单并且不会再改变了,这样做也不是不可以。举个例子来说,游戏中有某种魔法可以使一个陆地unit拥有短暂的水上能力,那么考虑它的寻径问题就非常复杂(注意还有时效问题),难道你把这些都放在map的寻径中吗。
一个好的设计应该把属于逻辑规则的东西提取出来,这样做出的游戏才能够用脚本来写游戏剧本。
8alang8 2003-05-29
  • 打赏
  • 举报
回复

不如先考虑一下游戏的可玩性、平衡性等,提取出游戏的比较大的特征。比如星际里的隐形兵种,这些特征一般需要程序的特别处理,所以要先确定,以免后期改来改去。

如果是写着玩的话,不如找个成功的游戏作基本模型,再根据自己的情况做些增删,确定好了游戏框架后再讨论实现方法。
jackmay 2003-05-28
  • 打赏
  • 举报
回复
回来了
再续我的蜂窝理论^_^

当战斗单元从当前的控制区域找到一条路径时
从当前所在位置找到到下一个区域控制点的最短路径
并依这条路径前进
到达下一个区域时
再如法炮制
如此这般
到达目标地所在区域后
直达目标地点即可

这样的方法有几个好处
首先
当玩家要某个战斗单位前往某个地点时
立刻就可以知道是否可以到达(查控制点的路径表即可)
然后的寻径也是每次只需完成很少的运算量就可以(因为相邻的区域很容易找到路径)
而且不会产生比如某些战斗单元先找路径,而某些后找的现象
保证游戏的连贯性
其次
这种方法可以保证战斗单位绝对可以到达目标地点(只要路途中没有埋伏或者桥梁断掉)
而且速度有保障
因为战斗单位不是盲目的寻找(即使用A*算法,也需要有一些无谓的探索)

这种方法的缺点是地图需要一些额外的内存开销
因为路径表每个控制点都要有
但只要控制好每个区域的大小和数量
这点开销还是可以接受的
况且现在的计算机内存已经达到了几百兆的水平
已经可以满足很大的内存需求了

可以说
这种方法是以空间换时间的策略
只需在地图生成时
将每个控制点的路径表生成即可
然后游戏过程中就会得到很轻松的寻径服务了

突发奇想
请高手指教

alin19 2003-05-28
  • 打赏
  • 举报
回复
肯定要用a*算法的拉,远距离在设事先设好的路径
jackmay 2003-05-28
  • 打赏
  • 举报
回复
大家说的是
我只是想到哪里就说哪里
见笑
8alang8 2003-05-28
  • 打赏
  • 举报
回复

现在就讨论算法太早了。还要涉及到很多问题的。比如,陆地单位本身就有可能成为障碍,这个问题不是仅仅考虑地图上的因素就可以解决的。

墙都没垒好呢,就要盖瓦片,往哪儿盖啊?
天堂里的死神 2003-05-28
  • 打赏
  • 举报
回复
说句不中听的话……我觉得在这么早就介入这些具体的细节,意义不是特别大……

其实现在连Map和Unit以及Unit所属的Object之间的关系都没有搞清楚。Map是不可能与Unit同级考虑的,信息的传递?Trigger?等等问题全都跟总体架构密切相关。而寻路算法只能算是这个体系中的一个方法。只有当体系框架清楚了,方法以及他的收益才能特定清楚:这也许算是OO的硬伤。

当然海里的猫先生对算法的描述很正确,是否能对更高层的东西展开讨论?
天堂里的死神 2003-05-28
  • 打赏
  • 举报
回复
阿,对不起,我以为您贴出来的是框架,后来才发现原来只是单位,

没有构架好游戏层框架之前,最好不要深入某个部分的细节,否则会很痛苦。
天堂里的死神 2003-05-28
  • 打赏
  • 举报
回复
这个框架有问题,抽象度可能还不够,地图渲染和物体渲染是分开的、调度器、Trigger、脚本都没有留出位置,而应用程序层没有建立起来。所以我觉得……

您的框架里的部分东西,应该是作为地图Update和物体Update的内容,对于框架来说,应力求做到与游戏细节无关。

凌晨了,不多说,有兴趣了我们可以继续讨论。
jackmay 2003-05-28
  • 打赏
  • 举报
回复
风自吟同志
关于不同单位的寻径问题
我这样认为
陆地上的所有单位
不管是坦克、矿车、士兵还是旺财
其寻径方法应该差不多
然后天上飞的更简单
根本不用寻径
沿着两点坐标间的直线图象飞过去就可以了
海里的嘛
由于海洋只有船只等少量单位可以行走
所以只要加上特殊标记
不允许陆地的进入就可以
同理
海里的也不能进入陆地

请指教
DarthVader 2003-05-27
  • 打赏
  • 举报
回复
//------------------------------------------------------------------------
// Name: CAstarFind::CheckOPEN()
// Desc: Check from node open for a node with the desired number
//------------------------------------------------------------------------

NODE* CAstarFind::CheckOPEN(int num)
{
NODE *temp;
temp = open;
while(temp != NULL)
{
if (temp->number == num)
return temp;
temp = temp->next;
}
return temp;
}



//------------------------------------------------------------------------
// Name: CAstarFind::CheckCLOSE()
// Desc: Check from node close for a node with the desired number
//------------------------------------------------------------------------

NODE* CAstarFind::CheckCLOSE(int num)
{
NODE *temp;
temp = close;
while(temp != NULL)
{
if (temp->number == num)
return temp;
temp = temp->next;
}
return temp;
}



//------------------------------------------------------------------------
// Name: CAstarFind::Push()
// Desc: Push a node into the stack. Why should we prepare a stack
// for a node?
//------------------------------------------------------------------------

void CAstarFind::Push(NODE * node)
{
STACK *temp = new STACK;
temp->node = node;
temp->next = stack;
stack = temp;
}



//------------------------------------------------------------------------
// Name: CAstarFind::Pop()
// Desc: Pop a node from the stack.
//------------------------------------------------------------------------

NODE* CAstarFind::Pop()
{
STACK *tempS;
NODE *tempN;
tempS = stack;
tempN = stack->node;
stack = stack->next;
free(tempS);
return tempN;
}



//------------------------------------------------------------------------
// Name: CAstarFind::PropagateDown()
// Desc: Propagate down and include more nodes
//------------------------------------------------------------------------

void CAstarFind::PropagateDown(NODE * old)
{
int c, g;
NODE *child, *father;

// 把旧节点的属性遗传给子节点(如果有的话),把子节点入栈
g = old->g;
for (c = 0; c < 8; c++)
{

if ((child = old->child[c]) == NULL)
break;

// 子节点的g值应该比父节点大一
if (g + 1 < child->g)
{
child->g = g + 1;
child->f = child->g + child->h;
child->parent = old;
Push(child);
}
}

// 为栈中每个元素的子节点生成属性,呵呵,象深度优先的顺序
while(stack->next != NULL)
{
father = Pop();
for (c = 0; c < 8; c++)
{
if ((child = father->child[c]) == NULL)
break;
if (father->g + 1 < child->g)
{
child->g = father->g + 1;
child->f = child->g + child->h;
child->parent = father;
Push(child);
}
}
}
}



//------------------------------------------------------------------------
// Name: CAstarFind::Insert()
// Desc: Insert a node:succ, into the list, according to its eval
//------------------------------------------------------------------------

void CAstarFind::Insert(NODE * succ)
{
NODE *tmp1, *tmp2;
int f;

if (open == NULL)
{
open = succ;
succ->next = NULL;
return;
}

f = succ->f;
tmp1 = open;
tmp2 = open->next;

while((tmp2 != NULL) && (tmp2->f < f))
{
tmp1 = tmp2;
tmp2 = tmp2->next;
}

succ->next = tmp2;
tmp1->next = succ;
}



//------------------------------------------------------------------------
// Name: CAstarFind::FreeNodes()
// Desc: Free the linked nodes from two start points: open and close
//------------------------------------------------------------------------

void CAstarFind::FreeNodes()
{
NODE *Node, *OldNode;

if (open != NULL)
{
Node = open;
while(Node != NULL)
{
OldNode = Node;
Node = Node->next;
free(OldNode);
}
}

if (close != NULL)
{
Node = close;
while(Node != NULL)
{
OldNode = Node;
Node = Node->next;
free(OldNode);
}
}

open = close = NULL;
}



//------------------------------------------------------------------------
// Name: CAstarFind::FreeStack()
// Desc: Free the work stack
//------------------------------------------------------------------------

void CAstarFind::FreeStack()
{
STACK *Temp;

Temp = stack;
while(Temp != NULL)
{
free(Temp->node);
Temp = Temp->next;
}
stack = NULL;
}



//------------------------------------------------------------------------
// Name: CAstarFind::NewPath()
// Desc: Generate a new path from src to dest,calls FindPath()
//------------------------------------------------------------------------

BOOL CAstarFind::NewPath(int sx, int sy, int dx, int dy)
{
// 起点就是终点,不用麻烦了
if (GetTileNum(sx, sy) == GetTileNum(dx, dy))
{
findok = FALSE;
return FALSE;
}

// 如果起点终点都合法(即在地图范围内) 试图找到一条路径
if (*(map + sy * width + sx) <= 0 && *(map + dy * width + dx) <= 0)
{
FreeNodes();
FreeStack();
FindPath(sx, sy, dx, dy);
if (findok)
return TRUE;
return FALSE;
}
else
{
findok = FALSE;
return FALSE;
}
}
DarthVader 2003-05-27
  • 打赏
  • 举报
回复
这个程序有点问题,大家看看:
//------------------------------------------------------------------------
// File: AStarPath.cpp
// Desc: Implement a A*(A Star search) path finding algorithm.
// This file implements the CAstarFind class.Note that the map
// is a 1-D array.
// Modifier: Qt.Wang de Blizz 2003.5.25-
//------------------------------------------------------------------------

#include "AstarFind.h"


//------------------------------------------------------------------------
// Implementation of calss CAstarFind
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// Name: CAstarFind::CAstarFind()
// Desc: Constructor
//------------------------------------------------------------------------

CAstarFind::CAstarFind(int *m, int w, int h)
{
open = NULL;
close = NULL;
stack = NULL;
map = m;
width = w;
height = h;
tilecount = w * h;
findok = FALSE;
path.path = new POINT [tilecount + 1];
}


//------------------------------------------------------------------------
// Name: CAstarFind::~CAstarFind()
// Desc: Destructor
//------------------------------------------------------------------------

CAstarFind::~CAstarFind()
{
FreeNodes();
FreeStack();
delete path.path;
}


//------------------------------------------------------------------------
// Name: CAstarFind::FindPath()
// Desc: Find a path from (sx,sy) to (dx,dy) via A* algorithm
//------------------------------------------------------------------------

void CAstarFind::FindPath(int sx, int sy, int dx, int dy)
{
NODE *node, *bestnode;
int destnum = GetTileNum(sx, sy);

// 建立搜索开始节点
node = new NODE;
node->g = 0;
node->h = (dx - sx) * (dx - sx) + (dy - sy) * (dy - sy);
node->f = node->g + node->h;
node->x = dx;
node->y = dy;
node->number = GetTileNum(dx, dy);
node->parent = NULL;
node->next = NULL;
for (int i = 0; i < 8; i++)
node->child[i] = NULL;

open = node;

// 用A*算法寻找一条路径
while(TRUE)
{
// 当前下一步的最佳选择
bestnode = ReturnBestNode();

// 无路可走
if (bestnode == NULL)
{
findok = FALSE;
break;
}

// 抵达终点,逆序弹出每一步,找到从起点到终点的路径
else if (bestnode->number == destnum)
{
findok = TRUE;
NODE *temp = bestnode;
for (int i = 0; temp != NULL; i++, temp = temp->parent)
{
path.path[i].x = temp->x;
path.path[i].y = temp->y;
}
path.count = i;
break;
}

// 继续找下一步
CreateChild(bestnode, sx, sy);
}
}

//------------------------------------------------------------------------
// Name: CAstarFind::ReturnBestNode()
// Desc: 返回当前最佳节点
// (原open,后继是原close,当前open指针下移到后继,close变为原open)
//------------------------------------------------------------------------

NODE* CAstarFind::ReturnBestNode()
{
NODE *temp;

if (open == NULL)
return NULL;
temp = open;
open = open->next;
temp->next = close;
close = temp;
return temp;
}



//------------------------------------------------------------------------
// Name: CAstarFind::CreateChild()
// Desc: Create child nodes in the adjacent 8 directions
//------------------------------------------------------------------------

void CAstarFind::CreateChild(NODE * b, int dx, int dy)
{
int x, y;

for (int i = 0; i < 8; i++)
b->child[i] = NULL;
// up - left
if (GetTileType(x = b->x - 1, y = b->y - 1) <= 0)
if (x >= 0 && x < width && y >= 0 && y < height)
_CreateChild(b, x, y, dx, dy);
// up
if (GetTileType(x = b->x, y = b->y - 1) <= 0)
if (x >= 0 && x < width && y >= 0 && y < height)
_CreateChild(b, x, y, dx, dy);
// up - right
if (GetTileType(x = b->x + 1, y = b->y - 1) <= 0)
if (x >= 0 && x < width && y >= 0 && y < height)
_CreateChild(b, x, y, dx, dy);
// right
if (GetTileType(x = b->x + 1, y = b->y) <= 0)
if (x >= 0 && x < width && y >= 0 && y < height)
_CreateChild(b, x, y, dx, dy);
// down - right
if (GetTileType(x = b->x + 1, y = b->y + 1) <= 0)
if (x >= 0 && x < width && y >= 0 && y < height)
_CreateChild(b, x, y, dx, dy);
// down
if (GetTileType(x = b->x, y = b->y + 1) <= 0)
if (x >= 0 && x < width && y >= 0 && y < height)
_CreateChild(b, x, y, dx, dy);
// down - left
if (GetTileType(x = b->x - 1, y = b->y + 1) <= 0)
if (x >= 0 && x < width && y >= 0 && y < height)
_CreateChild(b, x, y, dx, dy);
// left
if (GetTileType(x = b->x - 1, y = b->y) <= 0)
if (x >= 0 && x < width && y >= 0 && y < height)
_CreateChild(b, x, y, dx, dy);
}



//------------------------------------------------------------------------
// Name: CAstarFind::_CreateChild()
// Desc: Create a childnode of b at (x,y) with the dest (dx,dy)
//------------------------------------------------------------------------

void CAstarFind::_CreateChild(NODE * b, int x, int y, int dx, int dy)
{
int i, snum = GetTileNum(x, y),g = b->g + 1;

NODE *old;

// 找到序号满足的(说明就是坐标为(x,y)的节点)
if ((old = CheckOPEN(snum)) != NULL)
{
// 如果全满怎么办,后面岂不要内存越界?
// 看看上一个函数,会知道不会全满:
// 一开始有八个空指针,生成8个子节点
for (i = 0; i < 8; i++)
if (b->child[i] == NULL)
break;

// 找到一个空位子
// 把old设置为b的子节点,b设为old的父节点
b->child[i] = old;

if (g < old->g)
{
old->parent = b;
old->g = g;
old->f = g + old->h;
}
}

// 这个分支和上面的那个有何区别!?
else if ((old = CheckOPEN(snum)) != NULL)
{
for (i = 0; i < 8; i++)
if (b->child[i] == NULL)
break;
b->child[i] = old;
if (g < old->g)
{
old->g = g;
old->f = g + old->h;
PropagateDown(old);
}
}

// 不存在这样的结点,那么新建一个,再插入
else
{
NODE *succ = new NODE;
succ->parent = b;
succ->g = g;
succ->h = (x - dx) * (x - dx) + (y - dy) * (y - dy);
succ->f = g + succ->h;
succ->x = x;
succ->y = y;
succ->number = snum;
for (i = 0; i < 8; i++)
succ->child[i] = NULL;
Insert(succ);
for (i = 0; i < 8; i++)
if (b->child[i] == NULL)
break;
b->child[i] = succ;
}
}
jackmay 2003-05-27
  • 打赏
  • 举报
回复
要熄灯了
明早再续^_^
jackmay 2003-05-27
  • 打赏
  • 举报
回复
时间太短
马上就要熄灯
没时间看你的程序
这里先写点今天想出的东西

关于即时战略里的寻径问题
可不可以模拟蜂窝电话的网络服务方式
即:
整张地图分成若干区域
每个区域内的所有地形均互相可见
就是在该区域内任意一点均可以到达该区域内任意另一点
然后
每个区域都有一控制点
该控制点存有一张路径表
记录该区域可到达的所有区域
并记录到达的路径
比如:(1,45,67,7,8,10)
其中1是当前点,10是目标点,其他都是中间路径
当有若干单元要从当前区域到达目标区域某点时
只需要查一下当前区域的控制点记录表内是否有到达目标区域的路径
立即就可以得知是否可以到达
省出很多时间来查找路径
当有可以到达的路径
选择一条最近的
nnfish 2003-05-27
  • 打赏
  • 举报
回复
学习。。
libi 2003-05-26
  • 打赏
  • 举报
回复
我的意思并不是说计算机应该采用什么样的策略去寻径,这是游戏设计者去考虑的事情,我在上面只是举个例子而已。
我的意思是map对象的寻径只考虑地形因素,而unit对象的寻径则考虑其自身因素,不应该把不属于其职责的东西强加给它,否则就会形成强耦合。如果这种耦合无法避免,例如说不同unit对不同地形的机动力是不同的,这就使得寻径时得对地形加权,这种情况就应该设计一个新的与unit和map关联的类来专门处理。这就是面向对象的思想,显然这种处理效率是不高的,但是它很灵活,可以使游戏设计者从算法脱离出来,专心去考虑unit的寻径策略。
针对这一问题,我想应该这样设计。由于unit的“个性”,还包括分布在map上的可见敌军友军,以及根据各种信息及其智能程度推测出的隐藏的敌军友军,在它眼里的map是“不同”的,所以应该定义一个与unit一一对应的对象“视图map”,它的寻径和行动判断都基于这个视图map。但这样一来,就会有很多的视图map对象,造成信息冗余,并且不易管理,效率低下,这对实时性要求高的游戏来说,恐怕就是致命的了。
libi 2003-05-24
  • 打赏
  • 举报
回复
我说的是对应真实的情况,你所说的实际上应该算是计算机作弊,就好像牌类游戏,计算机应该只能根据手中的和出过的牌来考虑,但通常都是把玩家手中牌也考虑在内的。
当然我的意思并不是不允许这样做,把寻径分开,你就有了选择的余地,作弊也可以,不作弊也可以,而且可以根据unit自身的属性决定路径,比如说走水路,走陆地等。
jackmay 2003-05-24
  • 打赏
  • 举报
回复
只能是先到达视野内一个靠近目标的位置,再接着寻下一个位置,最后到达目标。不过这样一来,效率就不高了,本来OO的效率通常不高。

应该不是这样吧
如果是这样
就是以局部最优导致全局最优
但是这种算法可能会得到最后一步才发现采用的是完全错误的结果
也就是说
一两坦克要到河对岸去
按照你说的方法
也许它会找到最靠近河对岸目标点的地方
然后才发现得先过河
再折回去
而这种情况在红警中是不会发生的
玩家命令作战单位到一个地点
它会直接找到最短路径
然后走过去
而不是走一点
发现不对
再找别的路

另外
你的意思是
unit公用map中的寻径函数
是吗
加载更多回复(17)

8,303

社区成员

发帖
与我相关
我的任务
社区描述
游戏开发相关内容讨论专区
社区管理员
  • 游戏开发
  • 呆呆敲代码的小Y
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧