summaryrefslogtreecommitdiff
path: root/engine/components
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2023-07-20 20:47:32 -0700
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2023-07-20 20:47:32 -0700
commit72c6c7de12e9833f52bf2d0718d70f044f8ab57e (patch)
tree152f5f31d59011bb8c617bfbcfc44cc8f47ecad5 /engine/components
parent0fd9fb097552686f2257c1aa689d797e80057bd1 (diff)
downloadjumpstorm-72c6c7de12e9833f52bf2d0718d70f044f8ab57e.tar.gz
jumpstorm-72c6c7de12e9833f52bf2d0718d70f044f8ab57e.zip
a bit of refactoring; importing engine into bun for server
Diffstat (limited to 'engine/components')
-rw-r--r--engine/components/BoundingBox.ts97
-rw-r--r--engine/components/Collide.ts7
-rw-r--r--engine/components/Component.ts7
-rw-r--r--engine/components/Control.ts7
-rw-r--r--engine/components/FacingDirection.ts13
-rw-r--r--engine/components/Forces.ts17
-rw-r--r--engine/components/Gravity.ts13
-rw-r--r--engine/components/Jump.ts10
-rw-r--r--engine/components/Mass.ts10
-rw-r--r--engine/components/Moment.ts10
-rw-r--r--engine/components/Sprite.ts92
-rw-r--r--engine/components/TopCollidable.ts7
-rw-r--r--engine/components/Velocity.ts15
-rw-r--r--engine/components/WallBounded.ts7
-rw-r--r--engine/components/index.ts15
-rw-r--r--engine/components/names.ts15
16 files changed, 342 insertions, 0 deletions
diff --git a/engine/components/BoundingBox.ts b/engine/components/BoundingBox.ts
new file mode 100644
index 0000000..2b1d648
--- /dev/null
+++ b/engine/components/BoundingBox.ts
@@ -0,0 +1,97 @@
+import { Component, ComponentNames } from ".";
+import type { Coord2D, Dimension2D } from "../interfaces";
+import { dotProduct, rotateVector, normalizeVector } from "../utils";
+
+export class BoundingBox extends Component {
+ public center: Coord2D;
+ public dimension: Dimension2D;
+ public rotation: number;
+
+ constructor(center: Coord2D, dimension: Dimension2D, rotation?: number) {
+ super(ComponentNames.BoundingBox);
+
+ this.center = center;
+ this.dimension = dimension;
+ this.rotation = rotation ?? 0;
+ }
+
+ public isCollidingWith(box: BoundingBox): boolean {
+ const boxes = [this.getVertices(), box.getVertices()];
+ for (const poly of boxes) {
+ for (let i = 0; i < poly.length; ++i) {
+ const [A, B] = [poly[i], poly[(i + 1) % poly.length]];
+ const normal: Coord2D = { x: B.y - A.y, y: A.x - B.x };
+
+ const [[minThis, maxThis], [minBox, maxBox]] = boxes.map((box) =>
+ box.reduce(
+ ([min, max], vertex) => {
+ const projection = dotProduct(normal, vertex);
+ return [Math.min(min, projection), Math.max(max, projection)];
+ },
+ [Infinity, -Infinity]
+ )
+ );
+
+ if (maxThis < minBox || maxBox < minThis) return false;
+ }
+ }
+
+ return true;
+ }
+
+ public getVertices(): Coord2D[] {
+ return [
+ { x: -this.dimension.width / 2, y: -this.dimension.height / 2 },
+ { x: -this.dimension.width / 2, y: this.dimension.height / 2 },
+ { x: this.dimension.width / 2, y: this.dimension.height / 2 },
+ { x: this.dimension.width / 2, y: -this.dimension.height / 2 },
+ ]
+ .map((vertex) => rotateVector(vertex, this.rotation))
+ .map((vertex) => {
+ return {
+ x: vertex.x + this.center.x,
+ y: vertex.y + this.center.y,
+ };
+ });
+ }
+
+ private getAxes() {
+ const corners: Coord2D[] = this.getVerticesRelativeToCenter();
+ const axes: Coord2D[] = [];
+
+ for (let i = 0; i < corners.length; ++i) {
+ const [cornerA, cornerB] = [
+ corners[i],
+ corners[(i + 1) % corners.length],
+ ].map((corner) => rotateVector(corner, this.rotation));
+
+ axes.push(
+ normalizeVector({
+ x: cornerB.y - cornerA.y,
+ y: -(cornerB.x - cornerA.x),
+ })
+ );
+ }
+
+ return axes;
+ }
+
+ private project(axis: Coord2D): [number, number] {
+ const corners = this.getCornersRelativeToCenter();
+ let [min, max] = [Infinity, -Infinity];
+
+ for (const corner of corners) {
+ const rotated = rotateVector(corner, this.rotation);
+ const translated = {
+ x: rotated.x + this.center.x,
+ y: rotated.y + this.center.y,
+ };
+ const projection = dotProduct(translated, axis);
+
+ min = Math.min(projection, min);
+ max = Math.max(projection, max);
+ }
+
+ return [min, max];
+ }
+}
diff --git a/engine/components/Collide.ts b/engine/components/Collide.ts
new file mode 100644
index 0000000..889ecf8
--- /dev/null
+++ b/engine/components/Collide.ts
@@ -0,0 +1,7 @@
+import { Component, ComponentNames } from ".";
+
+export class Collide extends Component {
+ constructor() {
+ super(ComponentNames.Collide);
+ }
+}
diff --git a/engine/components/Component.ts b/engine/components/Component.ts
new file mode 100644
index 0000000..7331982
--- /dev/null
+++ b/engine/components/Component.ts
@@ -0,0 +1,7 @@
+export abstract class Component {
+ public readonly name: string;
+
+ constructor(name: string) {
+ this.name = name;
+ }
+}
diff --git a/engine/components/Control.ts b/engine/components/Control.ts
new file mode 100644
index 0000000..094ef1c
--- /dev/null
+++ b/engine/components/Control.ts
@@ -0,0 +1,7 @@
+import { Component, ComponentNames } from ".";
+
+export class Control extends Component {
+ constructor() {
+ super(ComponentNames.Control);
+ }
+}
diff --git a/engine/components/FacingDirection.ts b/engine/components/FacingDirection.ts
new file mode 100644
index 0000000..1c701a3
--- /dev/null
+++ b/engine/components/FacingDirection.ts
@@ -0,0 +1,13 @@
+import { Component, ComponentNames, Sprite } from ".";
+
+export class FacingDirection extends Component {
+ public readonly facingLeftSprite: Sprite;
+ public readonly facingRightSprite: Sprite;
+
+ constructor(facingLeftSprite: Sprite, facingRightSprite: Sprite) {
+ super(ComponentNames.FacingDirection);
+
+ this.facingLeftSprite = facingLeftSprite;
+ this.facingRightSprite = facingRightSprite;
+ }
+}
diff --git a/engine/components/Forces.ts b/engine/components/Forces.ts
new file mode 100644
index 0000000..bf540a1
--- /dev/null
+++ b/engine/components/Forces.ts
@@ -0,0 +1,17 @@
+import type { Accel2D, Force2D } from "../interfaces";
+import { Component } from "./Component";
+import { ComponentNames } from ".";
+
+/**
+ * A list of forces and torque, (in newtons, and newton-meters respectively)
+ * to apply on one Physics system update (after which, they are cleared).
+ */
+export class Forces extends Component {
+ public forces: Force2D[];
+
+ constructor(forces?: Force2D[]) {
+ super(ComponentNames.Forces);
+
+ this.forces = forces ?? [];
+ }
+}
diff --git a/engine/components/Gravity.ts b/engine/components/Gravity.ts
new file mode 100644
index 0000000..89fcb67
--- /dev/null
+++ b/engine/components/Gravity.ts
@@ -0,0 +1,13 @@
+import { ComponentNames, Component } from ".";
+
+export class Gravity extends Component {
+ private static DEFAULT_TERMINAL_VELOCITY = 5;
+
+ public terminalVelocity: number;
+
+ constructor(terminalVelocity?: number) {
+ super(ComponentNames.Gravity);
+ this.terminalVelocity =
+ terminalVelocity ?? Gravity.DEFAULT_TERMINAL_VELOCITY;
+ }
+}
diff --git a/engine/components/Jump.ts b/engine/components/Jump.ts
new file mode 100644
index 0000000..0b40767
--- /dev/null
+++ b/engine/components/Jump.ts
@@ -0,0 +1,10 @@
+import { Component, ComponentNames } from ".";
+
+export class Jump extends Component {
+ public canJump: boolean;
+
+ constructor() {
+ super(ComponentNames.Jump);
+ this.canJump = false;
+ }
+}
diff --git a/engine/components/Mass.ts b/engine/components/Mass.ts
new file mode 100644
index 0000000..daa2d71
--- /dev/null
+++ b/engine/components/Mass.ts
@@ -0,0 +1,10 @@
+import { Component, ComponentNames } from ".";
+
+export class Mass extends Component {
+ public mass: number;
+
+ constructor(mass: number) {
+ super(ComponentNames.Mass);
+ this.mass = mass;
+ }
+}
diff --git a/engine/components/Moment.ts b/engine/components/Moment.ts
new file mode 100644
index 0000000..3d0dd2f
--- /dev/null
+++ b/engine/components/Moment.ts
@@ -0,0 +1,10 @@
+import { Component, ComponentNames } from ".";
+
+export class Moment extends Component {
+ public inertia: number;
+
+ constructor(inertia: number) {
+ super(ComponentNames.Moment);
+ this.inertia = inertia;
+ }
+}
diff --git a/engine/components/Sprite.ts b/engine/components/Sprite.ts
new file mode 100644
index 0000000..90e1389
--- /dev/null
+++ b/engine/components/Sprite.ts
@@ -0,0 +1,92 @@
+import { Component, ComponentNames } from ".";
+import type { Dimension2D, DrawArgs, Coord2D } from "../interfaces";
+
+export class Sprite extends Component {
+ private sheet: HTMLImageElement;
+
+ private spriteImgPos: Coord2D;
+ private spriteImgDimensions: Dimension2D;
+
+ private msPerFrame: number;
+ private msSinceLastFrame: number;
+ private currentFrame: number;
+ private numFrames: number;
+
+ constructor(
+ sheet: HTMLImageElement,
+ spriteImgPos: Coord2D,
+ spriteImgDimensions: Dimension2D,
+ msPerFrame: number,
+ numFrames: number
+ ) {
+ super(ComponentNames.Sprite);
+
+ this.sheet = sheet;
+ this.spriteImgPos = spriteImgPos;
+ this.spriteImgDimensions = spriteImgDimensions;
+ this.msPerFrame = msPerFrame;
+ this.numFrames = numFrames;
+
+ this.msSinceLastFrame = 0;
+ this.currentFrame = 0;
+ }
+
+ public update(dt: number) {
+ this.msSinceLastFrame += dt;
+ if (this.msSinceLastFrame >= this.msPerFrame) {
+ this.currentFrame = (this.currentFrame + 1) % this.numFrames;
+ this.msSinceLastFrame = 0;
+ }
+ }
+
+ public draw(ctx: CanvasRenderingContext2D, drawArgs: DrawArgs) {
+ const { center, rotation, tint, opacity } = drawArgs;
+
+ ctx.save();
+ ctx.translate(center.x, center.y);
+ if (rotation != 0) {
+ ctx.rotate(rotation * (Math.PI / 180));
+ }
+ ctx.translate(-center.x, -center.y);
+
+ if (opacity) {
+ ctx.globalAlpha = opacity;
+ }
+
+ ctx.drawImage(
+ this.sheet,
+ ...this.getSpriteArgs(),
+ ...this.getDrawArgs(drawArgs)
+ );
+
+ if (tint) {
+ ctx.globalAlpha = 0.5;
+ ctx.globalCompositeOperation = "source-atop";
+ ctx.fillStyle = tint;
+ ctx.fillRect(...this.getDrawArgs(drawArgs));
+ }
+
+ ctx.restore();
+ }
+
+ private getSpriteArgs(): [sx: number, sy: number, sw: number, sh: number] {
+ return [
+ this.spriteImgPos.x + this.currentFrame * this.spriteImgDimensions.width,
+ this.spriteImgPos.y,
+ this.spriteImgDimensions.width,
+ this.spriteImgDimensions.height,
+ ];
+ }
+
+ private getDrawArgs({
+ center,
+ dimension,
+ }: DrawArgs): [dx: number, dy: number, dw: number, dh: number] {
+ return [
+ center.x - dimension.width / 2,
+ center.y - dimension.height / 2,
+ dimension.width,
+ dimension.height,
+ ];
+ }
+}
diff --git a/engine/components/TopCollidable.ts b/engine/components/TopCollidable.ts
new file mode 100644
index 0000000..7fb147d
--- /dev/null
+++ b/engine/components/TopCollidable.ts
@@ -0,0 +1,7 @@
+import { Component, ComponentNames } from ".";
+
+export class TopCollidable extends Component {
+ constructor() {
+ super(ComponentNames.TopCollidable);
+ }
+}
diff --git a/engine/components/Velocity.ts b/engine/components/Velocity.ts
new file mode 100644
index 0000000..119427d
--- /dev/null
+++ b/engine/components/Velocity.ts
@@ -0,0 +1,15 @@
+import type { Velocity2D } from "../interfaces";
+import { Component } from "./Component";
+import { ComponentNames } from ".";
+
+export class Velocity extends Component {
+ public dCartesian: Velocity2D;
+ public dTheta: number;
+
+ constructor(dCartesian: Velocity2D, dTheta: number) {
+ super(ComponentNames.Velocity);
+
+ this.dCartesian = dCartesian;
+ this.dTheta = dTheta;
+ }
+}
diff --git a/engine/components/WallBounded.ts b/engine/components/WallBounded.ts
new file mode 100644
index 0000000..5f787e1
--- /dev/null
+++ b/engine/components/WallBounded.ts
@@ -0,0 +1,7 @@
+import { Component, ComponentNames } from ".";
+
+export class WallBounded extends Component {
+ constructor() {
+ super(ComponentNames.WallBounded);
+ }
+}
diff --git a/engine/components/index.ts b/engine/components/index.ts
new file mode 100644
index 0000000..67f1259
--- /dev/null
+++ b/engine/components/index.ts
@@ -0,0 +1,15 @@
+export * from "./Component";
+export * from "./BoundingBox";
+export * from "./Velocity";
+export * from "./Forces";
+export * from "./Sprite";
+export * from "./FacingDirection";
+export * from "./Jump";
+export * from "./TopCollidable";
+export * from "./Collide";
+export * from "./Control";
+export * from "./WallBounded";
+export * from "./Gravity";
+export * from "./Mass";
+export * from "./Moment";
+export * from "./names";
diff --git a/engine/components/names.ts b/engine/components/names.ts
new file mode 100644
index 0000000..e2ee3d3
--- /dev/null
+++ b/engine/components/names.ts
@@ -0,0 +1,15 @@
+export namespace ComponentNames {
+ export const Sprite = "Sprite";
+ export const BoundingBox = "BoundingBox";
+ export const Velocity = "Velocity";
+ export const FacingDirection = "FacingDirection";
+ export const Control = "Control";
+ export const Jump = "Jump";
+ export const TopCollidable = "TopCollidable";
+ export const Collide = "Collide";
+ export const WallBounded = "WallBounded";
+ export const Gravity = "Gravity";
+ export const Forces = "Forces";
+ export const Mass = "Mass";
+ export const Moment = "Moment";
+}