【问题标题】:fillOval() not working inside a if statement [closed]fillOval() 在 if 语句中不起作用[关闭]
【发布时间】:2022-01-22 02:11:56
【问题描述】:

我正在构建一个贪吃蛇游戏,但遇到了问题。我希望只画一次 10 个水果,但我需要更新蛇的位置,所以我添加了一个 if 语句,但 fillOval() 方法不起作用。我通过删除 for 循环和 if 语句对其进行了测试,它工作得很好。代码如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SnakeFrame extends JPanel implements ActionListener {

    boolean hasPaintedFruits;

    SnakeFrame(){
        JFrame frame = new JFrame("Snake Game");
        frame.setSize(800,600);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
        hasPaintedFruits = false;
        Timer t = new Timer(16, this);
        t.restart();
        frame.add(this);
        frame.setVisible(true);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(!hasPaintedFruits) {
            new Fruit().paint(g);
            hasPaintedFruits = true;
        }
        new Fruit().paint(g);
        Snake sHead = new Snake();
        sHead.paint(g);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
    }
}

import java.awt.*;
import java.util.Random;

public class Fruit {
    //pos
    int x, y;

    Fruit(){
        Random random = new Random();
        x = random.nextInt(800);
        y = random.nextInt(600);
    }
    public void paint(Graphics g) {
        g.setColor(Color.RED);
        g.fillOval(x,y,10,10);
    }
}

【问题讨论】:

  • 您发布的代码中的 fillOval(...) 调用在哪里?
  • 另外,Fruit 类是扩展 Swing 组件的类吗?如果是这样,您不应该在paint 中创建实例或直接调用paint 方法。
  • 另外,paint 方法不应调用super.paintComponent,因为这会破坏绘制链。它应该调用super.paint。更好的是,你应该覆盖paintComponent,而不是paint。
  • Fruit 类没有扩展 Swing 组件。让我在这里发布该类的代码
  • 您的绘图方法中似乎有程序逻辑代码,可以更改您的 Swing 组件的状态,这是不明智的。逻辑应该在你的 Swing Timer 中,而绘制方法(应该是 paintComponent 覆盖)应该只根据对象的状态进行绘制,仅此而已。

标签: java user-interface graphics


【解决方案1】:

您的目标是绘制一次,解决方案是摆脱 if 块,并在 paintComponent 方法中简单地绘制需要绘制的内容。例如,假设您有一个带有 x 和 y 位置的 Fruit2 类以及一个 draw 方法:

class Fruit2 {
    private static final Color FRUIT_COLOR = Color.BLUE.brighter();
    public static final int FRUIT_SIDE = 20;
    private int x, y;

    public Fruit2(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void draw(Graphics g) {
        g.setColor(FRUIT_COLOR);
        g.fillRect(x, y, FRUIT_SIDE, FRUIT_SIDE);
    }   
}

比如说,主绘图类包含一个包含 10 个这些项目的数组:

    private static final int FRUIT_COUNT = 10;
    //.....
    private Fruit2[] fruits = new Fruit2[FRUIT_COUNT];

假设绘图 JPanel 也有一个 Snake2 对象,该对象也有一个 draw 方法(知道如何绘制自己),那么您的 paintComponent 方法将很简单:

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Fruit2 fruit : fruits) {
            fruit.draw(g);
        }
        snake.draw(g);
    }

就是这样。 Fruit2 对象自己绘制自己,而蛇自己绘制自己——完成。

同样,正如我在上面的 cmets 中所提到的,绘画方法不应该包含移动蛇的代码 - 将其留给计时器的 ActionListener。相反,绘画方法,这里 paintComponent(...) 只是绘制 GUI 状态的表示,仅此而已。

作为我的意思的一个有效示例,请运行以下代码:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;

public class SnakePanel2 extends JPanel {
    private static final long serialVersionUID = 1L;
    private static final int PANEL_WIDTH = 800;
    private static final int PANEL_HEIGHT = 650;
    private static final int TIMER_DELAY = 40;
    private static final Color BG = Color.WHITE;
    private static final int FRUIT_COUNT = 10;
    private Snake2 snake = new Snake2(PANEL_WIDTH, PANEL_HEIGHT);
    private Fruit2[] fruits = new Fruit2[FRUIT_COUNT];

