如何防止我的 KeyEvent 重新绘制两个对象?
How to prevent my KeyEvent from repainting both objects?
我正在开发一个简单的游戏,它需要 1 个玩家(正方形)和一些在游戏区域内随机生成的敌人。我现在 运行 遇到了一个问题,因为当我 运行 我的程序时,按任意箭头键不仅会重绘玩家的新位置,还会将所有敌人重新生成到新位置地点。
我已经检查了我的代码几次,但我仍然不明白为什么会这样。任何帮助将不胜感激。
P.S.我不是一个非常有经验的程序员,所以这段代码中的一些可能不是尽可能高效,有些地方可能不正确;除了手头的问题,请随时指出任何错误。谢谢!
主要Class
public class Eat {
public static void main(String[] args) {
// Creating the main frame
JFrame main = new JFrame("Eat 'Em All - Version 1.0.2");
main.setSize(497, 599);
main.setLocationRelativeTo(null);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setResizable(false);
// Colours and borders
Border areaBorder = new LineBorder(Color.LIGHT_GRAY, 3);
// Creating main JPanel
JPanel area = new JPanel();
area.setLayout(new BoxLayout(area, BoxLayout.PAGE_AXIS));
area.setBackground(Color.WHITE);
main.setContentPane(area);
// Creating the drawing/image/player
DrawPlayer player = new DrawPlayer();
player.setPreferredSize(new Dimension(497, 539));
player.setOpaque(false);
// Enemies
DrawEnemy enemy = new DrawEnemy();
enemy.setPreferredSize(new Dimension(497, 539));
enemy.setBackground(Color.WHITE);
// Creating the control panel for buttons, etc
JPanel control = new JPanel();
control.setPreferredSize(new Dimension(497, 60));
control.setLayout(new GridLayout(1, 2, 0, 0));
control.setBorder(areaBorder);
JLabel welcome = new JLabel(" Welcome to Eat 'Em All |--| Press 'Start'");
JButton start = new JButton("Start");
// Adding it all to the frame
main.add(enemy);
enemy.add(player);
control.add(welcome);
control.add(start);
area.add(control);
// Adding keylistener and making button false
player.addKeyListener(player);
player.setFocusable(true);
start.setFocusable(false);
enemy.setFocusable(false);
// Bring frame to front and visible
main.toFront();
main.setVisible(true);
System.out.println(player.getWidth() / 2);
System.out.println(player.getHeight() / 2);
}
}
绘图玩家Class
public class DrawPlayer extends JPanel implements KeyListener {
long xPosition = 0;
long yPosition = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Making loop to get points and move it
// Center of area is x: 245 y: 255
int xPoints[] = {235, 255, 255, 235, 235, 255};
int yPoints[] = {265, 265, 245, 245, 265, 245};
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] += xPosition;
yPoints[i] += yPosition;
}
g.setColor(Color.BLUE);
g.drawPolygon(xPoints, yPoints, xPoints.length);
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_DOWN:
if (yPosition == 245) {
yPosition -= 5;
} else {
yPosition += 5;
}
break;
case KeyEvent.VK_UP:
if (yPosition == -245) {
yPosition += 5;
} else {
yPosition -= 5;
}
break;
case KeyEvent.VK_LEFT:
if (xPosition == -235) {
xPosition += 5;
} else {
xPosition -= 5;
}
break;
case KeyEvent.VK_RIGHT:
if (xPosition == 235) {
xPosition -= 5;
} else {
xPosition += 5;
}
break;
}
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
引敌Class
public class DrawEnemy extends JPanel {
public void paintComponent(Graphics f) {
super.paintComponent(f);
for (int i = 0; i < 10; i++ ){
f.setColor(Color.RED);
f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
}
}
}
你这里有问题:
public void paintComponent(Graphics f) {
super.paintComponent(f);
for (int i = 0; i < 10; i++ ){
f.setColor(Color.RED);
f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
}
}
您的程序逻辑在绘制方法中,这是您永远不应该做的事情,因为您永远无法完全控制何时甚至是否调用绘制方法.解决方案,获取 paintComponent 方法的随机化 out 并进入其自己的单独方法,当且仅当您想要随机化敌人时才调用该方法,而不是每次重新绘制时调用。
其他问题:
- 将程序逻辑与 GUI 分开。
- 例如,你应该有一个非 GUI Enemy class,它有自己的位置、大小、移动的字段,也许是
move()
方法,也许是 collision(Player p)
方法。
- 您应该只有 一个 绘图的 JPanel,这应该是它唯一的工作。
- 同样,您不会将任何东西的移动与绘画方法联系起来。
- 您可能需要某种游戏循环,也许是摇摆计时器。这将生成规则间隔的滴答声,促使敌人和玩家移动。
- 摆脱 KeyListener 代码并支持键绑定。当涉及到组件焦点时,后者就不那么笨拙了。请检查教程。
我正在开发一个简单的游戏,它需要 1 个玩家(正方形)和一些在游戏区域内随机生成的敌人。我现在 运行 遇到了一个问题,因为当我 运行 我的程序时,按任意箭头键不仅会重绘玩家的新位置,还会将所有敌人重新生成到新位置地点。
我已经检查了我的代码几次,但我仍然不明白为什么会这样。任何帮助将不胜感激。
P.S.我不是一个非常有经验的程序员,所以这段代码中的一些可能不是尽可能高效,有些地方可能不正确;除了手头的问题,请随时指出任何错误。谢谢!
主要Class
public class Eat {
public static void main(String[] args) {
// Creating the main frame
JFrame main = new JFrame("Eat 'Em All - Version 1.0.2");
main.setSize(497, 599);
main.setLocationRelativeTo(null);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setResizable(false);
// Colours and borders
Border areaBorder = new LineBorder(Color.LIGHT_GRAY, 3);
// Creating main JPanel
JPanel area = new JPanel();
area.setLayout(new BoxLayout(area, BoxLayout.PAGE_AXIS));
area.setBackground(Color.WHITE);
main.setContentPane(area);
// Creating the drawing/image/player
DrawPlayer player = new DrawPlayer();
player.setPreferredSize(new Dimension(497, 539));
player.setOpaque(false);
// Enemies
DrawEnemy enemy = new DrawEnemy();
enemy.setPreferredSize(new Dimension(497, 539));
enemy.setBackground(Color.WHITE);
// Creating the control panel for buttons, etc
JPanel control = new JPanel();
control.setPreferredSize(new Dimension(497, 60));
control.setLayout(new GridLayout(1, 2, 0, 0));
control.setBorder(areaBorder);
JLabel welcome = new JLabel(" Welcome to Eat 'Em All |--| Press 'Start'");
JButton start = new JButton("Start");
// Adding it all to the frame
main.add(enemy);
enemy.add(player);
control.add(welcome);
control.add(start);
area.add(control);
// Adding keylistener and making button false
player.addKeyListener(player);
player.setFocusable(true);
start.setFocusable(false);
enemy.setFocusable(false);
// Bring frame to front and visible
main.toFront();
main.setVisible(true);
System.out.println(player.getWidth() / 2);
System.out.println(player.getHeight() / 2);
}
}
绘图玩家Class
public class DrawPlayer extends JPanel implements KeyListener {
long xPosition = 0;
long yPosition = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Making loop to get points and move it
// Center of area is x: 245 y: 255
int xPoints[] = {235, 255, 255, 235, 235, 255};
int yPoints[] = {265, 265, 245, 245, 265, 245};
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] += xPosition;
yPoints[i] += yPosition;
}
g.setColor(Color.BLUE);
g.drawPolygon(xPoints, yPoints, xPoints.length);
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_DOWN:
if (yPosition == 245) {
yPosition -= 5;
} else {
yPosition += 5;
}
break;
case KeyEvent.VK_UP:
if (yPosition == -245) {
yPosition += 5;
} else {
yPosition -= 5;
}
break;
case KeyEvent.VK_LEFT:
if (xPosition == -235) {
xPosition += 5;
} else {
xPosition -= 5;
}
break;
case KeyEvent.VK_RIGHT:
if (xPosition == 235) {
xPosition -= 5;
} else {
xPosition += 5;
}
break;
}
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
引敌Class
public class DrawEnemy extends JPanel {
public void paintComponent(Graphics f) {
super.paintComponent(f);
for (int i = 0; i < 10; i++ ){
f.setColor(Color.RED);
f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
}
}
}
你这里有问题:
public void paintComponent(Graphics f) {
super.paintComponent(f);
for (int i = 0; i < 10; i++ ){
f.setColor(Color.RED);
f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
}
}
您的程序逻辑在绘制方法中,这是您永远不应该做的事情,因为您永远无法完全控制何时甚至是否调用绘制方法.解决方案,获取 paintComponent 方法的随机化 out 并进入其自己的单独方法,当且仅当您想要随机化敌人时才调用该方法,而不是每次重新绘制时调用。
其他问题:
- 将程序逻辑与 GUI 分开。
- 例如,你应该有一个非 GUI Enemy class,它有自己的位置、大小、移动的字段,也许是
move()
方法,也许是collision(Player p)
方法。 - 您应该只有 一个 绘图的 JPanel,这应该是它唯一的工作。
- 同样,您不会将任何东西的移动与绘画方法联系起来。
- 您可能需要某种游戏循环,也许是摇摆计时器。这将生成规则间隔的滴答声,促使敌人和玩家移动。
- 摆脱 KeyListener 代码并支持键绑定。当涉及到组件焦点时,后者就不那么笨拙了。请检查教程。