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
* 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.
*

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
* 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) {

View File

@ -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);
}
}

View File

@ -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()) {

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}