我们都知道,在诸如魔兽的很多战略游戏中,会出现要求某A角色接近某B角色的情况(***或是怎么着咱不考虑……),玩家很简单的一步操作,却会引发开发者“怎么走过去”这个“复杂”的算法问题,也就是所谓的“Path-finding”——寻径。

好的寻径算法,不但能避免不必要的资源损耗,而且能令游戏友好度增加。反之则会严重影响游戏的可玩性或诸如GIS等系统的可靠性。

在本次,我以Java为例,演示一个最简单的寻径系统——甚至可以说是伪寻径系统的实现。 (^^)

首先,我们建立一个追踪者(一说到这里我就想起了生化里的掠食者……)

package  org.test.tracker;

import  java.awt.Color;
import  java.awt.Graphics;

/** */ /**
 * 


 * Title: LoonFramework
 * 


 * 


 * Description:追踪者。
 * 


 * 


 * Copyright: Copyright (c) 2007
 * 


 * 


 * Company: LoonFramework
 * 


 * 
 * 
@author chenpeng
 * @email:[email][email protected][/email]
 * 
@version 0.1
 
*/

public   class  Tracker  ... {

    
private static final int SIZE = TrackerPanel.SIZE;

    
public int x;

    
public int y;

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

    
public Tracker() ...{
        
this(00);
    }


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

    
public Tracker(int x, int y) ...{
        
this.x = x;
        
this.y = y;
    }


    
/** *//**
     * 设定追踪对象
     * 
     * 
@param prey
     
*/

    
public void chase(Objective objective) ...{
        
//始终以目标坐标矫正追踪者坐标。
        if (x > objective.x) ...{
            x
--;
        }
 else if (x < objective.x) ...{
            x
++;
        }


        
if (y > objective.y) ...{
            y
--;
        }
 else if (y < objective.y) ...{
            y
++;
        }

    }


    
/** *//**
     * 绘制追踪者
     * 
     * 
@param g
     
*/

    
public void draw(Graphics g) ...{
        g.setColor(Color.RED);
        g.fillRect(x 
* SIZE, y * SIZE, SIZE, SIZE);
    }

}


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

package  org.test.tracker;

import  java.awt.Color;
import  java.awt.Graphics;

/** */ /**
 * 


 * Title: LoonFramework
 * 


 * 


 * Description:被跟踪的目标对象。
 * 


 * 


 * Copyright: Copyright (c) 2007
 * 


 * 


 * Company: LoonFramework
 * 


 * 
 * 
@author chenpeng
 * @email:[email][email protected][/email]
 * 
@version 0.1
 
*/

public   class  Objective  ... {

    
private static final int SIZE = TrackerPanel.SIZE;

    
private static final int UP = 0;

    
private static final int DOWN = 1;

    
private static final int LEFT = 2;

    
private static final int RIGHT = 3;

    
public int x;

    
public int y;

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

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

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

    
public Objective(int x, int y) ...{
        
this.x = x;
        
this.y = y;
    }


    
/** *//**
     * 移动目标
     * 
     * 
@param dir
     
*/

    
public void move(int dir) ...{
        
switch (dir) ...{
        
case UP:
            y
--;
            
break;
        
case DOWN:
            y
++;
            
break;
        
case LEFT:
            x
--;
            
break;
        
case RIGHT:
            x
++;
            
break;
        }

    }


    
/** *//**
     * 绘制目标
     * 
     * 
@param g
     
*/

    
public void draw(Graphics g) ...{
        g.setColor(Color.BLUE);
        g.fillOval(x 
* SIZE, y * SIZE, SIZE, SIZE);
    }

}


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

package  org.test.tracker;

import  java.awt.Color;
import  java.awt.Dimension;
import  java.awt.Frame;
import  java.awt.Graphics;
import  java.awt.Image;
import  java.awt.Panel;
import  java.awt.event.KeyEvent;
import  java.awt.event.KeyListener;
import  java.awt.p_w_picpath.BufferedImage;

/** */ /**
 * 


 * Title: LoonFramework
 * 


 * 


 * Description:追踪演示面板。
 * 


 * 


 * Copyright: Copyright (c) 2007
 * 


 * 


 * Company: LoonFramework
 * 


 * 
 * 
@author chenpeng
 * @email:[email][email protected][/email]
 * 
@version 0.1
 
*/

public   class  TrackerPanel  extends  Panel  implements  Runnable, KeyListener  ... {
    
/** *//**
     * 
     
*/

    
private static final long serialVersionUID = 1L;

    
// 设定窗体宽与高
    private static final int WIDTH = 480;

    
private static final int HEIGHT = 480;

    
// 描绘的正方体大小
    static final int SIZE = 8;

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

    
public static final int COL = WIDTH / SIZE;

    
// 获得对应行数
    private static final int UP = 0;

    
private static final int DOWN = 1;

    
private static final int LEFT = 2;

    
private static final int RIGHT = 3;

    
// 追踪者
    private Tracker tracker;

    
// 目标
    private Objective objective;

    
private Thread thread;

    
private Image screen = null;

    
private Graphics bg = null;

    
public TrackerPanel() ...{
        setPreferredSize(
new Dimension(WIDTH, HEIGHT));
        setFocusable(
true);
        addKeyListener(
this);
        screen 
= new BufferedImage(WIDTH, HEIGHT, 1);
        bg 
= screen.getGraphics();
        
// 追踪者初始位置,0行,0列
        tracker = new Tracker(00);
        
// 目标初始位置,50行,50列
        objective = new Objective(5050);
        thread 
= new Thread(this);
        thread.start();
    }


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


    
public void update(Graphics g) ...{
        paint(g);
    }


    
public void run() ...{
        
while (true...{
            
// 设定追击的目标。
            tracker.chase(objective);
            repaint();
            
try ...{
                Thread.sleep(
110);
            }
 catch (InterruptedException e) ...{
                e.printStackTrace();
            }

        }

    }


    
public void keyTyped(KeyEvent e) ...{
    }


    
public void keyPressed(KeyEvent e) ...{
        
int key = e.getKeyCode();
        
switch (key) ...{
        
case KeyEvent.VK_UP:
            objective.move(UP);
            
break;
        
case KeyEvent.VK_DOWN:
            objective.move(DOWN);
            
break;
        
case KeyEvent.VK_LEFT:
            objective.move(LEFT);
            
break;
        
case KeyEvent.VK_RIGHT:
            objective.move(RIGHT);
            
break;
        }

        repaint();
    }


    
public void keyReleased(KeyEvent e) ...{
    }


    
public static void main(String[] args) ...{
        Frame frm 
= new Frame();
        frm.setTitle(
"简单的Java图形寻径追踪实现(由Loonframework提供)");
        frm.setSize(WIDTH, HEIGHT);
        frm.setResizable(
false);
        frm.add(
new TrackerPanel());
        frm.setVisible(
true);
    }


}


这时,画面上显示的红色正方体为追踪者,蓝色圆球为被追踪目标,而无论篮球如何移动,红色正方体都将始终向篮球靠拢。

实际上,通 过代码我们就可以知道,这时两者间的移动路径,被没有经过复杂的方法演算,而是以目标的坐标来决定的,颇有独孤九剑那种,敌人若是只有一招,我也只有一 招,他若是有千招万招,我也自是千招万招。但是,这种方法在实际的寻径处理中,并不能很好的解决如障碍物,区域转换等问题,所以只是一种[伪]寻径,
或者说是在无障碍情况下的简单解决方案。

如果关注寻径算法在Java中的进一步实现,还请继续关注我的blog……