Как я могу заставить своего «врага» преследовать «цель» - Java - PullRequest
0 голосов
/ 16 мая 2018

Я пытался написать наполовину собранную простую Java-игру, которую мне подарил друг (я хотел попробовать освоить программирование, поэтому он дал мне это старое задание с 1-го года обучения программированию). Он сказал мне попытаться построить игру, используя 2 класса, которые он мне дал, основной класс и подкласс.

Пока у меня есть все, чтобы работать, как задумано, кроме как найти способ заставить мой класс противника двигаться к цели независимо от его положения. Я могу заставить его всегда двигаться в фиксированном направлении к цели, если я его правильно настрою, но хочу, чтобы я всегда мог найти положение цели и пробиться к ней.

Код должен быть написан в методе peformAction в Enemy.

Если кто-то будет достаточно любезен, чтобы объяснить, как я могу это сделать, это будет очень удобно, или даже если вы просто можете связать меня с другим постом, в котором объясняется, как делать то, что я пытаюсь сделать.

Заранее спасибо.

GameManager (основной) Класс:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;

public class GameManager extends JFrame implements KeyListener {
    private int canvasWidth;
    private int canvasHeight;
    private int borderLeft;
    private int borderTop;
    private BufferedImage canvas;
    private Stage stage;
    private Enemy[] enemies;
    private Player player;
    private Goal goal;
    private Graphics gameGraphics;
    private Graphics canvasGraphics;
    private int numEnemies;
    private boolean continueGame;

    public static void main(String[] args) {
        // During development, you can adjust the values provided in the brackets below
        // as needed. However, your code must work with different/valid combinations
        // of values.
        GameManager managerObj = new GameManager(1920, 1280, 30);
    }

    public GameManager(int preferredWidth, int preferredHeight, int maxEnemies) {
        this.borderLeft = getInsets().left;
        this.borderTop = getInsets().top;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        if (screenSize.width < preferredWidth)
            this.canvasWidth = screenSize.width - getInsets().left - getInsets().right;
        else
            this.canvasWidth = preferredWidth - getInsets().left - getInsets().right;
        if (screenSize.height < preferredHeight)
            this.canvasHeight = screenSize.height - getInsets().top - getInsets().bottom;
        else
            this.canvasHeight = preferredHeight - getInsets().top - getInsets().bottom;
        setSize(this.canvasWidth, this.canvasHeight);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        addKeyListener(this);
        Random rng = new Random(2);
        this.canvas = new BufferedImage(this.canvasWidth, this.canvasHeight, BufferedImage.TYPE_INT_RGB);
        // Create a Stage object to hold the background images
        this.stage = new Stage();
        // Create a Goal object with its initial x and y coordinates
        this.goal = new Goal(this.canvasWidth / 2, Math.abs(rng.nextInt()) % this.canvasHeight);
        // Create a Player object with its initial x and y coordinates
        this.player = new Player(this.canvasWidth - (Math.abs(rng.nextInt()) %  (this.canvasWidth / 2)),
            (Math.abs(rng.nextInt()) % this.canvasHeight));
        // Create the Enemy objects, each with a reference to this (GameManager) object
        // and their initial x and y coordinates.
        this.numEnemies = maxEnemies;
        this.enemies = new Enemy[this.numEnemies];
        for (int i = 0; i < this.numEnemies; i++) {
            this.enemies[i] = new Enemy(this, Math.abs(rng.nextInt()) % (this.canvasWidth / 4),
            Math.abs(rng.nextInt()) % this.canvasHeight);
        }
        this.gameGraphics = getGraphics();
        this.canvasGraphics = this.canvas.getGraphics();
        this.continueGame = true;
        while (this.continueGame) {
            updateCanvas();
        }
        this.stage.setGameOverBackground();
        updateCanvas();
    }

