collision working

This commit is contained in:
Lukas 2020-07-24 22:51:50 +02:00
parent 55ae01febe
commit 90dd49e83e
10 changed files with 167 additions and 230 deletions

View File

@ -0,0 +1,12 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SuspiciousNameCombination" enabled="false" level="WARNING" enabled_by_default="false">
<group names="x,width,left,right" />
<group names="y,height,top,bottom" />
<ignored>
<option name="METHOD_MATCHER_CONFIG" value="java.io.PrintStream,println,java.io.PrintWriter,println,java.lang.System,identityHashCode,java.sql.PreparedStatement,set.*,java.sql.ResultSet,update.*,java.sql.SQLOutput,write.*,java.lang.Integer,compare.*,java.lang.Long,compare.*,java.lang.Short,compare,java.lang.Byte,compare,java.lang.Character,compare,java.lang.Boolean,compare,java.lang.Math,.*,java.lang.StrictMath,.*" />
</ignored>
</inspection_tool>
</profile>
</component>

View File

@ -1,6 +1,6 @@
/* /*
* Codename Minosoft * 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. * 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.
* *

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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<BlockPosition> result = new ArrayList<>();
float width = controller.getPlayerWidth();
List<Integer> xPositions = new ArrayList<>();
for (int zCoordinate : valuesBetween(betterRound(testPos.x + 0.5 * width), betterRound(testPos.x - 0.5 * width))) {
xPositions.add(zCoordinate);
}
List<Integer> 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<BlockPosition> result = new ArrayList<>();
float width = controller.getPlayerWidth();
List<Integer> xPositions = new ArrayList<>();
for (int xCoordinate : valuesBetween(betterRound(testPos.x + 0.5 * width), betterRound(testPos.x - 0.5 * width))) {
xPositions.add(xCoordinate);
}
List<Integer> 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<BlockPosition> result = new ArrayList<>();
float width = controller.getPlayerWidth();
List<Integer> yPositions = new ArrayList<>();
for (int yCoordinate : valuesBetween(betterRound(testPos.y + 1), betterRound(testPos.y + controller.getPlayerHeight()))) {
yPositions.add(yCoordinate);
}
List<Integer> 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]);
}
}

View File

@ -1,6 +1,6 @@
/* /*
* Codename Minosoft * 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. * 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.blockModels.BlockModelLoader;
import de.bixilon.minosoft.render.utility.Vec3; import de.bixilon.minosoft.render.utility.Vec3;
import static de.bixilon.minosoft.render.utility.Vec3.mul;
import static org.lwjgl.opengl.GL11.glTranslatef; import static org.lwjgl.opengl.GL11.glTranslatef;
public class PlayerController { public class PlayerController {
@ -31,13 +32,18 @@ public class PlayerController {
float gravity = 9.81f; float gravity = 9.81f;
boolean onGround; boolean onGround;
private boolean enableGravity; private boolean enableGravity;
private final CollisionHandler collisionHandler;
public Vec3 oldPos;
public PlayerController(long window) { public PlayerController(long window) {
cameraMovement = new CameraMovement(); cameraMovement = new CameraMovement();
playerMovement = new PlayerMovement(window); playerMovement = new PlayerMovement(window);
collisionHandler = new CollisionHandler(this);
} }
public void loop(float deltaTime) { public void loop(float deltaTime) {
oldPos = playerPos.copy();
GameMode gameMode = MainWindow.getConnection().getPlayer().getGameMode(); GameMode gameMode = MainWindow.getConnection().getPlayer().getGameMode();
enableGravity = gameMode == GameMode.CREATIVE || gameMode == GameMode.SPECTATOR; enableGravity = gameMode == GameMode.CREATIVE || gameMode == GameMode.SPECTATOR;
handleGravity(deltaTime); handleGravity(deltaTime);
@ -60,7 +66,7 @@ public class PlayerController {
return; return;
} }
BlockModelLoader modelLoader = MainWindow.getRenderer().getModelLoader(); BlockModelLoader modelLoader = MainWindow.getRenderer().getModelLoader();
CollisionHandling.handleCollisions(world, this, modelLoader, playerMovement.deltaPos); collisionHandler.handleCollisions();
} }
public boolean isEnableGravity() { public boolean isEnableGravity() {
@ -76,7 +82,7 @@ public class PlayerController {
} }
private void applyVelocity(float deltaTime) { private void applyVelocity(float deltaTime) {
playerPos.add(Vec3.mul(playerVelocity, deltaTime)); playerPos.add(mul(playerVelocity, deltaTime));
} }
private void handleGravity(float deltaTime) { private void handleGravity(float deltaTime) {

View File

@ -1,6 +1,6 @@
/* /*
* Codename Minosoft * 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. * 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.MainWindow;
import de.bixilon.minosoft.render.utility.Vec3; 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.*; import static org.lwjgl.glfw.GLFW.*;
public class PlayerMovement { public class PlayerMovement {
@ -31,14 +32,12 @@ public class PlayerMovement {
float flySpeed = 0.1f; float flySpeed = 0.1f;
Vec3 playerPos; Vec3 playerPos;
Vec3 deltaPos;
public PlayerMovement(long window) { public PlayerMovement(long window) {
this.window = window; this.window = window;
} }
private void processInput(float deltaTime) { private void processInput(float deltaTime) {
Vec3 posBefore = playerPos.copy();
float cameraSpeed = flySpeed / deltaTime; float cameraSpeed = flySpeed / deltaTime;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { 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 (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) {
if (!MainWindow.getPlayerMovement().isEnableGravity()) { if (!MainWindow.getPlayerController().isEnableGravity()) {
playerPos.add(0, cameraSpeed * deltaTime, 0); playerPos.add(0, cameraSpeed * deltaTime, 0);
} }
} }
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
if (!MainWindow.getPlayerMovement().isEnableGravity()) { if (!MainWindow.getPlayerController().isEnableGravity()) {
playerPos.add(0, -cameraSpeed * deltaTime, 0); playerPos.add(0, -cameraSpeed * deltaTime, 0);
} }
if (MainWindow.getPlayerMovement().isOnGround()) { if (MainWindow.getPlayerController().isOnGround()) {
MainWindow.getPlayerController().jump();
MainWindow.getPlayerMovement().jump();
} }
} }
deltaPos = add(playerPos, mul(posBefore, -1));
} }
public void loop(float deltaTime) { public void loop(float deltaTime) {
cameraFront = MainWindow.getPlayerMovement().getCameraMovement().getCameraFront(); cameraFront = MainWindow.getPlayerController().getCameraMovement().getCameraFront();
playerPos = MainWindow.getPlayerMovement().getPlayerPos(); playerPos = MainWindow.getPlayerController().getPlayerPos();
processInput(deltaTime); processInput(deltaTime);
} }
} }

View File

@ -346,8 +346,8 @@ public class PacketHandler {
} }
public void handle(PacketPlayerPositionAndRotation pkg) { public void handle(PacketPlayerPositionAndRotation pkg) {
MainWindow.getPlayerMovement().getCameraMovement().setRotation(pkg.getPitch(), pkg.getYaw()); MainWindow.getPlayerController().getCameraMovement().setRotation(pkg.getPitch(), pkg.getYaw());
MainWindow.getPlayerMovement().setPlayerPos(new Vec3(pkg.getLocation())); MainWindow.getPlayerController().setPlayerPos(new Vec3(pkg.getLocation()));
//TODO: location //TODO: location
if (!connection.getPlayer().isSpawnConfirmed()) { if (!connection.getPlayer().isSpawnConfirmed()) {

View File

@ -34,7 +34,7 @@ public class MainWindow {
static MainMenu mainMenu; static MainMenu mainMenu;
static WorldRenderer renderer; static WorldRenderer renderer;
static Connection connection; static Connection connection;
private static PlayerController playerMovement; private static PlayerController playerController;
public static void start(Connection serverConnection) { public static void start(Connection serverConnection) {
@ -44,7 +44,7 @@ public class MainWindow {
openGLWindow.init(); openGLWindow.init();
renderer = new WorldRenderer(); renderer = new WorldRenderer();
renderer.init(); renderer.init();
playerMovement = new PlayerController(openGLWindow.getWindow()); playerController = new PlayerController(openGLWindow.getWindow());
renderMode = MAIN_MENU; renderMode = MAIN_MENU;
mainMenu = new MainMenu(openGLWindow.getWidth(), openGLWindow.getHeight()); mainMenu = new MainMenu(openGLWindow.getWidth(), openGLWindow.getHeight());
mainLoop(); mainLoop();
@ -69,7 +69,7 @@ public class MainWindow {
break; break;
case PLAY: case PLAY:
OpenGLWindow.gluPerspective(FOVY, (float) WIDTH / (float) HEIGHT, 0.1f, 500f); OpenGLWindow.gluPerspective(FOVY, (float) WIDTH / (float) HEIGHT, 0.1f, 500f);
playerMovement.loop(deltaTime); playerController.loop(deltaTime);
renderer.draw(); renderer.draw();
break; break;
} }
@ -91,7 +91,7 @@ public class MainWindow {
renderMode = PLAY; renderMode = PLAY;
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glfwSetCursorPosCallback(openGLWindow.getWindow(), playerMovement.getCameraMovement()::mouseCallback); glfwSetCursorPosCallback(openGLWindow.getWindow(), playerController.getCameraMovement()::mouseCallback);
glfwSetInputMode(openGLWindow.getWindow(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(openGLWindow.getWindow(), GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
connection.connect(); connection.connect();
@ -111,7 +111,7 @@ public class MainWindow {
System.exit(1); System.exit(1);
} }
public static PlayerController getPlayerMovement() { public static PlayerController getPlayerController() {
return playerMovement; return playerController;
} }
} }

View File

@ -39,4 +39,8 @@ public class AdditionalMath {
} }
return (int) x - 1; return (int) x - 1;
} }
public static boolean isBetween(double x, double a, double b) {
return x <= a && x >= b || x >= a && x <= b;
}
} }

View File

@ -25,10 +25,10 @@ public class Vec3 {
x = y = z = 0; x = y = z = 0;
} }
public Vec3(float x_, float y_, float z_) { public Vec3(float x, float y, float z) {
x = x_; this.x = x;
y = y_; this.y = y;
z = z_; this.z = z;
} }
public Vec3(Location location) { public Vec3(Location location) {
@ -84,10 +84,11 @@ public class Vec3 {
z += v.z; z += v.z;
} }
public void add(float x_, float y_, float z_) { public Vec3 add(float x, float y, float z) {
x += x_; this.x += x;
y += y_; this.y += y;
z += z_; this.z += z;
return this;
} }
public float len() { public float len() {
@ -108,22 +109,4 @@ public class Vec3 {
public void zero() { public void zero() {
x = y = z = 0f; 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;
}
} }