From 006ab3c4e6e414fed5550230b3c54e416d2f7c7d Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Sun, 16 Aug 2020 10:24:12 +0200 Subject: [PATCH] Refactor shapes --- .../drawing/drawables/drawable-tunnel.ts | 26 +++++ .../scripts/drawing/drawables/i-drawable.ts | 7 +- .../drawing/drawables/lights/circle-light.ts | 15 +-- .../drawing/drawables/lights/i-light.ts | 1 + .../drawing/drawables/lights/point-light.ts | 7 -- .../drawing/drawables/primitives/circle.ts | 47 --------- .../drawables/primitives/i-primitive.ts | 5 - .../drawables/primitives/tunnel-shape.ts | 99 ------------------- frontend/src/scripts/drawing/i-renderer.ts | 4 +- .../drawing/rendering/rendering-pass.ts | 2 +- .../drawing/rendering/webgl2-renderer.ts | 23 ++--- frontend/src/scripts/objects/types/camera.ts | 2 +- .../src/scripts/objects/types/character.ts | 8 +- frontend/src/scripts/objects/types/tunnel.ts | 13 ++- .../physics/containers/bounding-box-list.ts | 2 +- .../physics/containers/bounding-box-tree.ts | 18 +--- .../containers/immutable-bounding-box.ts | 14 --- frontend/src/scripts/physics/physics.ts | 4 +- .../bounding-box-base.ts | 12 +-- .../containers => shapes}/bounding-box.ts | 29 +++--- frontend/src/scripts/shapes/i-shape.ts | 12 +++ .../scripts/shapes/immutable-bounding-box.ts | 3 + frontend/src/scripts/shapes/types/circle.ts | 41 ++++++++ .../src/scripts/shapes/types/tunnel-shape.ts | 65 ++++++++++++ 24 files changed, 203 insertions(+), 256 deletions(-) create mode 100644 frontend/src/scripts/drawing/drawables/drawable-tunnel.ts delete mode 100644 frontend/src/scripts/drawing/drawables/primitives/circle.ts delete mode 100644 frontend/src/scripts/drawing/drawables/primitives/i-primitive.ts delete mode 100644 frontend/src/scripts/drawing/drawables/primitives/tunnel-shape.ts delete mode 100644 frontend/src/scripts/physics/containers/immutable-bounding-box.ts rename frontend/src/scripts/{physics/containers => shapes}/bounding-box-base.ts (80%) rename frontend/src/scripts/{physics/containers => shapes}/bounding-box.ts (68%) create mode 100644 frontend/src/scripts/shapes/i-shape.ts create mode 100644 frontend/src/scripts/shapes/immutable-bounding-box.ts create mode 100644 frontend/src/scripts/shapes/types/circle.ts create mode 100644 frontend/src/scripts/shapes/types/tunnel-shape.ts diff --git a/frontend/src/scripts/drawing/drawables/drawable-tunnel.ts b/frontend/src/scripts/drawing/drawables/drawable-tunnel.ts new file mode 100644 index 0000000..7c656d8 --- /dev/null +++ b/frontend/src/scripts/drawing/drawables/drawable-tunnel.ts @@ -0,0 +1,26 @@ +import { IDrawable } from './i-drawable'; +import { TunnelShape } from '../../shapes/types/tunnel-shape'; +import { IDrawableDescriptor } from './i-drawable-descriptor'; +import { settings } from '../settings'; + +export class DrawableTunnel extends TunnelShape implements IDrawable { + public static descriptor: IDrawableDescriptor = { + uniformName: 'lines', + countMacroName: 'lineCount', + shaderCombinationSteps: settings.shaderCombinations.lineSteps, + }; + + public serializeToUniforms(uniforms: any): void { + const uniformName = DrawableTunnel.descriptor.uniformName; + if (!uniforms.hasOwnProperty(uniformName)) { + uniforms[uniformName] = []; + } + + uniforms[uniformName].push({ + from: this.from, + toFromDelta: this.toFromDelta, + fromRadius: this.fromRadius, + toRadius: this.toRadius, + }); + } +} diff --git a/frontend/src/scripts/drawing/drawables/i-drawable.ts b/frontend/src/scripts/drawing/drawables/i-drawable.ts index 70d2618..beb84a8 100644 --- a/frontend/src/scripts/drawing/drawables/i-drawable.ts +++ b/frontend/src/scripts/drawing/drawables/i-drawable.ts @@ -1,11 +1,6 @@ import { vec2 } from 'gl-matrix'; -import { ImmutableBoundingBox } from '../../physics/containers/immutable-bounding-box'; -import { GameObject } from '../../objects/game-object'; export interface IDrawable { - serializeToUniforms(uniforms: any): void; distance(target: vec2): number; - minimumDistance(target: vec2): number; - readonly owner: GameObject; - readonly boundingBox: ImmutableBoundingBox; + serializeToUniforms(uniforms: any): void; } diff --git a/frontend/src/scripts/drawing/drawables/lights/circle-light.ts b/frontend/src/scripts/drawing/drawables/lights/circle-light.ts index 66913d0..7e1c678 100644 --- a/frontend/src/scripts/drawing/drawables/lights/circle-light.ts +++ b/frontend/src/scripts/drawing/drawables/lights/circle-light.ts @@ -1,6 +1,5 @@ import { vec2, vec3 } from 'gl-matrix'; import { GameObject } from '../../../objects/game-object'; -import { ImmutableBoundingBox } from '../../../physics/containers/immutable-bounding-box'; import { settings } from '../../settings'; import { IDrawableDescriptor } from '../i-drawable-descriptor'; import { ILight } from './i-light'; @@ -20,24 +19,18 @@ export class CircleLight implements ILight { public lightness: number ) {} - boundingBox: ImmutableBoundingBox; - public distance(target: vec2): number { return 0; } - public minimumDistance(target: vec2): number { - return 0; - } - public serializeToUniforms(uniforms: any): void { - const listName = CircleLight.descriptor.uniformName; + const uniformName = CircleLight.descriptor.uniformName; - if (!uniforms.hasOwnProperty(listName)) { - uniforms[listName] = []; + if (!uniforms.hasOwnProperty(uniformName)) { + uniforms[uniformName] = []; } - uniforms[listName].push({ + uniforms[uniformName].push({ center: this.center, radius: this.radius, value: this.value, diff --git a/frontend/src/scripts/drawing/drawables/lights/i-light.ts b/frontend/src/scripts/drawing/drawables/lights/i-light.ts index 0ed88cd..3739bf0 100644 --- a/frontend/src/scripts/drawing/drawables/lights/i-light.ts +++ b/frontend/src/scripts/drawing/drawables/lights/i-light.ts @@ -1,3 +1,4 @@ +import { vec2 } from 'gl-matrix'; import { IDrawable } from '../i-drawable'; export interface ILight extends IDrawable {} diff --git a/frontend/src/scripts/drawing/drawables/lights/point-light.ts b/frontend/src/scripts/drawing/drawables/lights/point-light.ts index 0832db9..c4ea132 100644 --- a/frontend/src/scripts/drawing/drawables/lights/point-light.ts +++ b/frontend/src/scripts/drawing/drawables/lights/point-light.ts @@ -2,7 +2,6 @@ import { ILight } from './i-light'; import { vec2, vec3 } from 'gl-matrix'; import { IDrawableDescriptor } from '../i-drawable-descriptor'; import { settings } from '../../settings'; -import { ImmutableBoundingBox } from '../../../physics/containers/immutable-bounding-box'; import { GameObject } from '../../../objects/game-object'; export class PointLight implements ILight { @@ -20,16 +19,10 @@ export class PointLight implements ILight { public lightness: number ) {} - boundingBox: ImmutableBoundingBox; - public distance(target: vec2): number { return vec2.distance(this.center, target) - this.radius; } - public minimumDistance(target: vec2): number { - return vec2.distance(this.center, target) - this.radius; - } - public serializeToUniforms(uniforms: any): void { const listName = PointLight.descriptor.uniformName; diff --git a/frontend/src/scripts/drawing/drawables/primitives/circle.ts b/frontend/src/scripts/drawing/drawables/primitives/circle.ts deleted file mode 100644 index d55977a..0000000 --- a/frontend/src/scripts/drawing/drawables/primitives/circle.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { vec2 } from 'gl-matrix'; -import { GameObject } from '../../../objects/game-object'; -import { ImmutableBoundingBox } from '../../../physics/containers/immutable-bounding-box'; -import { IPrimitive } from './i-primitive'; - -export class Circle implements IPrimitive { - public constructor( - public readonly owner: GameObject, - public center = vec2.create(), - public radius = 0 - ) { } - - public serializeToUniforms(uniforms: any): void { - throw new Error('Method not implemented.'); - } - - public distance(target: vec2): number { - return vec2.distance(this.center, target) - this.radius; - } - - public minimumDistance(target: vec2): number { - return vec2.distance(this.center, target) - this.radius; - } - - public get boundingBox(): ImmutableBoundingBox { - return new ImmutableBoundingBox( - this, - this.center.x - this.radius, - this.center.x + this.radius, - this.center.y - this.radius, - this.center.y + this.radius - ); - } - - public isInside(target: vec2): boolean { - return this.distance(target) < 0; - } - - public areIntersecting(other: Circle): boolean { - const distance = vec2.distance(this.center, other.center); - return distance < this.radius + other.radius; - } - - public clone(): Circle { - return new Circle(this.owner, this.center, this.radius); - } -} diff --git a/frontend/src/scripts/drawing/drawables/primitives/i-primitive.ts b/frontend/src/scripts/drawing/drawables/primitives/i-primitive.ts deleted file mode 100644 index 2675475..0000000 --- a/frontend/src/scripts/drawing/drawables/primitives/i-primitive.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { IDrawable } from '../i-drawable'; - -export interface IPrimitive extends IDrawable { - clone(): IPrimitive -} diff --git a/frontend/src/scripts/drawing/drawables/primitives/tunnel-shape.ts b/frontend/src/scripts/drawing/drawables/primitives/tunnel-shape.ts deleted file mode 100644 index f8197d3..0000000 --- a/frontend/src/scripts/drawing/drawables/primitives/tunnel-shape.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { vec2 } from 'gl-matrix'; -import { clamp01 } from '../../../helper/clamp'; -import { mix } from '../../../helper/mix'; -import { GameObject } from '../../../objects/game-object'; -import { ImmutableBoundingBox } from '../../../physics/containers/immutable-bounding-box'; -import { settings } from '../../settings'; -import { IDrawableDescriptor } from '../i-drawable-descriptor'; -import { Circle } from './circle'; -import { IPrimitive } from './i-primitive'; - -export class TunnelShape implements IPrimitive { - public static descriptor: IDrawableDescriptor = { - uniformName: 'lines', - countMacroName: 'lineCount', - shaderCombinationSteps: settings.shaderCombinations.lineSteps, - }; - - public readonly toFromDelta: vec2; - - private boundingCircle: Circle; - - constructor( - public readonly owner: GameObject, - public readonly from: vec2, - public readonly to: vec2, - public readonly fromRadius: number, - public readonly toRadius: number - ) { - this.toFromDelta = vec2.subtract(vec2.create(), to, from); - - this.boundingCircle = new Circle( - this.owner, - vec2.fromValues(from.x / 2 + to.x / 2, from.y / 2 + to.y / 2), - Math.max(fromRadius, toRadius) + vec2.distance(from, to) - ); - } - - public serializeToUniforms(uniforms: any): void { - if (!uniforms.hasOwnProperty(TunnelShape.descriptor.uniformName)) { - uniforms[TunnelShape.descriptor.uniformName] = []; - } - - uniforms[TunnelShape.descriptor.uniformName].push({ - from: this.from, - toFromDelta: this.toFromDelta, - fromRadius: this.fromRadius, - toRadius: this.toRadius, - }); - } - - public get boundingBox(): ImmutableBoundingBox { - const xMin = Math.min( - this.from.x - this.fromRadius, - this.to.x - this.toRadius - ); - const yMin = Math.min( - this.from.y - this.fromRadius, - this.to.y - this.toRadius - ); - const xMax = Math.max( - this.from.x + this.fromRadius, - this.to.x + this.toRadius - ); - const yMax = Math.max( - this.from.y + this.fromRadius, - this.to.y + this.toRadius - ); - - return new ImmutableBoundingBox(this, xMin, xMax, yMin, yMax); - } - - public distance(target: vec2): number { - const targetFromDelta = vec2.subtract(vec2.create(), target, this.from); - const h = clamp01( - vec2.dot(targetFromDelta, this.toFromDelta) / - vec2.dot(this.toFromDelta, this.toFromDelta) - ); - return ( - vec2.distance( - targetFromDelta, - vec2.scale(vec2.create(), this.toFromDelta, h) - ) - mix(this.fromRadius, this.toRadius, h) - ); - } - - public minimumDistance(target: vec2): number { - return this.boundingCircle.distance(target); - } - - public clone(): TunnelShape { - return new TunnelShape( - this.owner, - this.from, - this.to, - this.fromRadius, - this.toRadius - ); - } -} diff --git a/frontend/src/scripts/drawing/i-renderer.ts b/frontend/src/scripts/drawing/i-renderer.ts index 76bc606..ac073c6 100644 --- a/frontend/src/scripts/drawing/i-renderer.ts +++ b/frontend/src/scripts/drawing/i-renderer.ts @@ -1,12 +1,12 @@ import { vec2 } from 'gl-matrix'; import { ILight } from './drawables/lights/i-light'; -import { IPrimitive } from './drawables/primitives/i-primitive'; +import { IDrawable } from './drawables/i-drawable'; export interface IRenderer { startFrame(deltaTime: DOMHighResTimeStamp): void; finishFrame(): void; - drawPrimitive(primitive: IPrimitive): void; + drawShape(drawable: IDrawable): void; drawLight(light: ILight): void; drawInfoText(text: string): void; diff --git a/frontend/src/scripts/drawing/rendering/rendering-pass.ts b/frontend/src/scripts/drawing/rendering/rendering-pass.ts index 0d647d9..4201ff2 100644 --- a/frontend/src/scripts/drawing/rendering/rendering-pass.ts +++ b/frontend/src/scripts/drawing/rendering/rendering-pass.ts @@ -38,7 +38,7 @@ export class RenderingPass { const tileUvSize = vec2.fromValues(q, q); const possiblyOnScreenDrawables = this.drawables.filter( - (p) => p.minimumDistance(viewBoxCenter) < viewBoxRadius + (p) => p.distance(viewBoxCenter) < viewBoxRadius ); const origin = vec2.transformMat2d( diff --git a/frontend/src/scripts/drawing/rendering/webgl2-renderer.ts b/frontend/src/scripts/drawing/rendering/webgl2-renderer.ts index 1b5ed7b..7f0fd0d 100644 --- a/frontend/src/scripts/drawing/rendering/webgl2-renderer.ts +++ b/frontend/src/scripts/drawing/rendering/webgl2-renderer.ts @@ -2,8 +2,6 @@ import { mat2d, vec2 } from 'gl-matrix'; import { CircleLight } from '../drawables/lights/circle-light'; import { ILight } from '../drawables/lights/i-light'; import { PointLight } from '../drawables/lights/point-light'; -import { IPrimitive } from '../drawables/primitives/i-primitive'; -import { TunnelShape } from '../drawables/primitives/tunnel-shape'; // import lightsShader from '../shaders/rainbow-shading-fs.glsl'; import { DefaultFrameBuffer } from '../graphics-library/frame-buffer/default-frame-buffer'; import { IntermediateFrameBuffer } from '../graphics-library/frame-buffer/intermediate-frame-buffer'; @@ -16,6 +14,8 @@ import caveVertexShader from '../shaders/passthrough-distance-vs.glsl'; import lightsVertexShader from '../shaders/passthrough-shading-vs.glsl'; import { FpsAutoscaler } from './fps-autoscaler'; import { RenderingPass } from './rendering-pass'; +import { IDrawable } from '../drawables/i-drawable'; +import { DrawableTunnel } from '../drawables/drawable-tunnel'; export class WebGl2Renderer implements IRenderer { private gl: WebGL2RenderingContext; @@ -50,7 +50,7 @@ export class WebGl2Renderer implements IRenderer { this.distancePass = new RenderingPass( this.gl, [caveVertexShader, caveFragmentShader], - [TunnelShape.descriptor], + [DrawableTunnel.descriptor], this.distanceFieldFrameBuffer ); @@ -68,11 +68,11 @@ export class WebGl2Renderer implements IRenderer { try { this.stopwatch = new WebGlStopwatch(this.gl); - } catch { } + } catch {} } - public drawPrimitive(primitive: IPrimitive) { - this.distancePass.addDrawable(primitive); + public drawShape(shape: IDrawable) { + this.distancePass.addDrawable(shape); } public drawLight(light: ILight) { @@ -94,14 +94,11 @@ export class WebGl2Renderer implements IRenderer { vec2.scale(vec2.create(), this.viewBoxSize, 0.5) ); - this.distancePass.render( - this.uniforms, - this.cameraPosition, - viewBoxRadius - ); + this.distancePass.render(this.uniforms, this.cameraPosition, viewBoxRadius); this.lightingPass.render( - this.uniforms, this.cameraPosition, + this.uniforms, + this.cameraPosition, viewBoxRadius, this.distanceFieldFrameBuffer.colorTexture ); @@ -111,7 +108,7 @@ export class WebGl2Renderer implements IRenderer { private get uniforms(): any { const cursorPosition = this.screenUvToWorldCoordinate(this.cursorPosition); - return { ...this.matrices, cursorPosition, viewBoxSize: this.viewBoxSize } + return { ...this.matrices, cursorPosition, viewBoxSize: this.viewBoxSize }; } private calculateMatrices() { diff --git a/frontend/src/scripts/objects/types/camera.ts b/frontend/src/scripts/objects/types/camera.ts index ed2aead..418cca0 100644 --- a/frontend/src/scripts/objects/types/camera.ts +++ b/frontend/src/scripts/objects/types/camera.ts @@ -3,7 +3,7 @@ import { BeforeRenderCommand } from '../../drawing/commands/before-render'; import { CursorMoveCommand } from '../../input/commands/cursor-move-command'; import { ZoomCommand } from '../../input/commands/zoom'; import { MoveToCommand } from '../../physics/commands/move-to'; -import { BoundingBox } from '../../physics/containers/bounding-box'; +import { BoundingBox } from '../../shapes/bounding-box'; import { Physics } from '../../physics/physics'; import { GameObject } from '../game-object'; import { Lamp } from './lamp'; diff --git a/frontend/src/scripts/objects/types/character.ts b/frontend/src/scripts/objects/types/character.ts index d50ec63..454f482 100644 --- a/frontend/src/scripts/objects/types/character.ts +++ b/frontend/src/scripts/objects/types/character.ts @@ -1,5 +1,5 @@ import { vec2 } from 'gl-matrix'; -import { Circle } from '../../drawing/drawables/primitives/circle'; +import { Circle } from '../../shapes/types/circle'; import { KeyDownCommand } from '../../input/commands/key-down'; import { KeyUpCommand } from '../../input/commands/key-up'; import { SwipeCommand } from '../../input/commands/swipe'; @@ -19,7 +19,7 @@ export class Character extends GameObject { constructor(private physics: Physics, private camera: Camera) { super(); - this.primitive = new Circle(this); + this.primitive = new Circle(); this.primitive.radius = 40; this.addCommandExecutor(StepCommand, this.stepHandler.bind(this)); @@ -45,9 +45,9 @@ export class Character extends GameObject { const intersects = this.physics .findIntersecting(nextPrimitive.boundingBox) - .filter((b) => b.value) + .filter((b) => b.shape) .map( - (b) => b.value.distance(nextPrimitive.center) + nextPrimitive.radius + (b) => b.shape.distance(nextPrimitive.center) + nextPrimitive.radius ); console.log(intersects); diff --git a/frontend/src/scripts/objects/types/tunnel.ts b/frontend/src/scripts/objects/types/tunnel.ts index 7e8f972..850aca7 100644 --- a/frontend/src/scripts/objects/types/tunnel.ts +++ b/frontend/src/scripts/objects/types/tunnel.ts @@ -2,12 +2,11 @@ import { vec2 } from 'gl-matrix'; import { GameObject } from '../game-object'; import { RenderCommand } from '../../drawing/commands/render'; import { Physics } from '../../physics/physics'; -import { TunnelShape } from '../../drawing/drawables/primitives/tunnel-shape'; - -export interface Line {} +import { TunnelShape } from '../../shapes/types/tunnel-shape'; +import { DrawableTunnel } from '../../drawing/drawables/drawable-tunnel'; export class Tunnel extends GameObject { - private primitive: TunnelShape; + private shape: DrawableTunnel; constructor( physics: Physics, @@ -18,12 +17,12 @@ export class Tunnel extends GameObject { ) { super(); - this.primitive = new TunnelShape(this, from, to, fromRadius, toRadius); - physics.addStaticBoundingBox(this.primitive.boundingBox); + this.shape = new DrawableTunnel(from, to, fromRadius, toRadius); + physics.addStaticBoundingBox(this.shape.boundingBox); this.addCommandExecutor(RenderCommand, this.draw.bind(this)); } private draw(c: RenderCommand) { - c.renderer.drawPrimitive(this.primitive); + c.renderer.drawShape(this.shape); } } diff --git a/frontend/src/scripts/physics/containers/bounding-box-list.ts b/frontend/src/scripts/physics/containers/bounding-box-list.ts index a16f70e..7a2bc6e 100644 --- a/frontend/src/scripts/physics/containers/bounding-box-list.ts +++ b/frontend/src/scripts/physics/containers/bounding-box-list.ts @@ -1,4 +1,4 @@ -import { BoundingBoxBase } from './bounding-box-base'; +import { BoundingBoxBase } from '../../shapes/bounding-box-base'; export class BoundingBoxList { constructor(private boundingBoxes: Array = []) {} diff --git a/frontend/src/scripts/physics/containers/bounding-box-tree.ts b/frontend/src/scripts/physics/containers/bounding-box-tree.ts index 5598838..3d5aaeb 100644 --- a/frontend/src/scripts/physics/containers/bounding-box-tree.ts +++ b/frontend/src/scripts/physics/containers/bounding-box-tree.ts @@ -1,7 +1,7 @@ -import { ImmutableBoundingBox } from './immutable-bounding-box'; - // source: https://github.com/ubilabs/kd-tree-javascript/blob/master/kdTree.js +import { ImmutableBoundingBox } from '../../shapes/immutable-bounding-box'; + class Node { public left?: Node = null; public right?: Node = null; @@ -63,20 +63,6 @@ export class BoundingBoxTree { } } - public print() { - this.printRecursive(this.root, 0); - } - - private printRecursive(node: Node, tabCount: number) { - if (node === null) { - return; - } - - console.log(' '.repeat(tabCount) + '- ' + node.rectangle.value); - this.printRecursive(node.left, tabCount + 2); - this.printRecursive(node.right, tabCount + 2); - } - public findIntersecting( box: ImmutableBoundingBox ): Array { diff --git a/frontend/src/scripts/physics/containers/immutable-bounding-box.ts b/frontend/src/scripts/physics/containers/immutable-bounding-box.ts deleted file mode 100644 index 1aabc35..0000000 --- a/frontend/src/scripts/physics/containers/immutable-bounding-box.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { BoundingBoxBase } from './bounding-box-base'; -import { IPrimitive } from '../../drawing/drawables/primitives/i-primitive'; - -export class ImmutableBoundingBox extends BoundingBoxBase { - constructor( - value: IPrimitive, - xMin: number = 0, - xMax: number = 0, - yMin: number = 0, - yMax: number = 0 - ) { - super(value, xMin, xMax, yMin, yMax); - } -} diff --git a/frontend/src/scripts/physics/physics.ts b/frontend/src/scripts/physics/physics.ts index 0d541ba..8d6556a 100644 --- a/frontend/src/scripts/physics/physics.ts +++ b/frontend/src/scripts/physics/physics.ts @@ -1,7 +1,7 @@ import { BoundingBoxTree } from './containers/bounding-box-tree'; import { BoundingBoxList } from './containers/bounding-box-list'; -import { ImmutableBoundingBox } from './containers/immutable-bounding-box'; -import { BoundingBoxBase } from './containers/bounding-box-base'; +import { ImmutableBoundingBox } from '../shapes/immutable-bounding-box'; +import { BoundingBoxBase } from '../shapes/bounding-box-base'; export class Physics { private isTreeInitialized = false; diff --git a/frontend/src/scripts/physics/containers/bounding-box-base.ts b/frontend/src/scripts/shapes/bounding-box-base.ts similarity index 80% rename from frontend/src/scripts/physics/containers/bounding-box-base.ts rename to frontend/src/scripts/shapes/bounding-box-base.ts index b674561..8657388 100644 --- a/frontend/src/scripts/physics/containers/bounding-box-base.ts +++ b/frontend/src/scripts/shapes/bounding-box-base.ts @@ -1,13 +1,13 @@ import { vec2 } from 'gl-matrix'; -import { IPrimitive } from '../../drawing/drawables/primitives/i-primitive'; +import { IShape } from './i-shape'; export abstract class BoundingBoxBase { constructor( - public readonly value: IPrimitive, - protected _xMin: number, - protected _xMax: number, - protected _yMin: number, - protected _yMax: number + public readonly shape: IShape, + protected _xMin: number = 0, + protected _xMax: number = 0, + protected _yMin: number = 0, + protected _yMax: number = 0 ) {} public get 0(): number { diff --git a/frontend/src/scripts/physics/containers/bounding-box.ts b/frontend/src/scripts/shapes/bounding-box.ts similarity index 68% rename from frontend/src/scripts/physics/containers/bounding-box.ts rename to frontend/src/scripts/shapes/bounding-box.ts index 5fda1ab..94d20c0 100644 --- a/frontend/src/scripts/physics/containers/bounding-box.ts +++ b/frontend/src/scripts/shapes/bounding-box.ts @@ -1,32 +1,33 @@ import { vec2 } from 'gl-matrix'; import { BoundingBoxBase } from './bounding-box-base'; -import { IPrimitive } from '../../drawing/drawables/primitives/i-primitive'; +import { ImmutableBoundingBox } from './immutable-bounding-box'; export class BoundingBox extends BoundingBoxBase { - constructor( - value: IPrimitive, - xMin: number = 0, - xMax: number = 0, - yMin: number = 0, - yMax: number = 0 - ) { - super(value, xMin, xMax, yMin, yMax); - } - public get topLeft(): vec2 { return vec2.fromValues(this._xMin, this._yMax); } - public get size(): vec2 { - return vec2.fromValues(this._xMax - this._xMin, this._yMax - this._yMin); - } public set topLeft(value: vec2) { this._xMin = value.x; this._yMax = value.y; } + public get size(): vec2 { + return vec2.fromValues(this._xMax - this._xMin, this._yMax - this._yMin); + } + public set size(value: vec2) { this._xMax = this.xMin + value.x; this._yMin = this.yMax - value.y; } + + public cloneAsImmutable(): ImmutableBoundingBox { + return new ImmutableBoundingBox( + this.shape, + this.xMin, + this.xMax, + this.yMin, + this.yMax + ); + } } diff --git a/frontend/src/scripts/shapes/i-shape.ts b/frontend/src/scripts/shapes/i-shape.ts new file mode 100644 index 0000000..449413b --- /dev/null +++ b/frontend/src/scripts/shapes/i-shape.ts @@ -0,0 +1,12 @@ +import { BoundingBox } from './bounding-box'; +import { vec2 } from 'gl-matrix'; + +export interface IShape { + readonly isInverted: boolean; + readonly boundingBox: BoundingBox; + + distance(target: vec2): number; + normal(from: vec2): vec2; + + clone(): IShape; +} diff --git a/frontend/src/scripts/shapes/immutable-bounding-box.ts b/frontend/src/scripts/shapes/immutable-bounding-box.ts new file mode 100644 index 0000000..43b87e1 --- /dev/null +++ b/frontend/src/scripts/shapes/immutable-bounding-box.ts @@ -0,0 +1,3 @@ +import { BoundingBoxBase } from './bounding-box-base'; + +export class ImmutableBoundingBox extends BoundingBoxBase {} diff --git a/frontend/src/scripts/shapes/types/circle.ts b/frontend/src/scripts/shapes/types/circle.ts new file mode 100644 index 0000000..2947203 --- /dev/null +++ b/frontend/src/scripts/shapes/types/circle.ts @@ -0,0 +1,41 @@ +import { vec2 } from 'gl-matrix'; +import { IShape } from '../i-shape'; +import { BoundingBox } from '../bounding-box'; + +export class Circle implements IShape { + public readonly isInverted = false; + + public constructor(public center = vec2.create(), public radius = 0) {} + + public distance(target: vec2): number { + return vec2.distance(this.center, target) - this.radius; + } + + public normal(from: vec2): vec2 { + const diff = vec2.subtract(vec2.create(), from, this.center); + return vec2.normalize(diff, diff); + } + + public get boundingBox(): BoundingBox { + return new BoundingBox( + this, + this.center.x - this.radius, + this.center.x + this.radius, + this.center.y - this.radius, + this.center.y + this.radius + ); + } + + public isInside(target: vec2): boolean { + return this.distance(target) < 0; + } + + public areIntersecting(other: Circle): boolean { + const distance = vec2.distance(this.center, other.center); + return distance < this.radius + other.radius; + } + + public clone(): Circle { + return new Circle(this.center, this.radius); + } +} diff --git a/frontend/src/scripts/shapes/types/tunnel-shape.ts b/frontend/src/scripts/shapes/types/tunnel-shape.ts new file mode 100644 index 0000000..d48b43b --- /dev/null +++ b/frontend/src/scripts/shapes/types/tunnel-shape.ts @@ -0,0 +1,65 @@ +import { vec2 } from 'gl-matrix'; +import { BoundingBox } from '../bounding-box'; +import { clamp01 } from '../../helper/clamp'; +import { mix } from '../../helper/mix'; +import { IShape } from '../i-shape'; + +export class TunnelShape implements IShape { + public readonly isInverted = true; + + public readonly toFromDelta: vec2; + + constructor( + public readonly from: vec2, + public readonly to: vec2, + public readonly fromRadius: number, + public readonly toRadius: number + ) { + this.toFromDelta = vec2.subtract(vec2.create(), to, from); + } + + public get boundingBox(): BoundingBox { + const xMin = Math.min( + this.from.x - this.fromRadius, + this.to.x - this.toRadius + ); + const yMin = Math.min( + this.from.y - this.fromRadius, + this.to.y - this.toRadius + ); + const xMax = Math.max( + this.from.x + this.fromRadius, + this.to.x + this.toRadius + ); + const yMax = Math.max( + this.from.y + this.fromRadius, + this.to.y + this.toRadius + ); + + return new BoundingBox(this, xMin, xMax, yMin, yMax); + } + + public normal(from: vec2): vec2 { + throw new Error('Unimplemented'); + } + + public distance(target: vec2): number { + const targetFromDelta = vec2.subtract(vec2.create(), target, this.from); + + const h = clamp01( + vec2.dot(targetFromDelta, this.toFromDelta) / + vec2.dot(this.toFromDelta, this.toFromDelta) + ); + + return ( + vec2.distance( + targetFromDelta, + vec2.scale(vec2.create(), this.toFromDelta, h) + ) - mix(this.fromRadius, this.toRadius, h) + ); + } + + public clone(): TunnelShape { + return new TunnelShape(this.from, this.to, this.fromRadius, this.toRadius); + } +}