我们都知道,在诸如魔兽的很多战略游戏中,会出现要求某A角色接近某B角色的情况(攻击或是怎么着咱不考虑……),玩家很简单的一步操作,却会引发开发者“怎么走过去”这个“复杂”的算法问题,也就是所谓的“Path-finding”——寻径。
好的寻径算法,不但能避免不必要的资源损耗,而且能令游戏友好度增加。反之则会严重影响游戏的可玩性或诸如GIS等系统的可靠性。
在本次,我以Java为例,演示一个最简单的寻径系统——甚至可以说是伪寻径系统的实现。 (^^)
首先,我们建立一个追踪者(一说到这里我就想起了生化里的掠食者……)
packageorg.test.tracker;

importjava.awt.Color;
importjava.awt.Graphics;


/***//**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:追踪者。
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*@authorchenpeng
*@email:ceponline@yahoo.com.cn
*@version0.1
*/

publicclassTracker...{

privatestaticfinalintSIZE=TrackerPanel.SIZE;

publicintx;

publicinty;


/***//**
*析构函数,默认坐标为0,0
*
*/

publicTracker()...{
this(0,0);
}


/***//**
*析构函数,设定x,y坐标
*
*@paramx
*@paramy
*/

publicTracker(intx,inty)...{
this.x=x;
this.y=y;
}


/***//**
*设定追踪对象
*
*@paramprey
*/

publicvoidchase(Objectiveobjective)...{
//始终以目标坐标矫正追踪者坐标。

if(x>objective.x)...{
x--;

}elseif(x<objective.x)...{
x++;
}


if(y>objective.y)...{
y--;

}elseif(y<objective.y)...{
y++;
}
}


/***//**
*绘制追踪者
*
*@paramg
*/

publicvoiddraw(Graphicsg)...{
g.setColor(Color.RED);
g.fillRect(x*SIZE,y*SIZE,SIZE,SIZE);
}
}
而后,我们建立一个被追踪的目标。
packageorg.test.tracker;

importjava.awt.Color;
importjava.awt.Graphics;


/***//**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:被跟踪的目标对象。
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*@authorchenpeng
*@email:ceponline@yahoo.com.cn
*@version0.1
*/

publicclassObjective...{

privatestaticfinalintSIZE=TrackerPanel.SIZE;

privatestaticfinalintUP=0;

privatestaticfinalintDOWN=1;

privatestaticfinalintLEFT=2;

privatestaticfinalintRIGHT=3;

publicintx;

publicinty;


/***//**
*析构函数,内部转换x,y坐标。
*
*/

publicObjective()...{
x=TrackerPanel.COL/2;
y=TrackerPanel.ROW/2;
}


/***//**
*析构函数,设定x,y坐标。
*
*/

publicObjective(intx,inty)...{
this.x=x;
this.y=y;
}


/***//**
*移动目标
*
*@paramdir
*/

publicvoidmove(intdir)...{

switch(dir)...{
caseUP:
y--;
break;
caseDOWN:
y++;
break;
caseLEFT:
x--;
break;
caseRIGHT:
x++;
break;
}
}


/***//**
*绘制目标
*
*@paramg
*/

publicvoiddraw(Graphicsg)...{
g.setColor(Color.BLUE);
g.fillOval(x*SIZE,y*SIZE,SIZE,SIZE);
}
}
最后,我们建立一个面板,用以绘制图形。
packageorg.test.tracker;

importjava.awt.Color;
importjava.awt.Dimension;
importjava.awt.Frame;
importjava.awt.Graphics;
importjava.awt.Image;
importjava.awt.Panel;
importjava.awt.event.KeyEvent;
importjava.awt.event.KeyListener;
importjava.awt.image.BufferedImage;


/***//**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:追踪演示面板。
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*@authorchenpeng
*@email:ceponline@yahoo.com.cn
*@version0.1
*/

