【问题标题】:Having trouble animating my player character, and other animated objects无法为我的玩家角色和其他动画对象设置动画
【发布时间】:2019-04-27 07:23:10
【问题描述】:

在开始之前,这是我的 UML 图:

我正在尝试为我的玩家角色制作动画,一个 gif 文件,但拆分为 5 个单独的 png 文件。我宁愿直接在 5 帧时工作,因为它不是详细的图像,只是一个 8 位字符精灵。另外,很多照片编辑软件都不知道怎么用,所以我自己用的是单独的文件。

我在 Stack Overflow 和其他教程中尝试了很多示例,但似乎没有什么与我在必须为我的游戏构建的框架上尝试做的事情相匹配。这是一个学期末的项目,但我计划在截止日期之后继续开发并保持开源。

这是我的一些代码。

司机。加载游戏循环和其他功能。

package cactus;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;

public class Driver extends Canvas implements Runnable{
    private static final long serialVersionUID = 1L;

    private Thread t;
    private boolean running;

    private Controller controller;

    public Driver() {
        controller = new Controller();

        /*--- Add Game Objects ---------------------------------------*/
        controller.addObject(new Travis(500, 675, ID.Travis));
        /*------------------------------------------------------------*/

    }

    public synchronized void start() {
        t = new Thread(this);
        t.start();
        running = true;
    }