    public void updateCanvas() {
        long start = System.nanoTime();
        // If the player is alive, this should move the player in the direction of the
        // key that has been pressed
        // Note: See keyPressed and keyReleased methods in the GameManager class.
        this.player.performAction();
        // If the enemy is alive, the enemy must move towards the goal. The goal object
        // is obtained
        // via the GameManager object that is given at the time of creating an Enemy
        // object.
        // Note: The amount that the enemy moves by must be much smaller than that of
        // the player above
        // or else the game becomes too hard to play.
        for (int i = 0; i < this.numEnemies; i++) {
            this.enemies[i].performAction();
        }
        if ((Math.abs(this.goal.getX() - this.player.getX()) < (this.goal.getCurrentImage().getWidth() / 2))
            && (Math.abs(this.goal.getY() - this.player.getY()) < (this.goal.getCurrentImage().getWidth() / 2))) {
            for (int i = 0; i < this.numEnemies; i++) {
                // Sets the image of the enemy to the "dead" image and sets its status to
                // indicate dead
                this.enemies[i].die();
            }
            // Sets the image of the enemy to the "dead" image and sets its status to
            // indicate dead
            this.goal.die();
            // Sets the background of the stage to the finished game background.
            this.stage.setGameOverBackground();
            this.continueGame=false;
        }
        // If an enemy is close to the goal, the player and goal die
        int j=0;
        while(j<this.numEnemies) {
            if ((Math.abs(this.goal.getX() - this.enemies[j].getX()) < (this.goal.getCurrentImage().getWidth() / 2))
                && (Math.abs(this.goal.getY() - this.enemies[j].getY()) < (this.goal.getCurrentImage().getWidth()/ 2))) {
                this.player.die();
                this.goal.die();
                this.stage.setGameOverBackground();
                j=this.numEnemies;
                this.continueGame=false;
            }
            j++;
        }
        try {
            // Draw stage
            this.canvasGraphics.drawImage(stage.getCurrentImage(), 0, 0, null);
            // Draw player
            this.canvasGraphics.drawImage(player.getCurrentImage(),
            this.player.getX() - (this.player.getCurrentImage().getWidth() / 2),
            this.player.getY() - (this.player.getCurrentImage().getHeight() / 2), null);
            // Draw enemies
            for (int i = 0; i < this.numEnemies; i++) {
                this.canvasGraphics.drawImage(this.enemies[i].getCurrentImage(),
                this.enemies[i].getX() - (this.enemies[i].getCurrentImage().getWidth() / 2),
                this.enemies[i].getY() - (this.enemies[i].getCurrentImage().getHeight() / 2), null);
            }
            // Draw goal
            this.canvasGraphics.drawImage(this.goal.getCurrentImage(),
                this.goal.getX() - (this.goal.getCurrentImage().getWidth() / 2),
                this.goal.getY() - (this.goal.getCurrentImage().getHeight() / 2), null);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
        // Draw everything.
        this.gameGraphics.drawImage(this.canvas, this.borderLeft, this.borderTop, this);
        long end = System.nanoTime();
        this.gameGraphics.drawString("FPS: " + String.format("%2d", (int) (1000000000.0 / (end - start))),
            this.borderLeft + 50, this.borderTop + 50);
    }

    public Goal getGoal() {
        return this.goal;
    }

    public void keyPressed(KeyEvent ke) {
        // Below, the setKey method is used to tell the Player object which key is
        // currently pressed.
        // The Player object must keep track of the pressed key and use it for
        // determining the direction
        // to move.
        if (ke.getKeyCode() == KeyEvent.VK_LEFT)
            this.player.setKey('L', true);
        if (ke.getKeyCode() == KeyEvent.VK_RIGHT)
            this.player.setKey('R', true);
        if (ke.getKeyCode() == KeyEvent.VK_UP)
            this.player.setKey('U', true);
        if (ke.getKeyCode() == KeyEvent.VK_DOWN)
            this.player.setKey('D', true);
        if (ke.getKeyCode() == KeyEvent.VK_ESCAPE)
            this.continueGame = false;
    }

    @Override
    public void keyReleased(KeyEvent ke) {
        // Below, the setKey method is used to tell the Player object which key is
        // currently released.
        // The Player object must keep track of the pressed key and use it for
        // determining the direction
        // to move.
        if (ke.getKeyCode() == KeyEvent.VK_LEFT)
            this.player.setKey('L', false);
        if (ke.getKeyCode() == KeyEvent.VK_RIGHT)
            this.player.setKey('R', false);
        if (ke.getKeyCode() == KeyEvent.VK_UP)
            this.player.setKey('U', false);
        if (ke.getKeyCode() == KeyEvent.VK_DOWN)
            this.player.setKey('D', false);
    }

    @Override
    public void keyTyped(KeyEvent ke) {
    }
}

Мой враг (под) Класс:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Enemy {
    //variables 
    private BufferedImage imageRunning;
    private BufferedImage imageOver;
    private BufferedImage imageCurrent;
    int valX = 200;
    int valY = 200;

    public Enemy (GameManager gameManager, int x, int y) {
        try {
            this.imageRunning = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/enemy-alive.png"));
            this.imageOver = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/enemy-dead.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.imageCurrent = this.imageRunning;
    }

    public BufferedImage getCurrentImage() {
        return this.imageCurrent;
    }


    public void performAction() {
        valX += 1;
        valY += 1;
        return;

    }

    public void die() {
        // TODO Auto-generated method stub
        this.imageCurrent = this.imageOver;
    }

    public int getX() {
        // TODO Auto-generated method stub
        return this.valX;
    }

    public int getY() {
        // TODO Auto-generated method stub
        return this.valY;
}


}

Мой класс цели (под):

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Goal {
    private BufferedImage imageRunning;
    private BufferedImage imageOver;
    private BufferedImage imageCurrent;
    int posX = 500;
    int poxY = 500;

    public Goal(int x, int y) {
        try {
            this.imageRunning = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/goal-alive.png"));
            this.imageOver = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/goal-dead.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.imageCurrent = this.imageRunning;
    }

    public BufferedImage getCurrentImage() {
        return this.imageCurrent;
    }


    public int getX() {

        return this.posX;
    }

    public int getY() {

        return this.poxY;
    }

    public void die() {
        this.imageCurrent = this.imageOver;
    }


}

Ответы [ 3 ]

0 голосов
/ 16 мая 2018

В вашем методе performAction вы в настоящее время изменяете положение x и y соответственно, увеличивая их на 1 каждый раз, когда вызывается метод.

Это переместит вашего противника ровно на 1 единицу в направлении x и 1единица в направлении y.

Вместо этого вы хотите переместить своего персонажа в направлении цели.Это больше математическая проблема, чем проблема программирования, но давайте попробуем:

У вас есть две позиции:

У вашего врага есть позиция формы , и то же самое относится и к вашейцель с позицией

Теперь вы хотите переместить своего врага в направлении цели.Таким образом, вы вычисляете вектор, соединяющий эти две точки, с помощью

Затем вы изменяете длину вектора на скорость, с которой может двигаться ваш враг (возможно, определите это с помощью поля?), Нормализуя вектор и выполняяскалярное умножение с вашей скоростью.

Таким образом, с данной скоростью S это дает вам полную формулу:

Теперь давайте преобразуем это в код,В конструкторе вашего класса Enemy сохраните GameManager как поле, чтобы вы могли вызывать для него метод getGoal.

Поэтому мы добавляем поле private GameManager gameManager, а в конструкторе делаем this.gameManager = gameManager для хранения ссылки.

Также мы добавляем поле private double speed = 2 для нашего расчета.

И затем мы меняем метод performAction для реализации нашей формулы.Примерно так:

public void performAction()
{
    // Calculate our P_g - P_e
    double dX = gameManager.getGoal().getX() - valX;
    double dY = gameManager.getGoal().getX() - valX;

    // Calculate its length to normalize it
    double divider = Math.sqrt(dX * dX + dY * dY);

    // Normalize it
    dX /= divider;
    dY /= divider;

    // Do a scalar multiplication with our speed
    dX *= speed;
    dY *= speed;

    valX += dX;
    valY += dY;
}

Единственная проблема, с которой мы здесь сталкиваемся, заключается в том, что мы добавляем двойные значения к нашим целочисленным значениям valX и valY, поэтому, вероятно, измените их на двойные значения вообще, иначе выможет столкнуться с проблемами, когда ваш враг никогда не будет двигаться вообще.

0 голосов
/ 16 мая 2018

Очень простая реализация:

public void performAction()
{
    valX += Math.signum(gameManager.getGoal().getX() - valX);
    valY += Math.signum(gameManager.getGoal().getX() - valX);
}
0 голосов
/ 16 мая 2018

Это невозможно с текущим кодом, если вы хотите ограничить изменения только методом executeAction.

1) У врага нет возможности получить доступ (увидеть) координаты цели.Это означает, что код не может определить путь к цели, потому что он не имеет X и Y того, где находится пункт назначения.2) Чтобы исправить это, вам нужно, чтобы враг мог видеть X и Y цели.Самый быстрый способ - использовать методы получения и установки в классе GameManager для возврата сохраненного объекта Goal .Затем вы можете изменить конструктор Enemy , чтобы сохранить ссылку на GameManager, который его создал.

GameManager:

public Goal getGoal() {
    return goal;
}

Enemy:

 private GameManager gameManager;

 public Enemy (GameManager gameManager, int x, int y) {
        ...
        this.gameManager = gameManager;
 }

Последним шагом будет получение объекта Goal из сохраненного gameManager и использование его X и Y для выполнения некоторой логики (это будет выполнено внутри метода executeAction):

int goalX = gameManager.getGoal().getX();
int goalY = gameManager.getGoal().getY();

...some logic to calculate the direction here...

Я уверенвы узнаете, что делать с числами, и выясните, как двигаться к цели.

@ Edit Если нет - один из способов будет сравнивать X и Y обоихВраг и цель, а затем увеличивая / уменьшая valX и / или valY соответственно.

...