From 90dd49e83e62c5c517a6ba32b9b0df55df12d1c2 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 24 Jul 2020 22:51:50 +0200 Subject: [PATCH] collision working --- .idea/inspectionProfiles/Project_Default.xml | 12 ++ .../minosoft/movement/CameraMovement.java | 2 +- .../minosoft/movement/CollisionHandler.java | 115 +++++++++++ .../minosoft/movement/CollisionHandling.java | 180 ------------------ .../minosoft/movement/PlayerController.java | 12 +- .../minosoft/movement/PlayerMovement.java | 21 +- .../protocol/protocol/PacketHandler.java | 4 +- .../bixilon/minosoft/render/MainWindow.java | 12 +- .../render/utility/AdditionalMath.java | 4 + .../bixilon/minosoft/render/utility/Vec3.java | 35 +--- 10 files changed, 167 insertions(+), 230 deletions(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 src/main/java/de/bixilon/minosoft/movement/CollisionHandler.java delete mode 100644 src/main/java/de/bixilon/minosoft/movement/CollisionHandling.java diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..25c233443 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/src/main/java/de/bixilon/minosoft/movement/CameraMovement.java b/src/main/java/de/bixilon/minosoft/movement/CameraMovement.java index 1be35b0de..8108b3f28 100644 --- a/src/main/java/de/bixilon/minosoft/movement/CameraMovement.java +++ b/src/main/java/de/bixilon/minosoft/movement/CameraMovement.java @@ -1,6 +1,6 @@ /* * Codename Minosoft - * Copyright (C) 2020 Moritz Zwerger + * Copyright (C) 2020 Lukas Eisenhauer * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * diff --git a/src/main/java/de/bixilon/minosoft/movement/CollisionHandler.java b/src/main/java/de/bixilon/minosoft/movement/CollisionHandler.java new file mode 100644 index 000000000..f0a51e283 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/movement/CollisionHandler.java @@ -0,0 +1,115 @@ +/* + * Codename Minosoft + * Copyright (C) 2020 Lukas Eisenhauer + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.movement; + +import de.bixilon.minosoft.game.datatypes.world.BlockPosition; +import de.bixilon.minosoft.game.datatypes.world.World; +import de.bixilon.minosoft.render.MainWindow; +import de.bixilon.minosoft.render.blockModels.BlockModelLoader; +import de.bixilon.minosoft.render.utility.Vec3; + +import static de.bixilon.minosoft.render.utility.AdditionalMath.betterRound; +import static de.bixilon.minosoft.render.utility.AdditionalMath.valuesBetween; + +public class CollisionHandler { + World world; + PlayerController controller; + BlockModelLoader modelLoader; + + public CollisionHandler(PlayerController controller) { + world = MainWindow.getConnection().getPlayer().getWorld(); + modelLoader = MainWindow.getRenderer().getModelLoader(); + this.controller = controller; + } + + public void handleCollisions() { + if (isPositionValid(controller.playerPos)) { + // we aren't collided with anything so the player Position does not have to be adjusted + return; + } + xAxisCollision(); + yAxisCollision(); + zAxisCollision(); + if (!isPositionValid(controller.playerPos)) { + controller.playerPos.x = controller.oldPos.x; + controller.playerPos.z = controller.oldPos.z; + } + } + + private void xAxisCollision() { + float deltaX = controller.playerPos.x - controller.oldPos.x; + if (deltaX == 0) { + return; + } + Vec3 testPos = controller.oldPos.copy().add(deltaX, 0, 0); + if (isPositionValid(testPos)) { + return; + } + controller.playerPos.x = controller.oldPos.x; + controller.playerVelocity.x = 0; + } + + private void yAxisCollision() { + float deltaY = controller.playerPos.y - controller.oldPos.y; + if (deltaY == 0) { + return; + } + Vec3 testPos = controller.oldPos.copy().add(0, deltaY, 0); + if (isPositionValid(testPos)) { + return; + } + controller.playerPos.y = controller.oldPos.y; + controller.playerVelocity.y = 0; + //TODO: check if player is actually standing ON a block and is not hanging on the ceiling + controller.onGround = true; + } + + private void zAxisCollision() { + float deltaZ = controller.playerPos.z - controller.oldPos.z; + if (deltaZ == 0) { + return; + } + Vec3 testPos = controller.oldPos.copy().add(0, 0, deltaZ); + if (isPositionValid(testPos)) { + return; + } + controller.playerPos.z = controller.oldPos.z; + controller.playerVelocity.z = 0; + } + + private boolean isPositionValid(Vec3 testPos) { + float width = controller.getPlayerWidth(); + + int[] xPositions = valuesBetween(betterRound(testPos.x + width), + betterRound(testPos.x - width)); + + int[] yPositions = valuesBetween(betterRound(testPos.y + 1), + betterRound(testPos.y + controller.getPlayerHeight() + 1)); + + int[] zPositions = valuesBetween(betterRound(testPos.z + width), + betterRound(testPos.z - width)); + + for (int xPos : xPositions) { + for (int yPos : yPositions) { + for (int zPos : zPositions) { + BlockPosition pos = new BlockPosition(xPos, (short) yPos, zPos); + if (modelLoader.isFull(world.getBlock(pos))) { + return false; + } + } + } + } + return true; + } +} diff --git a/src/main/java/de/bixilon/minosoft/movement/CollisionHandling.java b/src/main/java/de/bixilon/minosoft/movement/CollisionHandling.java deleted file mode 100644 index ad3528298..000000000 --- a/src/main/java/de/bixilon/minosoft/movement/CollisionHandling.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Codename Minosoft - * Copyright (C) 2020 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.movement; - -import de.bixilon.minosoft.game.datatypes.world.BlockPosition; -import de.bixilon.minosoft.game.datatypes.world.World; -import de.bixilon.minosoft.render.blockModels.BlockModelLoader; -import de.bixilon.minosoft.render.utility.Vec3; - -import java.util.ArrayList; -import java.util.List; - -import static de.bixilon.minosoft.render.utility.AdditionalMath.betterRound; -import static de.bixilon.minosoft.render.utility.AdditionalMath.valuesBetween; - -public class CollisionHandling { - public static void handleCollisions(World world, PlayerController controller, BlockModelLoader modelLoader, Vec3 deltaPos) { - - groundCollision(world, controller, modelLoader, deltaPos); - if (!controller.isOnGround()) { - // if we are stuck in a block, just stay there, otherwise, we would fall through the world - //topCollision(world, controller, modelLoader); - } - xAxisCollision(world, controller, modelLoader, deltaPos); - zAxisCollision(world, controller, modelLoader, deltaPos); - } - - private static void zAxisCollision(World world, PlayerController controller, BlockModelLoader modelLoader, Vec3 deltaPos) { - Vec3 playerPos = controller.getPlayerPos(); - int zVelocityDirection = deltaPos.getZNormalized(); - if (zVelocityDirection == 0) { - return; - } - - BlockPosition[] testPositions = getZAxisTestPositions(controller, playerPos); - - for (BlockPosition position : testPositions) { - if (modelLoader.isFull(world.getBlock(position))) { - if (zVelocityDirection == 1) { - playerPos.z = position.getZ() - controller.getPlayerWidth() * 0.5f; - } else { - playerPos.z = position.getZ() + 1 + controller.getPlayerWidth() * 0.5f; - } - controller.playerVelocity.z = 0; - return; - } - } - } - - private static BlockPosition[] getZAxisTestPositions(PlayerController controller, Vec3 testPos) { - List result = new ArrayList<>(); - float width = controller.getPlayerWidth(); - - List xPositions = new ArrayList<>(); - for (int zCoordinate : valuesBetween(betterRound(testPos.x + 0.5 * width), betterRound(testPos.x - 0.5 * width))) { - xPositions.add(zCoordinate); - } - - List yPositions = new ArrayList<>(); - for (int yCoordinate : valuesBetween(betterRound(testPos.y + 1), betterRound(testPos.y + controller.getPlayerHeight()))) { - yPositions.add(yCoordinate); - } - - for (int xPos : xPositions) { - for (int yPos : yPositions) { - result.add(new BlockPosition(xPos, (short) yPos, betterRound(testPos.z))); - } - } - - return result.toArray(new BlockPosition[0]); - } - - private static void xAxisCollision(World world, PlayerController controller, BlockModelLoader modelLoader, Vec3 deltaPos) { - Vec3 playerPos = controller.getPlayerPos(); - int xVelocityDirection = deltaPos.getXNormalized(); - if (xVelocityDirection == 0) { - return; - } - - BlockPosition[] testPositions = getXAxisTestPositions(controller, playerPos, xVelocityDirection); - - for (BlockPosition position : testPositions) { - if (modelLoader.isFull(world.getBlock(position))) { - if (xVelocityDirection == 1) { - playerPos.x = position.getX() - controller.getPlayerWidth() * 0.5f; - } else { - playerPos.x = position.getX() + 1 + controller.getPlayerWidth() * 0.5f; - } - controller.playerVelocity.x = 0; - return; - } - } - } - - private static void topCollision(World world, PlayerController controller, BlockModelLoader modelLoader) { - Vec3 headTop = controller.getPlayerPos().copy(); - headTop.y += controller.getPlayerHeight(); - - BlockPosition[] testPositions = getVerticalTestPositions(controller, headTop); - - for (BlockPosition position : testPositions) { - if (modelLoader.isFull(world.getBlock(position))) { - controller.playerVelocity.y = 0; - controller.playerPos.y = position.getY() - controller.getPlayerHeight(); - } - } - } - - public static void groundCollision(World world, PlayerController controller, BlockModelLoader modelLoader, Vec3 deltaPos) { - Vec3 playerPos = controller.playerPos.copy(); - playerPos.y++; - BlockPosition[] testPositions = getVerticalTestPositions(controller, playerPos); - - for (BlockPosition position : testPositions) { - if (modelLoader.isFull(world.getBlock(position))) { - controller.playerVelocity.y = 0; - controller.playerPos.y = position.getY(); - controller.onGround = true; - } - } - } - - private static BlockPosition[] getVerticalTestPositions(PlayerController controller, Vec3 testPos) { - List result = new ArrayList<>(); - float width = controller.getPlayerWidth(); - - List xPositions = new ArrayList<>(); - for (int xCoordinate : valuesBetween(betterRound(testPos.x + 0.5 * width), betterRound(testPos.x - 0.5 * width))) { - xPositions.add(xCoordinate); - } - - List zPositions = new ArrayList<>(); - for (int xCoordinate : valuesBetween(betterRound(testPos.z + 0.5 * width), betterRound(testPos.z - 0.5 * width))) { - zPositions.add(xCoordinate); - } - - for (int xPos : xPositions) { - for (int zPos : zPositions) { - result.add(new BlockPosition(xPos, (short) testPos.y, zPos)); - } - } - - return result.toArray(new BlockPosition[0]); - } - - private static BlockPosition[] getXAxisTestPositions(PlayerController controller, Vec3 testPos, int xVelocityDirection) { - List result = new ArrayList<>(); - float width = controller.getPlayerWidth(); - - List yPositions = new ArrayList<>(); - - for (int yCoordinate : valuesBetween(betterRound(testPos.y + 1), betterRound(testPos.y + controller.getPlayerHeight()))) { - yPositions.add(yCoordinate); - } - - List zPositions = new ArrayList<>(); - for (int zCoordinate : valuesBetween(betterRound(testPos.z + 0.5 * width), betterRound(testPos.z - 0.5 * width))) { - zPositions.add(zCoordinate); - } - - for (int yPos : yPositions) { - for (int zPos : zPositions) { - result.add(new BlockPosition(betterRound(testPos.x), (short) yPos, zPos)); - } - } - - return result.toArray(new BlockPosition[0]); - } -} diff --git a/src/main/java/de/bixilon/minosoft/movement/PlayerController.java b/src/main/java/de/bixilon/minosoft/movement/PlayerController.java index fd3262284..7a7c6770b 100644 --- a/src/main/java/de/bixilon/minosoft/movement/PlayerController.java +++ b/src/main/java/de/bixilon/minosoft/movement/PlayerController.java @@ -1,6 +1,6 @@ /* * Codename Minosoft - * Copyright (C) 2020 Moritz Zwerger + * Copyright (C) 2020 Lukas Eisenhauer * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * @@ -19,6 +19,7 @@ import de.bixilon.minosoft.render.MainWindow; import de.bixilon.minosoft.render.blockModels.BlockModelLoader; import de.bixilon.minosoft.render.utility.Vec3; +import static de.bixilon.minosoft.render.utility.Vec3.mul; import static org.lwjgl.opengl.GL11.glTranslatef; public class PlayerController { @@ -31,13 +32,18 @@ public class PlayerController { float gravity = 9.81f; boolean onGround; private boolean enableGravity; + private final CollisionHandler collisionHandler; + public Vec3 oldPos; public PlayerController(long window) { cameraMovement = new CameraMovement(); playerMovement = new PlayerMovement(window); + collisionHandler = new CollisionHandler(this); } public void loop(float deltaTime) { + oldPos = playerPos.copy(); + GameMode gameMode = MainWindow.getConnection().getPlayer().getGameMode(); enableGravity = gameMode == GameMode.CREATIVE || gameMode == GameMode.SPECTATOR; handleGravity(deltaTime); @@ -60,7 +66,7 @@ public class PlayerController { return; } BlockModelLoader modelLoader = MainWindow.getRenderer().getModelLoader(); - CollisionHandling.handleCollisions(world, this, modelLoader, playerMovement.deltaPos); + collisionHandler.handleCollisions(); } public boolean isEnableGravity() { @@ -76,7 +82,7 @@ public class PlayerController { } private void applyVelocity(float deltaTime) { - playerPos.add(Vec3.mul(playerVelocity, deltaTime)); + playerPos.add(mul(playerVelocity, deltaTime)); } private void handleGravity(float deltaTime) { diff --git a/src/main/java/de/bixilon/minosoft/movement/PlayerMovement.java b/src/main/java/de/bixilon/minosoft/movement/PlayerMovement.java index dba0dc580..2ab3a0aa9 100644 --- a/src/main/java/de/bixilon/minosoft/movement/PlayerMovement.java +++ b/src/main/java/de/bixilon/minosoft/movement/PlayerMovement.java @@ -1,6 +1,6 @@ /* * Codename Minosoft - * Copyright (C) 2020 Moritz Zwerger + * Copyright (C) 2020 Lukas Eisenhauer * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * @@ -20,7 +20,8 @@ package de.bixilon.minosoft.movement; import de.bixilon.minosoft.render.MainWindow; import de.bixilon.minosoft.render.utility.Vec3; -import static de.bixilon.minosoft.render.utility.Vec3.*; +import static de.bixilon.minosoft.render.utility.Vec3.cross; +import static de.bixilon.minosoft.render.utility.Vec3.mul; import static org.lwjgl.glfw.GLFW.*; public class PlayerMovement { @@ -31,14 +32,12 @@ public class PlayerMovement { float flySpeed = 0.1f; Vec3 playerPos; - Vec3 deltaPos; public PlayerMovement(long window) { this.window = window; } private void processInput(float deltaTime) { - Vec3 posBefore = playerPos.copy(); float cameraSpeed = flySpeed / deltaTime; if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { @@ -58,25 +57,23 @@ public class PlayerMovement { } if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) { - if (!MainWindow.getPlayerMovement().isEnableGravity()) { + if (!MainWindow.getPlayerController().isEnableGravity()) { playerPos.add(0, cameraSpeed * deltaTime, 0); } } if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { - if (!MainWindow.getPlayerMovement().isEnableGravity()) { + if (!MainWindow.getPlayerController().isEnableGravity()) { playerPos.add(0, -cameraSpeed * deltaTime, 0); } - if (MainWindow.getPlayerMovement().isOnGround()) { - - MainWindow.getPlayerMovement().jump(); + if (MainWindow.getPlayerController().isOnGround()) { + MainWindow.getPlayerController().jump(); } } - deltaPos = add(playerPos, mul(posBefore, -1)); } public void loop(float deltaTime) { - cameraFront = MainWindow.getPlayerMovement().getCameraMovement().getCameraFront(); - playerPos = MainWindow.getPlayerMovement().getPlayerPos(); + cameraFront = MainWindow.getPlayerController().getCameraMovement().getCameraFront(); + playerPos = MainWindow.getPlayerController().getPlayerPos(); processInput(deltaTime); } } \ No newline at end of file diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java index f971ff92a..ee32d5c67 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java @@ -346,8 +346,8 @@ public class PacketHandler { } public void handle(PacketPlayerPositionAndRotation pkg) { - MainWindow.getPlayerMovement().getCameraMovement().setRotation(pkg.getPitch(), pkg.getYaw()); - MainWindow.getPlayerMovement().setPlayerPos(new Vec3(pkg.getLocation())); + MainWindow.getPlayerController().getCameraMovement().setRotation(pkg.getPitch(), pkg.getYaw()); + MainWindow.getPlayerController().setPlayerPos(new Vec3(pkg.getLocation())); //TODO: location if (!connection.getPlayer().isSpawnConfirmed()) { diff --git a/src/main/java/de/bixilon/minosoft/render/MainWindow.java b/src/main/java/de/bixilon/minosoft/render/MainWindow.java index c2ada5500..fb4318098 100644 --- a/src/main/java/de/bixilon/minosoft/render/MainWindow.java +++ b/src/main/java/de/bixilon/minosoft/render/MainWindow.java @@ -34,7 +34,7 @@ public class MainWindow { static MainMenu mainMenu; static WorldRenderer renderer; static Connection connection; - private static PlayerController playerMovement; + private static PlayerController playerController; public static void start(Connection serverConnection) { @@ -44,7 +44,7 @@ public class MainWindow { openGLWindow.init(); renderer = new WorldRenderer(); renderer.init(); - playerMovement = new PlayerController(openGLWindow.getWindow()); + playerController = new PlayerController(openGLWindow.getWindow()); renderMode = MAIN_MENU; mainMenu = new MainMenu(openGLWindow.getWidth(), openGLWindow.getHeight()); mainLoop(); @@ -69,7 +69,7 @@ public class MainWindow { break; case PLAY: OpenGLWindow.gluPerspective(FOVY, (float) WIDTH / (float) HEIGHT, 0.1f, 500f); - playerMovement.loop(deltaTime); + playerController.loop(deltaTime); renderer.draw(); break; } @@ -91,7 +91,7 @@ public class MainWindow { renderMode = PLAY; glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); - glfwSetCursorPosCallback(openGLWindow.getWindow(), playerMovement.getCameraMovement()::mouseCallback); + glfwSetCursorPosCallback(openGLWindow.getWindow(), playerController.getCameraMovement()::mouseCallback); glfwSetInputMode(openGLWindow.getWindow(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); glEnable(GL_TEXTURE_2D); connection.connect(); @@ -111,7 +111,7 @@ public class MainWindow { System.exit(1); } - public static PlayerController getPlayerMovement() { - return playerMovement; + public static PlayerController getPlayerController() { + return playerController; } } diff --git a/src/main/java/de/bixilon/minosoft/render/utility/AdditionalMath.java b/src/main/java/de/bixilon/minosoft/render/utility/AdditionalMath.java index d049f7f13..daa4a6be1 100644 --- a/src/main/java/de/bixilon/minosoft/render/utility/AdditionalMath.java +++ b/src/main/java/de/bixilon/minosoft/render/utility/AdditionalMath.java @@ -39,4 +39,8 @@ public class AdditionalMath { } return (int) x - 1; } + + public static boolean isBetween(double x, double a, double b) { + return x <= a && x >= b || x >= a && x <= b; + } } diff --git a/src/main/java/de/bixilon/minosoft/render/utility/Vec3.java b/src/main/java/de/bixilon/minosoft/render/utility/Vec3.java index 03acd2bd7..c2a78a80a 100644 --- a/src/main/java/de/bixilon/minosoft/render/utility/Vec3.java +++ b/src/main/java/de/bixilon/minosoft/render/utility/Vec3.java @@ -25,10 +25,10 @@ public class Vec3 { x = y = z = 0; } - public Vec3(float x_, float y_, float z_) { - x = x_; - y = y_; - z = z_; + public Vec3(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; } public Vec3(Location location) { @@ -84,10 +84,11 @@ public class Vec3 { z += v.z; } - public void add(float x_, float y_, float z_) { - x += x_; - y += y_; - z += z_; + public Vec3 add(float x, float y, float z) { + this.x += x; + this.y += y; + this.z += z; + return this; } public float len() { @@ -108,22 +109,4 @@ public class Vec3 { public void zero() { x = y = z = 0f; } - - public int getXNormalized() { - if (x == 0f) { - return 0; - } else if (x > 0) { - return 1; - } - return -1; - } - - public int getZNormalized() { - if (z == 0f) { - return 0; - } else if (z > 0) { - return 1; - } - return -1; - } }