I have been working on this game for quite a bit now. I looked through some of the game loops and animation systems online. After I felt confident about coding my own animation system, I came up with this one. I think it should work like a charm but currentFrame variable seems to stuck at '1' so my animation doesn't play. Can get some help for this? What did I code wrong?
Here are the four classes (GamePanel, Player, Animation, Frames) that are used for the system:
GamePanel class:
package main;
import entity.*;
import animation.*;
import javax.swing.*;
import java.awt.*;
public class GamePanel extends JPanel implements Runnable {
public static final String GAME_VERSION = "0.0.1a";
public static final String GAME_TITLE = "Test " + GAME_VERSION +;
public static final int ORIGINAL_TILE_SIZE = 32;
public static final int SCALE = 2;
public static final int SCALED_TILE_SIZE = ORIGINAL_TILE_SIZE * SCALE;
public static final int[] SCREEN_RATIO = {16, 9};
public static final int SCREEN_WIDTH = SCREEN_RATIO[0] * SCALED_TILE_SIZE;
public static final int SCREEN_HEIGHT = SCREEN_RATIO[1] * SCALED_TILE_SIZE;
public static final int MAX_TPS = 60;
public int fpsCount;
public int tpsCount;
private JFrame frame;
public boolean isRunning = false;
KeyHandler keyHandler = new KeyHandler();
Thread gameThread;
Player player = new Player(this, keyHandler);
public GamePanel(){
this.setMinimumSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setMaximumSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setBackground(Color.BLACK);
this.addKeyListener(keyHandler);
this.setDoubleBuffered(true);
this.setFocusable(true);
frame = new JFrame(GAME_TITLE);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public synchronized void start(){
gameThread = new Thread(this);
gameThread.start();
isRunning = true;
}
public synchronized void stop(){
isRunning = false;
}
@Override
public void run() {
long lastTime = System.nanoTime();
long deltaTime = 0;
long tickInterval = 1000000000 / MAX_TPS;
while(isRunning == true){
long currentTime = System.nanoTime();
deltaTime += (currentTime - lastTime) / tickInterval;
if(deltaTime >= 1){
Update();
lastTime = currentTime;
deltaTime -= 1;
if(tpsCount == 60){
System.out.println("--------------------------------------");
System.out.println("FPS: " + fpsCount + " TPS: " + tpsCount);
System.out.println("W: " + player.isPressedW);
System.out.println("S: " + player.isPressedS);
System.out.println("A: " + player.isPressedA);
System.out.println("D: " + player.isPressedD);
System.out.println("Direction: " + player.direction);
System.out.println("Idle: " + player.isIdle);
System.out.println("Animating: " + player.testAnimation.isRunning);
System.out.println("Current Animation Frame: " + player.testAnimation.currentFrame);
System.out.println("--------------------------------------");
tpsCount -= 60;
fpsCount = 0;
}
}
Render();
}
}
public void Update() {
player.update();
tpsCount++;
}
public void Render(){
repaint();
fpsCount++;
}
public void paintComponent(Graphics g) { //This is called 'repaint' in the Render method
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
player.render(g2d);
g2d.dispose();
}
}
Player class:
package entity;
import main.*;
import animation.*;
import java.awt.*;
public class Player extends Entity {
GamePanel gp;
KeyHandler kh;
public String direction;
public boolean isIdle;
Frames idleSouth, idleNorth, idleEast, idleWest;
Frames movingSouth, movingNorth, movingEast, movingWest;
Animation movementAnimation;
public Frames testFrames = new Frames("player/move_animations", 1, 8);
public Animation testAnimation = new Animation(testFrames, true);
public boolean isPressedS, isPressedW, isPressedD, isPressedA;
public Player(GamePanel gp, KeyHandler kh){
this.gp = gp;
this.kh = kh;
setDefaultProperties();
}
public void setDefaultProperties(){
x = 320;
y = 320;
speed = 240 / this.gp.MAX_TPS;
maxHealth = 100;
curHealth = 100;
direction = "South";
}
public void update(){
testAnimation.update();
isPressedS = kh.pressed_S;
isPressedW = kh.pressed_W;
isPressedD = kh.pressed_D;
isPressedA = kh.pressed_A;
if(kh.pressed_S != true && kh.pressed_W != true && kh.pressed_D != true && kh.pressed_A != true){
isIdle = true;
testAnimation.start();
}else{
isIdle = false;
testAnimation.stop();
}
if(kh.pressed_S == true){
direction = "South";
moveSouth();
}
if(kh.pressed_W == true){
direction = "North";
moveNorth();
}
if(kh.pressed_D == true){
direction = "East";
moveEast();
}
if(kh.pressed_A == true){
direction = "West";
moveWest();
}
}
public void render(Graphics2D g2d){
g2d.drawImage(testAnimation.getFrame(), x, y, GamePanel.SCALED_TILE_SIZE, GamePanel.SCALED_TILE_SIZE, null);
}
public void moveSouth(){
y += speed;
}
public void moveNorth(){
y -= speed;
}
public void moveEast(){
x += speed;
}
public void moveWest(){
x -= speed;
}
}
Animation class:
package animation;
import main.*;
import entity.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
public class Animation {
public boolean isRunning = false;
public boolean isContinuous;
private int frameTimer;
public int currentFrame = 1;
Frames frames;
public Animation(Frames frames, boolean isCountinuous){
this.frames = frames;
this.isContinuous = isCountinuous;
}
public void update(){
if(this.isRunning == true){
if(this.isContinuous == true){
if(frameTimer == 14){
if(currentFrame < frames.frameCount){
currentFrame++;
frameTimer -= 14;
}else if(currentFrame == frames.frameCount){
currentFrame = 1;
frameTimer -= 14;
}
}else{
frameTimer++;
}
}else if(this.isContinuous == false){
if(frameTimer == 14){
if(currentFrame < frames.frameCount){
currentFrame++;
frameTimer -= 14;
}else if(currentFrame == frames.frameCount){
currentFrame = 1;
frameTimer -= 14;
this.stop();
}
}else{
frameTimer++;
}
}
}
}
public void start(){
frameTimer = 0;
isRunning = true;
}
public void stop(){
frameTimer = 0;
currentFrame = 1;
isRunning = false;
}
public BufferedImage getFrame(){
return frames.framelist.get(currentFrame - 1);
// return null;
}
}
Frames class:
package animation;
import main.*;
import entity.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.Buffer;
import java.util.ArrayList;
public class Frames {
public BufferedImage spriteSheet;
public int frameCount;
public ArrayList<BufferedImage> framelist;
public Frames(String path, int row, int frameCount){
this.frameCount = frameCount;
try {
spriteSheet = ImageIO.read(getClass().getResourceAsStream("/" + path + ".png"));
} catch(IOException e) {
throw new RuntimeException(e);
}
framelist = new ArrayList<>();
for(int col = 1; col <= frameCount; col++){
framelist.add(spriteSheet.getSubimage((GamePanel.ORIGINAL_TILE_SIZE * col) - GamePanel.ORIGINAL_TILE_SIZE, (GamePanel.ORIGINAL_TILE_SIZE * row) - GamePanel.ORIGINAL_TILE_SIZE, GamePanel.ORIGINAL_TILE_SIZE, GamePanel.ORIGINAL_TILE_SIZE));
}
}
}