考虑速度的A *算法

时间:2014-05-04 02:04:05

标签: java algorithm a-star racing

我正在开发像http://harmmade.com/vectorracer/这样的赛车游戏,我已经实现了A *算法用于AI玩家。该算法适用于1-tile运动,但我不希望AI玩家一次只移动1个瓦片(仅使用相邻的点),我需要它们能够加速和减速时他们正在转弯。他们的下一个位置应该取决于他们之前的位置,就像Vector Racer一样。

public boolean createRoute() {

    // The list where the points will be added in reverse order (from finish_point)
    ArrayList<Track_Point> path = new ArrayList<>();
    // The list where the unchecked points will be stored
    ArrayList<Track_Point> open = new ArrayList<>();
    // The list where the checked points will be stored
    ArrayList<Track_Point> closed = new ArrayList<>();
    // The starting point is always added as the first point to be checked
    open.add(starting_point);
    Track_Point current;

    while (true) {
        current = null;

        // If all points from the open list have been removed (be being checked), it means that there isn't a possible path from the starting to the finish point
        if (open.isEmpty()) {
            System.out.println("no route available");
            return false;
        }

        // Selects the point with the lowest F value from the open list
        for (Track_Point temp : open) {
            temp.show();
            if (current == null || temp.getF() < current.getF()) {
                current = temp;
            }
        }

         // If the current point has reached the finish point, break the loop to construct the path
        if (current.equals(finish_point)) {
            break;
        }

        // Removes the current point (with the lowest F value) from the open list
        open.remove(current);
        // Adds the current point (with the lowest F value) to the closed list
        closed.add(current);
        ArrayList<Track_Point> possible_points = createNextPossibleTrackPoints(current);
        //Sets the parent of the possible points
        for (Track_Point tp : possible_points) {
            if (!tp.equals(current)) {
                tp.setParent(current);
            }
        }

        for (Track_Point possible_point : possible_points) {
            double nextG = current.getG() + current.distance(possible_point);
            if (nextG < possible_point.getG()) {
                open.remove(possible_point);
                closed.remove(possible_point);
            }

            if (!open.contains(possible_point) && !closed.contains(possible_point)) {
                possible_point.setParent(current);
                open.add(possible_point);
            }
        }
    }
    //Track_Point current = finish_point;
    while (current.getParent() != null) {
        path.add(current);
        current = current.getParent();
    }
    // optimalRacingLine is the list where all the points will be held in the correct order
    optimalRacingLine.add(starting_point);
    for (int k = path.size() - 1; k >= 0; k--) {
        optimalRacingLine.add(path.get(k));
    }
    return true;
}

createPossiblePoints(Point current)到目前为止返回当前点的邻接列表。 每个点的H值都是在它们的构造函数中计算的,因为我在那里通过终点并计算它们之间的距离。 当我为其设置父项时,计算每个点的G值,G值是从新点到其父项的距离+父项的G值。

如何修改此代码以允许加速/减速?

Track_Point的代码:

package model;

import javafx.geometry.Point2D;

public class Track_Point extends Point2D {

    private Track_Point parent, velocity;
    private double f, g, h;

    public Track_Point(double x, double y) {
    super(x, y);
    }

    public Track_Point(double x, double y, Track_Point f) { // f is the finish point
    super(x, y);
    h = distance(f);
    }

    public void setParent(Track_Point tp) {
    parent = tp;
    g = distance(tp) + tp.getG();
    f = g + h;
    velocity = new Track_Point(getX() - parent.getX(), getY() - parent.getY());
    }

    public Track_Point getParent() {
    return parent;
    }

    public double getG() {
    return g;
    }

    public double getH() {
    return h;
    }

    public double getF() {
    return f;
    }

    public Track_Point getVelocity() {
    return velocity;
    }

    @Override
    public String toString() {
    return "( " + (int) getX() + " , " + (int) getY() + " )";
    }

    public void show() {
    System.out.println(toString());
    }

}

添加了我失败的尝试和工作简单的A *版本

的一些截图

http://tinypic.com/r/zlakg2/8 - 工作版

http://tinypic.com/r/2e3u07o/8 - 修改版本(使用velocity作为createNextPossiblePoints方法中的参数)

1 个答案:

答案 0 :(得分:2)

首先,不要将整数用于x / y位置。应该没有&#39; 1 tile&#39;在赛车游戏中。您的游戏世界和输出可能完全不同。例如,考虑使用双精度来存储x和y。 Ssh,不用担心,你的JFrame不需要知道。

启发式

您正在使用A *来运行AI吗?考虑这些额外的启发式方法:

  • 喜欢高速; cost = max velocity - current velocity
  • 靠近转弯边缘(想象转弯为圆圈的外边缘); cost = distance_from(focus of turn)
  • 避免墙壁; cost = isMovable(x, y) ? 0 : infinite/high
  • 编辑选择最短路径以避免在第二张图片时进行不必要的移动(广度优先搜索 Djikstra); cost = steps from first node

A *的工作方式如下:

  1. 使用Djikstra(距离原点)+贪婪(距离目标)
  2. 在此处插入您的启发录
  3. 将它们全部添加在一起并选择最小数字
  4. 没有f,g或h这样的东西;它不是你不需要知道的数学废话。

    速度

    velocity = Math.abs(position1 - position2);所以... position1 + velocity = position2。 您需要添加以下变量:

    • int xVelocity
    • int yVelocity

    每一刻,x += xVelocity; y += yVelocity。 下一个职位将是xf = x + xVelocity; yf = y + yVelocity。然后,您在该位置周围绘制一个环,如下所示:

             +yVelocity
                \|/
    -xVelocity  -0-  +xVelocity
                /|\
            -yVelocity
    

    因此,中心保持相同的速度,任何相邻的一侧都会改变一个速度,任何对角线都会改变两个速度。 至于使用A *,转弯的解决方案空间足够小,你可以强行使用它;如果碰到墙壁并且喜欢最高速度,请不要将TrackPoint添加到打开列表中。

    真的,这就是它的全部;简单的东西,但前几次你需要这样做可能会很乏味和困难。

    编辑:刚刚玩过矢量赛车,它实际上比我想象的要简单得多。我以为你正在制作一个完整的2d赛车游戏。我告诉你的内容仍然非常适用,但你需要做一些调整,特别是你处理轮换的方式。你肯定想查找racing line。我现在还没有时间浏览赛车线的数学,但是this应该帮助你计算它。

    EDIT2:更新了Velocity部分。我会做一些计算以找出更快的启发式算法,但是现有的内容足以检查3-10步,而不会出现重大的性能问题。