diff options
author | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2023-07-20 20:47:32 -0700 |
---|---|---|
committer | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2023-07-20 20:47:32 -0700 |
commit | 72c6c7de12e9833f52bf2d0718d70f044f8ab57e (patch) | |
tree | 152f5f31d59011bb8c617bfbcfc44cc8f47ecad5 /engine/components | |
parent | 0fd9fb097552686f2257c1aa689d797e80057bd1 (diff) | |
download | jumpstorm-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.ts | 97 | ||||
-rw-r--r-- | engine/components/Collide.ts | 7 | ||||
-rw-r--r-- | engine/components/Component.ts | 7 | ||||
-rw-r--r-- | engine/components/Control.ts | 7 | ||||
-rw-r--r-- | engine/components/FacingDirection.ts | 13 | ||||
-rw-r--r-- | engine/components/Forces.ts | 17 | ||||
-rw-r--r-- | engine/components/Gravity.ts | 13 | ||||
-rw-r--r-- | engine/components/Jump.ts | 10 | ||||
-rw-r--r-- | engine/components/Mass.ts | 10 | ||||
-rw-r--r-- | engine/components/Moment.ts | 10 | ||||
-rw-r--r-- | engine/components/Sprite.ts | 92 | ||||
-rw-r--r-- | engine/components/TopCollidable.ts | 7 | ||||
-rw-r--r-- | engine/components/Velocity.ts | 15 | ||||
-rw-r--r-- | engine/components/WallBounded.ts | 7 | ||||
-rw-r--r-- | engine/components/index.ts | 15 | ||||
-rw-r--r-- | engine/components/names.ts | 15 |
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"; +} |