简体   繁体   English

我应该如何在这个2D游戏中实现跳跃/重力/下降

[英]How should I implement Jumping/gravity/falling in this 2d Java Game

So Here's my Player class (The object I would like to jump on spacebar), I just don't know where to begin, are there any good resources I can read on the internet that relates to me? 所以这是我的Player类(我想跳到空格键上的对象),我只是不知道从哪里开始,我能在网上看到与我有关的任何好资源吗? Any help is great, thank-you. 任何帮助都很棒,谢谢你。

package com.zetcode;
import java.awt.Color;
import java.awt.Graphics;

public class Player extends Creature {

    private boolean jumping = false;
    private Creature creature;

    public Player(Handler handler, float x, float y) {
        super(handler, x, y, Creature.PLAYER_WIDTH, Creature.PLAYER_HEIGHT);

        bounds.x = 16;
        bounds.y = 31;
        bounds.width = 40;
        bounds.height = 58;
    }

    @Override
    public void tick() {
        getInput();
        move();
        handler.getGameCamera().centerOnEntity(this);
    }

    private void getInput(){
        xMove = 0;
        yMove = 3;
        gravity = 2;

        if(handler.getKeyManager().jump)
            yMove = -speed;
        if(handler.getKeyManager().down)
            yMove = speed;
        if(handler.getKeyManager().left)
            xMove = -speed;
        if(handler.getKeyManager().right)
            xMove = speed;
    }

    @Override
    public void render(Graphics g) {
        g.drawImage(Assets.player, (int) (x -     handler.getGameCamera().getxOffset()), (int) (y -   handler.getGameCamera().getyOffset()), width, height, null);
    }
}

And here is my KeyManager class: 这是我的KeyManager类:

package com.zetcode;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class KeyManager implements KeyListener{

    private boolean[] keys;
    public boolean up, down, left, right, jump;

    public KeyManager(){
        keys = new boolean[256];
    }

    public void tick(){
        down = keys[KeyEvent.VK_S];
        left = keys[KeyEvent.VK_A];
        right = keys[KeyEvent.VK_D];
        jump = keys[KeyEvent.VK_SPACE];
    }

    @Override
    public void keyPressed(KeyEvent e) {
        keys[e.getKeyCode()] = true;
        System.out.println("A Key was pressed");
    }

    @Override
    public void keyReleased(KeyEvent e) {
        keys[e.getKeyCode()] = false;
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
}

I have been struggling to implement a way for my character to jump, currently the player moves up the Y axis on spacebar press but I can hold the key down and jump endlessly. 我一直在努力为我的角色实现跳跃的方式,目前玩家在空格键按下时向上移动Y轴,但我可以按住键并无休止地跳跃。

I'll add my Creature class which has my collision detection: 我将添加我的碰撞检测的Creature类:

package com.zetcode;

public abstract class Creature extends Entity {

    public static final int DEFAULT_HEALTH = 10;
    public static final float DEFAULT_SPEED = 3.0f;
    public static final int DEFAULT_CREATURE_WIDTH = 64,
            DEFAULT_CREATURE_HEIGHT = 64;
    public static final int PLAYER_HEIGHT = 90, PLAYER_WIDTH = 64;

    protected int health;
    protected float speed;
    protected float xMove, yMove;
    protected float gravity;

    public boolean falling = true;
    private boolean jumping = false;

    public Creature(Handler handler, float x, float y, int width, int height) {
        super(handler, x, y, width, height);
        health = DEFAULT_HEALTH;
        speed = DEFAULT_SPEED;
        xMove = 0;
        yMove = 0;
        gravity = 0;
    }

    //collision detection

    public void move(){
        moveX();
        moveY();
    }

    public void moveX(){
        if(xMove > 0){//move right
            int tx = (int) (x + xMove + bounds.x + bounds.width) / Tile.TILE_WIDTH;

            if(!collisionWithTile(tx, (int) (y + bounds.y) / Tile.TILE_HEIGHT) && //check top right corner of hitbox
                    !collisionWithTile(tx, (int) (y + bounds.y + bounds.height) / Tile.TILE_HEIGHT)){ //check bottom right corner of hitbox
                x += xMove;
            }else{
                x = tx * Tile.TILE_WIDTH - bounds.x - bounds.width - 1;
            }

        }else if(xMove < 0){//move left
            int tx = (int) (x + xMove + bounds.x) / Tile.TILE_WIDTH;

            if(!collisionWithTile(tx, (int) (y + bounds.y) / Tile.TILE_HEIGHT) && //check top left corner of hitbox
                    !collisionWithTile(tx, (int) (y + bounds.y + bounds.height) / Tile.TILE_HEIGHT)){ //check bottom left corner of hitbox
                x += xMove;
            }else{
                x = tx * Tile.TILE_WIDTH + Tile.TILE_WIDTH - bounds.x;
            }
        }
    }

    public void moveY(){
        if(yMove < 0){//up
            int ty = (int) (y+ yMove + bounds.y) / Tile.TILE_HEIGHT;

            if(!collisionWithTile((int) (x + bounds.x) / Tile.TILE_WIDTH, ty) &&
                    !collisionWithTile((int) (x + bounds.x + bounds.width) / Tile.TILE_WIDTH,ty)){
                y += yMove;
            }else{
                y = ty * Tile.TILE_HEIGHT + Tile.TILE_HEIGHT - bounds.y;
            }

        }else if(yMove > 0){//down
            int ty = (int) (y+ yMove + bounds.y + bounds.getHeight()) /      Tile.TILE_HEIGHT;

            if(!collisionWithTile((int) (x + bounds.x) / Tile.TILE_WIDTH,ty) &&
                    !collisionWithTile((int) (x + bounds.x + bounds.width) /   Tile.TILE_WIDTH,ty)){
                y += yMove;
            }else{
                y = ty * Tile.TILE_HEIGHT - bounds.y - bounds.height -1;
            }
        }
    }

    protected boolean collisionWithTile(int x, int y){
        return handler.getWorld().getTile(x, y).isSolid();
    }

    //getters and setters

    public float getxMove() {
        return xMove;
    }

    public void setxMove(float xMove) {
        this.xMove = xMove;
    }

    public float getyMove() {
        return yMove;
    }

    public void setyMove(float yMove) {
        this.yMove = yMove;
    }

    public int getHealth() {
        return health;
    }

    public void setHealth(int health) {
        this.health = health;
    }

    public float getSpeed() {
        return speed;
    }

    public void setSpeed(float speed) {
        this.speed = speed;
    }
}

What you want to do, is implement speed , acceleration and gravity for the objects on your scene. 您想要做的是为场景中的对象实现速度加速度重力 Speed is a 2D vector, which tells you how fast something moves , while acceleration tells you how much the speed increases . 速度是一个2D矢量,可以告诉您某些物体的移动速度 ,而加速度则告诉您速度增加了多少

All objects should have an update() method, which is called periodically. 所有对象都应该有一个update()方法,该方法定期调用。 It will apply the speed of the object to it's position (that's how speed and position are related anyways) and when you want to accelerate an object, you will basically just increase its speed. 它会将物体的速度应用到它的位置(这就是速度和位置之间的相关关系),当你想要加速一个物体时,你基本上只会提高它的速度。 In the update() method we also apply gravity (in form of negative Y acceleration) update()方法中我们也应用重力(以负Y加速的形式)

