问题描述
我想重新粉刷我的屏幕.到目前为止,它所做的只是显示第一个屏幕,该屏幕上带有一个圆点,该圆点应该位于头部.很好,但是我已经在代码中编写了想要将磁头每秒向下移动10个像素的操作.我正在打印打印头应该位于的位置,并且在命令提示符下显示y值确实在增加.但是在我的屏幕上,头部没有动.
I would like to repaint my screen. As of now all it does is show the first screen with a dot where the head is supposed to be. This is fine, however I've written in my code that I want to move the head down 10 pixels every second. I'm printing at what point the head is supposed to be at, and in the command prompt it shows that the y value is indeed increasing. However on my screen the head is not moving.
我尝试使用revalidate方法,尝试扩展canvas类而不是jframe,我尝试仅针对paint方法使用不同的类,我尝试将paint方法替换为paintComponent方法.正如您可能会告诉我的那样,我对与Java绘画有关的任何内容都不太了解.我已经尝试阅读这些超类,但是它们太复杂了,以至于我无法理解.我还尝试了在没有睡眠声明的情况下运行.没关系.
I have tried using the revalidate method, trying to extend the canvas class instead of jframe, I have tried using different classes just for the paint method, i have tried replacing the paint method with the paintComponent method. And as you can probably tell I have a subpar understanding of anything related to painting in java. I have tried reading into these superclasses but they are too complicated for me to understand. I have also tried running without the sleep declaration. This didn't matter.
主类:此类包含开始运行蛇游戏的主要方法.
Main class:This class contains the main method to start running the snake game.
import java.util.concurrent.TimeUnit;
public class Main{
public static void main(String[] args) throws InterruptedException {
Main programma = new Main();
programma.rungame();
}
void rungame() throws InterruptedException {
AllGUIElements gui = new AllGUIElements();
gui.gui();
while (true) {
TimeUnit.SECONDS.sleep(1);
gui.setGameScreen();
}
}
}
AllGUIElements类:此类创建一个新框架,其中包含一个新面板.此面板是使用paintComponent绘制的. setGameScreen更新头部的位置,并应该重新绘制屏幕.
AllGUIElements class: This class makes a new frame, containing a new panel. This panel is being painted using paintComponent. setGameScreen updates the position of the head and is supposed to repaint the screen.
import javax.swing.*;
import java.awt.*;
public class AllGUIElements extends JPanel {
private JFrame frame;
private JPanel panel;
private int screen;
Snake hoofd = new Head(new Point(30,30),3,null);
void gui() throws InterruptedException {
frame = new JFrame("Snake Game");
panel = new AllGUIElements();
panel.setBackground(Color.GRAY);
panel.setSize(1000,500);
frame.setSize(1000,500);
frame.add(panel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void setGameScreen() {
repaint();
if (hoofd.getDirection() == 1) {
hoofd.setPosition(new Point(hoofd.getPosition().x, hoofd.getPosition().y-10));
}
if (hoofd.getDirection() == 2) {
hoofd.setPosition(new Point(hoofd.getPosition().x+10, hoofd.getPosition().y));
}
if (hoofd.getDirection() == 3) {
hoofd.setPosition(new Point(hoofd.getPosition().x, hoofd.getPosition().y+10));
}
if (hoofd.getDirection() == 4) {
hoofd.setPosition(new Point(hoofd.getPosition().x-10, hoofd.getPosition().y));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, 1000, 10);
g.fillRect(0, 0, 10, 500);
g.fillRect(990, 0, 10, 500);
g.fillRect(0, 490, 1000, 10);
g.setColor(Color.GREEN);
g.fillRect(hoofd.getPosition().x, hoofd.getPosition().y, 10, 10);
}
}
Screenobject类:Snake和Food的父类(由于没有必要,因此不发布),该类返回头部,身体部位和食物的位置.
Screenobject class: Parent class of Snake and Food (which is not posted since it's not necessary) which returns the position of the head, bodypart and food.
import java.awt.*;
public class Screenobject{
Point pos;
Screenobject(Point pos){
this.pos = pos;
}
void setPosition(Point pos){
this.pos = pos;
}
Point getPosition() {
return pos;
}
}
蛇类:Screenobject的子级,Head和Body的父级.此类设置对象的方向.
Snake class: Child of Screenobject and parent of Head and Body. This class sets the direction of the objects.
import java.awt.*;
public class Snake extends Screenobject{
int direction;
//directions:
//1 = up
//2 = right
//3 = down
//4 = left
Snake nextpart;
Snake(Point pos, int direction, Snake nextpart){
super(pos);
this.direction = direction;
this.nextpart = nextpart;
}
int getDirection() {
return direction;
}
}
头类:蛇的子类,应该是蛇链表的第一个对象.
Head class: Child class of snake and is supposed to be the first object of a linked list for the snake.
import java.awt.*;
public class Head extends Snake{
Head(Point pos, int direction, Snake nextpart){
super(pos, direction, nextpart);
}
}
身体阶层:蛇的孩子阶层,每食用一种食物都会增长一次.
Body class: Child class of Snake and grows for every food eaten.
import java.awt.*;
public class Body extends Snake{
Body(Point pos, int direction, Snake nextpart){
super(pos, direction, nextpart);
}
}
推荐答案
第一件事:
是的,您仅发布了必要的信息,但对于 MCVE/MRE 并为此使用了enum
,因此代码更易读,因为我们都知道TOP
应该将其移到顶部,但我们不知道1
应该将其移到顶部.
Gets rid of the "magic numbers" for the directions and uses an enum
for this matter, and thus the code is more readable as we all know that TOP
should move it to top, but we don't know that 1
should move it to top.
使用Shape
API在JPanel
上绘制形状,如
Makes use of the Shape
API to draw the shapes on the JPanel
as shown in this answer
我还建议您使用camelCase
命名您的方法,以使rungame()
变为runGame()
,因为它更易于阅读,与其他方法一样.并给它们起更有意义的名称,例如hoofd
,我不知道那是什么,如果我独自阅读而没有上下文,将很难说出它是什么类型的对象.
I would also suggest naming your methods using camelCase
so that rungame()
becomes runGame()
as it's easier to read, same for other methods. And give them more meaningful names such as hoofd
, I don't know what that is and if I read it alone without context it would be extremely difficult to say what type of object it is.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SnakeGame {
private JFrame frame;
private Snake snake;
private JPanel buttonsPane;
private JButton[] buttons; // Our array of buttons
private Timer timer;
private Direction currentDirection;
// This enum will be used to determine the direction the snake will take.
private enum Direction {
TOP, LEFT, BOTTOM, RIGHT
}
public static void main(String[] args) {
// We place our program on the EDT using Java 8 lambda expressions.
SwingUtilities.invokeLater(() -> new SnakeGame().createAndShowGUI());
}
private void createAndShowGUI() {
frame = new JFrame(getClass().getSimpleName());
snake = new Snake();
buttonsPane = new JPanel();
buttons = new JButton[Direction.values().length];
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton(Direction.values()[i].toString()); // We create a JButton with the current value of the direction
buttons[i].addActionListener(listener); // We set their ActionListeners
buttonsPane.add(buttons[i]); // And add them to the buttonsPane
}
currentDirection = Direction.RIGHT; // We set a default direction
timer = new Timer(1000, listener); // And start our Swing Timer
// We add our components and then pack the frame, after that we start the timer.
frame.add(snake);
frame.add(buttonsPane, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
timer.start();
}
// Our ActionListener for moving the snake
private ActionListener listener = e -> { // Using Java 8 lambda expressions again
// We set the current direction using a ternary, if the source of the event is
// the timer we leave the current direction as is
// otherwise we set it to the direction from the button clicked
currentDirection = e.getSource().equals(timer) ? currentDirection : Direction.valueOf(e.getActionCommand());
snake.move(currentDirection); // And we call the move method
};
@SuppressWarnings("serial")
class Snake extends JPanel {
private int xPos;
private int yPos;
private static final int SPEED = 10; // We set the speed as a constant (10 pixels at a time) in any direction
// We determine the movement direction
public void move(Direction direction) {
switch (direction) {
case TOP:
yPos -= SPEED;
break;
case LEFT:
xPos -= SPEED;
break;
case BOTTOM:
yPos += SPEED;
break;
case RIGHT:
xPos += SPEED;
break;
}
this.repaint(); // And repaint the snake
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.DARK_GRAY);
g2d.fill(new Rectangle2D.Double(xPos, yPos, 10, 10)); // We draw a rectangle using the Shape API
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300); // We set the preferredSize of the JPanel to 300 x 300
}
}
}
对于Java 7或更低版本,或者对于您不想使用lambda表达式或对您来说太困难,上面的代码会产生以下结果,请检查此答案的第二点,它显示了如何放置程序在没有Lambda表达式和此答案展示了如何在没有它们的情况下也写ActionListener
.
The above code produces the following result, for Java 7 and below or if you don't want to use lambda expressions or are too difficult for you, check the point #2 on this answer, it shows how to place the program on the EDT without lambda expressions and this answer shows how to write the ActionListener
without them as well.
您去了,这是一个简单的可运行示例,它是完整的,可验证的,最小的,这就是我们在以后的问题中对您的期望.
There you go, a simple runnable example, it's complete, it's verifiable, it's minimal and that's what we expect from you in future questions.
这篇关于重涂不会更新屏幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!