如何 use/invoke 主要 class 中的 KeyEvents 在子 class 中使用
How to use/invoke KeyEvents from main class to use in sub class
好吧,基本上我已经在主要 class 中设置了这些关键事件:https://prnt.sc/jhbxz9.
我在这里试图完成的是使用我的主要 class 中设置的这些关键事件,这样我就可以在我的子 class 中的 peformAction 下使用 if/else 语句编写一个方法(播放器) 使播放器在按下键时移动并在释放时停止移动。目前我所能做的就是一直朝一个方向移动直到它离开屏幕而不需要按下任何键,但我想要它以便它在按下 VK_LEFT 时改变 velX 但我有 0想法如何在不破坏代码的情况下引用我的子 class 中的关键事件。最后一件事是我注意到每个按键事件下都有 setKey,这让我觉得我需要使用 setKeys,但仍然没有。
如果不能要求您阅读所有代码,请提供完整的屏幕截图。
玩家 Class(子 class):http://prntscr.com/jhbx58 + http://prntscr.com/jhbxim
游戏管理器Class(主要class):http://prntscr.com/jhbxz9
游戏管理器Class:
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) {
}
}
我的播放器Class(子class):
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Player {
private BufferedImage imageRunning;
private BufferedImage imageOver;
private BufferedImage imageCurrent;
int valx = 500;
int valy = 100;
public Player(int valx, int valy) {
try {
this.imageRunning = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/player-alive.png"));
this.imageOver = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/player-dead.png"));
} catch (IOException e) {
e.printStackTrace();
}
this.imageCurrent = this.imageRunning;
}
public BufferedImage getCurrentImage() {
return this.imageCurrent;
}
public void setGameOverBackground() {
this.imageCurrent = this.imageOver;
}
public void performAction() {
if(Player.setKey('D', true) == true) {
this.valx += 2;
}
else if(Player.setKey('D', false) == false) {
this.valx = 0;
}
return;
}
public int getX() {
return valx;
}
public int getY() {
return valy;
}
public void die() {
return;
}
public static boolean setKey(char c, boolean b) {
return b;
}
}
所以当调用 keyPressed
或 keyReleased
时,它们将依次调用 Player.setKey
。当它被调用时,你存储状态。
例如...
public class Player {
//...
// I really, really, really don't static been used this way, it
// has a bad code smell about it...
public static Set<Character> inputState = new TreeSet<Character>();
//...
public static void setKey(char c, boolean b) {
if (b) {
inputState.add(c);
} else {
inputState.remove(c);
}
}
}
因此,所有这一切实际上是将 char
添加到 Set
或将其删除。因为Set
保证了唯一性,所以我们不需要关心这个键是否已经被按下了。
然后当 performAction
被调用时,您检查输入是否在 Set
中并采取适当的行动...
public void performAction() {
if (inputState.contains('U')) {
// Going up
} else if (inputState.contains('D')) {
// Going down
}
//... other inputs
}
好吧,基本上我已经在主要 class 中设置了这些关键事件:https://prnt.sc/jhbxz9.
我在这里试图完成的是使用我的主要 class 中设置的这些关键事件,这样我就可以在我的子 class 中的 peformAction 下使用 if/else 语句编写一个方法(播放器) 使播放器在按下键时移动并在释放时停止移动。目前我所能做的就是一直朝一个方向移动直到它离开屏幕而不需要按下任何键,但我想要它以便它在按下 VK_LEFT 时改变 velX 但我有 0想法如何在不破坏代码的情况下引用我的子 class 中的关键事件。最后一件事是我注意到每个按键事件下都有 setKey,这让我觉得我需要使用 setKeys,但仍然没有。
如果不能要求您阅读所有代码,请提供完整的屏幕截图。 玩家 Class(子 class):http://prntscr.com/jhbx58 + http://prntscr.com/jhbxim
游戏管理器Class(主要class):http://prntscr.com/jhbxz9
游戏管理器Class:
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) {
}
}
我的播放器Class(子class):
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Player {
private BufferedImage imageRunning;
private BufferedImage imageOver;
private BufferedImage imageCurrent;
int valx = 500;
int valy = 100;
public Player(int valx, int valy) {
try {
this.imageRunning = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/player-alive.png"));
this.imageOver = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/player-dead.png"));
} catch (IOException e) {
e.printStackTrace();
}
this.imageCurrent = this.imageRunning;
}
public BufferedImage getCurrentImage() {
return this.imageCurrent;
}
public void setGameOverBackground() {
this.imageCurrent = this.imageOver;
}
public void performAction() {
if(Player.setKey('D', true) == true) {
this.valx += 2;
}
else if(Player.setKey('D', false) == false) {
this.valx = 0;
}
return;
}
public int getX() {
return valx;
}
public int getY() {
return valy;
}
public void die() {
return;
}
public static boolean setKey(char c, boolean b) {
return b;
}
}
所以当调用 keyPressed
或 keyReleased
时,它们将依次调用 Player.setKey
。当它被调用时,你存储状态。
例如...
public class Player {
//...
// I really, really, really don't static been used this way, it
// has a bad code smell about it...
public static Set<Character> inputState = new TreeSet<Character>();
//...
public static void setKey(char c, boolean b) {
if (b) {
inputState.add(c);
} else {
inputState.remove(c);
}
}
}
因此,所有这一切实际上是将 char
添加到 Set
或将其删除。因为Set
保证了唯一性,所以我们不需要关心这个键是否已经被按下了。
然后当 performAction
被调用时,您检查输入是否在 Set
中并采取适当的行动...
public void performAction() {
if (inputState.contains('U')) {
// Going up
} else if (inputState.contains('D')) {
// Going down
}
//... other inputs
}