我用 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 时间 将身体换成子弹 不使用翻译功能 使用其他游戏循环。
我尝试过但无济于事的其他事情。