我试图让球逐渐移动 [英] I am trying to make ball gradually move

查看:31
本文介绍了我试图让球逐渐移动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当你按下一个箭头键时,我试图让球逐渐移动,现在它只是传送.我想要它,这样你就可以看到它在移动.基于这个示例,我正在使用键绑定,并且有一个名为 delta 的变量会导致球移动 50 个像素,但就像我说的,无论你按下箭头键的哪个方向,球都会出现 50 个像素,我希望它就像你踢球一样,你可以看到它从 a 点到 b 点.转到第 89 行,这就是我认为问题所在.

I am trying to make a ball gradually move when you press one of the arrow keys, right now it kind of just teleports. I want it so that you can see it move. Based on this example, I am using key bindings, and there is a variable called delta that causes the ball move by 50 pixels, but like I said the ball just appears 50 pixels in whichever direction the arrow key is you pressed, I want it to be like if you were to kick a ball you can see it get from point a to b. Go to line 89 that is where I think the problem is.

package game;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

/**
 * @see https://stackoverflow.com/questions/6991648
 * @see https://stackoverflow.com/questions/6887296
 * @see https://stackoverflow.com/questions/5797965
 */
public class LinePanel extends JPanel {
myObject ball;

private Point b1 = new Point(0,0);


private MouseHandler mouseHandler = new MouseHandler();
private Point p1 = new Point(100, 100);
private Point p2 = new Point(540, 380);
private boolean drawing;

public LinePanel() {
    this.setPreferredSize(new Dimension(640, 480));
    this.addMouseListener(mouseHandler);
    this.addMouseMotionListener(mouseHandler);
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(Color.blue);
    g2d.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setStroke(new BasicStroke(8,
        BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
    g.drawLine(p1.x, p1.y, p2.x, p2.y);
    ball = new myObject(b1.x,b1.y,"Stuff/ball.png",50,50);
    g.drawImage(ball.getImage(),ball.getX(),ball.getY(), ball.getWidth(),         ball.getHeight(), null);
    repaint();
}

private class MouseHandler extends MouseAdapter {

    @Override
    public void mousePressed(MouseEvent e) {
        drawing = true;
        p1 = e.getPoint();
        p2 = p1;
        repaint();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        drawing = false;
        p2 = e.getPoint();
        repaint();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        if (drawing) {
            p2 = e.getPoint();
            repaint();
        }
    }
}

private class ControlPanel extends JPanel {

    private static final int DELTA = 50;
// above is telling the ball to move by 50 pixels
    // I want it to move by 50 pixels but gradually I dont want it to teleport
    public ControlPanel() {
        this.add(new MoveButton("u2190", KeyEvent.VK_LEFT, -DELTA, 0));
        this.add(new MoveButton("u2191", KeyEvent.VK_UP, 0, -DELTA));
        this.add(new MoveButton("u2192", KeyEvent.VK_RIGHT, DELTA, 0));
        this.add(new MoveButton("u2193", KeyEvent.VK_DOWN, 0, DELTA));


    }


    private class MoveButton extends JButton {

        KeyStroke k;
        int myX, myY;

        public MoveButton(String name, int code, final int myX, final int myY) {
            super(name);
            this.k = KeyStroke.getKeyStroke(code, 0);
            this.myX = myX;
            this.myY = myY;
            this.setAction(new AbstractAction(this.getText()) {

                @Override
                public void actionPerformed(ActionEvent e) {
                    LinePanel.this.b1.translate(myX, myY);

                    LinePanel.this.repaint();
                }
            });
            ControlPanel.this.getInputMap(
                WHEN_IN_FOCUSED_WINDOW).put(k, k.toString());
            ControlPanel.this.getActionMap().put(k.toString(), new AbstractAction() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    MoveButton.this.doClick();
                }
            });
        }
    }
}



private void display() {
    JFrame f = new JFrame("LinePanel");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.add(this);
    f.add(new ControlPanel(), BorderLayout.SOUTH);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setVisible(true);
}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            new LinePanel().display();
        }
    });
}


}

推荐答案

任何动画的基本前提都是随时间变化.

The basic premise for any animation is change over time.

您需要能够在给定的时间段内将球从位置 A 移动到位置 B.要做到这一点,您需要某种自动收报机",可用于在该时间段内更新球的位置.一般来说,25fps(或约40毫秒)就足够了.

You need to be able to move the ball from position A to position B over a given time period. To do that, you need some kind of "ticker" that can be used to update the position of the ball over that period. Generally speaking, 25fps (or about 40 milliseconds) is more than enough.

为了在 Swing 中安全地实现这一点,最简单的解决方案是使用 Swing Timer.您可以使用 Thread,但随后您将负责将更新同步回 UI,并且在此阶段真正需要它更复杂.

To achieve this safely in Swing, the easiest solution is to use a Swing Timer. You could use a Thread, but then you become responsible for syncing the updates back to the UI and it's more complexity then is really required at this stage.

此示例使用 1 秒的持续时间将球从 A 点移动到 B 点.这是一个线性动画,您需要研究合适的动画框架以获得更复杂的解决方案.

