【问题标题】:Image object is not moving(Spaceship Game) - Java Swing [duplicate]图像对象不移动(宇宙飞船游戏)-Java Swing [重复]
【发布时间】:2016-02-20 15:33:43
【问题描述】:

所以我得到了这个类,它继承自 JPanel 和一个 Thread,它实例化一个 Image 对象并使其水平移动。问题是 Image 只是使用 Graphics 类和 drawImage() 方法绘制的,但保持静止不动。

MyJPanel.java

import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class MyJPanel extends JPanel implements ActionListener,Runnable
{
    private static final long serialVersionUID = 1L;

    private Timer timer;
    private Image backgroundImage;
    private Image player;
    private int playerX, playerY;
    private int projectileX,projectileY;
    private Image projectileImage;
    private ArrayList<Image> projectiles = new ArrayList<Image>();

    boolean flag = false;

    public MyJPanel(Image backgroundImage, Image player,Image projectileImage)
    {
        this.backgroundImage = backgroundImage;
        this.player = player;
        this.projectileImage = projectileImage;
        this.setLayout(null);

        timer = new Timer(50, this);
        timer.start();

        this.addKeyListener(new KeyAdapter() // Listens for a keyboard event
        {
            public void keyPressed(KeyEvent e) 
            {
                if (e.getKeyCode() == KeyEvent.VK_SPACE) // If pressing space - shoot
                {
                    ProjectileThread projectileThread = new ProjectileThread(playerX,playerY);
                    projectileThread.start(); // Create a Thread and call run() method
                }
                repaint();
            }
        });

        // Mouse listener
        this.addMouseMotionListener(new MouseMotionListener()
        {   
            @Override
            public void mouseMoved(MouseEvent e)
            {
                playerX = e.getX();
                playerY = e.getY();
            }

            @Override
            public void mouseDragged(MouseEvent e)
            {

            }
        });
        hideMouseCursor();

        this.setFocusable(true);
        this.setVisible(true);
    } // End of JPanel constructor

    public void paintComponent(Graphics graphics)
    {
        super.paintComponent(graphics);

        graphics.drawImage(backgroundImage,0,0,this.getWidth(),this.getHeight(),null); // Draw the background
        graphics.drawImage(player,playerX,playerY,null); // Draw the player
        graphics.drawImage(projectileImage,projectileX,projectileY,null);
    }

    public void moveProjectile()
    {
        while (projectileX < this.getWidth())
        {
            this.projectileX += 2;
        }
    }

    public void  hideMouseCursor() // Hides the mouse cursor
    {
        //Transparent 16 x 16 pixel cursor image.
        BufferedImage cursorbackgroundImgage = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);

        // Create a new blank cursor.
        Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
                cursorbackgroundImgage, new Point(0, 0), "Blank Cursor");

        // Set the blank cursor to the JPanel.
        this.setCursor(blankCursor);
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) // Without the method and the repaint() the mouse listener will not work 
    {
        repaint();
    }

    public class ProjectileThread extends Thread
    {
        Graphics graphics;

        public ProjectileThread(int playerX,int playerY)
        {
            projectileX = playerX + player.getWidth(null);
            projectileY = playerY + player.getHeight(null) / 2;
        }
        @Override
        public void run()
        {
            graphics.drawImage(projectileImage,projectileX,projectileY,null);
            while (projectileX < getWidth())
            {
                projectileX += 2;
            }
            try 
            {
                Thread.sleep(500);
            } 
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame("A Game by me");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH); // Making the frame take a full screen

        ImageIcon backgroundImageIcon = new ImageIcon("space_background_2.jpg");
        Image backgroundImgage = backgroundImageIcon.getImage();
        ImageIcon playerImageIcon = new ImageIcon("spaceship_1.png");
        Image playerImage = playerImageIcon.getImage();
        ImageIcon projectileIcon = new ImageIcon("spaceship_projectile_1.png");
        Image projectileImage = projectileIcon.getImage();  

        frame.add(new MyJPanel(backgroundImgage,playerImage,projectileImage));
        frame.setVisible(true);
    }

    @Override
    public void run() 
    {

    }
} // End of MyJPanel