    public SnakePanel2() {
        setBackground(BG);
        new Timer(TIMER_DELAY, e -> timerStep()).start();
        
        for (int i = 0; i < fruits.length; i++) {
            int x = (int) ((PANEL_WIDTH - Fruit2.FRUIT_SIDE) * Math.random());
            int y = (int) ((PANEL_HEIGHT - Fruit2.FRUIT_SIDE) * Math.random());
            fruits[i] = new Fruit2(x, y);
        }
        
    }

    private void timerStep() {
        snake.move();
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Fruit2 fruit : fruits) {
            fruit.draw(g);
        }
        snake.draw(g);
    }
    
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            SnakePanel2 panel = new SnakePanel2();
            JFrame frame = new JFrame("Snake Game");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(panel);
            frame.pack();
            frame.setResizable(false);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

class Fruit2 {
    private static final Color FRUIT_COLOR = Color.BLUE.brighter();
    public static final int FRUIT_SIDE = 20;
    private int x, y;

    public Fruit2(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void draw(Graphics g) {
        g.setColor(FRUIT_COLOR);
        g.fillRect(x, y, FRUIT_SIDE, FRUIT_SIDE);
    }   
}

class Snake2 {
    private static final int MAX_POINTS = 60;
    private static final int RADIUS = 8;
    private static final int DELTA = 8;
    private static final int DIRECTION_STEPS = 16;
    private static final int DIR_MAX_DELTA = 2;
    private static final Point2D[] DIRECTION_ARRAY = new Point2D[DIRECTION_STEPS];
    private static final Color SNAKE_COLOR = Color.RED;
    private List<Point2D> units = new ArrayList<>();
    private int currentDirection = (DIRECTION_STEPS * 3) / 8;
    private int maxWidth;
    private int maxHeight;
    
    static {
        for (int i = 0; i < DIRECTION_ARRAY.length; i++) {
            double x = DELTA * Math.cos((2 * Math.PI * i) / DIRECTION_ARRAY.length);
            double y = DELTA * Math.sin((2 * Math.PI * i) / DIRECTION_ARRAY.length);
            DIRECTION_ARRAY[i] = new Point2D.Double(x, y);
        }
    }

    public Snake2(int maxWidth, int maxHeight) {
        this.maxWidth = maxWidth;
        this.maxHeight = maxHeight;
        units.add(new Point2D.Double(0, 0));
    }

    public void move() {
        if (units.size() != 1) {
            currentDirection += (2 * DIR_MAX_DELTA + 1) * (Math.random()) - DIR_MAX_DELTA;
            currentDirection += DIRECTION_STEPS;
            currentDirection %= DIRECTION_STEPS; 
        }
        
        double x = units.get(0).getX() + DIRECTION_ARRAY[currentDirection].getX();
        double y = units.get(0).getY() + DIRECTION_ARRAY[currentDirection].getY();
        
        if (x < 0) {
            x += maxWidth;
        } else if (x > maxWidth) {
            x -= maxWidth;
        }
        
        if (y < 0) {
            y += maxHeight;
        } else if (y > maxHeight) {
            y -= maxHeight;
        }
        
        units.add(0, new Point2D.Double(x, y));
        if (units.size() >= MAX_POINTS) {
            units.remove(units.size() - 1);
        }
    }

    public void draw(Graphics g) {
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(SNAKE_COLOR);
        for (Point2D unit : units) {
            double x = unit.getX() - RADIUS;
            double y = unit.getY() - RADIUS;
            double w = 2 * RADIUS;
            double h = w;
            Ellipse2D e2d = new Ellipse2D.Double(x, y, w, h);
            g2.fill(e2d);
        }

        g2.dispose();
    }

}

【讨论】:

  • 感谢您的帮助!不幸的是,它仍然没有被绘制一次。每次调用paintComponent() 方法时,都会重新绘制水果
猜你喜欢
  • 1970-01-01
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多