Java 中的 Box2D 物理隧道问题

问题描述 投票:0回答:0

我用 Java 编写了一个简单的视频游戏已有一段时间了,并且一直在努力解决隧道问题。我使用的物理引擎是 Intellij IDE 中的 JBox2d。

这是我的代码,我将按标签拆分。

这可能是我的代码太多了,但我真的不确定这个问题,似乎无法隔离它。

附言这是我的第一个堆栈溢出帖子,但我不确定提问的所有手续。请在阅读这篇文章时考虑到这一点。

public final class Launcher {

    /**
     * 
     */
    private Launcher() {

    }

    /**
     * @param args arguments passed by cl
     */
    public static void main(final String[] args) {
        GameLoop loop = new VariableStepLoop();
        loop.setup();
        loop.mainLoop();
    }
}

package dragonslayer.view;

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import dragonslayer.KeyHandler;
import dragonslayer.model.Game;
/**
 *
 */
public class Scene {
    private final JFrame frame;
    private final ScenePanel panel;

    KeyHandler keyHandler = new KeyHandler();

    /**
     * @param game the game reference
     * @param w the window width
     * @param h the window height
     */
    public Scene(final Game game, final int w, final int h) {
        GraphicsEnvironment graphics = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice device = graphics.getDefaultScreenDevice();
        this.frame = new JFrame("DragonSlayer");
        device.setFullScreenWindow(this.frame);
        this.frame.setMinimumSize(new Dimension(w, h));
        this.frame.setResizable(false);
        this.panel = new ScenePanel(game, 1920, 1080);

        this.frame.getContentPane().add(this.panel);
        this.frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(final WindowEvent ev) {
                System.exit(-1);
            }
            public void windowClosed(final WindowEvent ev) {
                System.exit(-1);
            }
        });
        this.frame.pack();
        this.frame.setVisible(true);
    }

    /**
     * Method used to render the scene.
     */
    public void render() {
        try {
            SwingUtilities.invokeAndWait(() -> {
                this.panel.render();
            });
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * The panel containing the scene and used to perform the rendering.
     */
    public class ScenePanel extends JPanel {

        private Game game;

        /**
         * @param game game reference
         * @param w panel width
         * @param h panel height
         */
        public ScenePanel(final Game game, final int w, final int h) {
            this.setSize(w, h);
            setFocusable(true);
            setFocusTraversalKeysEnabled(false);
            requestFocusInWindow();
            this.addKeyListener(keyHandler);
            this.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(final MouseEvent e) {

                }
            });

            this.game = game;
        }


        /**
         * rendering without time interference.
         */
        public void render() {
            this.repaint();
        }

        @Override
        protected final void paintComponent(final Graphics g) {
            super.paintComponent(g);

            Game.draw(g);
        }
    }
}




package dragonslayer.controller;

import java.awt.Toolkit;
import dragonslayer.model.Game;
import dragonslayer.view.Scene;

import static dragonslayer.model.Game.world;

/**
 * A game loop that updates the game dependently on the time elapsed from a game cycle to another, 
 * using interpolation to normalize the time.
 */
public class VariableStepLoop implements GameLoop {

    private static final long FPS = 60;
    private static final long PERIOD = 1000 / VariableStepLoop.FPS;

    private boolean running;
    private boolean stopped;

    private Scene scene;
    private Game game;

    @Override
    public final void setup() {
        this.game = new Game();
        this.scene = new Scene(game, (int) ((Toolkit.getDefaultToolkit().getScreenSize().getWidth())),
                (int) ((Toolkit.getDefaultToolkit().getScreenSize().getHeight())));

        this.running = true;
        this.stopped = false;
        this.gameRender();
    }

    @Override
    public final void mainLoop() {
        long currentLagCalc = 0;
        long lastTime = System.currentTimeMillis();
        long lastTimeLag = System.currentTimeMillis();
        while (this.running) {
            final long current = System.currentTimeMillis();
            final int startLag = (int) (currentLagCalc - lastTimeLag);
            final int elapsed = (int) (current - lastTime);
            final double delta = elapsed / ((double) VariableStepLoop.PERIOD);
            //System.out.println(elapsed);
            this.processInput();
            for(int i = 0; i < 1; i++){
                currentLagCalc = System.currentTimeMillis();
            }
            this.gameUpdate(startLag);
            this.gameRender();
            world.step(((float) 1 /180) * 100, 8, 3);
            world.clearForces();
            this.waitForNextFrame(current);
            lastTime = current;
        }
    }

