简体   繁体   English

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

[英]How do I make a sprite move in a custom JPanel?

How do I make a sprite move in a custom JPanel ? 如何在自定义JPanel移动精灵?

I have looked at the similar questions and although one question is similar, it isn't addressing my problem. 我看过类似的问题,尽管一个问题很相似,但并不能解决我的问题。 I have a sprite in a JPanel and I am unable to get it to move. 我在JPanel有一个精灵,无法移动它。 One of the requirements I have to meet for the program is that it must begin moving when a JButton is pressed ( Mouse Click ). 我对该程序必须满足的要求之一是,当按下JButton时,它必须开始移动( 鼠标单击 )。 I have the code set-up in a way I believe should work, but it will spit out a long list of errors when I press the button. 我以我认为应该可以的方式设置了代码,但是当我按下按钮时,它将吐出一长串的错误。 I'm also required to have the panel be a custom panel class. 我还要求面板是自定义面板类。

What I need to know is this: 我需要知道的是:

  1. Methods (ha) of programming sprite movement. 编程精灵运动的方法(ha)。
  2. Continuing to move the sprite without a trail. 继续移动精灵,没有任何痕迹。
  3. Making the sprite bounce off the edges of the panel. 使精灵从面板的边缘反弹。 Done (Unable to test due to no moving ball) 完成(由于没有移动的球而无法测试)

Here's the code I have ( MainClient ). 这是我的代码( 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);
}
}

And here are my other Classes ( Logic ) 这是我的其他班级( 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);

}


}

If you do not understand my Java comments, you can just ignore them. 如果您不理解我的Java注释,则可以忽略它们。 If you need more details to help me, let me know. 如果您需要更多详细信息来帮助我,请告诉我。

EDIT 1: Andrew, the closest article I could find used arrow keys to move a sprite. 编辑1:安德鲁,我能找到的最近的文章使用箭头键移动精灵。 The article was "Sprite not moving in JPanel". 文章为“ Sprite不在JPanel中移动”。 All the other articles I found either addressed JPanels without sprites, or animating a sprite. 我发现的所有其他文章都是针对没有精灵的JPanels或为精灵设置动画。 However, I need a JButton that is MouseClicked to simply start the movement, and the ball does not change shape or color. 但是,我需要一个被MouseClicked的JButton来简单地开始运动,并且球不会改变形状或颜色。 I believe I have the collision part working, but I'm unable to test it until the ball starts moving. 我相信碰撞部分已经起作用,但是直到球开始移动之前我无法对其进行测试。

EDIT 2: LuxxMiner, Thanks for the hints. 编辑2:LuxxMiner,谢谢提示。 I have refined my collision portion to be a little more accurate using the getHeight and getWidth methods. 我使用getHeight和getWidth方法将碰撞部分进行了改进,使其更加准确。

EDIT 3: MadProgrammer, Thanks...? 编辑3:MadProgrammer,谢谢...? The problem is not the painting of the ball, I cannot get the ball to move in the first place to repaint it. 问题不在于球的上漆,我无法使球首先移动来重新上漆。 And the example uses arrow keys, not a mouse click or JButton. 该示例使用箭头键,而不是单击鼠标或JButton。

First, take a look at Painting in AWT and Swing and Performing Custom Painting to understand how painting works in Swing. 首先,看一下AWT和Swing中的 绘画以及执行自定义绘画,以了解绘画在Swing中的工作方式。

Let's have a look at the code... 让我们看一下代码...

You have a Ball class, which has it's own properties, but then your DrawSprite method passes in values which override these properties? 您有一个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);

    }

}

What's the point of that? 有什么意义呢? The Ball should paint it's own current state. Ball应该绘制自己的当前状态。 You should get rid of the additional parameters 您应该摆脱其他参数

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 and SpriteField all have their own Ball references, none of which is shared so if Logic where to update the state of it's Ball , neither ClientClass or SpriteField would actually see those changes. ClientClassLogicSpriteField都具有自己的Ball引用,没有一个共享,因此,如果Logic在哪里更新Ball的状态,则ClientClassSpriteField都不会实际看到那些更改。

In reality, only SpriteField needs an instance of Ball , as it's basically the "ball container", it has the information need to determine if the ball moves out of bounds and wants to know when the ball should be repainted, better to isolate the functionality/responsibility for the Ball to SpriteField at this time. 实际上,只有SpriteField需要Ball的实例,因为它基本上是“球容器”,它具有确定球是否超出范围并需要知道何时应该重新绘制球的信息,更好地隔离了功能/负责此BallSpriteField

You also need a means to actually move the ball. 您还需要一种实际移动球的方法。 While you could use other events, I'd be nice if the ball just moved itself, to this end, you can use a Swing Timer , which won't block the Event Dispatching Thread, but which notifies the registered ActionListener within the context of the EDT, making it safe to update the UI from within. 尽管可以使用其他事件,但如果球刚刚移动,我会很好,为此,您可以使用Swing Timer ,它不会阻塞Event Dispatching Thread,但会在以下情况下通知已注册的ActionListener : EDT,从而可以安全地从内部更新UI。

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);
    }

}

Now, all you need to do, is when the "Start" button is clicked, call the start method 现在,您需要做的就是单击“开始”按钮时,调用start方法

public class ClientClass {

    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;
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 590, 520);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        SpriteField panel = new SpriteField();

        panel.setForeground(Color.WHITE);
        panel.setBackground(Color.GRAY);
        frame.getContentPane().add(panel);

        JButton btnStart = new JButton("Start");
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                panel.start();
            }
        });
        frame.getContentPane().add(btnStart, BorderLayout.SOUTH);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM