游戏编程-将玩家保持在比赛场地内并避免某些障碍

时间:2018-12-15 09:34:33

标签: java

我的课程下周将学习Java子类化和extends。我们的讲师为我们提供了一个游戏代码,人工智能在其中移动并收集了所谓的“苹果”。

A是好苹果,而B是坏苹果。 1到处移动(运行代码时)是我们的参与者。无论苹果A是否在其范围内,播放器都会自动移向苹果B。它还倾向于越界,这将停止程序。如果播放器没有超出范围,则该程序将在循环500次后停止。

我们的讲师要求我们更正此代码中的某些部分,以便

  1. 玩家AI永无止境,
  2. 玩家AI尽可能避免使用苹果B(除非它靠近边界,否则玩家别无选择,只能取走坏苹果)

我们唯一可以纠正的地方分别标记为※1class MyPlayerAI extends PlayerAIBase)和※2PlayerAIBase playerAI = new in main class)。我一直在尝试添加条件,但没有添加条件,但似乎仍无法获得理想的结果。

我知道这个问题可能含糊且不限成员名额,但是有人可以帮助我解决该代码中的错误吗?非常感谢任何帮助/指针。我并没有直接要求解决方案,但是现在我很迷茫。

我还在我的代表的最后添加了一个链接,以运行此代码。

import java.util.*;

class GameObject {
    public double x;
    public double y;
    char mark = '*';

    public GameObject(double x, double y, char mark) {
        this.x = x;
        this.y = y;
        this.mark = mark;
    }
}

class GoodApple extends GameObject {
    public GoodApple(double x, double y) {
        super(x, y, 'A');
    }
    public GoodApple(GoodApple other) {
        super(other.x, other.y, other.mark);
    }
}

class BadApple extends GameObject {
    public BadApple(double x, double y) {
        super(x, y, 'B');
    }
    public BadApple(BadApple other) {
        super(other.x, other.y, other.mark);
    }
}

class Player extends GameObject {
    public double vx;
    public double vy;

    public Player(double x, double y, char mark) {
        super(x, y, mark);
        vx = 0.0;
        vy = 0.0;
    }
    public Player(Player other) {
        super(other.x, other.y, other.mark);
        this.vx = other.vx;
        this.vy = other.vy;
    }
}

class Accel {
    double ax;
    double ay;
    public Accel(double ax, double ay) {
        this.ax = ax;
        this.ay = ay;
    }
}

class PlayerAIBase {
    public Accel next(Player player, GoodApple goodApple, BadApple badApple, double stageSize) {
        return new Accel(0.0, 0.0);
    }
}

class PlayerAIDummyHead extends PlayerAIBase {
    @Override
    public Accel next(Player player, GoodApple goodApple, BadApple badApple, double stageSize) {
        double dx = goodApple.x - player.x;
        double dy = goodApple.y - player.y;
        Accel a = new Accel(dx / 4, dy / 4);
        return a;
    }
}

class MyPlayerAI extends PlayerAIBase {
    // ※1 recode class PlayerAIDummyHead so that player does not go out of bounds, and avoids apple B

  // public Accel next(Player player, GoodApple goodApple, BadApple badApple, double stageSize) {

  //   }

}

class Main {
    public static void main(String[] args) throws InterruptedException {
        PlayerAIBase playerAI = new PlayerAIDummyHead(); // ※2 change this line to PlayerAIBase playerAI = new MyPlayerAI(); 

        GameManager gm = new GameManager(playerAI);

        gm.initializeStage();
        while (gm.gameTick < 500) {
            gm.printStage();
            System.out.println("time: " + gm.gameTick + " score: " + gm.playerScore);
            Thread.sleep(50);
            gm.next();
            if (gm.playerDropped) {
                break; // while gm.gameTick
            }
        }
        gm.printStage();
        System.out.println("time: " + gm.gameTick + " score: " + gm.playerScore);
    }
}

class GameManager {
    static final double stageSize = 20.0;
    static final double maxAccel = 1.0;
    static final double maxVelocity = 2.5;

    Random rand = new Random();

    PlayerAIBase playerAI;
    int playerScore;
    int gameTick;
    Player player;
    boolean playerDropped;
    GoodApple goodApple;
    BadApple badApple;

    public GameManager(PlayerAIBase playerAI) {
        this.playerAI = playerAI;
    }

    public void initializeStage() {
        playerScore = 0;
        gameTick = 0;
        double r = stageSize - 2.0 * 2;
        player = new Player(rand.nextDouble() * r + 2.0, rand.nextDouble() *  r + 2.0, '1');
        goodApple = new GoodApple(rand.nextDouble() * r + 2.0, rand.nextDouble() *  r + 2.0);
        badApple = new BadApple(rand.nextDouble() * r + 2.0, rand.nextDouble() *  r + 2.0);
    }

    public static double distance(GameObject obj, double px, double py) {
        double dx = obj.x - px;
        double dy = obj.y - py;
        return Math.sqrt(dx * dx + dy * dy);
    }

    public static double distance(GameObject obj1, GameObject obj2) {
        double dx = obj1.x - obj2.x;
        double dy = obj1.y - obj2.y;
        return Math.sqrt(dx * dx + dy * dy);
    }

