Recent i started my fist "real" project. My goal is to code the first gen of Pokemon in Java. I have higly oriented my code on a YouTube viedo (https://www.youtube.com/watch?v=dEKs-3GhVKQ&list=PLah6faXAgguMnTBs3JnEJY0shAc18XYQZ&index=1). I have learned a lot working through the tutorial and understood everything so far. Now i am at the point to intigrate my tile based movement, and i am really not sure if i did this the right way. The problem is that if i render the player just by tiles (or move the player just by tiles) he is hopping from one tile to another. Its not a smoth walking animation anymore. I have solved this problem by using a timer to the pressed keys. If u press a key the key press detection is set to true for a amount of time. The issue with this is that i cant controll the speed of my player in a nice way. Now the question, can solve this problem in a better way maybe throug tweening ? Or is there a other way ?
I am new to game coding so any advides or help would be really kind.
Here is the whole projekt : https://github.com/komiza24/Pokemom
In here is the timer set up for the amount of time the key is pressed : https://github.com/komiza24/Pokemom/blob/main/src/input/KeyManager.java
public class KeyManager implements KeyListener {
private boolean[] keys;
public boolean up, down, left, right;
private long lastTime, timer;
private float timeToWaitUntilTick;
public KeyManager() {
keys = new boolean[256];
timer = 0;
lastTime = System.currentTimeMillis();
timeToWaitUntilTick = 520.00f ;
}
public void tick() {
timer += System.currentTimeMillis() - lastTime;
lastTime = System.currentTimeMillis();
if (timer > timeToWaitUntilTick) {
up = keys[KeyEvent.VK_W];
down = keys[KeyEvent.VK_S];
left = keys[KeyEvent.VK_A];
right = keys[KeyEvent.VK_D];
timer = 0 ;
}
}
@Override
public void keyPressed(KeyEvent e) {
keys[e.getKeyCode()] = true;
}
@Override
public void keyReleased(KeyEvent e) {
keys[e.getKeyCode()] = false;
}
In here is the creature speed set : https://github.com/komiza24/Pokemom/blob/main/src/entities/creatures/Creatures.java
public abstract class Creatures extends Entity {
public static final int DEFAULT_HEALTH = 10;
// public static final float DEFAULT_SPPED = 0.125f; // größe des Spieler damit er sich nur in Tiles bewegt (1 tile ist eig 8x8 aber spieler 16x16 ) WER FÜR TILEBASIERTES MOVEMENT
public static final float DEFAULT_SPPED = 2 ;
public static final int DEFAULT_CREATURE_WIDTH = 64,
DEFAULT_CREATURE_HEIGHT = 64;
protected int health;
protected float speed;
protected float xMove, yMove;
public Creatures(Handler handler, float x, float y, int width, int height) {
super(handler, x, y, width, height);
health = DEFAULT_HEALTH;
speed = DEFAULT_SPPED;
xMove = 0;
yMove = 0;
}
public void move() {
if (!checkEntitiyCollision(xMove, 0f))
moveX();
if (!checkEntitiyCollision(0f, yMove))
moveY();
}
public void moveX() {
if (xMove > 0) { //right
int tx = (int) (x /** Tile.TILEWIDTH*/ + xMove + bounds.x + bounds.width) / Tile.TILEWIDTH;
if (!collisionWithTile(tx, (int) (y /** Tile.TILEHEIGHT */+ bounds.y) / Tile.TILEHEIGHT)
&& // oben rechts
!collisionWithTile(tx, (int) (y /** Tile.TILEHEIGHT*/ + bounds.y - 1 + bounds.height) / Tile.TILEHEIGHT)) { // unten rechts
x += xMove;
}
} else if (xMove < 0) { // left
int tx = (int) (x /** Tile.TILEWIDTH*/ + xMove + bounds.x) / Tile.TILEWIDTH;
if (!collisionWithTile(tx, (int) (y /** Tile.TILEHEIGHT*/ + bounds.y) / Tile.TILEHEIGHT)
&& // oben links
!collisionWithTile(tx, (int) (y /** Tile.TILEHEIGHT*/ + bounds.y - 1 + bounds.height) / Tile.TILEHEIGHT)) { // unten links
x += xMove;
}
}
}
public void moveY() {
if (yMove < 0) {//up
int ty = (int) (y /** Tile.TILEHEIGHT*/ + yMove + bounds.y) / Tile.TILEHEIGHT;
if (!collisionWithTile((int) (x /** Tile.TILEWIDTH */+ bounds.x) / Tile.TILEWIDTH, ty)
&&// oben links
!collisionWithTile((int) (x /** Tile.TILEWIDTH*/ + bounds.x - 1 + bounds.width) / Tile.TILEWIDTH, ty)) { // oben rechts
y += yMove;
}
} else if (yMove > 0) { //down
int ty = (int) (y /** Tile.TILEHEIGHT*/ + yMove + bounds.y + bounds.height) / Tile.TILEHEIGHT;
if (!collisionWithTile((int) (x /** Tile.TILEWIDTH*/ + bounds.x) / Tile.TILEWIDTH, ty)
&&// oben links
!collisionWithTile((int) (x /** Tile.TILEWIDTH*/ + bounds.x - 1 + bounds.width) / Tile.TILEWIDTH, ty)) { // oben rechts
y += yMove;
}
}
}
protected boolean collisionWithTile(int x, int y) {
return handler.getWorld().getTile(x, y).isSolid();
}
public int getHealth() {
return health;
}
public float getSpeed() {
return speed;
}
public void setHealth(int health) {
this.health = health;
}
public void setSpeed(float speed) {
this.speed = speed;
}
public void setxMove(float xMove) {
this.xMove = xMove;
}
public void setyMove(float yMove) {
this.yMove = yMove;
}
public float getxMove() {
return xMove;
}
public float getyMove() {
return yMove;
}
}
And finally in here the player is beeing moved : https://github.com/komiza24/Pokemom/blob/main/src/entities/creatures/Player.java
public class Player extends Creatures {
//animations
private Animation animDown, animUp, animRight, animLeft;
private int direktion;
public Player(Handler handler, float x, float y) {
super(handler, x, y, Creatures.DEFAULT_CREATURE_WIDTH, Creatures.DEFAULT_CREATURE_HEIGHT);
// animations Time to wait = time to wait until get next input my keymanager so läuft die animation genau 1 mal pro Tile(Feld 16x16 micht 8x8 ! )
animDown = new Animation(175, Assets.player_down);
animUp = new Animation(175, Assets.player_up);
animRight = new Animation(175, Assets.player_right);
animLeft = new Animation(175, Assets.player_left);
}
@Override
public void tick() {
//animations
animRight.tick();
animLeft.tick();
animDown.tick();
animUp.tick();
getInput();
//movement
move();
handler.getGameCamera().centerOnEntity(this);
}
private void getInput() {
xMove = 0;
yMove = 0;
if (handler.getKeyManager().up && !handler.getKeyManager().down && !handler.getKeyManager().left && !handler.getKeyManager().right) {
yMove = -speed;
direktion = 1;
}
if (handler.getKeyManager().down && !handler.getKeyManager().up && !handler.getKeyManager().left && !handler.getKeyManager().right) {
yMove = +speed;
direktion = 4;
}
if (handler.getKeyManager().left && !handler.getKeyManager().right && !handler.getKeyManager().down && !handler.getKeyManager().up) {
xMove = -speed;
direktion = 3;
}
if (handler.getKeyManager().right && !handler.getKeyManager().left && !handler.getKeyManager().down && !handler.getKeyManager().up) {
xMove = +speed;
direktion = 2;
}
}
@Override
public void render(Graphics g) {
g.drawImage(getCurrentAnimationFrame(), (int) (x - handler.getGameCamera().getxOffset()), (int) (y - handler.getGameCamera().getyOffset()), width, height, null);
// HitBox Rectagle :D
g.setColor(Color.RED);
g.fillRect((int) (x + bounds.x - handler.getGameCamera().getxOffset()),
(int) (y + bounds.y - handler.getGameCamera().getyOffset()),
bounds.width, bounds.height);
}
private BufferedImage getCurrentAnimationFrame() {
if (xMove < 0) {
return animLeft.getCurrentFrame();
} else if (xMove > 0) {
return animRight.getCurrentFrame();
} else if (yMove < 0) {
return animUp.getCurrentFrame();
} else if (yMove > 0) {
return animDown.getCurrentFrame();
} else {
switch (direktion) {
case 1:
return Assets.player_default_up;
case 2:
return Assets.player_default_right;
case 3:
return Assets.player_default_left;
default:
return Assets.player_default_down;
}
}
}
}