繁体   English   中英

让动画更流畅

[英]Make animation more smoother

我正在尝试使用 JPanel 和 painComponent 创建一些动画(每当按下键时就会运行的男孩)。 所以,首先我声明了一些图像、图像数组和一些绘图方法。 我创建了计时器并将其添加到构造函数中。

Image img1;
Image img2;
Image img3;
Image img4;

int index = 0;

Image currentImage l;
Image[] images = new Image[4]

public class Animation extends JPanel implements ActionListener
{

    public Animation()
    {
     loadImages();
     getTimer();
     imgAdder();
     addFirstImage();
    }

    public void serCurrentImage(Image currentImage)
  {
     this.currentImage = currentImage;
   }
     public void getTimer()
   {
     Timer timer = new Timer(20,this)
      timer.start();
   }
     public void imgAdder()
   {
     images[1] = img1;
        ...
   }
     public void addFirstImage()
   {
      currentImage = img1;
   }
      private void loadImages()
   {
       try
   {
      BufferedImage img = ImageIO.read(getClass.getResource(“/resources/images/img1.png”);
      img1 = img;
      // and so on for every image
    }catch(IOexception ioe )
     ioe.printStackTrace();
    }
  }
     public void paintComponent (Graphics g)
     {
           super.paintComponent(g);
           g.drewImage(currentImage,0,0,this);
           requestsFocus();
      }
            public class FieldKeyListener extends KeyAdapter
    {
            public void move()
      {
            setCurrentImage(image[index]);
             index++;
             if( index == 4 )
                      index = 0;
       }
             public void keyPressed(KeyEvent e)
       {
             super.keyPressed(e);
             int key = e.getKeyCode();
             if(key == Key.Event.VK_LEFT)
             move();
       }
     }
}

然后使用我的数组的循环通过paintComponent绘制所有图像。 我还声明了扩展 KeyAdapter 的类。 一切似乎都很好,我的动画也能正常工作,但问题是它没有我想要的那么顺利。 当我按住键时,图像变化太快,处理看起来不自然。 例如,我想要每秒更改 3 或 4 个图像而不是 20 个。我可以用错误的方法添加计时器吗? 可能有时间延迟之类的东西。 我不知道它究竟是如何工作的,我应该在计时器中提及哪个侦听器作为参数。 Ps 我只是初学者,我的代码在编码标准方面可能看起来不正确。 此外,我只写了项目的关键部分,这些部分代表了问题。 我希望你能帮我解决这个问题。 提前致谢。

动画是一门复杂的学科,有很多枯燥的理论。 基本上,动画是随时间变化的幻觉。 这非常重要,因为您在动画中所做的一切都将基于时间。

在像游戏这样的东西中,你会有一堆实体以不同的时间速率在玩。 挑战之一是花时间设计一种解决方案,允许实体在与刷新周期(即帧数)分离的情况下在一段时间内播放,除非您的精灵具有正确的帧数以匹配您的刷新循环,但即便如此,我还是会担心,因为系统不够灵活,无法适应操作系统和硬件无法跟上的情况。

下面是一个简单的例子,它需要一个精灵表(存储在单个图像中的一系列图像)、预期图像/帧的数量以及完成一个完整周期的时间。

它计算单个帧大小并根据精灵动画的时间量返回一个帧...

public class Sprite {

    private BufferedImage source;
    private int imageCount;
    private int imageWidth;

    // How long it takes to play a full cycle
    private Duration duration;
    // When the last cycle was started
    private Instant startedAt;

    public Sprite(BufferedImage source, int imageCount, int cycleTimeInSeconds) throws IOException {
        this.source = source;
        this.imageCount = imageCount;
        imageWidth = source.getWidth() / imageCount;
        duration = Duration.ofSeconds(cycleTimeInSeconds);
    }

    public BufferedImage getFrame() {
        if (startedAt == null) {
            startedAt = Instant.now();
        }
        Duration timePlayed = Duration.between(startedAt, Instant.now());
        double progress = timePlayed.toMillis() / (double)duration.toMillis();
        if (progress > 1.0) {
            progress = 1.0;
            startedAt = Instant.now();
        }
        int frame = Math.min((int)(imageCount * progress), imageCount - 1);
        return getImageAt(frame);
    }

    protected BufferedImage getImageAt(int index) {
        if (index < 0 || index >= imageCount) {
            return null;
        }
        int xOffset = imageWidth * index;
        return source.getSubimage(xOffset, 0, imageWidth, source.getHeight());
    }

}

注意:它还需要一种重置或停止的方法,所以你可以强制精灵回到开始,但我会留给你

接下来,我们需要一些播放动画的方法

public class TestPane extends JPanel {

    private Sprite sprite;

    public TestPane(Sprite sprite) {
        this.sprite = sprite;
        Timer timer = new Timer(5, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                repaint();
            }
        });
        timer.start();
    }

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

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        BufferedImage img = sprite.getFrame();
        int x = (getWidth() - img.getWidth()) / 2;
        int y = (getHeight() - img.getHeight()) / 2;
        g2d.drawImage(img, x, y, this);
        g2d.dispose();
    }

}

这里没有什么特别的,它是一个简单的 Swing Timer设置为高分辨率(5 毫秒),它不断更新 UI,从精灵请求下一帧并绘制它。

这里的重要部分是精灵和刷新周期是独立的。 希望角色走得更快,更改精灵持续时间,希望角色走得更慢,更改精灵持续时间,刷新周期不需要更改(或任何其他实体)

所以,从...

精灵表

相同的循环,第一次超过 1 秒,第二次超过 5 秒

快走 慢走

您还可以查看诸如How to create a usable KeyReleased method in java 之类的内容,它演示了键绑定和集中式Set作为“动作”存储库的使用

暂无
暂无

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

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