publicclassTrackerPanelextendsPanelimplementsRunnable,KeyListener...{

/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;

//设定窗体宽与高
privatestaticfinalintWIDTH=480;

privatestaticfinalintHEIGHT=480;

//描绘的正方体大小
staticfinalintSIZE=8;

//获得对应列数,即将frame转化为类数组的存在。
publicstaticfinalintROW=HEIGHT/SIZE;

publicstaticfinalintCOL=WIDTH/SIZE;

//获得对应行数
privatestaticfinalintUP=0;

privatestaticfinalintDOWN=1;

privatestaticfinalintLEFT=2;

privatestaticfinalintRIGHT=3;

//追踪者
privateTrackertracker;

//目标
privateObjectiveobjective;

privateThreadthread;

privateImagescreen=null;

privateGraphicsbg=null;


publicTrackerPanel()...{
setPreferredSize(newDimension(WIDTH,HEIGHT));
setFocusable(true);
addKeyListener(this);
screen=newBufferedImage(WIDTH,HEIGHT,1);
bg=screen.getGraphics();
//追踪者初始位置,0行,0列
tracker=newTracker(0,0);
//目标初始位置,50行,50列
objective=newObjective(50,50);
thread=newThread(this);
thread.start();
}


publicvoidpaint(Graphicsg)...{
//设定底色为白色,并清屏
bg.setColor(Color.white);
bg.fillRect(0,0,WIDTH,HEIGHT);
//绘制追踪者
tracker.draw(bg);
//绘制目标
objective.draw(bg);
g.drawImage(screen,0,0,this);
g.dispose();
}


publicvoidupdate(Graphicsg)...{
paint(g);
}


publicvoidrun()...{

while(true)...{
//设定追击的目标。
tracker.chase(objective);
repaint();

try...{
Thread.sleep(110);

}catch(InterruptedExceptione)...{
e.printStackTrace();
}
}
}


publicvoidkeyTyped(KeyEvente)...{
}


publicvoidkeyPressed(KeyEvente)...{
intkey=e.getKeyCode();

switch(key)...{
caseKeyEvent.VK_UP:
objective.move(UP);
break;
caseKeyEvent.VK_DOWN:
objective.move(DOWN);
break;
caseKeyEvent.VK_LEFT:
objective.move(LEFT);
break;
caseKeyEvent.VK_RIGHT:
objective.move(RIGHT);
break;
}
repaint();
}


publicvoidkeyReleased(KeyEvente)...{
}


publicstaticvoidmain(String[]args)...{
Framefrm=newFrame();
frm.setTitle("简单的Java图形寻径追踪实现(由Loonframework提供)");
frm.setSize(WIDTH,HEIGHT);
frm.setResizable(false);
frm.add(newTrackerPanel());
frm.setVisible(true);
}

}
这时,画面上显示的红色正方体为追踪者,蓝色圆球为被追踪目标,而无论篮球如何移动,红色正方体都将始终向篮球靠拢。
实际上,通过代码我们就可以知道,这时两者间的移动路径,被没有经过复杂的方法演算,而是以目标的坐标来决定的,颇有独孤九剑那种,敌人若是只有一招,我也只有一招,他若是有千招万招,我也自是千招万招。但是,这种方法在实际的寻径处理中,并不能很好的解决如障碍物,区域转换等问题,所以只是一种[伪]寻径,
或者说是在无障碍情况下的简单解决方案。
如果关注寻径算法在Java中的进一步实现,还请继续关注我的blog……
好的寻径算法,不但能避免不必要的资源损耗,而且能令游戏友好度增加。反之则会严重影响游戏的可玩性或诸如GIS等系统的可靠性。
在本次,我以Java为例,演示一个最简单的寻径系统——甚至可以说是伪寻径系统的实现。 (^^)
首先,我们建立一个追踪者(一说到这里我就想起了生化里的掠食者……)































































































而后,我们建立一个被追踪的目标。





































































































最后,我们建立一个面板,用以绘制图形。




































































































































































这时,画面上显示的红色正方体为追踪者,蓝色圆球为被追踪目标,而无论篮球如何移动,红色正方体都将始终向篮球靠拢。
实际上,通过代码我们就可以知道,这时两者间的移动路径,被没有经过复杂的方法演算,而是以目标的坐标来决定的,颇有独孤九剑那种,敌人若是只有一招,我也只有一招,他若是有千招万招,我也自是千招万招。但是,这种方法在实际的寻径处理中,并不能很好的解决如障碍物,区域转换等问题,所以只是一种[伪]寻径,
或者说是在无障碍情况下的简单解决方案。
如果关注寻径算法在Java中的进一步实现,还请继续关注我的blog……
