summaryrefslogtreecommitdiff
path: root/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics
diff options
context:
space:
mode:
Diffstat (limited to 'composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics')
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/CollisionTick.kt28
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/Components.kt15
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/IntegrationTick.kt27
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/PhysicsSystem.kt26
4 files changed, 96 insertions, 0 deletions
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/CollisionTick.kt b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/CollisionTick.kt
new file mode 100644
index 0000000..bc34ac1
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/CollisionTick.kt
@@ -0,0 +1,28 @@
+package coffee.liz.ecs.physics
+
+import coffee.liz.ecs.Rect
+import coffee.liz.ecs.World
+
+internal class CollisionTick<Outside>(
+ private val collisionResolver: CollisionResolver<Outside>
+) {
+ fun runTick(world: World<Outside>) {
+ // Eh, fast enough for now. Don't need to do any fancy collision detection. There's always later to improve if
+ // it's that bad.
+ world.query(Collidable::class, Position::class).forEach { a ->
+ world.query(Collidable::class, Position::class).forEach { b ->
+ val aHitBoxes = a.get(Position::class).let { pos -> a.get(Collidable::class).hitboxes.map {
+ Rect(pos.vec2, it.dimensions)
+ }}
+ val bHitBoxes = b.get(Position::class).let { pos -> b.get(Collidable::class).hitboxes.map {
+ Rect(pos.vec2, it.dimensions)
+ }}
+
+ val collisionDetected = aHitBoxes.any { a -> bHitBoxes.any { b -> a.overlaps(b) } }
+ if (collisionDetected) {
+ collisionResolver.resolveCollision(world, a, b)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/Components.kt b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/Components.kt
new file mode 100644
index 0000000..ffae10b
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/Components.kt
@@ -0,0 +1,15 @@
+package coffee.liz.ecs.physics
+
+import coffee.liz.ecs.Component
+import coffee.liz.ecs.Rect
+import coffee.liz.ecs.Vec2
+
+data class Position(val vec2: Vec2): Component
+data class Velocity(val vec2: Vec2) : Component
+data class Acceleration(val vec2: Vec2) : Component
+
+/**
+ * @param hitboxes a collection of hitboxes to check collisions against relative to [Rect.topLeft] as the top left of
+ * [Position].
+ */
+data class Collidable(val hitboxes: Collection<Rect>): Component
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/IntegrationTick.kt b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/IntegrationTick.kt
new file mode 100644
index 0000000..03af835
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/IntegrationTick.kt
@@ -0,0 +1,27 @@
+package coffee.liz.ecs.physics
+
+import coffee.liz.ecs.World
+
+internal class IntegrationTick<Outside> {
+ fun runTick(world: World<Outside>) {
+ world.query(Velocity::class, Acceleration::class).forEach { entity ->
+ val velocity = entity.get(Velocity::class)
+ val acceleration = entity.get(Acceleration::class)
+ entity.add(
+ Velocity(
+ vec2 = velocity.vec2.plus(acceleration.vec2)
+ )
+ )
+ }
+
+ world.query(Position::class, Velocity::class).forEach { entity ->
+ val position = entity.get(Position::class)
+ val velocity = entity.get(Acceleration::class)
+ entity.add(
+ Position(
+ vec2 = position.vec2.plus(velocity.vec2)
+ )
+ )
+ }
+ }
+} \ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/PhysicsSystem.kt b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/PhysicsSystem.kt
new file mode 100644
index 0000000..703e614
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/ecs/physics/PhysicsSystem.kt
@@ -0,0 +1,26 @@
+package coffee.liz.ecs.physics
+
+import coffee.liz.ecs.Entity
+import coffee.liz.ecs.TickedSystem
+import coffee.liz.ecs.World
+import kotlin.time.Duration
+
+internal fun interface CollisionResolver<Outside> {
+ fun resolveCollision(world: World<Outside>, a: Entity, b: Entity)
+}
+
+abstract class PhysicsSystem<Outside>(
+ physicsTickRate: Duration
+): TickedSystem<Outside>(physicsTickRate), CollisionResolver<Outside> {
+ private val integrationTick = IntegrationTick<Outside>()
+ private val collisionTick = CollisionTick(this)
+
+ abstract override fun resolveCollision(world: World<Outside>, a: Entity, b: Entity)
+
+ override fun update(world: World<Outside>, state: Outside, ticks: Int) {
+ for (tick in 1..ticks) {
+ collisionTick.runTick(world)
+ integrationTick.runTick(world)
+ }
+ }
+} \ No newline at end of file