[英]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.