    /**
     * @param current the time got at the beginning of the current game cycle
     */
    private void waitForNextFrame(final long current) {
        final long dt = System.currentTimeMillis() - current;
        if (dt < VariableStepLoop.PERIOD) {
            try {
                Thread.sleep(VariableStepLoop.PERIOD - dt);
            } catch (final Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * Method used to process input.
     */
    private void processInput() {

    }

    /**
     * Method used to pause the game. 
     */
    public void stopOrResumeGame() {
        this.stopped = !this.stopped;
    }

    /**
     * @param delta the elapsed time passed from the start of the previous game cycle to the beginning of the current,+
     *              divided by the optimal time.
     */
    private void gameUpdate(double startLag) {
        if (!this.stopped) {
            Game.update(startLag);
        }
    }

    /**
     * Method used to render the game.
     */
    private void gameRender() {
        this.scene.render();
    }
}







package dragonslayer.model;


import dragonslayer.KeyHandler;
import dragonslayer.controller.VariableStepLoop;
import dragonslayer.model.Objects.*;
import javafx.scene.transform.Translate;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.World;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Vector;


import static java.lang.System.currentTimeMillis;
import static javafx.scene.transform.Transform.translate;
import static org.jbox2d.common.MathUtils.map;

/**
 * An example of a game, to move an object on a 2d space.
 */
public class Game {
    static boolean onStart = true;
    static Vec2 gravity = new Vec2(0, 1);
    public static World world = new World(gravity);
    static KeyHandler keyHandler = new KeyHandler();

    //Bedrock b;
    //Cave cave;
    //Cave_Exit cave_exit;
    //Hell hell;
    static Skipper skipper = new Skipper(200, 200);
    static boolean resting = true;
    static boolean facing = true; //if facing left == true
    Vector<Integer> caving = new Vector<Integer>();
    static GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
    static int width = gd.getDisplayMode().getWidth();
    static int height = gd.getDisplayMode().getHeight();
    static int mouseX = (int) MouseInfo.getPointerInfo().getLocation().getX();
    static int mouseY = (int) MouseInfo.getPointerInfo().getLocation().getY();
    static float x_;
    float y_;
    float xAlign;
    float yAlign;
    int treeType;
    static int directionX = 10;
    static long lastTime = 0;
    boolean full = false;
    boolean tree = true;
    boolean acorn = true;
    boolean stalagmite = true;
    boolean move = false;
    static int worldNum = 0;
    boolean mainScreen = false;
    public static int skipperAnimation = 0;
    Random randomXCaveInit = new Random();
    int randomXCaveMax = 50000;

    int randomXCave = randomXCaveInit.nextInt(randomXCaveMax);
    Random randomXExitCaveInit = new Random();

    int randomXExitCaveMax = 50000;
    int randomXExit = randomXExitCaveInit.nextInt(randomXExitCaveMax);

    Random randomXHellPortalInit = new Random();

    int randomXHellPortalMax = 50000;

    int randomXHellPortal = randomXHellPortalInit.nextInt(randomXHellPortalMax);
    int itemHeld = (0);
    static int hp = 10;
    int dmgSpeed = 400;
    int bossHP = 1800;
    int jawPosY = 0;
    int[] items = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int acornDropChance;
    int[] i = {55, 80, 105, 130, 155, 180, 205, 230, 255, 280};
    static BufferedImage cave_exitImg = null;
    static BufferedImage caveImg = null;
    static BufferedImage screenSaverImg = null;
    static BufferedImage inventoryImg = null;
    public static BufferedImage[] skipperImg = new BufferedImage[12];
    public static BufferedImage skipperRestImg = null;
    public static BufferedImage grassImg = null;
    public static BufferedImage dirtImg = null;
    public static BufferedImage pebbleImg = null;
    public static BufferedImage rockImg = null;
    static BufferedImage treeImg = null;
    public static BufferedImage sandImg = null;
    static BufferedImage waterImg = null;
    public static BufferedImage bedrockImg = null;
    static BufferedImage heartImg = null;
    static BufferedImage skullImg = null;
    static BufferedImage jawImg = null;
    static BufferedImage skullBossArenaImg = null;
    static BufferedImage mouthPortal = null;
    static BufferedImage acornImg = null;
    static BufferedImage treeImg2 = null;
    static BufferedImage surfaceImg = null;
    static BufferedImage cavesImg = null;
    static BufferedImage hellImg = null;
    static BufferedImage stalagmiteImg = null;
    static BufferedImage stalactiteImg = null;
    static BufferedImage hellstoneImg = null;
    static BufferedImage brimstoneImg = null;
    static BufferedImage ashImg = null;
    static BufferedImage hellPortalImg = null;
    public static ArrayList<Grass> grasses = new ArrayList<>();
    public static ArrayList<Dirt> dirty = new ArrayList<>();
    public static ArrayList<Sand> sandy = new ArrayList<>();
    public static ArrayList<Pebble> pebbles = new ArrayList<>();
    public static ArrayList<Rock> rocks = new ArrayList<>();
    public static void surface() {
        for (int i = 0; i < 200; i++) {
            Random randomXTreeInit = new Random();

            int randomXTreeMax = 50000;

            int randomXTree = randomXTreeInit.nextInt(randomXTreeMax);
            //-------------------------------------
            Random randomWTreeInit = new Random();

            int randomWTreeMax = 100;

            int randomWTree = randomWTreeInit.nextInt(randomWTreeMax);
            //------------------------------------
            Random randomHTreeInit = new Random();

            int randomHTreeMax = 400;

            int randomHTree = randomHTreeInit.nextInt(randomHTreeMax);

            //Tree t = new Tree(this, randomXTree, 540, randomWTree + 100, randomHTree + 100);
            //trees.add(t);
        }
        int EnviorPosX = 10;
        for (int i = 0; i < 500; i++) {
            Random grassRandomInit = new Random();

            int grassRandomMax = 3;

            int grassRandom = grassRandomInit.nextInt(grassRandomMax);

            //-------------------------------------

            Random dirtRandomInit = new Random();

            int dirtRandomMax = 5;

            int dirtRandom = dirtRandomInit.nextInt(dirtRandomMax);

            //--------------------------------------

            Random pebbleRandomInit = new Random();

            int pebbleRandomMax = 3;

            int pebbleRandom = pebbleRandomInit.nextInt(pebbleRandomMax);

            //---------------------------------------

            Random stoneRandomInit = new Random();

            int stoneRandomMax = 3;

            int stoneRandom = stoneRandomInit.nextInt(stoneRandomMax);

            //--------------------------------------

            if (grassRandom == 1 || grassRandom == 2) {
                grasses.add(new Grass(EnviorPosX, 725, 50, 50));//world first value 725
                dirty.add(new Dirt(EnviorPosX, 775, 50, 50));
            } else {
                grasses.add(new Grass(EnviorPosX, 775, 50, 50));
            }
            if (dirtRandom == 1 || dirtRandom == 2) {
                dirty.add(new Dirt(EnviorPosX, 825, 50, 50));
            } else {
                pebbles.add(new Pebble(EnviorPosX, 825, 50, 50));
            }
            if (pebbleRandom == 1 || pebbleRandom == 2) {
                pebbles.add(new Pebble(EnviorPosX, 875, 50, 50));
            } else {
                rocks.add(new Rock(EnviorPosX, 875, 50, 50));
            }
            if (stoneRandom == 1) {
                pebbles.add(new Pebble(EnviorPosX, 925, 50, 50));
            } else {
                rocks.add(new Rock(EnviorPosX, 925, 50, 50));
            }
            rocks.add(new Rock(EnviorPosX, 975, 50, 50));
            rocks.add(new Rock(EnviorPosX, 1025, 50, 50));
            EnviorPosX += 50;
        }
    }
    public static void setupImg() {
        try {
            inventoryImg = ImageIO.read(new FileInputStream("res/sprites/inventory.png"));
            bedrockImg = ImageIO.read(new FileInputStream("res/sprites/bedrock.png"));
            treeImg = ImageIO.read(new FileInputStream("res/sprites/tree.png"));
            treeImg2 = ImageIO.read(new FileInputStream("res/sprites/tree2.png"));
            rockImg = ImageIO.read(new FileInputStream("res/sprites/rock.png"));
            pebbleImg = ImageIO.read(new FileInputStream("res/sprites/pebble.png"));
            dirtImg = ImageIO.read(new FileInputStream("res/sprites/dirt.png"));
            sandImg = ImageIO.read(new FileInputStream("res/sprites/sand.png"));
            waterImg = ImageIO.read(new FileInputStream("res/sprites/water.png"));
            grassImg = ImageIO.read(new FileInputStream("res/sprites/grass.png"));
            skipperRestImg = ImageIO.read(new FileInputStream("res/sprites/skipper.png"));
            skipperImg[0] = ImageIO.read(new FileInputStream("res/sprites/skipper2.png"));
            skipperImg[1] = ImageIO.read(new FileInputStream("res/sprites/skipper3.png"));
            skipperImg[2] = ImageIO.read(new FileInputStream("res/sprites/skipper4.png"));
            skipperImg[3] = ImageIO.read(new FileInputStream("res/sprites/skipper5.png"));
            skipperImg[4] = ImageIO.read(new FileInputStream("res/sprites/skipper6.png"));
            skipperImg[5] = ImageIO.read(new FileInputStream("res/sprites/skipper7.png"));
            skipperImg[6] = ImageIO.read(new FileInputStream("res/sprites/skipper8.png"));
            skipperImg[7] = ImageIO.read(new FileInputStream("res/sprites/skipper9.png"));
            skipperImg[8] = ImageIO.read(new FileInputStream("res/sprites/skipper10.png"));
            skipperImg[9] = ImageIO.read(new FileInputStream("res/sprites/skipper11.png"));
            skipperImg[10] = ImageIO.read(new FileInputStream("res/sprites/skipper12.png"));
            skipperImg[11] = ImageIO.read(new FileInputStream("res/sprites/skipper13.png"));
            heartImg = ImageIO.read(new FileInputStream("res/sprites/heart.png"));
            acornImg = ImageIO.read(new FileInputStream("res/sprites/acorn.png"));
            skullImg = ImageIO.read(new FileInputStream("res/sprites/skull.png"));
            jawImg = ImageIO.read(new FileInputStream("res/sprites/jaw.png"));
            caveImg = ImageIO.read(new FileInputStream("res/sprites/cave.png"));
            stalagmiteImg = ImageIO.read(new FileInputStream("res/sprites/stalagmite.png"));
            stalactiteImg = ImageIO.read(new FileInputStream("res/sprites/stalactite.png"));
            cavesImg = ImageIO.read(new FileInputStream("res/sprites/caves.png"));
            surfaceImg = ImageIO.read(new FileInputStream("res/sprites/surface.png"));
            skullBossArenaImg = ImageIO.read(new FileInputStream("res/sprites/skullbossarena.png"));
            hellImg = ImageIO.read(new FileInputStream("res/sprites/hell.png"));
            hellstoneImg = ImageIO.read(new FileInputStream("res/sprites/hellstone.png"));
            brimstoneImg = ImageIO.read(new FileInputStream("res/sprites/brimstone.png"));
            ashImg = ImageIO.read(new FileInputStream("res/sprites/ash.png"));
            hellPortalImg = ImageIO.read(new FileInputStream("res/sprites/hellportal.png"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
    static void pan(float s, Graphics graphics){
        float centerX = width/2;
        float posX = s;
        float d = posX - centerX;
        graphics.translate((int) (d *-1), 0);
    }
    public static void display(Graphics2D graphics) {
        for (Grass g : grasses) {
            g.display(graphics);
        }
        for (Dirt d : dirty) {
            d.display(graphics);
        }
        for (Pebble p : pebbles) {
            p.display(graphics);
        }
        for (Rock r : rocks) {
            r.display(graphics);
        }
        for (Sand s : sandy) {
            s.display(graphics);
        }
        //bedrock.display();
        if(!facing && !resting){
            skipper.displayRight(graphics, skipperImg[skipperAnimation]);
        }else if(facing && !resting){
            skipper.displayLeft(graphics, skipperImg[skipperAnimation]);
        }else if(facing && resting){
            skipper.displayRestRight(graphics);
        } else if(!facing && resting){
            skipper.displayRestLeft(graphics);
        }
    }

    public static void draw(Graphics graphics) {
        //pan(Skipper.x(), graphics);
        if(onStart) {
            setupImg();
            surface();
            onStart = false;
        }
        display((Graphics2D) graphics);
    }

    public static void update(double time) {
        //System.out.println(time);
        if(KeyHandler.LEFT){
        }
        if(KeyHandler.RIGHT){

        }
        if(KeyHandler.UP){

        }

        Vec2 right = new Vec2(directionX, Skipper.LinearVelo);
        Vec2 left = new Vec2(directionX *-1, Skipper.LinearVelo);
        if(KeyHandler.ESCAPE){
            System.exit(0);
        }
        if(KeyHandler.RIGHT){
            if(lastTime + map(1/(directionX/10), 0, 1, 0, 100) < time){
                skipperAnimation = (skipperAnimation + 1) % skipperImg.length;
                lastTime = (long) time;
            }
            skipper.applyForce(right);
            facing = false;
            resting = false;
        }
        if(KeyHandler.LEFT){
            if(lastTime + map(1/(directionX/10), 0, 1, 0, 100) < time){
                skipperAnimation = (skipperAnimation + 1) % skipperImg.length;
                lastTime = (long) time;
            }
            skipper.applyForce(left);
            facing = true;
            resting = false;
        }
    }

}











package dragonslayer.model.Objects;

import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.*;

import java.awt.*;
import java.awt.image.BufferedImage;

import static dragonslayer.model.Game.skipperRestImg;
import static dragonslayer.model.Game.world;
import static javafx.scene.transform.Transform.scale;

public class Skipper {
    public static float LinearVelo;
    static Body body;
   // public float transX = 320.0f;
  //  public float transY = 240.0f;
    public float scaleFactor = 10.0f;

    float w, h;
    float x, y;

    public Skipper(float x_, float y_) {
        w = 64;
        h = 184;
        x = x_;
        y = y_;
        BodyDef bd = new BodyDef();
        bd.type = BodyType.DYNAMIC;
        bd.position.set(x, y);
        bd.bullet = true;
        body = world.createBody(bd);

        PolygonShape sd = new PolygonShape();
        float box2dW = (w);
        float box2dH = (h);
        sd.setAsBox(box2dW, box2dH);

        FixtureDef fd = new FixtureDef();
        fd.shape = sd;
        fd.restitution = 0.0f;
        fd.density = 1f;
        fd.friction = 0f;
        body.createFixture(fd);
        LinearVelo = body.getLinearVelocity().y;
    }
    public void applyForce(Vec2 force){
        body.setLinearVelocity(force);
    }
    public static float x(){
    float x = body.getPosition().x;
      return x;
    }
    public static float y(){
    float y = body.getPosition().y;
    return y;
    }
    public void update(){

    }

    public void displayLeft(Graphics2D graphics, BufferedImage img) {
        graphics.drawImage(img, (int) ((body.getPosition().x + w)),  (int) (body.getPosition().y), (int) w * -1, (int) h, null);
    }

    public void displayRight(Graphics2D graphics, BufferedImage img) {
        graphics.drawImage(img,  (int) ((body.getPosition().x)),  (int) (body.getPosition().y), (int) w, (int) h, null);
    }

    public void displayRestRight(Graphics graphics) {
        graphics.drawImage(skipperRestImg, (int) (body.getPosition().x + w),  (int) (body.getPosition().y), (int) w * -1, (int) h, null);
    }

    public void displayRestLeft(Graphics graphics) {
        graphics.drawImage(skipperRestImg,  (int) ((body.getPosition().x)),  (int) (body.getPosition().y), (int) w, (int) h, null);
    }
}




















package dragonslayer.model.Objects;


import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;

import java.awt.*;

import static dragonslayer.model.Game.grassImg;
import static dragonslayer.model.Game.world;

public class Grass{
    float x;
    float y;
    float h;
    float w;
    Body body;
    public Grass(float x_, float y_, float w_, float h_) {//worldwolrd
        x = x_;
        y = y_;
        w = w_;
        h = h_;
        BodyDef bd = new BodyDef();
        bd.type = BodyType.STATIC;
        bd.position.set(x, y + 50);
        body = world.createBody(bd);

        PolygonShape sd = new PolygonShape();
        float box2dW = (w);
        float box2dH = (h);
        sd.setAsBox(box2dW, box2dH);

        FixtureDef fd = new FixtureDef();
        fd.shape = sd;
        body.createFixture(fd);

    }


    public void display(Graphics2D graphics) {
        graphics.drawImage(grassImg, (int) (body.getPosition().x), (int) (body.getPosition().y - 50), (int) w, (int) h, null);

    }
}


改变游戏循环时间步长 改变 world.step 时间 将身体换成子弹 不使用翻译功能 使用其他游戏循环。

我尝试过但无济于事的其他事情。

java box2d physics-engine jbox2d
© www.soinside.com 2019 - 2024. All rights reserved.