capsule-block collision correction
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
9566bf2720
commit
cafc5f25c8
@ -388,9 +388,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"collidable" : {
|
"collidable" : {
|
||||||
"type" : "CYLINDER",
|
"type" : "CAPSULE",
|
||||||
"dimension1" : 0.35,
|
"dimension1" : 0.35,
|
||||||
"dimension2" : 1.6,
|
"dimension2" : 0.7,
|
||||||
"dimension3" : 0.35,
|
"dimension3" : 0.35,
|
||||||
"linearFriction": 0.001,
|
"linearFriction": 0.001,
|
||||||
"mass": 0.3,
|
"mass": 0.3,
|
||||||
@ -399,7 +399,7 @@
|
|||||||
"rotZ": 0,
|
"rotZ": 0,
|
||||||
"rotW": 1,
|
"rotW": 1,
|
||||||
"offsetX" : 0,
|
"offsetX" : 0,
|
||||||
"offsetY" : 0.8,
|
"offsetY" : 0.7,
|
||||||
"offsetZ" : 0,
|
"offsetZ" : 0,
|
||||||
"angularlyStatic" : true
|
"angularlyStatic" : true
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1838,6 +1838,9 @@ Fix virtual scrollable working with certain panels
|
|||||||
Humans use capsule shape now
|
Humans use capsule shape now
|
||||||
Physics numbers reworked
|
Physics numbers reworked
|
||||||
|
|
||||||
|
(05/16/2025)
|
||||||
|
Capsule-BlockChunk collision correction in collidable trees
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import org.joml.Vector3d;
|
|||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
import electrosphere.client.interact.select.AreaSelection;
|
import electrosphere.client.interact.select.AreaSelection;
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.data.block.BlockFab;
|
import electrosphere.data.block.BlockFab;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
|
|
||||||
@ -95,8 +96,8 @@ public class ClientBlockSelection {
|
|||||||
if(!startChunk.equals(endChunk)){
|
if(!startChunk.equals(endChunk)){
|
||||||
throw new Error("Unsupported case! Selected are coverts multiple chunks.. " + startChunk + " " + endChunk);
|
throw new Error("Unsupported case! Selected are coverts multiple chunks.. " + startChunk + " " + endChunk);
|
||||||
}
|
}
|
||||||
Vector3i blockStart = Globals.clientState.clientWorldData.convertRealToBlockSpace(selection.getRectStart());
|
Vector3i blockStart = ClientWorldData.convertRealToLocalBlockSpace(selection.getRectStart());
|
||||||
Vector3i blockEnd = Globals.clientState.clientWorldData.convertRealToBlockSpace(selection.getRectEnd());
|
Vector3i blockEnd = ClientWorldData.convertRealToLocalBlockSpace(selection.getRectEnd());
|
||||||
|
|
||||||
BlockChunkData chunk = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(startChunk, 0);
|
BlockChunkData chunk = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(startChunk, 0);
|
||||||
if(chunk == null){
|
if(chunk == null){
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import java.util.Set;
|
|||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.terrain.cache.ChunkData;
|
import electrosphere.client.terrain.cache.ChunkData;
|
||||||
import electrosphere.client.terrain.manager.ClientTerrainManager;
|
import electrosphere.client.terrain.manager.ClientTerrainManager;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
@ -322,14 +323,14 @@ public class FluidCellManager {
|
|||||||
for(int z = -(int)drawRadius; z < drawRadius; z = z + ChunkData.CHUNK_DATA_SIZE){
|
for(int z = -(int)drawRadius; z < drawRadius; z = z + ChunkData.CHUNK_DATA_SIZE){
|
||||||
Vector3d newPos = new Vector3d(playerPos.x + x, playerPos.y + y, playerPos.z + z);
|
Vector3d newPos = new Vector3d(playerPos.x + x, playerPos.y + y, playerPos.z + z);
|
||||||
Vector3i worldPos = new Vector3i(
|
Vector3i worldPos = new Vector3i(
|
||||||
Globals.clientState.clientWorldData.convertRealToChunkSpace(newPos.x),
|
ClientWorldData.convertRealToChunkSpace(newPos.x),
|
||||||
Globals.clientState.clientWorldData.convertRealToChunkSpace(newPos.y),
|
ClientWorldData.convertRealToChunkSpace(newPos.y),
|
||||||
Globals.clientState.clientWorldData.convertRealToChunkSpace(newPos.z)
|
ClientWorldData.convertRealToChunkSpace(newPos.z)
|
||||||
);
|
);
|
||||||
Vector3d chunkRealSpace = new Vector3d(
|
Vector3d chunkRealSpace = new Vector3d(
|
||||||
Globals.clientState.clientWorldData.convertChunkToRealSpace(worldPos.x),
|
ClientWorldData.convertChunkToRealSpace(worldPos.x),
|
||||||
Globals.clientState.clientWorldData.convertChunkToRealSpace(worldPos.y),
|
ClientWorldData.convertChunkToRealSpace(worldPos.y),
|
||||||
Globals.clientState.clientWorldData.convertChunkToRealSpace(worldPos.z)
|
ClientWorldData.convertChunkToRealSpace(worldPos.z)
|
||||||
);
|
);
|
||||||
if(
|
if(
|
||||||
playerPos.distance(chunkRealSpace) < drawRadius &&
|
playerPos.distance(chunkRealSpace) < drawRadius &&
|
||||||
|
|||||||
@ -113,9 +113,9 @@ public class ClientFluidManager {
|
|||||||
public boolean containsChunkDataAtRealPoint(double x, double y, double z){
|
public boolean containsChunkDataAtRealPoint(double x, double y, double z){
|
||||||
assert clientWorldData != null;
|
assert clientWorldData != null;
|
||||||
return fluidCache.containsChunkDataAtWorldPoint(
|
return fluidCache.containsChunkDataAtWorldPoint(
|
||||||
clientWorldData.convertRealToChunkSpace(x),
|
ClientWorldData.convertRealToChunkSpace(x),
|
||||||
clientWorldData.convertRealToChunkSpace(y),
|
ClientWorldData.convertRealToChunkSpace(y),
|
||||||
clientWorldData.convertRealToChunkSpace(z)
|
ClientWorldData.convertRealToChunkSpace(z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import org.ode4j.ode.DBody;
|
|||||||
|
|
||||||
import electrosphere.client.block.BlockChunkData;
|
import electrosphere.client.block.BlockChunkData;
|
||||||
import electrosphere.client.entity.camera.CameraEntityUtils;
|
import electrosphere.client.entity.camera.CameraEntityUtils;
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.terrain.cache.ChunkData;
|
import electrosphere.client.terrain.cache.ChunkData;
|
||||||
import electrosphere.client.ui.menu.ingame.InteractionTargetMenu;
|
import electrosphere.client.ui.menu.ingame.InteractionTargetMenu;
|
||||||
import electrosphere.collision.CollisionBodyCreation;
|
import electrosphere.collision.CollisionBodyCreation;
|
||||||
@ -279,7 +280,7 @@ public class ClientInteractionEngine {
|
|||||||
//grab block at point
|
//grab block at point
|
||||||
BlockChunkData blockChunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(Globals.clientState.clientWorldData.convertRealToWorldSpace(collisionPosition), 0);
|
BlockChunkData blockChunkData = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(Globals.clientState.clientWorldData.convertRealToWorldSpace(collisionPosition), 0);
|
||||||
if(blockChunkData != null){
|
if(blockChunkData != null){
|
||||||
Vector3i blockPos = Globals.clientState.clientWorldData.convertRealToBlockSpace(new Vector3d(collisionPosition).add(new Vector3d(eyePos).mul(-BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0f)));
|
Vector3i blockPos = ClientWorldData.convertRealToLocalBlockSpace(new Vector3d(collisionPosition).add(new Vector3d(eyePos).mul(-BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0f)));
|
||||||
if(!blockChunkData.isEmpty(blockPos.x, blockPos.y, blockPos.z)){
|
if(!blockChunkData.isEmpty(blockPos.x, blockPos.y, blockPos.z)){
|
||||||
short type = blockChunkData.getType(blockPos.x, blockPos.y, blockPos.z);
|
short type = blockChunkData.getType(blockPos.x, blockPos.y, blockPos.z);
|
||||||
String text = Globals.gameConfigCurrent.getBlockData().getTypeFromId(type).getName();
|
String text = Globals.gameConfigCurrent.getBlockData().getTypeFromId(type).getName();
|
||||||
@ -293,7 +294,7 @@ public class ClientInteractionEngine {
|
|||||||
if(!set){
|
if(!set){
|
||||||
ChunkData chunkData = Globals.clientState.clientTerrainManager.getChunkDataAtWorldPoint(Globals.clientState.clientWorldData.convertRealToWorldSpace(collisionPosition), 0);
|
ChunkData chunkData = Globals.clientState.clientTerrainManager.getChunkDataAtWorldPoint(Globals.clientState.clientWorldData.convertRealToWorldSpace(collisionPosition), 0);
|
||||||
if(chunkData != null){
|
if(chunkData != null){
|
||||||
int voxelType = chunkData.getType(Globals.clientState.clientWorldData.convertRealToVoxelSpace(new Vector3d(collisionPosition).add(new Vector3d(ServerTerrainChunk.VOXEL_SIZE / 2.0f))));
|
int voxelType = chunkData.getType(ClientWorldData.convertRealToVoxelSpace(new Vector3d(collisionPosition).add(new Vector3d(ServerTerrainChunk.VOXEL_SIZE / 2.0f))));
|
||||||
if(voxelType != ServerTerrainChunk.VOXEL_TYPE_AIR){
|
if(voxelType != ServerTerrainChunk.VOXEL_TYPE_AIR){
|
||||||
String text = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(voxelType).getName();
|
String text = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(voxelType).getName();
|
||||||
InteractionTargetMenu.setInteractionTargetString(text);
|
InteractionTargetMenu.setInteractionTargetString(text);
|
||||||
|
|||||||
@ -64,11 +64,19 @@ public class ClientWorldData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int convertRealToChunkSpace(double real){
|
public static int convertRealToChunkSpace(double real){
|
||||||
return (int)Math.floor(real / ServerTerrainChunk.CHUNK_DIMENSION);
|
return (int)Math.floor(real / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float convertChunkToRealSpace(int chunk){
|
public static Vector3i convertRealToChunkSpace(Vector3d real){
|
||||||
|
return new Vector3i(
|
||||||
|
ClientWorldData.convertRealToChunkSpace(real.x),
|
||||||
|
ClientWorldData.convertRealToChunkSpace(real.y),
|
||||||
|
ClientWorldData.convertRealToChunkSpace(real.z)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float convertChunkToRealSpace(int chunk){
|
||||||
return chunk * ServerTerrainChunk.CHUNK_DIMENSION;
|
return chunk * ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,11 +193,11 @@ public class ClientWorldData {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3i convertRealToVoxelSpace(Vector3d position){
|
public static Vector3i convertRealToVoxelSpace(Vector3d position){
|
||||||
return new Vector3i(
|
return new Vector3i(
|
||||||
(int)Math.floor(position.x - this.convertChunkToRealSpace(this.convertRealToChunkSpace(position.x))),
|
(int)Math.floor(position.x - ClientWorldData.convertChunkToRealSpace(ClientWorldData.convertRealToChunkSpace(position.x))),
|
||||||
(int)Math.floor(position.y - this.convertChunkToRealSpace(this.convertRealToChunkSpace(position.y))),
|
(int)Math.floor(position.y - ClientWorldData.convertChunkToRealSpace(ClientWorldData.convertRealToChunkSpace(position.y))),
|
||||||
(int)Math.floor(position.z - this.convertChunkToRealSpace(this.convertRealToChunkSpace(position.z)))
|
(int)Math.floor(position.z - ClientWorldData.convertChunkToRealSpace(ClientWorldData.convertRealToChunkSpace(position.z)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +206,7 @@ public class ClientWorldData {
|
|||||||
* @param real The real position
|
* @param real The real position
|
||||||
* @return The closest block position
|
* @return The closest block position
|
||||||
*/
|
*/
|
||||||
public int convertRealToLocalBlockSpace(double real){
|
public static int convertRealToLocalBlockSpace(double real){
|
||||||
return (int)Math.floor(real * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE % BlockChunkData.CHUNK_DATA_WIDTH);
|
return (int)Math.floor(real * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE % BlockChunkData.CHUNK_DATA_WIDTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,11 +215,11 @@ public class ClientWorldData {
|
|||||||
* @param position The real-space position
|
* @param position The real-space position
|
||||||
* @return The nearest block-space position
|
* @return The nearest block-space position
|
||||||
*/
|
*/
|
||||||
public Vector3i convertRealToBlockSpace(Vector3d position){
|
public static Vector3i convertRealToLocalBlockSpace(Vector3d position){
|
||||||
return new Vector3i(
|
return new Vector3i(
|
||||||
this.convertRealToLocalBlockSpace(position.x),
|
ClientWorldData.convertRealToLocalBlockSpace(position.x),
|
||||||
this.convertRealToLocalBlockSpace(position.y),
|
ClientWorldData.convertRealToLocalBlockSpace(position.y),
|
||||||
this.convertRealToLocalBlockSpace(position.z)
|
ClientWorldData.convertRealToLocalBlockSpace(position.z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,4 +257,17 @@ public class ClientWorldData {
|
|||||||
chunkPos.x < this.worldDiscreteSize && chunkPos.y < this.worldDiscreteSize && chunkPos.z < this.worldDiscreteSize;
|
chunkPos.x < this.worldDiscreteSize && chunkPos.y < this.worldDiscreteSize && chunkPos.z < this.worldDiscreteSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clamps a real space position to the closest block space position
|
||||||
|
* @param realPos The real space position
|
||||||
|
* @return The real space position that is clamped to the closest block space position
|
||||||
|
*/
|
||||||
|
public static Vector3d clampRealToBlock(Vector3d realPos){
|
||||||
|
return new Vector3d(
|
||||||
|
realPos.x - realPos.x % BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
realPos.y - realPos.y % BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
realPos.z - realPos.z % BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import org.joml.Vector3d;
|
|||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
import electrosphere.client.interact.select.AreaSelection;
|
import electrosphere.client.interact.select.AreaSelection;
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.controls.cursor.CursorState;
|
import electrosphere.controls.cursor.CursorState;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
@ -22,7 +23,7 @@ public class ScriptClientAreaUtils {
|
|||||||
// Vector3d blockCursorPos = Globals.cursorState.getBlockCursorPos();
|
// Vector3d blockCursorPos = Globals.cursorState.getBlockCursorPos();
|
||||||
Vector3d cursorPos = new Vector3d(EntityUtils.getPosition(Globals.cursorState.playerCursor));
|
Vector3d cursorPos = new Vector3d(EntityUtils.getPosition(Globals.cursorState.playerCursor));
|
||||||
Vector3i chunkPos = Globals.clientState.clientWorldData.convertRealToWorldSpace(cursorPos);
|
Vector3i chunkPos = Globals.clientState.clientWorldData.convertRealToWorldSpace(cursorPos);
|
||||||
Vector3i blockPos = Globals.clientState.clientWorldData.convertRealToBlockSpace(cursorPos);
|
Vector3i blockPos = ClientWorldData.convertRealToLocalBlockSpace(cursorPos);
|
||||||
AreaSelection selection = AreaSelection.selectRectangularBlockCavity(chunkPos, blockPos, AreaSelection.DEFAULT_SELECTION_RADIUS);
|
AreaSelection selection = AreaSelection.selectRectangularBlockCavity(chunkPos, blockPos, AreaSelection.DEFAULT_SELECTION_RADIUS);
|
||||||
Globals.cursorState.selectRectangularArea(selection);
|
Globals.cursorState.selectRectangularArea(selection);
|
||||||
CursorState.makeAreaVisible();
|
CursorState.makeAreaVisible();
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import org.joml.Vector3i;
|
|||||||
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
|
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
|
||||||
import electrosphere.audio.movement.MovementAudioService.InteractionType;
|
import electrosphere.audio.movement.MovementAudioService.InteractionType;
|
||||||
import electrosphere.client.entity.camera.CameraEntityUtils;
|
import electrosphere.client.entity.camera.CameraEntityUtils;
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.terrain.editing.TerrainEditing;
|
import electrosphere.client.terrain.editing.TerrainEditing;
|
||||||
import electrosphere.collision.CollisionEngine;
|
import electrosphere.collision.CollisionEngine;
|
||||||
import electrosphere.controls.cursor.CursorState;
|
import electrosphere.controls.cursor.CursorState;
|
||||||
@ -145,7 +146,7 @@ public class ScriptClientVoxelUtils {
|
|||||||
String fabPath = Globals.cursorState.getSelectedFabPath();
|
String fabPath = Globals.cursorState.getSelectedFabPath();
|
||||||
Vector3d fabCursorPos = EntityUtils.getPosition(CursorState.getFabCursor());
|
Vector3d fabCursorPos = EntityUtils.getPosition(CursorState.getFabCursor());
|
||||||
Vector3i chunkPos = Globals.clientState.clientWorldData.convertRealToWorldSpace(fabCursorPos);
|
Vector3i chunkPos = Globals.clientState.clientWorldData.convertRealToWorldSpace(fabCursorPos);
|
||||||
Vector3i voxelPos = Globals.clientState.clientWorldData.convertRealToBlockSpace(fabCursorPos);
|
Vector3i voxelPos = ClientWorldData.convertRealToLocalBlockSpace(fabCursorPos);
|
||||||
int rotation = Globals.cursorState.getFabCursorRotation();
|
int rotation = Globals.cursorState.getFabCursorRotation();
|
||||||
Globals.clientState.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestPlaceFabMessage(
|
Globals.clientState.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestPlaceFabMessage(
|
||||||
chunkPos.x, chunkPos.y, chunkPos.z,
|
chunkPos.x, chunkPos.y, chunkPos.z,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package electrosphere.client.terrain.editing;
|
|||||||
|
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.script.ScriptClientVoxelUtils;
|
import electrosphere.client.script.ScriptClientVoxelUtils;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ public class BlockEditing {
|
|||||||
* @param metadata The metadata of the block
|
* @param metadata The metadata of the block
|
||||||
*/
|
*/
|
||||||
public static void editBlock(short type, short metadata){
|
public static void editBlock(short type, short metadata){
|
||||||
Vector3i cornerVoxel = Globals.clientState.clientWorldData.convertRealToBlockSpace(Globals.cursorState.getBlockCursorPos());
|
Vector3i cornerVoxel = ClientWorldData.convertRealToLocalBlockSpace(Globals.cursorState.getBlockCursorPos());
|
||||||
int blockSize = Globals.cursorState.getBlockSize();
|
int blockSize = Globals.cursorState.getBlockSize();
|
||||||
Vector3i chunkPos = Globals.clientState.clientWorldData.convertRealToWorldSpace(Globals.cursorState.getBlockCursorPos());
|
Vector3i chunkPos = Globals.clientState.clientWorldData.convertRealToWorldSpace(Globals.cursorState.getBlockCursorPos());
|
||||||
ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, type, metadata, blockSize);
|
ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, type, metadata, blockSize);
|
||||||
@ -26,7 +27,7 @@ public class BlockEditing {
|
|||||||
* Destroy blocks
|
* Destroy blocks
|
||||||
*/
|
*/
|
||||||
public static void destroyBlock(){
|
public static void destroyBlock(){
|
||||||
Vector3i cornerVoxel = Globals.clientState.clientWorldData.convertRealToBlockSpace(Globals.cursorState.getBlockCursorPos());
|
Vector3i cornerVoxel = ClientWorldData.convertRealToLocalBlockSpace(Globals.cursorState.getBlockCursorPos());
|
||||||
int blockSize = Globals.cursorState.getBlockSize();
|
int blockSize = Globals.cursorState.getBlockSize();
|
||||||
Vector3i chunkPos = Globals.clientState.clientWorldData.convertRealToWorldSpace(Globals.cursorState.getBlockCursorPos());
|
Vector3i chunkPos = Globals.clientState.clientWorldData.convertRealToWorldSpace(Globals.cursorState.getBlockCursorPos());
|
||||||
ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, (short)0, (short)0, blockSize);
|
ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, (short)0, (short)0, blockSize);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package electrosphere.client.terrain.sampling;
|
|||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.terrain.cache.ChunkData;
|
import electrosphere.client.terrain.cache.ChunkData;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
@ -36,7 +37,7 @@ public class ClientVoxelSampler {
|
|||||||
public static int getVoxelType(Vector3d realPos){
|
public static int getVoxelType(Vector3d realPos){
|
||||||
int voxelId = 0;
|
int voxelId = 0;
|
||||||
Vector3i chunkSpacePos = Globals.clientState.clientWorldData.convertRealToWorldSpace(realPos);
|
Vector3i chunkSpacePos = Globals.clientState.clientWorldData.convertRealToWorldSpace(realPos);
|
||||||
Vector3i voxelSpacePos = Globals.clientState.clientWorldData.convertRealToVoxelSpace(realPos);
|
Vector3i voxelSpacePos = ClientWorldData.convertRealToVoxelSpace(realPos);
|
||||||
if(Globals.clientState.clientTerrainManager.containsChunkDataAtWorldPoint(chunkSpacePos, ChunkData.NO_STRIDE)){
|
if(Globals.clientState.clientTerrainManager.containsChunkDataAtWorldPoint(chunkSpacePos, ChunkData.NO_STRIDE)){
|
||||||
ChunkData chunkData = Globals.clientState.clientTerrainManager.getChunkDataAtWorldPoint(chunkSpacePos, ChunkData.NO_STRIDE);
|
ChunkData chunkData = Globals.clientState.clientTerrainManager.getChunkDataAtWorldPoint(chunkSpacePos, ChunkData.NO_STRIDE);
|
||||||
voxelId = chunkData.getType(voxelSpacePos);
|
voxelId = chunkData.getType(voxelSpacePos);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package electrosphere.collision;
|
package electrosphere.collision;
|
||||||
|
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.terrain.manager.ClientTerrainManager;
|
import electrosphere.client.terrain.manager.ClientTerrainManager;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.server.datacell.ServerWorldData;
|
import electrosphere.server.datacell.ServerWorldData;
|
||||||
@ -45,7 +46,7 @@ public class CollisionWorldData {
|
|||||||
|
|
||||||
public int convertRealToWorld(double real){
|
public int convertRealToWorld(double real){
|
||||||
if(Globals.clientState.clientWorldData != null){
|
if(Globals.clientState.clientWorldData != null){
|
||||||
return Globals.clientState.clientWorldData.convertRealToChunkSpace(real);
|
return ClientWorldData.convertRealToChunkSpace(real);
|
||||||
} else {
|
} else {
|
||||||
return ServerWorldData.convertRealToChunkSpace(real);
|
return ServerWorldData.convertRealToChunkSpace(real);
|
||||||
}
|
}
|
||||||
@ -53,7 +54,7 @@ public class CollisionWorldData {
|
|||||||
|
|
||||||
public double convertWorldToReal(int world){
|
public double convertWorldToReal(int world){
|
||||||
if(Globals.clientState.clientWorldData != null){
|
if(Globals.clientState.clientWorldData != null){
|
||||||
return Globals.clientState.clientWorldData.convertChunkToRealSpace(world);
|
return ClientWorldData.convertChunkToRealSpace(world);
|
||||||
} else {
|
} else {
|
||||||
return ServerWorldData.convertChunkToRealSpace(world);
|
return ServerWorldData.convertChunkToRealSpace(world);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,54 @@
|
|||||||
|
package electrosphere.collision.physics;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result of a collision
|
||||||
|
*/
|
||||||
|
public class CollisionResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The penetration of two bodies
|
||||||
|
*/
|
||||||
|
double penetration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The normal of the collision
|
||||||
|
*/
|
||||||
|
Vector3d normal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the penetration of the collision result
|
||||||
|
* @return The penetration
|
||||||
|
*/
|
||||||
|
public double getPenetration() {
|
||||||
|
return penetration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the penetration of the collision result
|
||||||
|
* @param penetration The penetration
|
||||||
|
*/
|
||||||
|
public void setPenetration(double penetration) {
|
||||||
|
this.penetration = penetration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the normal of the collision result
|
||||||
|
* @return The normal
|
||||||
|
*/
|
||||||
|
public Vector3d getNormal() {
|
||||||
|
return normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the normal of the collision result
|
||||||
|
* @param normal The normal
|
||||||
|
*/
|
||||||
|
public void setNormal(Vector3d normal) {
|
||||||
|
this.normal = normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,16 +1,24 @@
|
|||||||
package electrosphere.entity.state.collidable;
|
package electrosphere.entity.state.collidable;
|
||||||
|
|
||||||
|
import org.joml.AABBd;
|
||||||
import org.joml.Quaterniond;
|
import org.joml.Quaterniond;
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3i;
|
||||||
import org.ode4j.ode.DBody;
|
import org.ode4j.ode.DBody;
|
||||||
|
import org.ode4j.ode.DCapsule;
|
||||||
|
|
||||||
|
import electrosphere.client.block.BlockChunkData;
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.collision.PhysicsUtils;
|
import electrosphere.collision.PhysicsUtils;
|
||||||
import electrosphere.collision.collidable.Collidable;
|
import electrosphere.collision.collidable.Collidable;
|
||||||
|
import electrosphere.collision.physics.CollisionResult;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
import electrosphere.entity.EntityDataStrings;
|
import electrosphere.entity.EntityDataStrings;
|
||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
import electrosphere.entity.btree.BehaviorTree;
|
import electrosphere.entity.btree.BehaviorTree;
|
||||||
|
import electrosphere.entity.types.collision.CollisionObjUtils;
|
||||||
|
import electrosphere.util.math.CollisionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client collidable tree
|
* Client collidable tree
|
||||||
@ -65,6 +73,91 @@ public class ClientCollidableTree implements BehaviorTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PhysicsUtils.setRigidBodyTransform(Globals.clientState.clientSceneWrapper.getCollisionEngine(), newPosition, rotation, body);
|
PhysicsUtils.setRigidBodyTransform(Globals.clientState.clientSceneWrapper.getCollisionEngine(), newPosition, rotation, body);
|
||||||
|
|
||||||
|
//capsule-specific block collision logic
|
||||||
|
if(body.isEnabled() && body.getFirstGeom() != null && (body.getFirstGeom() instanceof DCapsule)){
|
||||||
|
//get capsule params
|
||||||
|
DCapsule capsuleGeom = (DCapsule)body.getFirstGeom();
|
||||||
|
double length = capsuleGeom.getLength();
|
||||||
|
double halfLength = length / 2.0;
|
||||||
|
double radius = capsuleGeom.getRadius();
|
||||||
|
Vector3d bodyOffset = PhysicsUtils.odeVecToJomlVec(body.getFirstGeom().getOffsetPosition());
|
||||||
|
|
||||||
|
//entity spatial transforms
|
||||||
|
Vector3d entRealPos = EntityUtils.getPosition(parent);
|
||||||
|
Quaterniond entRot = EntityUtils.getRotation(parent);
|
||||||
|
|
||||||
|
//start and end of capsule
|
||||||
|
Vector3d realStart = new Vector3d(0,-halfLength,0).rotate(entRot).add(entRealPos).add(bodyOffset);
|
||||||
|
Vector3d realEnd = new Vector3d(0,halfLength,0).rotate(entRot).add(entRealPos).add(bodyOffset);
|
||||||
|
|
||||||
|
|
||||||
|
//block position of body
|
||||||
|
Vector3d blockPos = ClientWorldData.clampRealToBlock(entRealPos);
|
||||||
|
Vector3d currBlockPos = new Vector3d();
|
||||||
|
|
||||||
|
//get dims to scan along (ceil to overcompensate -- better to over scan than underscan)
|
||||||
|
int halfRadBlockLen = (int)Math.ceil(halfLength / BlockChunkData.BLOCK_SIZE_MULTIPLIER);
|
||||||
|
int radBlockLen = (int)Math.ceil(radius / BlockChunkData.BLOCK_SIZE_MULTIPLIER);
|
||||||
|
|
||||||
|
//final corrected position
|
||||||
|
Vector3d corrected = new Vector3d(entRealPos);
|
||||||
|
|
||||||
|
//scan for all potential blocks
|
||||||
|
for(int x = -radBlockLen; x <= radBlockLen; x++){
|
||||||
|
for(int z = -radBlockLen; z <= radBlockLen; z++){
|
||||||
|
for(int y = -halfRadBlockLen; y <= halfRadBlockLen; y++){
|
||||||
|
currBlockPos.set(blockPos).add(
|
||||||
|
x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||||
|
);
|
||||||
|
Vector3i chunkPos = ClientWorldData.convertRealToChunkSpace(currBlockPos);
|
||||||
|
Vector3i entBlockPos = ClientWorldData.convertRealToLocalBlockSpace(currBlockPos);
|
||||||
|
|
||||||
|
//error check bounds
|
||||||
|
if(chunkPos.x < 0 || chunkPos.y < 0 || chunkPos.z < 0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get block data for block to check
|
||||||
|
BlockChunkData data = Globals.clientState.clientBlockManager.getChunkDataAtWorldPoint(chunkPos, BlockChunkData.LOD_FULL_RES);
|
||||||
|
if(data != null){
|
||||||
|
//check type of voxel to skip math
|
||||||
|
short type = data.getType(entBlockPos.x, entBlockPos.y, entBlockPos.z);
|
||||||
|
if(type != BlockChunkData.BLOCK_TYPE_EMPTY){
|
||||||
|
|
||||||
|
//AABB for the voxel
|
||||||
|
AABBd voxelBox = new AABBd(
|
||||||
|
currBlockPos.x,
|
||||||
|
currBlockPos.y,
|
||||||
|
currBlockPos.z,
|
||||||
|
currBlockPos.x + BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
currBlockPos.y + BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
currBlockPos.z + BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||||
|
);
|
||||||
|
|
||||||
|
//actually collision check
|
||||||
|
CollisionResult collisionResult = CollisionUtils.collideCapsuleAABB(realStart, realEnd, radius, voxelBox);
|
||||||
|
if(collisionResult != null){
|
||||||
|
double pen = collisionResult.getPenetration();
|
||||||
|
double forceMul = pen * 0.3;
|
||||||
|
Vector3d normal = collisionResult.getNormal().mul(forceMul);
|
||||||
|
if(normal != null){
|
||||||
|
// body.addForce(normal.x, normal.y, normal.z);
|
||||||
|
//correct the position of the capsule
|
||||||
|
corrected.add(normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//apply correction
|
||||||
|
CollisionObjUtils.clientPositionCharacter(parent, newPosition, entRot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,40 +1,66 @@
|
|||||||
package electrosphere.entity.state.collidable;
|
package electrosphere.entity.state.collidable;
|
||||||
|
|
||||||
|
import electrosphere.client.block.BlockChunkData;
|
||||||
|
import electrosphere.collision.PhysicsUtils;
|
||||||
import electrosphere.collision.collidable.Collidable;
|
import electrosphere.collision.collidable.Collidable;
|
||||||
|
import electrosphere.collision.physics.CollisionResult;
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
import electrosphere.entity.EntityDataStrings;
|
import electrosphere.entity.EntityDataStrings;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
import electrosphere.entity.btree.BehaviorTree;
|
import electrosphere.entity.btree.BehaviorTree;
|
||||||
import electrosphere.entity.state.gravity.ServerGravityTree;
|
import electrosphere.entity.state.gravity.ServerGravityTree;
|
||||||
import electrosphere.entity.state.movement.fall.ServerFallTree;
|
import electrosphere.entity.state.movement.fall.ServerFallTree;
|
||||||
|
import electrosphere.entity.types.collision.CollisionObjUtils;
|
||||||
|
import electrosphere.server.datacell.Realm;
|
||||||
|
import electrosphere.server.datacell.ServerWorldData;
|
||||||
|
import electrosphere.server.datacell.interfaces.VoxelCellManager;
|
||||||
|
import electrosphere.util.math.CollisionUtils;
|
||||||
|
|
||||||
|
import org.joml.AABBd;
|
||||||
|
import org.joml.Quaterniond;
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3i;
|
||||||
import org.ode4j.ode.DBody;
|
import org.ode4j.ode.DBody;
|
||||||
|
import org.ode4j.ode.DCapsule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server collidable tree
|
* Server collidable tree
|
||||||
*/
|
*/
|
||||||
public class ServerCollidableTree implements BehaviorTree {
|
public class ServerCollidableTree implements BehaviorTree {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent of the collidable
|
||||||
|
*/
|
||||||
Entity parent;
|
Entity parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The body
|
||||||
|
*/
|
||||||
DBody body;
|
DBody body;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collidable
|
||||||
|
*/
|
||||||
Collidable collidable;
|
Collidable collidable;
|
||||||
boolean applyImpulses = true;
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param e The entity
|
||||||
|
* @param collidable The collidable
|
||||||
|
* @param body The body
|
||||||
|
*/
|
||||||
public ServerCollidableTree(Entity e, Collidable collidable, DBody body){
|
public ServerCollidableTree(Entity e, Collidable collidable, DBody body){
|
||||||
parent = e;
|
parent = e;
|
||||||
this.collidable = collidable;
|
this.collidable = collidable;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerCollidableTree(Entity e, Collidable collidable, DBody body, boolean applyImpulses){
|
/**
|
||||||
parent = e;
|
* Simulates the collidable tree
|
||||||
this.collidable = collidable;
|
* @param deltaTime The amount of time to simulate by
|
||||||
this.body = body;
|
*/
|
||||||
this.applyImpulses = applyImpulses;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int incrementer = 0;
|
|
||||||
|
|
||||||
public void simulate(float deltaTime){
|
public void simulate(float deltaTime){
|
||||||
//have we hit a terrain impulse?
|
//have we hit a terrain impulse?
|
||||||
//handle impulses
|
//handle impulses
|
||||||
@ -48,6 +74,94 @@ public class ServerCollidableTree implements BehaviorTree {
|
|||||||
this.resetGravityFall();
|
this.resetGravityFall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//capsule-specific block collision logic
|
||||||
|
if(body.isEnabled() && body.getFirstGeom() != null && (body.getFirstGeom() instanceof DCapsule)){
|
||||||
|
Realm realm = Globals.serverState.realmManager.getEntityRealm(parent);
|
||||||
|
if(realm.getDataCellManager() instanceof VoxelCellManager){
|
||||||
|
VoxelCellManager voxelCellManager = (VoxelCellManager)realm.getDataCellManager();
|
||||||
|
|
||||||
|
//get capsule params
|
||||||
|
DCapsule capsuleGeom = (DCapsule)body.getFirstGeom();
|
||||||
|
double length = capsuleGeom.getLength();
|
||||||
|
double halfLength = length / 2.0;
|
||||||
|
double radius = capsuleGeom.getRadius();
|
||||||
|
Vector3d bodyOffset = PhysicsUtils.odeVecToJomlVec(body.getFirstGeom().getOffsetPosition());
|
||||||
|
|
||||||
|
//entity spatial transforms
|
||||||
|
Vector3d entRealPos = EntityUtils.getPosition(parent);
|
||||||
|
Quaterniond entRot = EntityUtils.getRotation(parent);
|
||||||
|
|
||||||
|
//start and end of capsule
|
||||||
|
Vector3d realStart = new Vector3d(0,-halfLength,0).rotate(entRot).add(entRealPos).add(bodyOffset);
|
||||||
|
Vector3d realEnd = new Vector3d(0,halfLength,0).rotate(entRot).add(entRealPos).add(bodyOffset);
|
||||||
|
|
||||||
|
|
||||||
|
//block position of body
|
||||||
|
Vector3d blockPos = ServerWorldData.clampRealToBlock(entRealPos);
|
||||||
|
Vector3d currBlockPos = new Vector3d();
|
||||||
|
|
||||||
|
//get dims to scan along (ceil to overcompensate -- better to over scan than underscan)
|
||||||
|
int halfRadBlockLen = (int)Math.ceil(halfLength / BlockChunkData.BLOCK_SIZE_MULTIPLIER);
|
||||||
|
int radBlockLen = (int)Math.ceil(radius / BlockChunkData.BLOCK_SIZE_MULTIPLIER);
|
||||||
|
|
||||||
|
//final corrected position
|
||||||
|
Vector3d corrected = new Vector3d(entRealPos);
|
||||||
|
|
||||||
|
//scan for all potential blocks
|
||||||
|
for(int x = -radBlockLen; x <= radBlockLen; x++){
|
||||||
|
for(int z = -radBlockLen; z <= radBlockLen; z++){
|
||||||
|
for(int y = -halfRadBlockLen; y <= halfRadBlockLen; y++){
|
||||||
|
currBlockPos.set(blockPos).add(
|
||||||
|
x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||||
|
);
|
||||||
|
Vector3i chunkPos = ServerWorldData.convertRealToChunkSpace(currBlockPos);
|
||||||
|
Vector3i entBlockPos = ServerWorldData.convertRealToLocalBlockSpace(currBlockPos);
|
||||||
|
|
||||||
|
//error check bounds
|
||||||
|
if(chunkPos.x < 0 || chunkPos.y < 0 || chunkPos.z < 0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get block data for block to check
|
||||||
|
BlockChunkData data = voxelCellManager.getBlocksAtPosition(chunkPos);
|
||||||
|
short type = data.getType(entBlockPos.x, entBlockPos.y, entBlockPos.z);
|
||||||
|
|
||||||
|
if(type != BlockChunkData.BLOCK_TYPE_EMPTY){
|
||||||
|
|
||||||
|
//AABB for the voxel
|
||||||
|
AABBd voxelBox = new AABBd(
|
||||||
|
currBlockPos.x,
|
||||||
|
currBlockPos.y,
|
||||||
|
currBlockPos.z,
|
||||||
|
currBlockPos.x + BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
currBlockPos.y + BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
currBlockPos.z + BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||||
|
);
|
||||||
|
|
||||||
|
//actually collision check
|
||||||
|
CollisionResult collisionResult = CollisionUtils.collideCapsuleAABB(realStart, realEnd, radius, voxelBox);
|
||||||
|
if(collisionResult != null){
|
||||||
|
double pen = collisionResult.getPenetration();
|
||||||
|
double forceMul = pen * 0.3;
|
||||||
|
Vector3d normal = collisionResult.getNormal().mul(forceMul);
|
||||||
|
if(normal != null){
|
||||||
|
// body.addForce(normal.x, normal.y, normal.z);
|
||||||
|
//correct the position of the capsule
|
||||||
|
corrected.add(normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//apply correction
|
||||||
|
CollisionObjUtils.serverPositionCharacter(parent, corrected);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -61,10 +175,20 @@ public class ServerCollidableTree implements BehaviorTree {
|
|||||||
this.collidable = collidable;
|
this.collidable = collidable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the entity has a server collidable tree
|
||||||
|
* @param e The entity
|
||||||
|
* @return true if it has a collidable tree, false otherwise
|
||||||
|
*/
|
||||||
public static boolean hasServerCollidableTree(Entity e){
|
public static boolean hasServerCollidableTree(Entity e){
|
||||||
return e.containsKey(EntityDataStrings.SERVER_COLLIDABLE_TREE);
|
return e.containsKey(EntityDataStrings.SERVER_COLLIDABLE_TREE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the server collidable tree on an entity
|
||||||
|
* @param e The entity
|
||||||
|
* @return The tree if it exists, false otherwise
|
||||||
|
*/
|
||||||
public static ServerCollidableTree getServerCollidableTree(Entity e){
|
public static ServerCollidableTree getServerCollidableTree(Entity e){
|
||||||
return (ServerCollidableTree)e.getData(EntityDataStrings.SERVER_COLLIDABLE_TREE);
|
return (ServerCollidableTree)e.getData(EntityDataStrings.SERVER_COLLIDABLE_TREE);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -423,7 +423,7 @@ public class ServerWorldData {
|
|||||||
* @param realPos The real space position
|
* @param realPos The real space position
|
||||||
* @return The real space position that is clamped to the closest block space position
|
* @return The real space position that is clamped to the closest block space position
|
||||||
*/
|
*/
|
||||||
public Vector3d clampRealToBlock(Vector3d realPos){
|
public static Vector3d clampRealToBlock(Vector3d realPos){
|
||||||
return new Vector3d(
|
return new Vector3d(
|
||||||
realPos.x - realPos.x % BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
realPos.x - realPos.x % BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
realPos.y - realPos.y % BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
realPos.y - realPos.y % BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||||
|
|||||||
136
src/main/java/electrosphere/util/math/CollisionUtils.java
Normal file
136
src/main/java/electrosphere/util/math/CollisionUtils.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package electrosphere.util.math;
|
||||||
|
|
||||||
|
import org.joml.AABBd;
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
import electrosphere.collision.physics.CollisionResult;
|
||||||
|
import io.github.studiorailgun.MathUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for performing collisions of geometry
|
||||||
|
*/
|
||||||
|
public class CollisionUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a capsule intersects an AABB
|
||||||
|
* @param capsuleStart The start of the capsule
|
||||||
|
* @param capsuleEnd The end of the capsule
|
||||||
|
* @param radius The radius of the capsule
|
||||||
|
* @param box The box
|
||||||
|
* @return true if they intersect, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean capsuleIntersectsAABB(Vector3d start, Vector3d end, double radius, AABBd box){
|
||||||
|
// Step 1: Find closest point on capsule segment to the AABB
|
||||||
|
// Approximate by projecting the center of the AABB onto the segment
|
||||||
|
double boxCenterX = (box.minX + box.maxX) * 0.5;
|
||||||
|
double boxCenterY = (box.minY + box.maxY) * 0.5;
|
||||||
|
double boxCenterZ = (box.minZ + box.maxZ) * 0.5;
|
||||||
|
|
||||||
|
double abX = end.x - start.x;
|
||||||
|
double abY = end.y - start.y;
|
||||||
|
double abZ = end.z - start.z;
|
||||||
|
|
||||||
|
double lenSquared = (boxCenterX - abX) * (boxCenterX - abX) + (boxCenterY - abY) * (boxCenterY - abY) + (boxCenterZ - abZ) * (boxCenterZ - abZ);
|
||||||
|
|
||||||
|
double t = MathUtils.dot(
|
||||||
|
boxCenterX - start.x,
|
||||||
|
boxCenterY - start.y,
|
||||||
|
boxCenterZ - start.z,
|
||||||
|
abX,
|
||||||
|
abY,
|
||||||
|
abZ
|
||||||
|
) / lenSquared;
|
||||||
|
t = Math.max(0f, Math.min(1f, t)); // clamp to [0,1]
|
||||||
|
|
||||||
|
double segClosesX = start.x + (abX * t);
|
||||||
|
double segClosesY = start.y + (abY * t);
|
||||||
|
double segClosesZ = start.z + (abZ * t);
|
||||||
|
|
||||||
|
// Step 2: Find closest point on AABB to that segment point
|
||||||
|
double boxClosestX = MathUtils.clamp(segClosesX, box.minX, box.maxX);
|
||||||
|
double boxClosestY = MathUtils.clamp(segClosesY, box.minY, box.maxY);
|
||||||
|
double boxClosestZ = MathUtils.clamp(segClosesZ, box.minZ, box.maxZ);
|
||||||
|
|
||||||
|
// Step 3: Compute distance squared
|
||||||
|
double diffX = segClosesX - boxClosestX;
|
||||||
|
double diffY = segClosesY - boxClosestY;
|
||||||
|
double diffZ = segClosesZ - boxClosestZ;
|
||||||
|
|
||||||
|
double distSq = (diffX * diffX) + (diffY * diffY) + (diffZ * diffZ);
|
||||||
|
|
||||||
|
return distSq <= radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a capsule intersects an AABB
|
||||||
|
* @param capsuleStart The start of the capsule
|
||||||
|
* @param capsuleEnd The end of the capsule
|
||||||
|
* @param radius The radius of the capsule
|
||||||
|
* @param box The box
|
||||||
|
* @return true if they intersect, false otherwise
|
||||||
|
*/
|
||||||
|
public static CollisionResult collideCapsuleAABB(Vector3d start, Vector3d end, double radius, AABBd box){
|
||||||
|
CollisionResult rVal = new CollisionResult();
|
||||||
|
// Step 1: Find closest point on capsule segment to the AABB
|
||||||
|
// Approximate by projecting the center of the AABB onto the segment
|
||||||
|
double boxCenterX = (box.minX + box.maxX) * 0.5;
|
||||||
|
double boxCenterY = (box.minY + box.maxY) * 0.5;
|
||||||
|
double boxCenterZ = (box.minZ + box.maxZ) * 0.5;
|
||||||
|
|
||||||
|
double abX = end.x - start.x;
|
||||||
|
double abY = end.y - start.y;
|
||||||
|
double abZ = end.z - start.z;
|
||||||
|
|
||||||
|
double lenSquared = (boxCenterX - abX) * (boxCenterX - abX) + (boxCenterY - abY) * (boxCenterY - abY) + (boxCenterZ - abZ) * (boxCenterZ - abZ);
|
||||||
|
|
||||||
|
double t = MathUtils.dot(
|
||||||
|
boxCenterX - start.x,
|
||||||
|
boxCenterY - start.y,
|
||||||
|
boxCenterZ - start.z,
|
||||||
|
abX,
|
||||||
|
abY,
|
||||||
|
abZ
|
||||||
|
) / lenSquared;
|
||||||
|
t = Math.max(0f, Math.min(1f, t)); // clamp to [0,1]
|
||||||
|
|
||||||
|
double segClosesX = start.x + (abX * t);
|
||||||
|
double segClosesY = start.y + (abY * t);
|
||||||
|
double segClosesZ = start.z + (abZ * t);
|
||||||
|
|
||||||
|
// Step 2: Find closest point on AABB to that segment point
|
||||||
|
double boxClosestX = MathUtils.clamp(segClosesX, box.minX, box.maxX);
|
||||||
|
double boxClosestY = MathUtils.clamp(segClosesY, box.minY, box.maxY);
|
||||||
|
double boxClosestZ = MathUtils.clamp(segClosesZ, box.minZ, box.maxZ);
|
||||||
|
|
||||||
|
// Step 3: Compute distance squared
|
||||||
|
double diffX = segClosesX - boxClosestX;
|
||||||
|
double diffY = segClosesY - boxClosestY;
|
||||||
|
double diffZ = segClosesZ - boxClosestZ;
|
||||||
|
|
||||||
|
//compute distance squared
|
||||||
|
double distSq = (diffX * diffX) + (diffY * diffY) + (diffZ * diffZ);
|
||||||
|
|
||||||
|
//early return if no collision occurred
|
||||||
|
if(distSq > radius * radius){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compute distance
|
||||||
|
double dist = Math.sqrt(distSq);
|
||||||
|
|
||||||
|
//compute penetration
|
||||||
|
double penetration = radius - dist;
|
||||||
|
rVal.setPenetration(penetration);
|
||||||
|
|
||||||
|
//compute normal
|
||||||
|
Vector3d normal = null;
|
||||||
|
if(dist > 1e-6){
|
||||||
|
normal = new Vector3d(diffX,diffY,diffZ).mul(1 / dist);
|
||||||
|
}
|
||||||
|
rVal.setNormal(normal);
|
||||||
|
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user