4
\$\begingroup\$

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;
            }
           
        }

    }

}
\$\endgroup\$
0

1 Answer 1

3
\$\begingroup\$

While testing your code, I found that the figure moves on a grid that doesn't actually exist. As such, I found myself running into signs, even though my figure was mostly above the sign. I also noticed that if you click quickly on the WASD keys, the figure doesn't move.

There's a few things to consider in order to address these issues:

  • You've made your movement so that it's based off of speed and time, instead of time and distance. If you use time and distance to calculate speed, this will help to make your figure stop at the right place. I would go even further though, by enforcing an end position. That way you truly do have a grid.
  • Try this: instead of only changing the keypress booleans at certain intervals, check the keypress booleans at certain intervals. If a keypress for a certain direction is detected, do the movement, animation and all. Once it's done check for a keypress again.

Here's something I whipped together- I do encourage you to try implementing my suggestions before looking at this. There's also some helper methods I made in here, so it won't run if you copy paste.

package entities.creatures;
import gfx.Animation;
import gfx.Assets;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import pokemon.Handler;
import tiles.Tile;

public class Player extends Creatures {
    //animations
    private final Animation animDown;
    private final Animation animUp;
    private final Animation animRight;
    private final Animation animLeft;

    private int standing_direction;
    private boolean moving;
    private long animation_start_time;
    private float animation_duration = 260f;

    public Player(Handler handler, float x, float y) {
        super(handler, x, y, Creatures.DEFAULT_CREATURE_WIDTH, Creatures.DEFAULT_CREATURE_HEIGHT);

        // 63 cause sliding from right to a wall wasn't functioning
        bounds.x = 0;
        bounds.y = 0;
        bounds.width = 63;
        bounds.height = 63;

        // 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();

        if (!moving) {
            setDirection();
        }

        move();

        handler.getGameCamera().centerOnEntity(this);
    }

    private void setDirection() {
        if (handler.getKeyManager().isOnlyUpPressed()) {
            yMove = -speed;
            standing_direction = 1;
            startAnimation();
        }
        if (handler.getKeyManager().isOnlyDownPressed()) {
            yMove = speed;
            standing_direction = 4;
            startAnimation();
        }
        if (handler.getKeyManager().isOnlyLeftPressed()) {
            xMove = -speed;
            standing_direction = 3;
            startAnimation();
        }
        if (handler.getKeyManager().isOnlyRightPressed()) {
            xMove = speed;
            standing_direction = 2;
            startAnimation();
        }
    }

    private void startAnimation() {
        moving = true;
        animation_start_time = System.currentTimeMillis();
    }

    private void stopAnimationIfRequired() {
        if (System.currentTimeMillis() - animation_start_time > animation_duration) {
            moving = false;
            xMove = 0;
            yMove = 0;

            setDirection();
        }
    }

    @Override
    public void render(Graphics g) {
        if (moving) {
            stopAnimationIfRequired();
        }

        g.drawImage(
                getCurrentAnimationFrame(),
                (int) (x - handler.getGameCamera().getxOffset()),
                (int) (y - handler.getGameCamera().getyOffset()),
                width,
                height,
                null);
    }

    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 (standing_direction) {
                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;
            }
        }
    }
 }

\$\endgroup\$
1
  • \$\begingroup\$ I am really really thankful for your answer, right now I don't got enaught time to read all of it because i am writing a math class work tomorrow in the morning. Tomorrow I will look above everything u wrote exactly ! Thank u ! \$\endgroup\$
    – G0ngB0ng
    Apr 15, 2021 at 22:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.