【问题标题】:Gradually speeding a sprite逐渐加速精灵
【发布时间】:2013-05-13 10:10:21
【问题描述】:

我试图让精灵在按下按钮时逐渐加速,而不是仅以恒定速度移动。还要设置最大速度限制。我希望你明白我的意思。

timer = new Timer(5, this);
timer.start();

public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D)g;
    g2d.drawImage(image, x, y, this); //x,y = position
    Toolkit.getDefaultToolkit().sync();
    g.dispose();
}

private class TAdapter extends KeyAdapter { 
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) {
            dx = -1;
        }
        if (key == KeyEvent.VK_RIGHT) {
            dx = 1;
        }
        if (key == KeyEvent.VK_UP) {
            dy = -1;
        }
        if (key == KeyEvent.VK_DOWN) {
            dy = 1;
        }
    }
}   
    public void actionPerformed(ActionEvent e) {
        x += dx;   
        y += dy;
        repaint();  
    }

【问题讨论】:

  • 有什么问题?请发布完整代码。同时,您可以使用多个xy,它们会从慢到快。 即: x = x * 2
  • 尝试增加定时器延迟。 5 毫秒足够接近 0,没有区别。 40 毫秒约为 25 fps,15 约为 60 fps...

标签: java swing timer paint keylistener


【解决方案1】:

您的示例代码有几处(最初)错误...

  1. 您正在覆盖paint 方法。建议您改用 paintComponent 方法。如果您要覆盖顶级容器的paint 方法,例如JFrame,那么建议您不要这样做。相反,请使用 JPanel 之类的内容作为自定义绘画的基础...
  2. 您正在处理过去的Graphics 上下文。这是非常危险的,因为这会阻止绘制其他任何东西。 Graphics 上下文是共享资源,在此重绘周期中需要更新的所有内容都将使用相同的 Graphics 上下文。
  3. 您正在使用KeyListenerKeyListener 有焦点问题。这可以通过使用Key Binding API 轻松解决。键绑定也更加灵活,因为它们将物理键与动作分开,让您可以轻松地将动作与不同的键关联起来和/或重用底层动作(例如使用按钮)。

所以。对于你的问题。你需要知道...

  • 当前速度...
  • 最低允许速度...
  • 最大允许速度...

您还需要保持正在更改的对象的当前位置。

这个例子实际上并没有移动“播放器”,而是移动了背景。背景位置由xDelta改变,也就是改变的速度……

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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestSpeed {

    public static void main(String[] args) {
        new TestSpeed();
    }

    public TestSpeed() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TestPane extends JPanel {

        private BufferedImage background;
        // The current position of the background
        private int xPos = 0;
        // The speed/delta that the xPos is changed...
        private int xDelta = 0;

        public TestPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (xPos < -(getWidth())) {
                        xPos = 0;
                    }
                    xPos -= xDelta;
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "slower");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "faster");

            ActionMap am = getActionMap();
            am.put("slower", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    setSpeed(-1);
                }
            });
            am.put("faster", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    setSpeed(1);
                }
            });
        }

        protected void setSpeed(int delta) {
            xDelta += delta;
            // Check the change in speed to ensure it's within the appropriate range
            if (xDelta < 0) {
                xDelta = 0;
            } else if (xDelta > 9) {
                xDelta = 9;
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        public void invalidate() {
            background = null;
            super.invalidate();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int x = xPos;
            g.setColor(Color.DARK_GRAY);
            while (x < getWidth()) {
                g.drawLine(x, 0, x, getHeight());
                x += 15;
            }

            int width = getWidth();
            int height = getHeight();
            x = (width / 2) - 5;
            int y = (height / 2) - 5;
            g.setColor(Color.RED);
            g.fillOval(x, y, 10, 10);
        }        
    }    
}

【讨论】:

    【解决方案2】:

    您需要定义和存储最大速度、实际速度和速度增量的值。 定义速度增量的最简单方法是定义一个恒定的速度增量,并且应该首先尝试。根据提供的代码:

    int maxspeed = 5;
    int speed = 1;
    int acceleration = 1;
    
    timer = new Timer(5, this);
    timer.start();
    
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D)g;
        g2d.drawImage(image, x, y, this); //x,y = position
        Toolkit.getDefaultToolkit().sync();
        g.dispose();
    }
    
    private class TAdapter extends KeyAdapter { 
        public void keyPressed(KeyEvent e) {
            int key = e.getKeyCode();
            if (key == KeyEvent.VK_LEFT) {
                dx = -acceleration;
            }
            if (key == KeyEvent.VK_RIGHT) {
                dx = acceleration;
            }
            if (key == KeyEvent.VK_UP) {
                dy = -acceleration;
            }
            if (key == KeyEvent.VK_DOWN) {
                dy = acceleration;
            }
        }
    }
    
    public void actionPerformed(ActionEvent e) {
        if (speed < maxspeed) {
            speed += acceleration;
        }
        x += dx * speed;   
        y += dy * speed;
        repaint();  
    }
    

    由于我真的不知道问题的背景或要实现的目标,所以我没有包含任何方法来再次减慢精灵,一旦达到 maxspeed。

    也可以考虑一些速度增益间隔。使用上面的代码,速度的更新会足够快,你可能不会注意到它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 2012-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多