【发布时间】: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 官方的建议,并且将永远与焦点问题作斗争。但这是你的派对。
标签: java multithreading swing user-interface jpanel