Implemented first version of collider
- Entities now can have an AABB collision model - Collisions of pairs of entities are handled properly - Added debug display of AABBs
This commit is contained in:
		| @@ -17,6 +17,8 @@ | ||||
|  *******************************************************************************/ | ||||
| package ru.windcorp.progressia.client.graphics; | ||||
|  | ||||
| import glm.vec._3.Vec3; | ||||
|  | ||||
| public class Colors { | ||||
| 	 | ||||
| 	public static final int | ||||
| @@ -35,4 +37,16 @@ public class Colors { | ||||
| 			DEBUG_MAGENTA = 0xFF00FF, | ||||
| 			DEBUG_YELLOW  = 0xFFFF00; | ||||
| 	 | ||||
| 	public static Vec3 toVector(int rgb) { | ||||
| 		return toVector(rgb, new Vec3()); | ||||
| 	} | ||||
| 	 | ||||
| 	public static Vec3 toVector(int rgb, Vec3 output) { | ||||
| 		output.x = ((rgb & 0xFF0000) >> 16) / 256f; | ||||
| 		output.y = ((rgb & 0x00FF00) >> 8 ) / 256f; | ||||
| 		output.z = ((rgb & 0x0000FF)      ) / 256f; | ||||
| 		 | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -227,7 +227,7 @@ public class RenderTarget { | ||||
| 		return Faces.createRectangle( | ||||
| 				FlatRenderProgram.getDefault(), | ||||
| 				texture, | ||||
| 				createVectorFromRGBInt(color), | ||||
| 				Colors.toVector(color), | ||||
| 				new Vec3(x, y, depth), | ||||
| 				new Vec3(width, 0, 0), | ||||
| 				new Vec3(0, height, 0), | ||||
| @@ -244,12 +244,4 @@ public class RenderTarget { | ||||
| 		); | ||||
| 	} | ||||
| 	 | ||||
| 	private static Vec3 createVectorFromRGBInt(int rgb) { | ||||
| 		int r = (rgb & 0xFF0000) >> 16; | ||||
| 		int g = (rgb & 0x00FF00) >> 8; | ||||
| 		int b = (rgb & 0x0000FF); | ||||
| 		 | ||||
| 		return new Vec3(r / 256f, g / 256f, b / 256f); | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
|   | ||||
| @@ -17,6 +17,9 @@ | ||||
|  *******************************************************************************/ | ||||
| package ru.windcorp.progressia.client.graphics.world; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import org.lwjgl.glfw.GLFW; | ||||
|  | ||||
| import glm.Glm; | ||||
| @@ -33,14 +36,18 @@ import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent; | ||||
| import ru.windcorp.progressia.client.graphics.input.InputEvent; | ||||
| import ru.windcorp.progressia.client.graphics.input.KeyEvent; | ||||
| import ru.windcorp.progressia.client.graphics.input.bus.Input; | ||||
| import ru.windcorp.progressia.common.collision.AABB; | ||||
| import ru.windcorp.progressia.common.collision.Collideable; | ||||
| import ru.windcorp.progressia.common.collision.CollisionClock; | ||||
| import ru.windcorp.progressia.common.collision.CollisionModel; | ||||
| import ru.windcorp.progressia.common.collision.colliders.Collider; | ||||
| import ru.windcorp.progressia.common.util.FloatMathUtils; | ||||
| import ru.windcorp.progressia.common.util.Vectors; | ||||
| import ru.windcorp.progressia.common.world.entity.EntityData; | ||||
| import ru.windcorp.progressia.test.AABBRenderer; | ||||
|  | ||||
| public class LayerWorld extends Layer { | ||||
| 	 | ||||
| 	private final Vec3 velocity = new Vec3(); | ||||
| 	 | ||||
| 	private final Mat3 angMat = new Mat3(); | ||||
|  | ||||
| 	private int movementForward = 0; | ||||
| @@ -98,20 +105,11 @@ public class LayerWorld extends Layer { | ||||
| 		angMat.mul_(movement); // bug in jglm, .mul() and mul_() are swapped | ||||
| 		movement.z = movementUp; | ||||
| 		movement.mul(movementSpeed); | ||||
| 		movement.sub(velocity); | ||||
| 		movement.sub(player.getVelocity()); | ||||
| 		movement.mul(controlAuthority); | ||||
| 		velocity.add(movement); | ||||
| 		player.getVelocity().add(movement); | ||||
| 		 | ||||
| 		Vectors.release(movement); | ||||
| 		 | ||||
| 		Vec3 velCopy = Vectors.grab3().set(velocity); | ||||
| 		 | ||||
| 		velCopy.mul((float) GraphicsInterface.getFrameLength()); | ||||
| 		 | ||||
| 		player.move(velCopy); | ||||
| 		player.getVelocity().set(velocity); | ||||
| 		 | ||||
| 		Vectors.release(velCopy); | ||||
| 	} | ||||
|  | ||||
| 	private void renderWorld() { | ||||
| @@ -126,8 +124,51 @@ public class LayerWorld extends Layer { | ||||
| 		helper.reset(); | ||||
| 	} | ||||
| 	 | ||||
| 	private final Collider.ColliderWorkspace tmp_colliderWorkspace = new Collider.ColliderWorkspace(); | ||||
| 	private final List<Collideable> tmp_collideableList = new ArrayList<>(); | ||||
| 	 | ||||
| 	private static final boolean RENDER_AABBS = false; | ||||
| 	 | ||||
| 	private void tmp_doEveryFrame() { | ||||
| 		// Stub for the future | ||||
| 		try { | ||||
| 			if (RENDER_AABBS) { | ||||
| 				for (EntityData data : this.client.getWorld().getData().getEntities()) { | ||||
| 					CollisionModel model = data.getCollisionModel(); | ||||
| 					if (model instanceof AABB) { | ||||
| 						AABBRenderer.renderAABB((AABB) model, helper); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			tmp_collideableList.clear(); | ||||
| 			tmp_collideableList.addAll(this.client.getWorld().getData().getEntities()); | ||||
| 			 | ||||
| 			Collider.performCollisions( | ||||
| 					tmp_collideableList, | ||||
| 					new CollisionClock() { | ||||
| 						private float t = 0; | ||||
| 						@Override | ||||
| 						public float getTime() { | ||||
| 							return t; | ||||
| 						} | ||||
| 						 | ||||
| 						@Override | ||||
| 						public void advanceTime(float change) { | ||||
| 							t += change; | ||||
| 						} | ||||
| 					}, | ||||
| 					(float) GraphicsInterface.getFrameLength(), | ||||
| 					tmp_colliderWorkspace | ||||
| 			); | ||||
| 			 | ||||
| 			final float frictionCoeff = 1 - 1e-2f; | ||||
| 			 | ||||
| 			for (EntityData data : this.client.getWorld().getData().getEntities()) { | ||||
| 				data.getVelocity().mul(frictionCoeff); | ||||
| 			} | ||||
| 		} catch (Exception e) { | ||||
| 			System.exit(31337); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
|   | ||||
| @@ -0,0 +1,93 @@ | ||||
| package ru.windcorp.progressia.common.collision; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.Map; | ||||
|  | ||||
| import glm.vec._3.Vec3; | ||||
| import ru.windcorp.progressia.common.world.block.BlockFace; | ||||
|  | ||||
| public class AABB implements CollisionModel { | ||||
|  | ||||
| 	private final Map<BlockFace, CollisionWall> faces = BlockFace.mapToFaces( | ||||
| 			new CollisionWall(-0.5f, -0.5f, -0.5f,   +1,  0,  0,    0,  0, +1), | ||||
| 			new CollisionWall(+0.5f, -0.5f, -0.5f,    0, +1,  0,    0,  0, +1), | ||||
| 			new CollisionWall(+0.5f, +0.5f, -0.5f,   -1,  0,  0,    0,  0, +1), | ||||
| 			new CollisionWall(-0.5f, +0.5f, -0.5f,    0, -1,  0,    0,  0, +1), | ||||
| 			 | ||||
| 			new CollisionWall(-0.5f, -0.5f, +0.5f,   +1,  0,  0,    0, +1,  0), | ||||
| 			new CollisionWall(-0.5f, -0.5f, -0.5f,    0, +1,  0,   +1,  0,  0) | ||||
| 	); | ||||
| 	 | ||||
| 	private final Vec3 origin = new Vec3(); | ||||
| 	private final Vec3 size = new Vec3(); | ||||
| 	 | ||||
| 	public AABB(Vec3 origin, Vec3 size) { | ||||
| 		this.origin.set(origin); | ||||
| 		this.size.set(size); | ||||
| 		 | ||||
| 		for (CollisionWall wall : getFaces()) { | ||||
| 			wall.moveOrigin(origin); | ||||
| 			wall.getWidth().mul(size); | ||||
| 			wall.getHeight().mul(size); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	public AABB( | ||||
| 			float ox, float oy, float oz, | ||||
| 			float xSize, float ySize, float zSize | ||||
| 	) { | ||||
| 		this.origin.set(ox, oy, oz); | ||||
| 		this.size.set(xSize, ySize, zSize); | ||||
| 		 | ||||
| 		for (CollisionWall wall : getFaces()) { | ||||
| 			wall.moveOrigin(ox, oy, oz); | ||||
| 			wall.getWidth().mul(xSize, ySize, zSize); | ||||
| 			wall.getHeight().mul(xSize, ySize, zSize); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	public Collection<CollisionWall> getFaces() { | ||||
| 		return faces.values(); | ||||
| 	} | ||||
| 	 | ||||
| 	public Vec3 getOrigin() { | ||||
| 		return origin; | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public void setOrigin(Vec3 origin) { | ||||
| 		for (CollisionWall wall : getFaces()) { | ||||
| 			wall.getOrigin().sub(this.origin).add(origin); | ||||
| 		} | ||||
|  | ||||
| 		this.origin.set(origin); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public void moveOrigin(Vec3 displacement) { | ||||
| 		for (CollisionWall wall : getFaces()) { | ||||
| 			wall.getOrigin().add(displacement); | ||||
| 		} | ||||
|  | ||||
| 		this.origin.add(displacement); | ||||
| 	} | ||||
| 	 | ||||
| 	public Vec3 getSize() { | ||||
| 		return size; | ||||
| 	} | ||||
| 	 | ||||
| 	public void setSize(Vec3 size) { | ||||
| 		setSize(size.x, size.y, size.z); | ||||
| 	} | ||||
| 	 | ||||
| 	public void setSize(float xSize, float ySize, float zSize) { | ||||
| 		for (CollisionWall wall : getFaces()) { | ||||
| 			wall.getWidth().div(this.size).mul(xSize, ySize, zSize); | ||||
| 			wall.getHeight().div(this.size).mul(xSize, ySize, zSize); | ||||
| 			wall.getOrigin().sub(getOrigin()).div(this.size).mul(xSize, ySize, zSize).add(getOrigin()); | ||||
| 		} | ||||
| 		 | ||||
| 		this.size.set(xSize, ySize, zSize); | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| package ru.windcorp.progressia.common.collision; | ||||
|  | ||||
| import glm.vec._3.Vec3; | ||||
| import ru.windcorp.progressia.common.collision.colliders.Collider; | ||||
|  | ||||
| public interface Collideable { | ||||
| 	 | ||||
| 	CollisionModel getCollisionModel(); | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Invoked by {@link Collider} when two entities are about to collide. | ||||
| 	 * The world is at the moment of collision. | ||||
| 	 * @param other the colliding object | ||||
| 	 * @return {@code true} iff the collision should not be handled normally (e.g. this object has disappeared) | ||||
| 	 */ | ||||
| 	boolean onCollision(Collideable other); | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Returns the mass of this {@link Collideable} that should be used to calculate collisions. | ||||
| 	 * Collision mass must be a positive number. Positive infinity is allowed. | ||||
| 	 * @return this object's collision mass | ||||
| 	 */ | ||||
| 	float getCollisionMass(); | ||||
| 	 | ||||
| 	void moveAsCollideable(Vec3 displacement); | ||||
| 	 | ||||
| 	void getCollideableVelocity(Vec3 output); | ||||
| 	void changeVelocityOnCollision(Vec3 velocityChange); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,8 @@ | ||||
| package ru.windcorp.progressia.common.collision; | ||||
|  | ||||
| public interface CollisionClock { | ||||
| 	 | ||||
| 	float getTime(); | ||||
| 	void advanceTime(float change); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,10 @@ | ||||
| package ru.windcorp.progressia.common.collision; | ||||
|  | ||||
| import glm.vec._3.Vec3; | ||||
|  | ||||
| public interface CollisionModel { | ||||
| 	 | ||||
| 	public void setOrigin(Vec3 origin); | ||||
| 	public void moveOrigin(Vec3 displacement); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,55 @@ | ||||
| package ru.windcorp.progressia.common.collision; | ||||
|  | ||||
| import glm.vec._3.Vec3; | ||||
|  | ||||
| public class CollisionWall { | ||||
| 	 | ||||
| 	private final Vec3 origin = new Vec3(); | ||||
| 	private final Vec3 width = new Vec3(); | ||||
| 	private final Vec3 height = new Vec3(); | ||||
| 	 | ||||
| 	public CollisionWall(Vec3 origin, Vec3 width, Vec3 height) { | ||||
| 		this.origin.set(origin); | ||||
| 		this.width.set(width); | ||||
| 		this.height.set(height); | ||||
| 	} | ||||
| 	 | ||||
| 	public CollisionWall( | ||||
| 		float ox, float oy, float oz, | ||||
| 		float wx, float wy, float wz, | ||||
| 		float hx, float hy, float hz | ||||
| 	) { | ||||
| 		this.origin.set(ox, oy, oz); | ||||
| 		this.width.set(wx, wy, wz); | ||||
| 		this.height.set(hx, hy, hz); | ||||
| 	} | ||||
| 	 | ||||
| 	public Vec3 getOrigin() { | ||||
| 		return origin; | ||||
| 	} | ||||
| 	 | ||||
| 	public Vec3 getWidth() { | ||||
| 		return width; | ||||
| 	} | ||||
| 	 | ||||
| 	public Vec3 getHeight() { | ||||
| 		return height; | ||||
| 	} | ||||
| 	 | ||||
| 	public void setOrigin(Vec3 origin) { | ||||
| 		setOrigin(origin.x, origin.y, origin.z); | ||||
| 	} | ||||
| 	 | ||||
| 	public void setOrigin(float x, float y, float z) { | ||||
| 		this.origin.set(x, y, z); | ||||
| 	} | ||||
| 	 | ||||
| 	public void moveOrigin(Vec3 displacement) { | ||||
| 		moveOrigin(displacement.x, displacement.y, displacement.z); | ||||
| 	} | ||||
| 	 | ||||
| 	public void moveOrigin(float dx, float dy, float dz) { | ||||
| 		this.origin.add(dx, dy, dz); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,53 @@ | ||||
| package ru.windcorp.progressia.common.collision; | ||||
|  | ||||
| import java.util.function.Consumer; | ||||
|  | ||||
| import glm.mat._4.Mat4; | ||||
| import glm.vec._3.Vec3; | ||||
| import ru.windcorp.progressia.common.util.VectorUtil; | ||||
| import ru.windcorp.progressia.common.util.Vectors; | ||||
|  | ||||
| public class TransformedCollisionModel implements CollisionModel { | ||||
| 	 | ||||
| 	private final CollisionModel parent; | ||||
| 	 | ||||
| 	private final Mat4 transform = new Mat4(); | ||||
| 	private final Mat4 inverseTransform = new Mat4(); | ||||
| 	 | ||||
| 	public TransformedCollisionModel(CollisionModel parent, Mat4 transform) { | ||||
| 		this.parent = parent; | ||||
| 		setTransform(transform); | ||||
| 	} | ||||
| 	 | ||||
| 	public TransformedCollisionModel(CollisionModel parent, Consumer<Mat4> transform) { | ||||
| 		this.parent = parent; | ||||
| 		transform.accept(this.transform); | ||||
| 		this.inverseTransform.set(this.transform).inverse(); | ||||
| 	} | ||||
| 	 | ||||
| 	public Mat4 getTransform() { | ||||
| 		return transform; | ||||
| 	} | ||||
| 	 | ||||
| 	public void setTransform(Mat4 newTransform) { | ||||
| 		this.transform.set(newTransform); | ||||
| 		this.inverseTransform.set(newTransform).inverse(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void setOrigin(Vec3 origin) { | ||||
| 		Vec3 vec3 = Vectors.grab3(); | ||||
| 		VectorUtil.applyMat4(origin, inverseTransform, vec3); | ||||
| 		this.parent.setOrigin(vec3); | ||||
| 		Vectors.release(vec3); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void moveOrigin(Vec3 displacement) { | ||||
| 		Vec3 vec3 = Vectors.grab3(); | ||||
| 		VectorUtil.applyMat4(displacement, inverseTransform, vec3); | ||||
| 		this.parent.moveOrigin(vec3); | ||||
| 		Vectors.release(vec3); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,198 @@ | ||||
| package ru.windcorp.progressia.common.collision.colliders; | ||||
|  | ||||
| import glm.mat._3.Mat3; | ||||
| import glm.vec._3.Vec3; | ||||
| import ru.windcorp.progressia.common.collision.AABB; | ||||
| import ru.windcorp.progressia.common.collision.Collideable; | ||||
| import ru.windcorp.progressia.common.collision.CollisionWall; | ||||
| import ru.windcorp.progressia.common.collision.colliders.Collider.ColliderWorkspace; | ||||
| import ru.windcorp.progressia.common.collision.colliders.Collider.Collision; | ||||
| import ru.windcorp.progressia.common.util.Matrices; | ||||
| import ru.windcorp.progressia.common.util.Vectors; | ||||
|  | ||||
| class AABBWithAABBCollider { | ||||
| 	 | ||||
| 	static Collider.Collision computeModelCollision( | ||||
| 			Collideable aBody, Collideable bBody, | ||||
| 			AABB aModel, AABB bModel, | ||||
| 			float tickLength, | ||||
| 			ColliderWorkspace workspace | ||||
| 	) { | ||||
| 		Collideable obstacleBody = bBody; | ||||
| 		Collideable colliderBody = aBody; | ||||
| 		AABB obstacleModel = bModel; | ||||
| 		AABB colliderModel = aModel; | ||||
| 		 | ||||
| 		Collision result = null; | ||||
| 		 | ||||
| 		AABB originCollisionSpace = | ||||
| 				createOriginCollisionSpace(obstacleModel, colliderModel, workspace.dummyAABB); | ||||
| 		 | ||||
| 		Vec3 collisionVelocity = Vectors.grab3(); | ||||
| 		computeCollisionVelocity(collisionVelocity, obstacleBody, colliderBody); | ||||
| 		 | ||||
| 		// For every wall of collision space | ||||
| 		for (CollisionWall wall : originCollisionSpace.getFaces()) { | ||||
| 				 | ||||
| 			Collision collision = computeWallCollision( | ||||
| 					wall, colliderModel, | ||||
| 					collisionVelocity, | ||||
| 					tickLength, workspace, | ||||
| 					aBody, bBody | ||||
| 			); | ||||
| 			 | ||||
| 			// Update result | ||||
| 			if (collision != null) { | ||||
| 				Collision second; | ||||
| 				 | ||||
| 				if (result == null || collision.time < result.time) { | ||||
| 					second = result; | ||||
| 					result = collision; | ||||
| 				} else { | ||||
| 					second = collision; | ||||
| 				} | ||||
| 				 | ||||
| 				// Release Collision that is no longer used | ||||
| 				if (second != null) workspace.release(second); | ||||
| 			} | ||||
| 				 | ||||
| 		} | ||||
| 		 | ||||
| 		Vectors.release(collisionVelocity); | ||||
| 		 | ||||
| 		return result; | ||||
| 	} | ||||
| 	 | ||||
| 	private static void computeCollisionVelocity( | ||||
| 			Vec3 output, | ||||
| 			Collideable obstacleBody, | ||||
| 			Collideable colliderBody | ||||
| 	) { | ||||
| 		Vec3 obstacleVelocity = Vectors.grab3(); | ||||
| 		Vec3 colliderVelocity = Vectors.grab3(); | ||||
| 		 | ||||
| 		obstacleBody.getCollideableVelocity(obstacleVelocity); | ||||
| 		colliderBody.getCollideableVelocity(colliderVelocity); | ||||
| 		 | ||||
| 		output.set(colliderVelocity).sub(obstacleVelocity); | ||||
| 		 | ||||
| 		Vectors.release(obstacleVelocity); | ||||
| 		Vectors.release(colliderVelocity); | ||||
| 	} | ||||
|  | ||||
| 	private static AABB createOriginCollisionSpace(AABB obstacle, AABB collider, AABB output) { | ||||
| 		output.setOrigin(obstacle.getOrigin()); | ||||
| 		 | ||||
| 		Vec3 size = Vectors.grab3().set(obstacle.getSize()).add(collider.getSize()); | ||||
| 		output.setSize(size); | ||||
| 		Vectors.release(size); | ||||
| 		 | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Here we determine whether a collision has actually happened, and if it did, at what moment. | ||||
| 	 *  | ||||
| 	 * The basic idea is to compute the moment of collision and impact coordinates in wall coordinate space. | ||||
| 	 * Then, we can check impact coordinates to determine if we actually hit the wall or flew by and then | ||||
| 	 * check time to make sure the collision is not too far in the future and not in the past. | ||||
| 	 *  | ||||
| 	 * DETAILED EXPLANATION: | ||||
| 	 *  | ||||
| 	 * Consider a surface defined by an origin r_wall and two noncollinear nonzero vectors w and h. | ||||
| 	 * Consider a line defined by an origin r_line and a nonzero vector v. | ||||
| 	 *  | ||||
| 	 * Then, a collision occurs if there exist x, y and t such that | ||||
| 	 *   ______   _ | ||||
| 	 *   r_line + v * t | ||||
| 	 *    | ||||
| 	 * and | ||||
| 	 *   ______   _       _ | ||||
| 	 *   r_wall + w * x + h * y | ||||
| 	 *    | ||||
| 	 * describe the same location (indeed, this corresponds to a collision at moment t0 + t | ||||
| 	 * with a point on the wall with coordinates (x; y) in (w; h) coordinate system). | ||||
| 	 *  | ||||
| 	 * Therefore, | ||||
| 	 *   ______   _     ______   _     _ | ||||
| 	 *   r_line + v*t = r_wall + w*x + h*y; | ||||
| 	 *    | ||||
| 	 *   _   ⎡w_x  h_x  -v_x⎤   ⎡x⎤        _   ______   ______ | ||||
| 	 *   r = ⎢w_y  h_y  -v_y⎥ * ⎢y⎥, where r = r_line - r_wall; | ||||
| 	 *       ⎣w_z  h_z  -v_z⎦   ⎣t⎦ | ||||
| 	 *        | ||||
| 	 *   ⎡x⎤   ⎡w_x  h_x  -v_x⎤ -1   _ | ||||
| 	 *   ⎢y⎥ = ⎢w_y  h_y  -v_y⎥    * r, if the matrix is invertible. | ||||
| 	 *   ⎣t⎦   ⎣w_z  h_z  -v_z⎦ | ||||
| 	 *  | ||||
| 	 * Then, one only needs to ensure that: | ||||
| 	 *   0 < x < 1, | ||||
| 	 *   0 < y < 1, and | ||||
| 	 *   0 < t < T, where T is remaining tick time. | ||||
| 	 *  | ||||
| 	 * If the matrix is not invertible or any of the conditions are not met, no collision happened. | ||||
| 	 * If all conditions are satisfied, then the moment of impact is t0 + t. | ||||
| 	 */ | ||||
| 	private static Collision computeWallCollision( | ||||
| 			CollisionWall obstacleWall, | ||||
| 			AABB colliderModel, | ||||
| 			Vec3 collisionVelocity, | ||||
| 			float tickLength, ColliderWorkspace workspace, | ||||
| 			Collideable aBody, Collideable bBody | ||||
| 	) { | ||||
| 		Vec3 w = obstacleWall.getWidth(); | ||||
| 		Vec3 h = obstacleWall.getHeight(); | ||||
| 		Vec3 v = Vectors.grab3(); | ||||
| 		Mat3 m = Matrices.grab3(); // The matrix [w h -v] | ||||
| 		Vec3 r = Vectors.grab3(); | ||||
| 		Vec3 xyt = Vectors.grab3(); | ||||
| 		 | ||||
| 		try { | ||||
| 			v.set(collisionVelocity); | ||||
| 			 | ||||
| 			if (isExiting(v, w, h)) { | ||||
| 				return null; | ||||
| 			} | ||||
| 			 | ||||
| 			r.set(colliderModel.getOrigin()).sub(obstacleWall.getOrigin()); | ||||
| 			m.c0(w).c1(h).c2(v.negate()); | ||||
| 			 | ||||
| 			if (Math.abs(m.det()) < 1e-6) { | ||||
| 				return null; | ||||
| 			} | ||||
| 			 | ||||
| 			m.inverse().mul(r, xyt); | ||||
| 			 | ||||
| 			float x = xyt.x; | ||||
| 			float y = xyt.y; | ||||
| 			float t = xyt.z; | ||||
| 			 | ||||
| 			if (x <= 0 || x >= 1 || y <= 0 || y >= 1) { | ||||
| 				// We're missing the wall | ||||
| 				return null; | ||||
| 			} | ||||
| 			 | ||||
| 			if (t < 0 || t > tickLength) { | ||||
| 				// We're colliding at the wrong moment | ||||
| 				return null; | ||||
| 			} | ||||
| 			 | ||||
| 			return workspace.grab().set(aBody, bBody, obstacleWall, t); | ||||
| 		} finally { | ||||
| 			Vectors.release(v); | ||||
| 			Vectors.release(r); | ||||
| 			Matrices.release(m); | ||||
| 			Vectors.release(xyt); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private static boolean isExiting(Vec3 v, Vec3 w, Vec3 h) { | ||||
| 		Vec3 tmp = Vectors.grab3().set(w).cross(h); | ||||
| 		boolean result = Vec3.dot(tmp, v) >= 0; | ||||
| 		Vectors.release(tmp); | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	private AABBWithAABBCollider() {} | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,338 @@ | ||||
| package ru.windcorp.progressia.common.collision.colliders; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
|  | ||||
| import org.apache.logging.log4j.LogManager; | ||||
|  | ||||
| import glm.vec._3.Vec3; | ||||
| import ru.windcorp.progressia.common.collision.AABB; | ||||
| import ru.windcorp.progressia.common.collision.Collideable; | ||||
| import ru.windcorp.progressia.common.collision.CollisionClock; | ||||
| import ru.windcorp.progressia.common.collision.CollisionModel; | ||||
| import ru.windcorp.progressia.common.collision.CollisionWall; | ||||
| import ru.windcorp.progressia.common.util.LowOverheadCache; | ||||
| import ru.windcorp.progressia.common.util.Vectors; | ||||
|  | ||||
| public class Collider { | ||||
| 	 | ||||
| 	private static final int MAX_COLLISIONS_PER_ENTITY = 64; | ||||
| 	 | ||||
| 	public static void performCollisions( | ||||
| 			List<? extends Collideable> colls, | ||||
| 			CollisionClock clock, | ||||
| 			float tickLength, | ||||
| 			ColliderWorkspace workspace | ||||
| 	) { | ||||
| 		int collisionCount = 0; | ||||
| 		int maxCollisions = colls.size() * MAX_COLLISIONS_PER_ENTITY; | ||||
| 		 | ||||
| 		while (true) { | ||||
| 			if (collisionCount > maxCollisions) { | ||||
| 				LogManager.getLogger().warn( | ||||
| 						"Attempted to handle more than {} collisions", | ||||
| 						maxCollisions | ||||
| 				); | ||||
| 				return; | ||||
| 			} | ||||
| 			 | ||||
| 			Collision firstCollision = getFirstCollision(colls, tickLength, workspace); | ||||
| 			 | ||||
| 			if (firstCollision == null) { | ||||
| 				break; | ||||
| 			} else { | ||||
| 				collide(firstCollision, colls, clock, tickLength, workspace); | ||||
| 				workspace.release(firstCollision); | ||||
| 				collisionCount++; | ||||
| 				 | ||||
| 				tickLength -= firstCollision.time; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		advanceTime(colls, clock, tickLength); | ||||
| 	} | ||||
|  | ||||
| 	private static Collision getFirstCollision( | ||||
| 			List<? extends Collideable> colls, | ||||
| 			float tickLength, | ||||
| 			ColliderWorkspace workspace | ||||
| 	) { | ||||
| 		Collision result = null; | ||||
| 		 | ||||
| 		// For every pair of colls | ||||
| 		for (int i = 0; i < colls.size(); ++i) { | ||||
| 			Collideable a = colls.get(i); | ||||
| 			 | ||||
| 			for (int j = i + 1; j < colls.size(); ++j) { | ||||
| 				Collideable b = colls.get(j); | ||||
| 				 | ||||
| 				Collision collision = getCollision(a, b, tickLength, workspace); | ||||
| 				 | ||||
| 				// Update result | ||||
| 				if (collision != null) { | ||||
| 					Collision second; | ||||
| 					 | ||||
| 					if (result == null || collision.time < result.time) { | ||||
| 						second = result; | ||||
| 						result = collision; | ||||
| 					} else { | ||||
| 						second = collision; | ||||
| 					} | ||||
| 					 | ||||
| 					// Release Collision that is no longer used | ||||
| 					if (second != null) workspace.release(second); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		return result; | ||||
| 	} | ||||
| 	 | ||||
| 	private static Collision getCollision( | ||||
| 			Collideable a, | ||||
| 			Collideable b, | ||||
| 			float tickLength, | ||||
| 			ColliderWorkspace workspace | ||||
| 	) { | ||||
| 		CollisionModel aModel = a.getCollisionModel(); | ||||
| 		CollisionModel bModel = b.getCollisionModel(); | ||||
| 		 | ||||
| 		if (aModel instanceof AABB && bModel instanceof AABB) { | ||||
| 			return AABBWithAABBCollider.computeModelCollision( | ||||
| 					a, b, | ||||
| 					(AABB) aModel, (AABB) bModel, | ||||
| 					tickLength, | ||||
| 					workspace | ||||
| 			); | ||||
| 		} | ||||
| 		 | ||||
| 		throw new UnsupportedOperationException( | ||||
| 				"Collisions between " + aModel + " and " + bModel + " are not yet implemented" | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| 	private static void collide( | ||||
| 			Collision collision, | ||||
| 			 | ||||
| 			Collection<? extends Collideable> colls, | ||||
| 			CollisionClock clock, | ||||
| 			float tickLength, | ||||
| 			ColliderWorkspace workspace | ||||
| 	) { | ||||
| 		advanceTime(colls, clock, collision.time); | ||||
| 		 | ||||
| 		boolean doNotHandle = false; | ||||
| 		 | ||||
| 		doNotHandle |= collision.a.onCollision(collision.b); | ||||
| 		doNotHandle |= collision.b.onCollision(collision.a); | ||||
| 		 | ||||
| 		if (doNotHandle) { | ||||
| 			return; | ||||
| 		} | ||||
| 		 | ||||
| 		handlePhysics(collision); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Here we compute the change in body velocities due to a collision. | ||||
| 	 *  | ||||
| 	 * We make the following simplifications: | ||||
| 	 *   1)  The bodies are perfectly rigid; | ||||
| 	 *   2)  The collision is perfectly inelastic | ||||
| 	 *       (no bouncing); | ||||
| 	 *   3)  The bodies are spherical; | ||||
| 	 *   4)  No tangential friction exists | ||||
| 	 *       (bodies do not experience friction when sliding against each other); | ||||
| 	 *   5)  Velocities are not relativistic. | ||||
| 	 *    | ||||
| 	 * Angular momentum is ignored per 3) and 4), | ||||
| 	 * e.g. when something pushes an end of a long stick, the stick does not rotate. | ||||
| 	 *  | ||||
| 	 * DETAILED EXPLANATION: | ||||
| 	 *  | ||||
| 	 * Two spherical (sic) bodies, a and b, experience a perfectly inelastic collision | ||||
| 	 * along a unit vector | ||||
| 	 *   _    _   _      _   _ | ||||
| 	 *   n = (w ⨯ h) / (|w ⨯ h|), | ||||
| 	 *       _     _ | ||||
| 	 * where w and h are two noncollinear nonzero vectors on the dividing plane. | ||||
| 	 *                                             ___  ___ | ||||
| 	 * Body masses and velocities are M_a, M_b and v_a, v_b, respectively. | ||||
| 	 *                                            ___     ___ | ||||
| 	 * After the collision desired velocities are u_a and u_b, respectively. | ||||
| 	 *                                                                          _ | ||||
| 	 * (Notation convention: suffix 'n' denotes a vector projection onto vector n, | ||||
| 	 * and suffix 't' denotes a vector projection onto the dividing plane.) | ||||
| 	 *  | ||||
| 	 * Consider the law of conservation of momentum for axis n and the dividing plane: | ||||
| 	 *        ____________   ____________   ________________ | ||||
| 	 *   n: ⎧ p_a_before_n + p_b_before_n = p_common_after_n; | ||||
| 	 *      ⎨ ___________   ____________ | ||||
| 	 *   t: ⎩ p_i_after_t = p_i_before_t    for any i in {a, b}. | ||||
| 	 *    | ||||
| 	 * Expressing all p_* in given terms: | ||||
| 	 *               ___   _           ___   _                  ___           ___   ____   ____ | ||||
| 	 *   n: ⎧ M_a * (v_a ⋅ n) + M_b * (v_b ⋅ n) = (M_a + M_b) * u_n,    where u_n ≡ u_an = u_bn; | ||||
| 	 *      ⎨ ____   ___   _    ___   _ | ||||
| 	 *   t: ⎩ u_it = v_i - n * (v_i ⋅ n)                                for any i in {a, b}. | ||||
| 	 *    | ||||
| 	 * Therefore: | ||||
| 	 *   ___   _                       ___   _                       ___   _ | ||||
| 	 *   u_n = n * ( M_a/(M_a + M_b) * v_a ⋅ n  +  M_b/(M_a + M_b) * v_b ⋅ n ); | ||||
| 	 *  | ||||
| 	 * or, equivalently, | ||||
| 	 *   ___   _           ___   _           ___   _ | ||||
| 	 *   u_n = n * ( m_a * v_a ⋅ n  +  m_b * v_b ⋅ n ), | ||||
| 	 *  | ||||
| 	 * where m_a and m_b are relative masses (see below). | ||||
| 	 *  | ||||
| 	 * Finally, | ||||
| 	 *   ___   ____   ___ | ||||
| 	 *   u_i = u_it + u_n    for any i in {a, b}. | ||||
| 	 *    | ||||
| 	 * The usage of relative masses m_i permits a convenient generalization of the algorithm | ||||
| 	 * for infinite masses, signifying masses "significantly greater" than finite masses: | ||||
| 	 *  | ||||
| 	 *   1)  If both M_a and M_b are finite,       let m_i = M_i / (M_a + M_b)    for any i in {a, b}. | ||||
| 	 *   2)  If M_i is finite but M_j is infinite, let m_i = 0 and m_j = 1. | ||||
| 	 *   3)  If both M_a and M_b are infinite,     let m_i = 1/2                  for any i in {a, b}. | ||||
| 	 */ | ||||
| 	private static void handlePhysics(Collision collision) { | ||||
| 		// Fuck JGLM | ||||
| 		Vec3 n = Vectors.grab3(); | ||||
| 		Vec3 v_a = Vectors.grab3(); | ||||
| 		Vec3 v_b = Vectors.grab3(); | ||||
| 		Vec3 u_n = Vectors.grab3(); | ||||
| 		Vec3 u_at = Vectors.grab3(); | ||||
| 		Vec3 u_bt = Vectors.grab3(); | ||||
| 		Vec3 du_a = Vectors.grab3(); | ||||
| 		Vec3 du_b = Vectors.grab3(); | ||||
| 		 | ||||
| 		n.set(collision.wall.getWidth()).cross(collision.wall.getHeight()).normalize(); | ||||
| 		collision.a.getCollideableVelocity(v_a); | ||||
| 		collision.b.getCollideableVelocity(v_b); | ||||
| 		 | ||||
| 		float M_a = collision.a.getCollisionMass(); | ||||
| 		float M_b = collision.b.getCollisionMass(); | ||||
| 		 | ||||
| 		float m_a, m_b; | ||||
| 		 | ||||
| 		if (Float.isFinite(M_a)) { | ||||
| 			if (Float.isFinite(M_b)) { | ||||
| 				float sum = M_a + M_b; | ||||
| 				m_a = M_a / sum; | ||||
| 				m_b = M_b / sum; | ||||
| 			} else { | ||||
| 				m_a = 0; | ||||
| 				m_b = 1; | ||||
| 			} | ||||
| 		} else { | ||||
| 			if (Float.isFinite(M_b)) { | ||||
| 				m_a = 1; | ||||
| 				m_b = 0; | ||||
| 			} else { | ||||
| 				m_a = 0.5f; | ||||
| 				m_b = 0.5f; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		u_n.set(n).mul(m_a * Vec3.dot(v_a, n) + m_b * Vec3.dot(v_b, n)); | ||||
| 		u_at.set(n).mul(Vec3.dot(v_a, n)).negate().add(v_a); | ||||
| 		u_bt.set(n).mul(Vec3.dot(v_b, n)).negate().add(v_b); | ||||
| 		du_a.set(u_n).add(u_at).sub(v_a); | ||||
| 		du_b.set(u_n).add(u_bt).sub(v_b); | ||||
| 		 | ||||
| 		collision.a.changeVelocityOnCollision(du_a); | ||||
| 		collision.b.changeVelocityOnCollision(du_b); | ||||
| 		 | ||||
| 		separate(collision, n, m_a, m_b); | ||||
| 		 | ||||
| 		// JGML is still to fuck | ||||
| 		Vectors.release(n); | ||||
| 		Vectors.release(v_a); | ||||
| 		Vectors.release(v_b); | ||||
| 		Vectors.release(u_n); | ||||
| 		Vectors.release(u_at); | ||||
| 		Vectors.release(u_bt); | ||||
| 		Vectors.release(du_a); | ||||
| 		Vectors.release(du_b); | ||||
| 	} | ||||
|  | ||||
| 	private static void separate( | ||||
| 			Collision collision, | ||||
| 			Vec3 normal, float aRelativeMass, float bRelativeMass | ||||
| 	) { | ||||
| 		final float margin = 1e-4f; | ||||
| 		 | ||||
| 		Vec3 displacement = Vectors.grab3(); | ||||
| 		 | ||||
| 		displacement.set(normal).mul(margin).mul(bRelativeMass); | ||||
| 		collision.a.moveAsCollideable(displacement); | ||||
| 		 | ||||
| 		displacement.set(normal).mul(margin).mul(aRelativeMass).negate(); | ||||
| 		collision.b.moveAsCollideable(displacement); | ||||
| 		 | ||||
| 		Vectors.release(displacement); | ||||
| 	} | ||||
|  | ||||
| 	private static void advanceTime( | ||||
| 			Collection<? extends Collideable> colls, | ||||
| 			CollisionClock clock, | ||||
| 			float step | ||||
| 	) { | ||||
| 		clock.advanceTime(step); | ||||
| 		 | ||||
| 		Vec3 tmp = Vectors.grab3(); | ||||
| 		 | ||||
| 		for (Collideable coll : colls) { | ||||
| 			coll.getCollideableVelocity(tmp); | ||||
| 			tmp.mul(step); | ||||
| 			coll.moveAsCollideable(tmp); | ||||
| 		} | ||||
| 		 | ||||
| 		Vectors.release(tmp); | ||||
| 	} | ||||
|  | ||||
| 	public static class ColliderWorkspace { | ||||
| 		 | ||||
| 		private final LowOverheadCache<Collision> collisionCache = | ||||
| 				new LowOverheadCache<>(Collision::new); | ||||
| 		 | ||||
| 		AABB dummyAABB = new AABB(0, 0, 0, 1, 1, 1); | ||||
|  | ||||
| 		Collision grab() { | ||||
| 			return collisionCache.grab(); | ||||
| 		} | ||||
|  | ||||
| 		void release(Collision object) { | ||||
| 			collisionCache.release(object); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| 	 | ||||
| 	static class Collision { | ||||
| 		public Collideable a; | ||||
| 		public Collideable b; | ||||
| 		public final CollisionWall wall = new CollisionWall(0, 0, 0, 0, 0, 0, 0, 0, 0); | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Time offset from the start of the tick. | ||||
| 		 * 0 means right now, tickLength means at the end of the tick. | ||||
| 		 */ | ||||
| 		public float time; | ||||
| 		 | ||||
| 		public Collision set(Collideable a, Collideable b, CollisionWall wall, float time) { | ||||
| 			this.a = a; | ||||
| 			this.b = b; | ||||
| 			this.wall.getOrigin().set(wall.getOrigin()); | ||||
| 			this.wall.getWidth().set(wall.getWidth()); | ||||
| 			this.wall.getHeight().set(wall.getHeight()); | ||||
| 			this.time = time; | ||||
| 			 | ||||
| 			return this; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	private Collider() {} | ||||
|  | ||||
| } | ||||
| @@ -2,7 +2,10 @@ package ru.windcorp.progressia.common.util; | ||||
|  | ||||
| import java.util.function.Consumer; | ||||
|  | ||||
| import glm.mat._4.Mat4; | ||||
| import glm.vec._3.Vec3; | ||||
| import glm.vec._3.i.Vec3i; | ||||
| import glm.vec._4.Vec4; | ||||
|  | ||||
| public class VectorUtil { | ||||
| 	 | ||||
| @@ -25,6 +28,25 @@ public class VectorUtil { | ||||
| 		Vectors.release(cursor); | ||||
| 	} | ||||
| 	 | ||||
| 	public static void applyMat4(Vec3 in, Mat4 mat, Vec3 out) { | ||||
| 		Vec4 vec4 = Vectors.grab4(); | ||||
| 		vec4.set(in, 1f); | ||||
| 		 | ||||
| 		mat.mul(vec4); | ||||
| 		 | ||||
| 		out.set(vec4.x, vec4.y, vec4.z); | ||||
| 		Vectors.release(vec4); | ||||
| 	} | ||||
| 	 | ||||
| 	public static void applyMat4(Vec3 inOut, Mat4 mat) { | ||||
| 		Vec4 vec4 = Vectors.grab4(); | ||||
| 		vec4.set(inOut, 1f); | ||||
| 		 | ||||
| 		mat.mul(vec4); | ||||
| 		 | ||||
| 		inOut.set(vec4.x, vec4.y, vec4.z); | ||||
| 	} | ||||
| 	 | ||||
| 	private VectorUtil() {} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -2,9 +2,12 @@ package ru.windcorp.progressia.common.world.entity; | ||||
|  | ||||
| import glm.vec._2.Vec2; | ||||
| import glm.vec._3.Vec3; | ||||
| import ru.windcorp.progressia.common.collision.Collideable; | ||||
| import ru.windcorp.progressia.common.collision.CollisionModel; | ||||
| import ru.windcorp.progressia.common.state.StatefulObject; | ||||
| import ru.windcorp.progressia.common.util.Vectors; | ||||
|  | ||||
| public class EntityData extends StatefulObject { | ||||
| public class EntityData extends StatefulObject implements Collideable { | ||||
| 	 | ||||
| 	private final Vec3 position = new Vec3(); | ||||
| 	private final Vec3 velocity = new Vec3(); | ||||
| @@ -13,6 +16,8 @@ public class EntityData extends StatefulObject { | ||||
| 	 | ||||
| 	private long entityId; | ||||
| 	 | ||||
| 	private CollisionModel collisionModel = null; | ||||
| 	 | ||||
| 	private double age = 0; | ||||
|  | ||||
| 	public EntityData(String namespace, String name) { | ||||
| @@ -24,7 +29,17 @@ public class EntityData extends StatefulObject { | ||||
| 	} | ||||
| 	 | ||||
| 	public void setPosition(Vec3 position) { | ||||
| 		this.position.set(position); | ||||
| 		Vec3 displacement = Vectors.grab3(); | ||||
| 		displacement.set(position).sub(getPosition()); | ||||
| 		move(displacement); | ||||
| 		Vectors.release(displacement); | ||||
| 	} | ||||
| 	 | ||||
| 	public void move(Vec3 displacement) { | ||||
| 		this.position.add(displacement); | ||||
| 		if (getCollisionModel() != null) { | ||||
| 			getCollisionModel().moveOrigin(displacement); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	public Vec3 getVelocity() { | ||||
| @@ -71,4 +86,38 @@ public class EntityData extends StatefulObject { | ||||
| 		this.age += increment; | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public CollisionModel getCollisionModel() { | ||||
| 		return collisionModel; | ||||
| 	} | ||||
| 	 | ||||
| 	public void setCollisionModel(CollisionModel collisionModel) { | ||||
| 		this.collisionModel = collisionModel; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public boolean onCollision(Collideable other) { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public float getCollisionMass() { | ||||
| 		return 1.0f; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void moveAsCollideable(Vec3 displacement) { | ||||
| 		move(displacement); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void getCollideableVelocity(Vec3 output) { | ||||
| 		output.set(getVelocity()); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public void changeVelocityOnCollision(Vec3 velocityChange) { | ||||
| 		getVelocity().add(velocityChange); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
							
								
								
									
										20
									
								
								src/main/java/ru/windcorp/progressia/test/AABBRenderer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/main/java/ru/windcorp/progressia/test/AABBRenderer.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| package ru.windcorp.progressia.test; | ||||
|  | ||||
| import ru.windcorp.progressia.client.graphics.model.Shape; | ||||
| import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; | ||||
| import ru.windcorp.progressia.client.graphics.model.Shapes; | ||||
| import ru.windcorp.progressia.client.graphics.texture.Texture; | ||||
| import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; | ||||
| import ru.windcorp.progressia.common.collision.AABB; | ||||
|  | ||||
| public class AABBRenderer { | ||||
| 	 | ||||
| 	private static final Shape CUBE = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null).setColorMultiplier(1.0f, 0.7f, 0.2f).create(); | ||||
| 	 | ||||
| 	public static void renderAABB(AABB aabb, ShapeRenderHelper helper) { | ||||
| 		helper.pushTransform().translate(aabb.getOrigin()).scale(aabb.getSize()); | ||||
| 		CUBE.render(helper); | ||||
| 		helper.popTransform(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -3,6 +3,8 @@ package ru.windcorp.progressia.test; | ||||
| import static ru.windcorp.progressia.client.world.block.BlockRenderRegistry.getBlockTexture; | ||||
| import static ru.windcorp.progressia.client.world.tile.TileRenderRegistry.getTileTexture; | ||||
|  | ||||
| import java.util.function.Consumer; | ||||
|  | ||||
| import org.lwjgl.glfw.GLFW; | ||||
|  | ||||
| import glm.vec._3.i.Vec3i; | ||||
| @@ -11,6 +13,7 @@ import ru.windcorp.progressia.client.graphics.input.KeyMatcher; | ||||
| import ru.windcorp.progressia.client.world.block.*; | ||||
| import ru.windcorp.progressia.client.world.entity.*; | ||||
| import ru.windcorp.progressia.client.world.tile.*; | ||||
| import ru.windcorp.progressia.common.collision.AABB; | ||||
| import ru.windcorp.progressia.common.comms.controls.*; | ||||
| import ru.windcorp.progressia.common.state.StatefulObjectRegistry.Factory; | ||||
| import ru.windcorp.progressia.common.world.ChunkData; | ||||
| @@ -78,7 +81,7 @@ public class TestContent { | ||||
| 	} | ||||
|  | ||||
| 	private static void registerEntities() { | ||||
| 		registerEntityData("Test", "Javapony"); | ||||
| 		registerEntityData("Test", "Javapony", e -> e.setCollisionModel(new AABB(0, 0, -0.05f, 0.75f, 0.75f, 1.2f))); | ||||
| 		register(new TestEntityRenderJavapony()); | ||||
| 		register(new EntityLogic("Test", "Javapony")); | ||||
| 		 | ||||
| @@ -125,9 +128,17 @@ public class TestContent { | ||||
| 	} | ||||
| 	 | ||||
| 	private static void registerEntityData( | ||||
| 			String namespace, String name | ||||
| 			String namespace, String name, | ||||
| 			Consumer<EntityData> transform | ||||
| 	) { | ||||
| 		EntityDataRegistry.getInstance().register(namespace, name); | ||||
| 		EntityDataRegistry.getInstance().register(namespace, name, new Factory<EntityData>() { | ||||
| 			@Override | ||||
| 			public EntityData build() { | ||||
| 				EntityData entity = new EntityData(namespace, name); | ||||
| 				transform.accept(entity); | ||||
| 				return entity; | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 	 | ||||
| 	private static void register(BlockRender x) { | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package ru.windcorp.progressia.test; | ||||
|  | ||||
| import ru.windcorp.progressia.common.collision.AABB; | ||||
| import ru.windcorp.progressia.common.state.IntStateField; | ||||
| import ru.windcorp.progressia.common.world.entity.EntityData; | ||||
|  | ||||
| @@ -10,6 +11,7 @@ public class TestEntityDataStatie extends EntityData { | ||||
|  | ||||
| 	public TestEntityDataStatie() { | ||||
| 		super("Test", "Statie"); | ||||
| 		setCollisionModel(new AABB(0, 0, 0, 16f/24, 16f/24, 16f/24)); | ||||
| 		setSizeNow(16); | ||||
| 	} | ||||
| 	 | ||||
| @@ -21,4 +23,9 @@ public class TestEntityDataStatie extends EntityData { | ||||
| 		this.size.setNow(this, size); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public float getCollisionMass() { | ||||
| 		return 50f; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user