    public void printStage() {
        int stageDisplaySize = 20;
        int stageDisplayMarginSize = 2;
        GameObject[] objs = { player, badApple, goodApple };
        for (int y = 0; y < stageDisplaySize + 2 * stageDisplayMarginSize; ++y) {
            double py = (y - stageDisplayMarginSize) * stageSize / stageDisplaySize;
            for (int x = 0; x < stageDisplaySize + 2 * stageDisplayMarginSize; ++x) {
                double px = (x - stageDisplayMarginSize) * stageSize / stageDisplaySize;
                boolean printed = false;
                for (GameObject obj : objs) {
                    if (distance(obj, px, py) <= 1.0) {
                        System.out.print(obj.mark);
                        printed = true;
                        break;  // for obj
                    }
                }
                if (! printed) {
                    if (0.0 <= py && py <= stageSize && 0.0 <= px && px <= stageSize) {
                        System.out.print('.');
                    }
                    else {
                        System.out.print(' ');
                    }
                }
            }
            System.out.println();
        }
    }

    public void next() {
        ++gameTick;

        Accel playerAccel = playerAI.next(new Player(player), new GoodApple(goodApple), new BadApple(badApple), stageSize);
        // if the absolute acceleration is more than maxAccel, recalculate to keep within bounds of maxAccel
        double aSize = Math.sqrt(playerAccel.ax * playerAccel.ax + playerAccel.ay * playerAccel.ay);
        if (aSize > maxAccel) {
            playerAccel.ax = playerAccel.ax / aSize * maxAccel;
            playerAccel.ay = playerAccel.ay / aSize * maxAccel;
        }

        player.vx += playerAccel.ax;
        player.vy += playerAccel.ay;
        // if absolute value of speed is more than maxVelocity, recalculate to keep within bounds of maxVelocity
        double vSize = Math.sqrt(player.vx * player.vx + player.vy * player.vy);
        if (vSize > maxVelocity) {
            player.vx = player.vx / vSize * maxVelocity;
            player.vy = player.vy / vSize * maxVelocity;
        }

        int timeResolution = 8;
        for (int t = 0; t < timeResolution; ++t) {
            player.x += player.vx / timeResolution;
            player.y += player.vy / timeResolution;
            if (player.x < 0.0 || player.x >= stageSize || player.y < 0.0 || player.y >= stageSize) {
                playerDropped = true;
                break; // for t
            }

            if (badApple != null && distance(player, badApple) < 2.0) {
                playerScore -= 10;
                badApple = null;
            }

            if (goodApple != null && distance(player, goodApple) < 2.0) {
                playerScore += 1;
                goodApple = null;
            }
        }

        if (badApple == null) {
            double r = stageSize - 2.0 * 2;
            badApple = new BadApple(rand.nextDouble() * r + 2.0, rand.nextDouble() *  r + 2.0);
        }
        if (goodApple == null) {
            double r = stageSize - 2.0 * 2;
            goodApple = new GoodApple(rand.nextDouble() * r + 2.0, rand.nextDouble() *  r + 2.0);
        }
    }
}

Good Apple vs Bad Apple

1 个答案:

答案 0 :(得分:0)

给出的代码编写得很不错,因此,即使您不了解它们的工作方式,也请先仔细阅读并尝试了解每个类和方法的工作。

  

有人可以帮我解决该代码中的错误吗?

有关您应该更正的内容以及在何处的说明也很明确:

  • ※1是您需要实施新的播放器AI逻辑以使其符合您所给予的行为的地方。
  • ※2只是用※1 PlayerAIDummyHead中编写的新类简单替换了实现类MyPlayerAI的旧播放器AI逻辑。在该行的注释中已明确将其给予您。

要解决※1,首先要了解当前的行为。 PlayerAIDummyHead会根据玩家和A之间的当前距离,在一定程度上加快播放器的速度。此计算是循环执行的,因此每次迭代的加速度都会根据先前的加速度给出的结果进行更改。

从不考虑B的位置或载物台的大小的角度来看,这种移动行为是有问题的,这两种情况都给出了计算方法。在您的MyPlayerAI的{​​{1}}方法中,尝试一点一点地改善数学运算,以更理想的方式迈向next。那是您的主要任务:改进计算路线的数学。

  

非常感谢任何帮助/指针。

您可以尝试以下几点:

  • 使玩家直接进入A
  • 目标是达到A时速度为0。当您无法及时停下来反转方向时,这将避免失步。
  • 查看A是否位于该直接路线的路径中。如果是这样,请向侧面或对角线移动,直到不在该路径中为止。
  • 避免在机动时越界。
  

我知道加速度在每次迭代中都会发生变化,但是我无法真正确定加速度是如何用来计算玩家应该采取的下一步。

加速度改变速度(速度):

B

然后速度通过执行改变位置

player.vx += playerAccel.ax;
player.vy += playerAccel.ay;

player.x += player.vx / timeResolution; player.y += player.vy / timeResolution; 次,因此基本上是timeResolution(与player.x += player.vx相同)。

因此,加速度决定了速度如何变化,而速度又决定了位置如何变化。如果您想到达某个点,则只需向其加速一次即可(将在该方向上设置正速度),然后将加速度设置为0(将保持恒定速度),然后将其设置为负加速度一次(将降低速度,可能为0)。如果您想更快地达到该点,请保持正的加速度,这将使速度进一步增加,但请记住要及时减速以降低该大速度。