【问题标题】:A* algorithm that takes account velocity考虑速度的 A* 算法
【发布时间】:2014-05-04 02:04:04
【问题描述】:

我正在开发像http://harmmade.com/vectorracer/ 这样的赛车游戏,并且我已经实现了供 AI 玩家使用的 A* 算法。该算法适用于 1 块移动,但我不希望 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 - 修改版(在 createNextPossiblePoints 方法中使用速度作为参数)

【问题讨论】:

  • 关键点是将您的 x 和 y 速度表示为状态的一部分,除了 x 和 y 位置。 Track_Point 是否包含它们的字段? (你需要显示Track_Point的定义。)
  • 我已经更新了代码:)
  • 我发现一些事情令人困惑(我不确定 f、g 和 h 代表什么,而且您似乎将速度存储在第二个 Track_Point 对象中(您忽略了它自己的速度) ?)),但您可能需要做的就是更改createNextPossibleTrackPoints(),以便生成与当前点相邻的点,而不是生成与当前点相邻的点,它们是实际的合法位置集,即与您将去的位置相邻的位置,如果您将速度添加到当前点的位置。
  • 还有几件事(那我得走了,对不起):如果distance() 测量欧几里得距离,那么它不一定是到达所需的剩余步数的下限完成,因为您每次移动的速度可能超过 1 个单位——尽管我认为distance() / velocity 会。您也可能对我自己的解决方案感兴趣:stackoverflow.com/a/6598303/47984。这会使用搜索空间的广度优先搜索来计算完全最优(可能的移动次数最少)的解决方案。
  • g 是从起点到当前点的移动成本,h 是当前点和终点之间的估计距离,f 是两者的总和 A* 算法使用的最佳-第一次搜索并这样做,它选择成本最低的节点,即这个解释涵盖了所有内容的 f 值,它是我用来实现 A* link Track_Point 速度的节点,这是我解决问题的失败尝试,我在 createPossiblePoints 方法中将它作为第二个参数传递,它确实创建了正确的下一个位置

标签: java algorithm a-star racing


【解决方案1】:

首先,不要在 x/y 位置使用整数。赛车游戏中不应该有“1 块”之类的东西。您的游戏世界和输出可能完全不同。例如,考虑使用双精度来存储 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(到原点的距离)+ Greedy(到目标的距离)
  2. 在此处插入您的启发式方法
  3. 将它们加在一起并选择最小的数字

没有 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*,一回合的解空间足够小,你可以暴力破解它;如果您撞到墙并喜欢最高速度,请不要将TrackPoints 添加到打开列表中。

真的,仅此而已;简单的东西,但在你需要做的前几次可能会很乏味和困难。

编辑:刚刚玩了矢量赛车,它实际上比我预期的要简单得多。我以为你正在制作一个完整的 2D 赛车游戏。我告诉你的仍然非常适用,但你需要做一些调整,特别是你处理旋转的方式。您一定要查找racing line。我目前没有时间复习赛车线的数学,但this 应该可以帮助您计算。

EDIT2:更新了速度部分。我将进行一些计算以找出更快的启发式算法,但目前的情况足以检查 3-10 步前进而不会出现重大性能问题。

【讨论】:

  • 如果您点击了该链接,您会发现浮点坐标对这个游戏没有任何意义。
  • @j_random_hacker 是的,我只是这样做并进行了编辑。感谢您的提醒。尽管如此,我所说的大部分内容仍然非常适用。我认为最困难的部分可能是决定哪些旋转角度适合网格。
  • 感谢您的快速回复,我会尝试您的建议并回复您。我只有 1 个问题:为什么在我的实现中仍然需要旋转角度?在 Vector Racer 中转动“汽车”取决于下一个可用位置,而这些位置又取决于前一个位置,即使用的速度
  • @fatherjim91 现在我有空闲时间更新了速度。我会看看我能不能找出一个好转的公式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-10
  • 1970-01-01
  • 1970-01-01
  • 2017-03-06
  • 2020-10-18
  • 1970-01-01
相关资源
最近更新 更多