You can also make use of friction. 你也可以利用摩擦力。 Friction makes sure that your objects will slow down, as they move into a certain direction. 摩擦确保您的物体在向某个方向移动时减速。

In this simple simulation, friction gets weaker, as the value approaches 1 . 在这个简单的模拟中,当值接近1 ,摩擦力会变弱。 That means at FRICTION==1 you have no friction and at FRICTION==0 your objects will stop immediately. 这意味着在FRICTION==1你没有摩擦,在FRICTION==0你的对象会立即停止。

public class PhysicsObject {
    public static final double FRICTION = 0.99;
    public static final double GRAVITY = 0.01;
    private double posX;
    private double posY;
    private double speedX = 0;
    private double speedY = 0;

    public PhysicsObject(double posX, double posY) {
        this.posX = posX;
        this.posY = posY;
    }

    public void accelerate(double accelerationX, double accelerationY) {
        speedX += accelerationX;
        speedY += accelerationY;
    }

    public void move(double xDelta, double yDelta) {
        posX += xDelta;
        posY += yDelta;
        // do collision detection here. upon collision, set speedX/speedY to zero..!
    }

    public void update() {
        move(speedX, speedY);
        speedX *= FRICTION;
        speedY *= FRICTION;
        accelerate(0, -GRAVITY); // gravity accelerates the object downwards each tick
    }

    public double getPosX() {
        return posX;
    }

    public double getPosY() {
        return posY;
    }
}

You can also use update() to process collision detection (which should set speed to zero) and enemies could do their AI logic.. 您还可以使用update()来处理碰撞检测(应该将速度设置为零),并且敌人可以执行他们的AI逻辑。

You class Player could extend this PhysicsObject and have the methods jump() , runLeft() and runRight() , which could look like this: 你的类Player可以扩展这个PhysicsObject并使用方法jump()runLeft()runRight() ,它们可能如下所示:

public class Player extends PhysicsObject{
    public static final double JUMP_STRENGTH = 5;
    public static final double SPEED = 1;
    public void jump() {
        accelerate(0, JUMP_STRENGTH); // change 5 for some constant or variable indicating the "strength" of the jump
    }

    public void runRight() {
        move(SPEED, 0);
    }

    public void runLeft() {
        move(-SPEED, 0);
    }
}

Collision detection is a huge thing on it's own and it would be too much to cover here, but this video describes it very well. 碰撞检测本身就是一件很大的事情,而且这里的内容太多了,但这段视频非常清楚地描述了它。 Go check it out! 去看看吧!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM