我的课程下周将学习Java子类化和extends
。我们的讲师为我们提供了一个游戏代码,人工智能在其中移动并收集了所谓的“苹果”。
A
是好苹果,而B
是坏苹果。 1
到处移动(运行代码时)是我们的参与者。无论苹果A
是否在其范围内,播放器都会自动移向苹果B
。它还倾向于越界,这将停止程序。如果播放器没有超出范围,则该程序将在循环500次后停止。
我们的讲师要求我们更正此代码中的某些部分,以便
B
(除非它靠近边界,否则玩家别无选择,只能取走坏苹果)我们唯一可以纠正的地方分别标记为※1
(class MyPlayerAI extends PlayerAIBase
)和※2
(PlayerAIBase 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);
}
}
}
答案 0 :(得分:0)
给出的代码编写得很不错,因此,即使您不了解它们的工作方式,也请先仔细阅读并尝试了解每个类和方法的工作。
有人可以帮我解决该代码中的错误吗?
有关您应该更正的内容以及在何处的说明也很明确:
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)。如果您想更快地达到该点,请保持正的加速度,这将使速度进一步增加,但请记住要及时减速以降低该大速度。