有些变量和对象我不使用所以请不要介意。

CS:

线程:

public class ProjectileThread extends Thread
    {
        Graphics graphics;

        public ProjectileThread(int playerX,int playerY)
        {
            projectileX = playerX + player.getWidth(null);
            projectileY = playerY + player.getHeight(null) / 2;
        }
        @Override
        public void run()
        {
            graphics.drawImage(projectileImage,projectileX,projectileY,null);
            while (projectileX < getWidth())
            {
                projectileX += 2;
            }
            try 
            {
                Thread.sleep(500);
            } 
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
}

每次空格键点击启动线程:

 this.addKeyListener(new KeyAdapter() // Listens for a keyboard event
        {
            public void keyPressed(KeyEvent e) 
            {
                if (e.getKeyCode() == KeyEvent.VK_SPACE) // If pressing space - shoot
                {
                    ProjectileThread projectileThread = new ProjectileThread(playerX,playerY);
                    projectileThread.start(); // Create a Thread and call run() method
                }
                repaint();
            }
        });

我经常遇到这个问题,但我似乎不记得如果我清楚地说this.projectileX += 2;,它为什么不动?

任何建议将不胜感激。谢谢。

【问题讨论】:

  • 您的代码看起来是为抛出大量 NullPointerExceptions 而设置的。考虑在这个网站上搜索类似的 Swing 动画问题,看看应该如何做。我永远不会像您那样使用 Graphics 字段(因为有抛出 NPE 的风险并且这会导致绘图不稳定),而是会在 paintComponent 中绘制,因为教程和此处的示例将告诉您并展示给您。也不要在每次调用键侦听器时启动游戏循环。而是使用某种类型的游戏循环运行并且其状态是......
  • 通过按键更改,最好使用按键绑定而不是按键监听器。
  • 另外,永远不要扩展 Thread,而是考虑实现 Runnable,尽管在您的情况下两者都不需要,因为您将在游戏循环中使用 Swing Timer。计时器应该做的不仅仅是调用repaint()。它应该有助于移动需要移动的精灵。
  • "Read about key bindings. I still want to stick with the keyListener" -- 那么你将违背 Swing 官方的建议,并且将永远与焦点问题作斗争。但这是你的派对。
  • " And i can't see any question on the site that deals with my problem." -- 我觉得这很难相信。以下是我回答的一些类似的帖子,还有很多其他类似的问题也有人回答:example 1example 2example 3example 4example 5

标签: java multithreading swing user-interface jpanel


【解决方案1】:

答案:

我只需要创建一个线程并将其添加到 threds(projectiles) 列表中,并在每次按下空格键时使用我想要的 x,y 值。然后在paintComponent() 方法中,我使用线程列表上的foreach 循环移动并绘制它们。我还在 while 循环中添加了 Thread.sleep(10) 来移动弹丸,这样它就不会移动得太快。

public class MyJPanel extends JPanel implements ActionListener
{
    private static final long serialVersionUID = 1L;

    private Timer timer;
    private Image backgroundImage;
    private Image player;
    private int playerX, playerY;
    private int projectileX,projectileY;
    private Image projectileImage;
    private ArrayList<ProjectileThread> projectiles = new ArrayList<ProjectileThread>();

    static boolean gameLoop = true;

    public MyJPanel(Image backgroundImage, Image player,Image projectileImage)
    {
        this.backgroundImage = backgroundImage;
        this.player = player;
        this.projectileImage = projectileImage;
        this.setLayout(null);

        timer = new Timer(50, this);
        timer.start();

        this.addKeyListener(new KeyAdapter() // Listens for a keyboard event
        {
            public void keyPressed(KeyEvent e) 
            {
                if (e.getKeyCode() == KeyEvent.VK_SPACE) // If pressing space - shoot
                {
                    ProjectileThread projectileThread = new ProjectileThread(playerX,playerY);
                    projectileThread.start(); // Create a Thread and call run() method
                    projectiles.add(projectileThread);
                    repaint();
                }
            }
        });

        // Mouse listener
        this.addMouseMotionListener(new MouseMotionListener()
        {   
            @Override
            public void mouseMoved(MouseEvent e)
            {
                playerX = e.getX();
                playerY = e.getY();
            }

            @Override
            public void mouseDragged(MouseEvent e)
            {

            }
        });
        hideMouseCursor();

        this.setFocusable(true);
        this.setVisible(true);
    } // End of JPanel constructor

    public int getX()
    {
        return this.projectileX;
    }

    public int getY()
    {
        return this.projectileX;
    }

    public void paintComponent(Graphics graphics)
    {
        super.paintComponent(graphics);

        graphics.drawImage(backgroundImage,0,0,this.getWidth(),this.getHeight(),null); // Draw the background
        graphics.drawImage(player,playerX,playerY,null); // Draw the player
        for (ProjectileThread projectileThread : projectiles)
        {
            graphics.drawImage(projectileImage,projectileThread.getX(),projectileThread.getY(),null);
        }
    }

    public void  hideMouseCursor() // Hides the mouse cursor
    {
        //Transparent 16 x 16 pixel cursor image.
        BufferedImage cursorbackgroundImgage = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);

        // Create a new blank cursor.
        Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
                cursorbackgroundImgage, new Point(0, 0), "Blank Cursor");

        // Set the blank cursor to the JPanel.
        this.setCursor(blankCursor);
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) // Without the method and the repaint() the mouse listener will not work 
    {
        repaint();
    }

    public class ProjectileThread extends Thread
    {   
        private int projectileX;
        private int projectileY;

        public ProjectileThread(int playerX,int playerY)
        {
            this.projectileX = playerX + player.getWidth(null);
            this.projectileY = playerY + player.getHeight(null) / 2 - 28;
        }
        @Override
        public void run()
        {
            try 
            {
                while (projectileX < backgroundImage.getWidth(null) - projectileImage.getWidth(null))
                {
                    projectileX += 2;
                    Thread.sleep(10);
                    repaint(); // Goes to paintComponent() method
                }
                projectiles.remove(this); // Remove the thread from the list
            } 
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        public int getX()
        {
            return this.projectileX;
        }

        public int getY()
        {
            return this.projectileY;
        }
    }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame("A Game by me");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH); // Making the frame take a full screen

        ImageIcon backgroundImageIcon = new ImageIcon("space_background_2.jpg");
        Image backgroundImgage = backgroundImageIcon.getImage();
        ImageIcon playerImageIcon = new ImageIcon("spaceship_1.png");
        Image playerImage = playerImageIcon.getImage();
        ImageIcon projectileIcon = new ImageIcon("spaceship_projectile_1.png");
        Image projectileImage = projectileIcon.getImage();  

        frame.add(new MyJPanel(backgroundImgage,playerImage,projectileImage));
        frame.setVisible(true);

        while (gameLoop)
        {

        }
    }
} // End of MyJPanel

【讨论】:

  • 不要只是代码转储。解释解决方案是什么。
  • @user1803551 处理好了。
  • 好的。我没有进入问题和你的答案,而是 2 个观察。 (1) 使用键绑定而不是键监听器。 (2) 不要在 EDT 中调用sleep,这样会导致整个 GUI 无响应。
  • @user1803551 EDT 是什么?
  • 事件调度线程。这是 GUI 运行的线程。如果你让它进入睡眠状态,那么用户就不能发出任何命令。见the tutorial。另外,key bindings.
猜你喜欢
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 2017-06-06
  • 1970-01-01
  • 2012-12-14
  • 2015-08-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多