diff --git a/engine/Vector.ts b/engine/Vector.ts index 36bfb0a..c902940 100644 --- a/engine/Vector.ts +++ b/engine/Vector.ts @@ -14,14 +14,14 @@ export function copyVector(vector: Vector): Vector { }; } -export function fromPolar(direction: number, magnitude: number): Vector { +export function fromPolar(angle: number, magnitude: number): Vector { return { - x: Math.cos(direction) * magnitude, - y: Math.sin(direction) * magnitude, + x: Math.cos(angle) * magnitude, + y: Math.sin(angle) * magnitude, }; } -export function getDirection(vector: Vector): number { +export function getAngle(vector: Vector): number { return Math.atan2(vector.y, vector.x); } diff --git a/engine/system/physics.ts b/engine/system/physics.ts new file mode 100644 index 0000000..f65108e --- /dev/null +++ b/engine/system/physics.ts @@ -0,0 +1,115 @@ +import type { Circle } from "#/engine/Circle.ts"; +import type { Polygon } from "#/engine/Polygon.ts"; +import type { Rect } from "#/engine/Rect.ts"; +import $ from "#/engine/Scene.ts"; +import { createVector, type Vector } from "#/engine/Vector.ts"; + +export enum Shape { + Cirle, + Rect, + Polygon, +} + +const CIRCLE = Shape.Cirle; +const RECT = Shape.Rect; +const POLYGON = Shape.Polygon; + +type ShapeType = Shape.Cirle | Shape.Rect | Shape.Polygon; + +type CollisionBuffer = { + size: number; + mask: number; + cursor: number; + pool: Array; + slice: Array; +}; + +function createCollisionBuffer(size: number): CollisionBuffer { + if ((size & (size - 1)) !== 0) { + throw new Error("size must be a power of two"); + } + + const pool: Array = []; + for (let i = 0; i < size; i++) { + pool.push(createCollision()); + } + + return { + size, + mask: size - 1, + cursor: 0, + pool, + slice: [], + }; +} + +function bufferNext(buffer: CollisionBuffer): Collision { + return buffer.pool[buffer.cursor++ & buffer.mask]; +} + +function bufferSliceReset(buffer: CollisionBuffer): void { + buffer.slice.length = 0; +} + +function bufferSliceAdd(buffer: CollisionBuffer): Collision { + const next = bufferNext(buffer); + buffer.slice.push(next); + + return next; +} + +export type Collider = { + shape: ShapeType; + body: Circle | Rect | Polygon; + buffer: CollisionBuffer; +}; + +export type Collision = { + cid: string; + normal: Vector; + position: Vector; + depth: 0; + angle: 0; +}; + +function createCollision(): Collision { + return { + cid: "", + normal: createVector(), + position: createVector(), + depth: 0, + angle: 0, + }; +} + +export function createCollider( + shape: ShapeType, + body: Circle | Rect | Polygon, + bufferSize: number = 8, +): Collider { + return { + shape, + body, + buffer: createCollisionBuffer(bufferSize), + }; +} + +export function moveAndCollide( + id: string, + velocity: Vector, + delta: number, +): Array { + const colliders = $("collider")!; + const self = colliders.get(id)!.value; + bufferSliceReset(self.buffer); + + for (const [cid, _] of colliders.entries()) { + if (cid === id) { + continue; + } + const collisoin = bufferSliceAdd(self.buffer); + collisoin.cid = cid; + } + + return self.buffer.slice; +} diff --git a/engine/system/processPhysics.ts b/engine/system/processPhysics.ts deleted file mode 100644 index f77ea1e..0000000 --- a/engine/system/processPhysics.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { Circle } from "#/engine/Circle.ts"; -import type MapProxy from "#/engine/lib/MapProxy.ts"; -import RingBuffer from "#/engine/lib/RingBuffer.ts"; -import type { Polygon } from "#/engine/Polygon.ts"; -import type { Rect } from "#/engine/Rect.ts"; -import $ from "#/engine/Scene.ts"; -import { createVector, type Vector } from "#/engine/Vector.ts"; - -const CIRCLE = 0; -const RECT = 1; -const POLYGON = 2; - -type Shape = 0 | 1 | 2; - -export type Collider = { - shape: Shape; - collision: Collision; -}; - -export type Collision = { - id: string; -}; - -export function createCollider(shape: Shape): Collider { - return { - shape, - collision: { id: "" }, - }; -} - -const collisions = new RingBuffer(128, { - id: "", - normal: createVector(), -}); - -export function moveAndCollide( - id: string, - velocity: Vector, - delta: number, -): void { - const colliders = $("collider")!; - - for (const [oid, _] of colliders.entries()) { - if (oid === id) { - continue; - } - - const self = colliders.get(id)!.value; - self.collision.id = oid; - } -} diff --git a/game/entities/hero/entity.ts b/game/entities/hero/entity.ts index 03aa6f0..78a8e4f 100644 --- a/game/entities/hero/entity.ts +++ b/game/entities/hero/entity.ts @@ -9,10 +9,10 @@ import { defineSpriteSheet, } from "#/engine/Sprite.ts"; import { - type Collider, createCollider, moveAndCollide, -} from "#/engine/system/processPhysics.ts"; + Shape, +} from "#/engine/system/physics.ts"; import { createVector, type Vector } from "#/engine/Vector.ts"; import charIdle from "#/game/assets/char-idle.png"; @@ -24,13 +24,12 @@ const process = defineEntity("hero", { sprite: createSprite(idleSrc), animation: createSpriteAnimation(500, 2), velocity: createVector(), - collider: createCollider(0), + collider: createCollider(Shape.Cirle, createCircle(createVector(), 8)), }); process((id, delta) => { const position = $("position").get(id)!.value; const velocity = $("velocity").get(id)!.value; - const collider = $("collider").get(id)!.value; if (pointer.isDown) { position.x = pointer.position.x; @@ -48,6 +47,6 @@ process((id, delta) => { velocity.x = 0; velocity.y = 0; - moveAndCollide(id, velocity, delta); - console.log(collider.collision.id); + const collisions = moveAndCollide(id, velocity, delta); + console.log(collisions); }); diff --git a/game/entities/portal/entity.ts b/game/entities/portal/entity.ts index 2524113..2c7b0f0 100644 --- a/game/entities/portal/entity.ts +++ b/game/entities/portal/entity.ts @@ -5,7 +5,7 @@ import { createSpriteAnimation, defineSpriteSheet, } from "#/engine/Sprite.ts"; -import { createCollider } from "#/engine/system/processPhysics.ts"; +import { createCollider, Shape } from "#/engine/system/physics.ts"; import { createVector } from "#/engine/Vector.ts"; import portal from "#/game/assets/portal.png"; @@ -15,5 +15,5 @@ defineEntity("portal", { position: createVector(), sprite: createSprite(portalSrc), animation: createSpriteAnimation(400, 0), - collider: createCollider(0), + collider: createCollider(Shape.Cirle, createCircle(createVector(), 8)), });