Java 平台游戏:玩家跳过平台

Java Platformer: Player Jumps Through Platform

所以,我即将完成一个简单的 Java 平台游戏,但还有一个大问题,当玩家跳跃并从下方与平台相撞时,玩家有时(并且总是如果他们're close to the platform) 跳过平台并落在上面的平台上。这是代码:

package Main;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

public class Platformer extends Applet implements Runnable, KeyListener {

    // buffering variables
    private Image dbImage;
    private Graphics dbg;

    // running boolean
    private boolean running = true;

    // Player coords
    private int rectX = 100;
    private int rectY = 420;

    // initialise dx and dy at zero
    private double dx = 0;
    private double dy = 0;

    private boolean jumping = false;

    //debug Strings
    private String inter = new String();
    private String coords = new String();
    private String debugX = "", debugY = "";

    //for moving the player
    private int worldShift = 0;

    //sprites
    Rectangle2D player = new Rectangle2D.Double();// = new Rectangle2D.Double(rectX, rectY, 10, 10);
    Rectangle2D ground = new Rectangle2D.Double(0, 420, 800, 150);
    int[][] platforms = { {300, 300, 100, 20}, { 450, 200, 100, 20 }, 
            { 500, 250, 100, 20 }, { 100, 200, 100, 20 }, { 600, 300, 100, 20 } };
    ArrayList<Rectangle2D> platformList = new ArrayList<Rectangle2D>();

    int level = 1;

    @Override
    public void init() {

        setSize(800, 480);
        setFocusable(true);
        addKeyListener(this);
        Frame frame = (Frame) this.getParent().getParent();
        frame.setTitle("Test");
        setVisible(true);

        for (int i = 0; i < platforms.length; i++){
            // platforms
            Rectangle2D platform = new Rectangle2D.Double();
            platform.setRect(platforms[i][0] + worldShift, platforms[i][1],
                    platforms[i][2], platforms[i][3]);
            platformList.add(platform);
        }
    }

    @Override
    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }

    public void paint(Graphics g) {
        //Double Buffering
        Graphics2D g2 = (Graphics2D) g;
        dbImage = createImage(getWidth(), getHeight());
        dbg = dbImage.getGraphics();
        paintComponent(dbg);
        g2.drawImage(dbImage, 0, 0, this);
    }

    // Paint objects
    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;

        //draw platforms
        if (level == 1) {
            g2.setColor(Color.blue);
            g2.draw(ground);
            g2.fill(ground);

            for (Rectangle2D plat : platformList){
                g2.setColor(Color.red);
                g2.draw(plat);
                g2.fill(plat);
            }

        g2.setColor(Color.red);
        //debug printouts   
        g.drawString(inter, 400, 30);
        g.drawString(coords, 20, 150);

        //draw player
        g2.setColor(Color.white);
        g2.draw(player);
        g2.fill(player);

        //print debug info to screen
        Font bold = new Font("Liberation Sans", Font.BOLD, 36);
        setFont(bold);
        g.drawString("dx, dy: (" + dx + ", " + dy + ")", 30, 30);
        g.drawString("x, y: (" + player.getX() + ", " + player.getY() + ")",
                30, 60);
        g.drawString("" + debugX + ", " + debugY + "", rectX, rectY);
        }
    }

    @Override
    public void run() {
        while (running) {

            update();
            repaint();

            try {
                Thread.sleep(17);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void update() {      
        rectX += dx;
        rectY += dy + 1;

        // stops player running off screen
        if (rectX < 1)  rectX = 0;
        if (rectX > 790) rectX = 790;

        // set sprite coords
        player.setRect(rectX, rectY, 10, 10);
        ground.setRect(0, 420, 800, 480);

        // collision detection
        if (player.intersects(ground)) {
            rectY = (int) (ground.getY() - player.getHeight());
            jumping = false;
            dy = 0;
        }

        for (int i = 0; i < platformList.size(); i++){
            Rectangle2D plat = platformList.get(i);
            //sets platform's coordinates
            plat.setRect(plat.getX() + worldShift, plat.getY(), plat.getWidth(), plat.getHeight());
            //sets debug Strings
            coords = "Not on platform";
            inter = " " + platformList.get(0).getX() + worldShift + ", " + worldShift;

            debugX = "" + rectX;
            debugY = "" + rectY;

            //for scrolling the background
            if (rectX > 700 && dx == 5){
                worldShift = -5;}
            else if (rectX < 100 && dx == -5){
                worldShift = 5;}
            else worldShift = 0;

            //collision detection
            if (player.intersects(plat)) {
                jumping = false;
                dy = 0;
                coords = " " + plat.getBounds();
                //if falling
                if (rectY <= (int) (plat.getY() + (plat.getHeight()/2))){
                    rectY = (int) (plat.getY() - player.getHeight());
                //if jumping
                else if (rectY >= plat.getY() + (plat.getHeight()/2)){
                    rectY = (int) (plat.getY() + plat.getHeight());}
                break;
            }
            else if (!player.intersects(plat) && !player.intersects(ground)) {
                jumping = true;
            }
        }

        //implements falling
        if (jumping)
            dy += 1;    
    }

    //button presses
    @Override
    public void keyPressed(KeyEvent e) {
        System.out.println("Key pressed code=" + e.getKeyCode() + ", char=" + e.getKeyChar());
        if (e.getKeyCode() == 37)
            dx -= 5; // 37 is left
        if (e.getKeyCode() == 39)
            dx += 5; // 39 is right
        // if (e.getKeyCode() == 40) dy -= 5; //40 is down
        if (e.getKeyCode() == 38 && jumping == false){
            // if on the ground,
            // i.e. only jump if on the ground
            // 38 is up
            dy -= 20;
            jumping = true;
        }
    }

    //key release
    @Override
    public void keyReleased(KeyEvent e) {
        if (e.getKeyCode() == 37)
            dx = 0; // 37 is left
        if (e.getKeyCode() == 39)
            dx = 0; // 39 is right
        if (e.getKeyCode() == 40)
            dy = 0; // 40 is down
        // if (e.getKeyCode() == 38)
    }

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub

    }
}

我确信 update() 的“//碰撞检测”部分没有问题,但我不知道问题出在哪里。除其他事项外,我尝试将跳转机制置于更新循环中,但它也没有用。

感谢您的帮助。

看跳跃大小,是20:

public void keyPressed(KeyEvent e) {
    System.out.println("Key pressed code=" + e.getKeyCode() + ", char=" + e.getKeyChar());
    if (e.getKeyCode() == 37)
        dx -= 5; // 37 is left
    if (e.getKeyCode() == 39)
        dx += 5; // 39 is right
    // if (e.getKeyCode() == 40) dy -= 5; //40 is down
    if (e.getKeyCode() == 38 && jumping == false){
        // if on the ground,
        // i.e. only jump if on the ground
        // 38 is up
        dy -= 20; // <- jump size 20
        jumping = true;
    }
}

但是你的平台高度也是20而且你是由平台中心决定的,这意味着它只需要超过中心10个像素,跳跃大小应该小于平台高度的一半

编辑 好的配置:

试试这个配置:

设置下降增量为+0.25,跳跃增量为-9

删除评论以使其更短

if (jumping)
    dy += 0.25;

public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == 37)
        dx -= 5; // 37 is left
    if (e.getKeyCode() == 39)
        dx += 5; // 39 is right
    if (e.getKeyCode() == 38 && jumping == false){
        dy -= 9; // <- jump size set to 9 (half is 10)
        jumping = true;
    }
}

注意:闪烁很糟糕,我已经解决了将 paint(Graphics) 方法重命名为 update(Graphics)