    public synchronized void stop() {
        try {
            t.join();
            running = false;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void run() {
        this.requestFocus();
        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0;
        double ns = 1000000000 / amountOfTicks;
        double delta = 0;
        long timer = System.currentTimeMillis();
        int frames = 0;
        while(running) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while(delta >= 1) {
                tick();
                delta--;
            }
            if(running) {
                render();
            }
            frames++;
            if(System.currentTimeMillis() - timer > 1000) {
                timer += 1000;
                System.out.println("FPS:" + frames);
                frames = 0;
            }
        }
        stop();
    }

    private void tick() {
        controller.tick();
    }

    private void render() {
        BufferStrategy buffer = this.getBufferStrategy();
        if (buffer == null) {
            this.createBufferStrategy(3);
            return;
        }

        Graphics g = buffer.getDrawGraphics();
        g.drawImage(background.getCurrentBG(), 0, 0, Frame.getWidth(), Frame.getHeight(), null);
        controller.render(g);
        g.dispose();
        buffer.show();
    }

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

控制器。循环遍历游戏对象以执行它们的一些渲染函数,显示它们的样子,以及控制它们的位置和一些未来动作的刻度函数。

package cactus;

import java.awt.Graphics;
import java.util.LinkedList;

public class Controller {
    LinkedList<Objects> gameObj = new LinkedList<Objects>();

    public void tick() {
        for (int i = 0; i < gameObj.size(); i++) {
            Objects currentObject = gameObj.get(i);

            if (currentObject.getId() == ID.ShootFire && currentObject.getX() > Frame.getWidth() + 30) {
                removeObject(currentObject);
                System.out.println("Fire Object Removed");
            }
            currentObject.tick();
        }
    }

    public void render(Graphics g) {
        for (int i = 0; i < gameObj.size(); i++) {
            Objects currentObject = gameObj.get(i);

            currentObject.render(g);
        }
    }

    public void addObject(Objects o) {
        this.gameObj.add(o);
    }

    public void removeObject(Objects o) {
        this.gameObj.remove(o);
    }
}

播放器类。从抽象对象类中获取方法

package cactus;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
// import javax.swing.Timer;

public class Travis extends Objects implements ActionListener{
    ArrayList<BufferedImage> animation;
    // Timer animationTimer;
    Graphics g;
    // int i = 0;

    public Travis(int x, int y, ID id) {
        super(x, y, id);
        this.animation = createAnimation();
        // this.animationTimer = createTimer(animationTimer);

        // animationTimer.start();
    }

    private synchronized ArrayList<BufferedImage> createAnimation() {
        animation = new ArrayList<BufferedImage>();
        for (int i = 0; i < 6; i++) {
            try {
                animation.add(ImageIO.read(new File("./src/resources/image/travis/frame_" + i + ".png")));
            } catch (IOException e) {e.printStackTrace(); System.exit(0);}
        }
        return animation;
    }

//  private synchronized Timer createTimer(Timer animationTimer) {
//      animationTimer = new Timer(15, this);
//      animationTimer.setDelay(15*1000);
//      return animationTimer;
//  }


    @Override
    public void tick() {
        x += velocityX;
    }

    /* 
     * drawImage(img, posX, posY, observe [null])
     * 
     * (non-Javadoc)
     * @see cactus.GameObjects#render(java.awt.Graphics)
     */
    @Override
    public void render(Graphics g) { 
              for (int i = 0; i < 6; i++) {
        g.drawImage(animation.get(i), x, y, null);
              }
              if (i == 6)
                  i = 0;
    }

    @Override
    public void actionPerformed(ActionEvent e) {

    }
}

我希望 ArrayList 的每个对象(尽管可能会将其更改为 Map),以在帧之间使用不同的延迟。 * frame_0: 1s * frame_1:2s * frame_2:2s * frame_3: 1s * frame_4: 2s * frame_5: 5s

我尝试过使用 Timer 和其他一些东西,但无法为其设置动画,它只显示最后一帧。

我没有足够的代表来发布照片。

【问题讨论】:

  • 除非我在这里忽略了这一点,否则Travis::render 方法在每次调用时都会绘制所有 6 张图像,所以您只会看到最后一张图像?您需要某种类型的当前帧 计数器,每次控制器调用render 时该计数器都会递增。作为线索,代码if (i == 6) i = 0; 绝对没有做任何事情,因为方法完成后循环变量超出范围。
  • @stridecolossus 嗨,我试过了,虽然它确实为角色设置了动画,但它每秒会执行近 60 次,所以看起来我的游戏角色正在癫痫发作。我需要知道如何应用某些东西(可能是 Timer)来延迟动画,以便在进入下一帧之前多次显示同一帧。最好在帧之间设置延迟,例如 0.1 秒、0.5 秒等。另外,为什么我会被否决?我尽力写了一篇写得很好的帖子。我不明白这个网站。
  • (来自您现在已删除的问题)。不要担心奇怪的反对票。看起来你在这里也有一个赞成票,所以应该取消它。我打算在你的另一个帖子上发布my discussion here,所以我会在这里添加它。这可能有点哲学,但它描述了一个问题是如何被接收的,部分是用于呈现它的语言的产物。

标签: java animation timer slick


【解决方案1】:

最简单的方法是让渲染线程在帧之间休眠几毫秒:

private static final long PERIOD = 1000 / FRAMES_PER_SECOND;
...

long now = System.currentTimeMillis();
while(running) {
    // Perform frame
    ...

    // Wait for next frame
    now += PERIOD;
    final long duration = now - System.currentTimeMillis();
    if(duration > 0) {
        Thread.sleep(duration);
    }
}

其中FRAMES_PER_SECOND 是所需的每秒帧数。

如果需要,您还可以添加一个计数器来计算帧速率。

还有很多其他(和更好的)创建渲染循环的方法,但首先应该这样做。

【讨论】:

  • 我已经在驱动程序类中设置了类似的功能,但是使用 Thread.sleep 可以阻止我的程序的其余部分。我读到使用多线程是不好的做法,而我也看到它完全没问题,但我不确定该使用什么。我更关注在我的 Player 类中本地循环 5 个图像的东西,它们之间有延迟
  • 我不确定您一直在阅读什么,但休眠线程不会“阻止程序的其余部分”。多线程也不是“坏习惯”,但它很难实现并且容易做坏事,因此应该谨慎使用。如果您对使用线程持谨慎态度,那么也许可以使用timer?
猜你喜欢
  • 1970-01-01
  • 2021-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-11
  • 1970-01-01
相关资源
最近更新 更多