如何在自定义JPanel
中进行精灵移动?
我看过类似的问题,虽然有一个问题很相似,但它并没有解决我的问题。我在JPanel
中有一个精灵,我无法让它移动。我必须满足的一个要求是,当按下JButton
时,它必须开始移动(鼠标单击)。我以一种我认为应该工作的方式设置代码,但是当我按下按钮时会出现一长串错误。我还需要让面板成为自定义面板类。
我需要知道的是:
这是我的代码(MainClient
)。
package clientPackage;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import logicPack.Logic;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ClientClass
{
Ball mSolo = new Ball();
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientClass window = new ClientClass();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ClientClass()
{
initialize();
}
/**
* Initialize the contents of the frame.
*/
Logic Logical;
Graphics g;
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 590, 520);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
SpriteField panel = new SpriteField();
panel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
/* int tX = e.getX();
Logical.MoveBallX();
int tY = e.getY();
Logical.MoveBallY();
panel.repaint();*/
Logical.MoveBallX();
Logical.MoveBallY();
panel.repaint();
}
});
panel.setForeground(Color.WHITE);
panel.setBackground(Color.GRAY);
panel.setBounds(64, 92, 434, 355);
frame.getContentPane().add(panel);
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
Graphics2D g2 = (Graphics2D)g;
mSolo.DrawSprite(g2 , Logical.MoveBallX(), Logical.MoveBallY());
}
});
btnStart.setBounds(64, 13, 174, 60);
frame.getContentPane().add(btnStart);
}
}
这是我的其他课程(Logic
)
package logicPack;
import clientPackage.Ball;
public class Logic
{
Ball mSolo;
public int MoveBallX()
{
int NewX = mSolo.xPos + 50;
return NewX;
}
public int MoveBallY()
{
int NewY = mSolo.yPos + 50;
return NewY;
}
//Motion, force, friction and collision GO HERE ONLY
}
SpriteField
package clientPackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class SpriteField extends JPanel
{
Ball mSolo;
SpriteField()
{
mSolo = new Ball();
repaint();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
mSolo.DrawSprite(g2 , mSolo.xPos , mSolo.yPos);
}
}
Ball
package clientPackage;
import java.awt.Color;
import java.awt.Graphics2D;
public class Ball
{
Ball()
{
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2, int xPos, int yPos)
{
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2 , yPos - diameter / 2 , diameter , diameter);
}
}
如果您不理解我的Java评论,您可以忽略它们。 如果您需要更多详细信息来帮助我,请告诉我。
编辑1: 安德鲁,我能找到的最接近的文章使用箭头键来移动精灵。这篇文章是" Sprite没有在JPanel"中移动。我发现的所有其他文章都是在没有精灵的情况下处理JPanel,或者是为精灵设置动画。但是,我需要一个鼠标点击的JButton来简单地开始移动,并且球不会改变形状或颜色。我相信我的碰撞部件有效,但是在球开始移动之前我无法测试它。
编辑2: LuxxMiner,感谢您的提示。我使用getHeight和getWidth方法将我的碰撞部分改进得更精确。
编辑3: MadProgrammer,谢谢......?问题不在于球的绘画,我不能让球在第一时间移动来重新绘制它。该示例使用箭头键,而不是鼠标单击或JButton。
答案 0 :(得分:1)
首先,看看Painting in AWT and Swing和Performing Custom Painting,了解绘画在Swing中的作用。
我们来看看代码......
你有一个Ball
类,它有自己的属性,但是你的DrawSprite
方法会传递覆盖这些属性的值吗?
public class Ball {
Ball() {
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2, int xPos, int yPos) {
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2, yPos - diameter / 2, diameter, diameter);
}
}
有什么意义? Ball
应该绘制它自己的当前状态。你应该摆脱额外的参数
public class Ball {
Ball() {
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2) {
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2, yPos - diameter / 2, diameter, diameter);
}
}
ClientClass
,Logic
和SpriteField
都有自己的Ball
引用,其中没有一个是共享的,所以如果Logic
在哪里更新它的状态Ball
,ClientClass
或SpriteField
实际上都不会看到这些变化。
实际上,只有SpriteField
需要Ball
的实例,因为它基本上是“球容器”,它有信息需要确定球是否移出范围并想知道何时应重新绘制球,最好在此时将Ball
与SpriteField
的功能/责任隔离开来。
你还需要一种实际移动球的方法。虽然你可以使用其他事件,但如果球只是移动了我会很好,为此,你可以使用Swing Timer
,它不会阻止事件调度线程,但会通知已注册的{{} 1)在EDT的上下文中,可以安全地从内部更新UI。
ActionListener
现在,您需要做的就是点击“开始”按钮,调用public class SpriteField extends JPanel {
private Ball mSolo;
private Timer timer;
private int xDelta, yDelta;
public SpriteField() {
mSolo = new Ball();
do {
xDelta = (int) ((Math.random() * 8) - 4);
} while (xDelta == 0);
do {
yDelta = (int) ((Math.random() * 8) - 4);
} while (yDelta == 0);
}
public void start() {
if (timer == null || !timer.isRunning()) {
timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
mSolo.xPos += xDelta;
mSolo.yPos += yDelta;
if (mSolo.xPos - (mSolo.diameter / 2) < 0) {
mSolo.xPos = mSolo.diameter / 2;
xDelta *= -1;
} else if (mSolo.xPos + (mSolo.diameter / 2) > getWidth()) {
mSolo.xPos = getWidth() - (mSolo.diameter / 2);
xDelta *= -1;
}
if (mSolo.yPos - (mSolo.diameter / 2) < 0) {
mSolo.yPos = (mSolo.diameter / 2);
yDelta *= -1;
} else if (mSolo.yPos + (mSolo.diameter / 2) > getHeight()) {
mSolo.yPos = getHeight() - (mSolo.diameter / 2);
yDelta *= -1;
}
repaint();
}
});
timer.start();
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
mSolo.DrawSprite(g2);
}
}
方法
start