fillOval() 在 if 语句中不起作用[关闭]

Posted

技术标签:

【中文标题】fillOval() 在 if 语句中不起作用[关闭]【英文标题】:fillOval() not working inside a if statement [closed] 【发布时间】: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 覆盖)应该只根据对象的状态进行绘制,仅此而已。 【参考方案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() 方法时,都会重新绘制水果

以上是关于fillOval() 在 if 语句中不起作用[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

基本的 If else 语句在 javascript 中不起作用

jQuery if 语句在 for 循环中不起作用

if 语句比较在目标 c 中不起作用的整数

比较 Mongoose 对象 ID 时,if 语句在 Jade 中不起作用

Liquid - if contains 语句在 for 循环中不起作用

使用 if 语句后跟调用似乎在批处理文件中不起作用