This example uses a duration of 1 second to move the ball from point A to point B. This is a linear animation and you would need to investigate an appropriate animation framework to get a more complex solution.

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;

public class LinePanel extends JPanel {

//    myObject ball;
    private Point b1 = new Point(0, 0);
    private Point startPoint = new Point(0, 0);
    private Point targetPoint = new Point(0, 0);
    private MouseHandler mouseHandler = new MouseHandler();
    private Point p1 = new Point(100, 100);
    private Point p2 = new Point(540, 380);
    private boolean drawing;

    private Timer animate;
    private long startTime;
    private int duration = 1000;

    public LinePanel() {
        this.setPreferredSize(new Dimension(640, 480));
        this.addMouseListener(mouseHandler);
        this.addMouseMotionListener(mouseHandler);
        animate = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                long now = System.currentTimeMillis();
                long dif = now - startTime;
                if (dif >= duration) {
                    dif = duration;
                    ((Timer)e.getSource()).stop();
                }
                float progress = (float)dif / (float)duration;
                b1 = calculateProgress(startPoint, targetPoint, progress);
                repaint();
            }
        });
        animate.setRepeats(true);
        animate.setCoalesce(true);
    }

    public void moveBallTo(Point target) {

        if (animate.isRunning()) {
            animate.stop();
        }

        startPoint = b1;
        targetPoint = target;

        startTime = System.currentTimeMillis();
        animate.start();

    }

    public void moveBallBy(int xDelta, int yDelta) {

        animate.stop();

        Point t = new Point(targetPoint == null ? b1 : targetPoint);
        t.x += xDelta;
        t.y += yDelta;

        moveBallTo(t);

    }

    public Point calculateProgress(Point startPoint, Point targetPoint, double progress) {

        Point point = new Point();

        if (startPoint != null && targetPoint != null) {

            point.x = calculateProgress(startPoint.x, targetPoint.x, progress);
            point.y = calculateProgress(startPoint.y, targetPoint.y, progress);

        }

        return point;

    }

    public int calculateProgress(int startValue, int endValue, double fraction) {

        int value = 0;
        int distance = endValue - startValue;
        value = (int)Math.round((double)distance * fraction);
        value += startValue;

        return value;

    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.blue);
        g2d.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setStroke(new BasicStroke(8,
                BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
        g.drawLine(p1.x, p1.y, p2.x, p2.y);

        g.setColor(Color.RED);
        g.drawOval(b1.x - 4, b1.y - 4, 8, 8);
//        ball = new myObject(b1.x, b1.y, "Stuff/ball.png", 50, 50);
//        g.drawImage(ball.getImage(), ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight(), null);
        repaint();
    }

    private class MouseHandler extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            drawing = true;
            p1 = e.getPoint();
            p2 = p1;
            repaint();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            drawing = false;
            p2 = e.getPoint();
            repaint();
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (drawing) {
                p2 = e.getPoint();
                repaint();
            }
        }
    }

    private class ControlPanel extends JPanel {

        private static final int DELTA = 50;
// above is telling the ball to move by 50 pixels
        // I want it to move by 50 pixels but gradually I dont want it to teleport

        public ControlPanel() {
            this.add(new MoveButton("u2190", KeyEvent.VK_LEFT, -DELTA, 0));
            this.add(new MoveButton("u2191", KeyEvent.VK_UP, 0, -DELTA));
            this.add(new MoveButton("u2192", KeyEvent.VK_RIGHT, DELTA, 0));
            this.add(new MoveButton("u2193", KeyEvent.VK_DOWN, 0, DELTA));


        }

        private class MoveButton extends JButton {

            KeyStroke k;
            int myX, myY;

            public MoveButton(String name, int code, final int myX, final int myY) {
                super(name);
                this.k = KeyStroke.getKeyStroke(code, 0);
                this.myX = myX;
                this.myY = myY;
                this.setAction(new AbstractAction(this.getText()) {
                    @Override
                    public void actionPerformed(ActionEvent e) {
//                        LinePanel.this.b1.translate(myX, myY);
                        moveBallBy(myX, myY);
                        LinePanel.this.repaint();
                    }
                });
                ControlPanel.this.getInputMap(
                        WHEN_IN_FOCUSED_WINDOW).put(k, k.toString());
                ControlPanel.this.getActionMap().put(k.toString(), new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        MoveButton.this.doClick();
                    }
                });
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("LinePanel");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.add(new ControlPanel(), BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new LinePanel().display();
            }
        });
    }
}

看看...

附注

这样做 ball = new myObject(b1.x, b1.y, "Stuff/ball.png", 50, 50); 在你的绘制方法中是非常低效的.paint 可以快速连续调用多次.在可能的情况下,您希望 paint 方法尽可能地优化,在您的paint方法上花费太多时间会使您的程序看起来很慢

Doing this ball = new myObject(b1.x, b1.y, "Stuff/ball.png", 50, 50); in you paint method is incredibly inefficient. paint may be called a number of times in quick succession. Where ever possible, you want the paint methods to be as optimized as you can make them, to much time spent in your paint method will make your program look slow

这篇关于我试图让球逐渐移动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