如何在自定义JPanel中进行精灵移动?

时间:2015-08-03 21:22:28

标签: java swing jpanel sprite

如何在自定义JPanel中进行精灵移动?

我看过类似的问题,虽然有一个问题很相似,但它并没有解决我的问题。我在JPanel中有一个精灵,我无法让它移动。我必须满足的一个要求是,当按下JButton时,它必须开始移动(鼠标单击)。我以一种我认为应该工作的方式设置代码,但是当我按下按钮时会出现一长串错误。我还需要让面板成为自定义面板类。

我需要知道的是:

  1. 编程精灵运动的方法(ha)。
  2. 继续移动精灵而没有踪迹。
  3. 使精灵从面板边缘反弹。完成(由于没有移动球而无法测试)
  4. 这是我的代码(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。

1 个答案:

答案 0 :(得分:1)

首先,看看Painting in AWT and SwingPerforming 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);

    }

}

ClientClassLogicSpriteField都有自己的Ball引用,其中没有一个是共享的,所以如果Logic在哪里更新它的状态BallClientClassSpriteField实际上都不会看到这些变化。

实际上,只有SpriteField需要Ball的实例,因为它基本上是“球容器”,它有信息需要确定球是否移出范围并想知道何时应重新绘制球,最好在此时将BallSpriteField的功能/责任隔离开来。

你还需要一种实际移动球的方法。虽然你可以使用其他事件,但如果球只是移动了我会很好,为此,你可以使用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