fix psyhics
not a typo
This commit is contained in:
parent
b4a72d274b
commit
7d69e1db4a
4 changed files with 178 additions and 63 deletions
|
@ -87,7 +87,7 @@ public class BallKicker { // TODO apply physics settings here
|
|||
Player player = event.getPlayer();
|
||||
|
||||
CollisionData collisionData = new CollisionData();
|
||||
Collision.pushOutside(player, stadium.ball, collisionData);
|
||||
Collision.pushOutside(player, stadium.ball, false, collisionData);
|
||||
double distance = collisionData.distance.withY(0).distance(0, 0, 0);
|
||||
|
||||
if (collisionData.distance.y() < verticalReach && distance < reach) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package net.pivipi.physics;
|
||||
|
||||
import java.lang.foreign.ValueLayout.OfBoolean;
|
||||
|
||||
import net.minestom.server.collision.BoundingBox;
|
||||
import net.minestom.server.collision.SweepResult;
|
||||
import net.minestom.server.collision.VisibleSweepResult;
|
||||
|
@ -7,31 +9,42 @@ import net.minestom.server.coordinate.Pos;
|
|||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.listener.common.KeepAliveListener;
|
||||
|
||||
public class Collision {
|
||||
private static CollisionData willCollide(Pos pos, BoundingBox boundingBox, Entity moving, Vec movement) {
|
||||
SweepResult sweepResult = new SweepResult(1, 0, 0, 0, null, 0, 0, 0);
|
||||
boolean collides = boundingBox.intersectBoxSwept(moving.getPosition(), movement, pos, moving.getBoundingBox(), sweepResult);
|
||||
VisibleSweepResult visibleSweepResult = new VisibleSweepResult(sweepResult);
|
||||
|
||||
CollisionData collisionData = new CollisionData();
|
||||
collisionData.swept = true;
|
||||
collisionData.percentage = visibleSweepResult.res;
|
||||
collisionData.collidedPosition = new Vec(visibleSweepResult.collidedPositionX, visibleSweepResult.collidedPositionY, visibleSweepResult.collidedPositionZ);
|
||||
collisionData.normal = new Vec(visibleSweepResult.normalX, visibleSweepResult.normalY, visibleSweepResult.normalZ);
|
||||
|
||||
return collides ? collisionData : null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param entity
|
||||
* @param entity the static entity
|
||||
* @param moving the moving entity
|
||||
* @param velocity the applied velocity
|
||||
* @param movement the movement
|
||||
* @return null if no collision
|
||||
*/
|
||||
public static VisibleSweepResult willCollideWithEntity(Entity entity, Entity moving, Vec movement) {
|
||||
SweepResult sweepResult = new SweepResult(1, 0, 0, 0, null, 0, 0, 0);
|
||||
boolean collided = entity.getBoundingBox().intersectBoxSwept(moving.getPosition(), movement, entity.getPosition(), moving.getBoundingBox(), sweepResult);
|
||||
return collided ? new VisibleSweepResult(sweepResult) : null;
|
||||
public static CollisionData willCollideWithEntity(Entity entity, Entity moving, Vec movement) {
|
||||
return willCollide(entity.getPosition(), entity.getBoundingBox(), moving, movement);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param groundY ground Y
|
||||
* @param moving the moving entity
|
||||
* @param movement the movement
|
||||
* @return null if no collision
|
||||
*/
|
||||
public static VisibleSweepResult willCollideWithGround(double groundY, Entity moving, Vec movement) {
|
||||
SweepResult sweepResult = new SweepResult(1, 0, 0, 0, null, 0, 0, 0);
|
||||
boolean collided = new BoundingBox(10, 1, 10).intersectBoxSwept(moving.getPosition(), movement, moving.getPosition().withY(groundY - 1).sub(5, 0, 5), moving.getBoundingBox(), sweepResult);
|
||||
return collided ? new VisibleSweepResult(sweepResult) : null;
|
||||
public static CollisionData willCollideWithGround(double groundY, Entity moving, Vec movement) {
|
||||
return willCollide(new Pos(Double.MIN_VALUE, 0, Double.MIN_VALUE), new BoundingBox(Double.MAX_VALUE, 64, Double.MAX_VALUE), moving, movement);
|
||||
}
|
||||
|
||||
public static boolean collidesWithEntity(Entity entity1, Entity entity2) {
|
||||
|
@ -42,32 +55,40 @@ public class Collision {
|
|||
return new BoundingBox(10, 1, 10).intersectEntity(entity.getPosition().withY(groundY - 1).sub(5, 0, 5), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pusher the entity that's pushing like a player
|
||||
* @param pushed the entity that's being pushed like a ball
|
||||
* @return offset you must apply to push the entity outside, null if doesn't collide
|
||||
*/
|
||||
public static Vec pushOutside(Entity pusher, Entity pushed) {
|
||||
return pushOutside(pusher, pushed, null);
|
||||
public static boolean collidesWithBlock(Pos blockPos, Entity entity) {
|
||||
return new BoundingBox(1, 1, 1).intersectEntity(blockPos, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pusher the entity that's pushing like a player
|
||||
* @param pushed the entity that's being pushed like a ball
|
||||
* @param collisionData puts data in this object
|
||||
* @return offset you must apply to push the entity outside, null if doesn't collide
|
||||
*/
|
||||
public static Vec pushOutside(Entity pusher, Entity pushed, CollisionData collisionData) {
|
||||
public static Vec pushOutside(Entity pusher, Entity pushed, boolean y, CollisionData collisionData) {
|
||||
return pushOutside(pusher.getBoundingBox(), pusher.getPosition(), pushed, y, collisionData);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pusher the entity that's pushing like a player
|
||||
* @param pushed the entity that's being pushed like a ball
|
||||
* @return offset you must apply to push the entity outside, null if doesn't collide
|
||||
*/
|
||||
public static Vec pushOutside(Pos blockPos, Entity pushed, boolean y, CollisionData collisionData) {
|
||||
return pushOutside(new BoundingBox(1, 1, 1), blockPos, pushed, y, collisionData);
|
||||
}
|
||||
|
||||
|
||||
/*public static Vec pushOutside(BoundingBox pusherBox, Pos pusherPos, Entity pushed, CollisionData collisionData) {
|
||||
double ballXSize = pushed.getBoundingBox().width();
|
||||
double playerXSize = pusher.getBoundingBox().width();
|
||||
double playerXSize = pusherBox.width();
|
||||
double ballZSize = pushed.getBoundingBox().depth();
|
||||
double playerZSize = pusher.getBoundingBox().depth();
|
||||
double playerZSize = pusherBox.depth();
|
||||
double ballHeight = pushed.getBoundingBox().height();
|
||||
double playerHeight = pusher.getBoundingBox().height();
|
||||
double playerHeight = pusherBox.height();
|
||||
Pos ballCenterPos = pushed.getPosition();
|
||||
Pos playerCenterPos = pusher.getPosition();
|
||||
Pos playerCenterPos = pusherPos;
|
||||
|
||||
Pos ballPos = ballCenterPos.sub(ballXSize / 2, 0, ballZSize / 2); // corner
|
||||
Pos playerPos = playerCenterPos.sub(playerXSize / 2, 0, playerZSize / 2);
|
||||
|
@ -107,5 +128,68 @@ public class Collision {
|
|||
return diffX < diffZ ? newBallOffset.withX(0) : newBallOffset.withZ(0);
|
||||
|
||||
return null;
|
||||
}*/
|
||||
/**
|
||||
*
|
||||
* @param pusherBox the entity that's pushing like a player or a block, its bounding box
|
||||
* @param pusherPos the position, bottom center
|
||||
* @param pushed the entity that's being pushed like a ball
|
||||
* @param collisionData puts data in this object
|
||||
* @return offset you must apply to push the entity outside, null if doesn't collide
|
||||
*/
|
||||
private static Vec pushOutside(BoundingBox pusherBox, Pos pusherPos, Entity pushed, boolean y, CollisionData collisionData) {
|
||||
double ballXSize = pushed.getBoundingBox().width();
|
||||
double playerXSize = pusherBox.width();
|
||||
double ballZSize = pushed.getBoundingBox().depth();
|
||||
double playerZSize = pusherBox.depth();
|
||||
double ballHeight = pushed.getBoundingBox().height();
|
||||
double playerHeight = pusherBox.height();
|
||||
|
||||
Pos ballCenterPos = pushed.getPosition();
|
||||
Pos playerCenterPos = pusherPos;
|
||||
|
||||
Pos ballPos = ballCenterPos.sub(ballXSize / 2, 0, ballZSize / 2);
|
||||
Pos playerPos = playerCenterPos.sub(playerXSize / 2, 0, playerZSize / 2);
|
||||
Vec ballDistance = ballCenterPos.sub(playerCenterPos).asVec();
|
||||
|
||||
if (collisionData != null) {
|
||||
collisionData.distance = ballDistance;
|
||||
}
|
||||
|
||||
double diffX = ballDistance.x() > 0
|
||||
? ballPos.x() - (playerPos.x() + playerXSize)
|
||||
: playerPos.x() - (ballPos.x() + ballXSize);
|
||||
double diffY = ballDistance.y() > 0
|
||||
? ballPos.y() - (playerPos.y() + playerHeight)
|
||||
: playerPos.y() - (ballPos.y() + ballHeight);
|
||||
double diffZ = ballDistance.z() > 0
|
||||
? ballPos.z() - (playerPos.z() + playerZSize)
|
||||
: playerPos.z() - (ballPos.z() + ballZSize);
|
||||
|
||||
Vec newBallOffset = new Vec(0);
|
||||
Vec offset = null;
|
||||
|
||||
if (diffX < 0 && diffZ < 0 && diffY < 0) {
|
||||
newBallOffset = newBallOffset.withX(ballDistance.x() > 0 ? -diffX : diffX);
|
||||
newBallOffset = newBallOffset.withY(ballDistance.x() > 0 ? -diffY : diffY);
|
||||
newBallOffset = newBallOffset.withZ(ballDistance.z() > 0 ? -diffZ : diffZ);
|
||||
|
||||
if (!y) diffY = Double.POSITIVE_INFINITY;
|
||||
|
||||
if (diffX < diffZ && diffX < diffY)
|
||||
offset = newBallOffset.mul(0, 0, 1);
|
||||
else if (diffY < diffX && diffY < diffZ)
|
||||
offset = newBallOffset.mul(0, 1, 0);
|
||||
else if (diffZ < diffX && diffZ < diffY)
|
||||
offset = newBallOffset.mul(1, 0, 0);
|
||||
}
|
||||
|
||||
if (collisionData != null) {
|
||||
collisionData.distance = ballDistance;
|
||||
collisionData.offset = offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,40 @@
|
|||
package net.pivipi.physics;
|
||||
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.Entity;
|
||||
|
||||
public class CollisionData {
|
||||
public boolean swept;
|
||||
|
||||
/**
|
||||
* distance between centers of entities (but bottom y)
|
||||
* only when not swept
|
||||
*/
|
||||
public Vec distance;
|
||||
|
||||
/**
|
||||
* the offset to the entity to to resolve the collision
|
||||
* only when not swept
|
||||
*/
|
||||
public Vec offset;
|
||||
|
||||
/**
|
||||
* percentage of movement until collision (only when swept)
|
||||
*/
|
||||
public double percentage;
|
||||
|
||||
/**
|
||||
* the position where the collision takes place (only when swept)
|
||||
*/
|
||||
public Vec collidedPosition;
|
||||
|
||||
/**
|
||||
* I don't know what this is but it looks useful (only when swept)
|
||||
*/
|
||||
public Vec normal;
|
||||
|
||||
/**
|
||||
* used to track what entity collided
|
||||
*/
|
||||
public Entity entity;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package net.pivipi.physics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minestom.server.collision.VisibleSweepResult;
|
||||
|
@ -60,29 +62,35 @@ public class Physics {
|
|||
|
||||
private Vec applyPhysics(double delta, Set<Player> players) {
|
||||
velocity = velocity.sub(0, gravity * delta, 0).mul(1 - (airFriction * delta), 1, 1 - (airFriction * delta));
|
||||
ArrayList<CollisionData> collisions = new ArrayList<>();
|
||||
|
||||
if (Collision.collidesWithGround(groundY, entity)) {
|
||||
entity.teleport(entity.getPosition().withY(groundY));
|
||||
velocity = velocity.mul(1 - (groundFriction * delta), -blockBounciness, 1 - (groundFriction * delta));
|
||||
} else {
|
||||
for (Player player : players) {
|
||||
boolean collides = Collision.collidesWithEntity(player, entity);
|
||||
if (collides) {
|
||||
handlePlayerTouch(player);
|
||||
CollisionData collisionData = new CollisionData();
|
||||
Vec offset = Collision.pushOutside(player, entity, false, collisionData); // TODO predict the collision
|
||||
|
||||
break;
|
||||
if (offset != null) {
|
||||
collisionData.entity = player;
|
||||
collisions.add(collisionData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (CollisionData collisionData : collisions) {
|
||||
if (collisionData.entity instanceof Player) {
|
||||
handlePlayerTouch((Player) collisionData.entity, collisionData);
|
||||
}
|
||||
}
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
private void handlePlayerTouch(Player player) {
|
||||
CollisionData collisionData = new CollisionData();
|
||||
Vec offset = Collision.pushOutside(player, entity, collisionData); // TODO predict the collision
|
||||
private void handlePlayerTouch(Player player, CollisionData collisionData) {
|
||||
Vec offset = collisionData.offset;
|
||||
|
||||
if (offset != null) {
|
||||
Pos movementPos = player.getPosition().sub(player.getPreviousPosition());
|
||||
|
||||
boolean oppositeX = (collisionData.distance.x() > 0 ? velocity.x() < 0 : velocity.x() > 0);
|
||||
|
@ -101,20 +109,13 @@ public class Physics {
|
|||
} else velocity = velocity.mul(1, player.isSneaking() ? -playerSneakingHeadBounciness : -playerHeadBounciness, 1);
|
||||
entity.teleport(entity.getPosition().withY(y -> y + headOffsetY));
|
||||
} else {
|
||||
System.out.println("tping");
|
||||
entity.teleport(entity.getPosition().add(offset.mul(1.1))); // magic value to make some space in case of desync
|
||||
double bodyBounciness = player.isSneaking() ? -playerSneakingBodyBounciness : -playerBodyBounciness;
|
||||
|
||||
System.out.println(velocity);
|
||||
|
||||
velocity = velocity
|
||||
.withX(x -> oppositeX ? x * bodyBounciness : x + movementPos.x() * playerCarryStrength)
|
||||
.withY(y -> collisionData.distance.y() < 1.0 ? movementPos.y() * jumpStrength : y) // magic value legs
|
||||
.withZ(z -> oppositeZ ? z * bodyBounciness : z + movementPos.z() * playerCarryStrength);
|
||||
|
||||
System.out.println(velocity);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue