Fix physics
This commit is contained in:
parent
37954e2ef1
commit
f9f6825776
51 changed files with 832 additions and 541 deletions
|
|
@ -1,21 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width,initial-scale=1,viewport-fit=cover"
|
||||
/>
|
||||
<meta name="theme-color" content="#b7455e" />
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
|
||||
<meta name="theme-color" content="#b7455e" />
|
||||
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||
|
||||
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<title>decla.red</title>
|
||||
</head>
|
||||
|
||||
<title>decla.red</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>Javascript is required for this website.</noscript>
|
||||
<div id="overlay"></div>
|
||||
<canvas id="main"></canvas>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<!--h1>Decla.red</h1>
|
||||
<section id="servers"></section-->
|
||||
<noscript>Javascript is required for this website.</noscript>
|
||||
<div id="overlay"></div>
|
||||
<canvas id="main"></canvas>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
import { glMatrix } from 'gl-matrix';
|
||||
import { CharacterBase, LampBase, overrideDeserialization, TunnelBase } from 'shared';
|
||||
import { CharacterBase, LampBase, overrideDeserialization, StoneBase } from 'shared';
|
||||
import { ProjectileBase } from 'shared/src/objects/types/projectile-base';
|
||||
import { Game } from './scripts/game';
|
||||
import { CharacterView } from './scripts/objects/character-view';
|
||||
import { LampView } from './scripts/objects/lamp-view';
|
||||
import { TunnelView } from './scripts/objects/tunnel-view';
|
||||
import { ProjectileView } from './scripts/objects/projectile-view';
|
||||
import { StoneView } from './scripts/objects/stone-view';
|
||||
import './styles/main.scss';
|
||||
|
||||
glMatrix.setMatrixArrayType(Array);
|
||||
|
||||
overrideDeserialization(CharacterBase, CharacterView);
|
||||
overrideDeserialization(TunnelBase, TunnelView);
|
||||
overrideDeserialization(StoneBase, StoneView);
|
||||
overrideDeserialization(LampBase, LampView);
|
||||
overrideDeserialization(ProjectileBase, ProjectileView);
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ import {
|
|||
SecondaryActionCommand,
|
||||
TernaryActionCommand,
|
||||
} from 'shared';
|
||||
import { Game } from '../../game';
|
||||
|
||||
export class MouseListener extends CommandGenerator {
|
||||
constructor(target: HTMLElement) {
|
||||
constructor(target: HTMLElement, private readonly game: Game) {
|
||||
super();
|
||||
|
||||
target.addEventListener('mousemove', (event: MouseEvent) => {
|
||||
|
|
@ -31,6 +32,8 @@ export class MouseListener extends CommandGenerator {
|
|||
}
|
||||
|
||||
private positionFromEvent(event: MouseEvent): vec2 {
|
||||
return vec2.fromValues(event.clientX, event.clientY);
|
||||
return this.game.displayToWorldCoordinates(
|
||||
vec2.fromValues(event.clientX, event.clientY),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ import {
|
|||
TernaryActionCommand,
|
||||
MoveActionCommand,
|
||||
} from 'shared';
|
||||
import { Game } from '../../game';
|
||||
|
||||
export class TouchListener extends CommandGenerator {
|
||||
private previousPosition = vec2.create();
|
||||
|
||||
constructor(target: HTMLElement) {
|
||||
constructor(target: HTMLElement, private readonly game: Game) {
|
||||
super();
|
||||
|
||||
target.addEventListener('touchstart', (event: TouchEvent) => {
|
||||
|
|
@ -53,10 +54,12 @@ export class TouchListener extends CommandGenerator {
|
|||
const touches = Array.prototype.slice.call(event.touches);
|
||||
const center = touches.reduce(
|
||||
(center: vec2, touch: Touch) =>
|
||||
vec2.add(center, center, vec2.fromValues(-touch.clientX, touch.clientY)),
|
||||
vec2.add(center, center, vec2.fromValues(-touch.clientX, -touch.clientY)),
|
||||
vec2.create(),
|
||||
);
|
||||
|
||||
return vec2.scale(center, center, 1 / event.touches.length);
|
||||
return this.game.displayToWorldCoordinates(
|
||||
vec2.scale(center, center, 1 / event.touches.length),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import {
|
|||
compile,
|
||||
FilteringOptions,
|
||||
Flashlight,
|
||||
InvertedTunnel,
|
||||
Renderer,
|
||||
renderNoise,
|
||||
WrapOptions,
|
||||
|
|
@ -13,25 +12,23 @@ import {
|
|||
import {
|
||||
broadcastCommands,
|
||||
deserialize,
|
||||
prettyPrint,
|
||||
serialize,
|
||||
settings,
|
||||
StepCommand,
|
||||
TransportEvents,
|
||||
SetAspectRatioActionCommand,
|
||||
rgb,
|
||||
} from 'shared';
|
||||
import { SetAspectRatioActionCommand } from 'shared/src/main';
|
||||
import io from 'socket.io-client';
|
||||
import { KeyboardListener } from './commands/generators/keyboard-listener';
|
||||
import { MouseListener } from './commands/generators/mouse-listener';
|
||||
import { TouchListener } from './commands/generators/touch-listener';
|
||||
import { CommandReceiverSocket } from './commands/receivers/command-receiver-socket';
|
||||
import { RenderCommand } from './commands/types/render';
|
||||
|
||||
import { Configuration } from './config/configuration';
|
||||
import { DeltaTimeCalculator } from './helper/delta-time-calculator';
|
||||
import { rgb } from './helper/rgb';
|
||||
|
||||
import { GameObjectContainer } from './objects/game-object-container';
|
||||
import { BlobShape } from './shapes/blob-shape';
|
||||
import { Polygon } from './shapes/polygon';
|
||||
|
||||
export class Game {
|
||||
public readonly gameObjects = new GameObjectContainer(this);
|
||||
|
|
@ -46,7 +43,7 @@ export class Game {
|
|||
private async setupCommunication(): Promise<void> {
|
||||
await Configuration.initialize();
|
||||
|
||||
this.socket = io(Configuration.servers[0], {
|
||||
this.socket = io(Configuration.servers[1], {
|
||||
reconnectionDelayMax: 10000,
|
||||
transports: ['websocket'],
|
||||
});
|
||||
|
|
@ -69,22 +66,22 @@ export class Game {
|
|||
broadcastCommands(
|
||||
[
|
||||
new KeyboardListener(document.body),
|
||||
new MouseListener(this.canvas),
|
||||
new TouchListener(this.canvas),
|
||||
new MouseListener(this.canvas, this),
|
||||
new TouchListener(this.canvas, this),
|
||||
],
|
||||
[this.gameObjects, new CommandReceiverSocket(this.socket)],
|
||||
);
|
||||
}
|
||||
|
||||
private async setupRenderer(): Promise<void> {
|
||||
const noiseTexture = await renderNoise([512, 1], 50, 1 / 10);
|
||||
const noiseTexture = await renderNoise([64, 1], 20, 1 / 10);
|
||||
|
||||
this.renderer = await compile(
|
||||
this.canvas,
|
||||
[
|
||||
{
|
||||
...InvertedTunnel.descriptor,
|
||||
shaderCombinationSteps: [0, 2, 6, 16],
|
||||
...Polygon.descriptor,
|
||||
shaderCombinationSteps: [0, 2, 6, 16, 32],
|
||||
},
|
||||
{
|
||||
...BlobShape.descriptor,
|
||||
|
|
@ -92,7 +89,7 @@ export class Game {
|
|||
},
|
||||
{
|
||||
...Circle.descriptor,
|
||||
shaderCombinationSteps: [0, 2, 16],
|
||||
shaderCombinationSteps: [0, 2, 16, 32],
|
||||
},
|
||||
{
|
||||
...CircleLight.descriptor,
|
||||
|
|
@ -111,16 +108,12 @@ export class Game {
|
|||
);
|
||||
|
||||
this.renderer.setRuntimeSettings({
|
||||
isWorldInverted: true,
|
||||
ambientLight: rgb(0.35, 0.1, 0.45),
|
||||
ambientLight: rgb(0.45, 0.4, 0.45),
|
||||
colorPalette: [
|
||||
rgb(0.4, 1, 0.6),
|
||||
rgb(1, 1, 0),
|
||||
rgb(0.3, 1, 1),
|
||||
rgb(0.3, 1, 1),
|
||||
rgb(0.3, 1, 1),
|
||||
rgb(0.3, 1, 1),
|
||||
rgb(1, 1, 1),
|
||||
rgb(0.4, 0.4, 0.4),
|
||||
rgb(0.3, 1, 1),
|
||||
...settings.playerColors,
|
||||
],
|
||||
enableHighDpiRendering: false,
|
||||
lightCutoffDistance: settings.lightCutoffDistance,
|
||||
|
|
@ -155,11 +148,11 @@ export class Game {
|
|||
private gameLoop(time: DOMHighResTimeStamp) {
|
||||
const deltaTime = this.deltaTimeCalculator.getNextDeltaTimeInMilliseconds(time);
|
||||
|
||||
this.gameObjects.sendCommand(new StepCommand(deltaTime));
|
||||
this.gameObjects.sendCommand(new RenderCommand(this.renderer));
|
||||
this.gameObjects.stepObjects(deltaTime);
|
||||
this.gameObjects.drawObjects(this.renderer);
|
||||
this.renderer.renderDrawables();
|
||||
|
||||
this.overlay.innerText = prettyPrint(this.renderer.insights);
|
||||
// this.overlay.innerText = prettyPrint(this.renderer.insights);
|
||||
requestAnimationFrame(this.gameLoop.bind(this));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
import { vec3 } from 'gl-matrix';
|
||||
|
||||
export const rgb = (r: number, g: number, b: number): vec3 => vec3.fromValues(r, g, b);
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { vec3 } from 'gl-matrix';
|
||||
|
||||
export const rgb255 = (r: number, g: number, b: number): vec3 =>
|
||||
vec3.fromValues(r / 255, g / 255, b / 255);
|
||||
|
|
@ -1,29 +1,38 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { calculateViewArea, CommandExecutors, GameObject } from 'shared';
|
||||
import { RenderCommand } from '../commands/types/render';
|
||||
import { Game } from '../game';
|
||||
import { Renderer } from 'sdf-2d';
|
||||
import { calculateViewArea, GameObject, mixRgb, settings } from 'shared';
|
||||
|
||||
export class Camera extends GameObject {
|
||||
import { Game } from '../game';
|
||||
import { ViewObject } from './view-object';
|
||||
|
||||
export class Camera extends GameObject implements ViewObject {
|
||||
public center: vec2 = vec2.create();
|
||||
|
||||
private aspectRatio?: number;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[RenderCommand.type]: this.draw.bind(this),
|
||||
};
|
||||
|
||||
constructor(private game: Game) {
|
||||
super(null);
|
||||
}
|
||||
|
||||
private draw(c: RenderCommand) {
|
||||
const canvasAspectRatio = c.renderer.canvasSize.x / c.renderer.canvasSize.y;
|
||||
public step(deltaTimeInMilliseconds: number): void {}
|
||||
|
||||
public draw(renderer: Renderer) {
|
||||
const canvasAspectRatio = renderer.canvasSize.x / renderer.canvasSize.y;
|
||||
if (canvasAspectRatio !== this.aspectRatio) {
|
||||
this.aspectRatio = canvasAspectRatio;
|
||||
this.game.aspectRatioChanged(canvasAspectRatio);
|
||||
}
|
||||
|
||||
const viewArea = calculateViewArea(this.center, canvasAspectRatio);
|
||||
c.renderer.setViewArea(viewArea.topLeft, viewArea.size);
|
||||
renderer.setViewArea(viewArea.topLeft, viewArea.size);
|
||||
|
||||
renderer.setRuntimeSettings({
|
||||
backgroundColor: mixRgb(
|
||||
settings.backgroundGradient[0],
|
||||
settings.backgroundGradient[1],
|
||||
(this.center.x - settings.worldLeftEdge) /
|
||||
(Math.abs(settings.worldLeftEdge) + Math.abs(settings.worldRightEdge)),
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,32 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { CharacterBase, CommandExecutors } from 'shared';
|
||||
import { RenderCommand } from '../commands/types/render';
|
||||
import { Renderer } from 'sdf-2d';
|
||||
import { CharacterBase, Circle, Id } from 'shared';
|
||||
|
||||
import { BlobShape } from '../shapes/blob-shape';
|
||||
import { ViewObject } from './view-object';
|
||||
|
||||
export class CharacterView extends CharacterBase {
|
||||
private shape = new BlobShape();
|
||||
export class CharacterView extends CharacterBase implements ViewObject {
|
||||
private shape: BlobShape;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[RenderCommand.type]: (c: RenderCommand) => {
|
||||
this.shape.setCircles([this.head, this.leftFoot, this.rightFoot]);
|
||||
c.renderer.addDrawable(this.shape);
|
||||
},
|
||||
};
|
||||
constructor(
|
||||
id: Id,
|
||||
colorIndex: number,
|
||||
head?: Circle,
|
||||
leftFoot?: Circle,
|
||||
rightFoot?: Circle,
|
||||
) {
|
||||
super(id, colorIndex, head, leftFoot, rightFoot);
|
||||
this.shape = new BlobShape(colorIndex);
|
||||
}
|
||||
|
||||
public get position(): vec2 {
|
||||
return this.head.center;
|
||||
return this.head!.center;
|
||||
}
|
||||
|
||||
public step(deltaTimeInMilliseconds: number): void {}
|
||||
|
||||
public draw(renderer: Renderer): void {
|
||||
this.shape.setCircles([this.head!, this.leftFoot!, this.rightFoot!]);
|
||||
renderer.addDrawable(this.shape);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,22 @@
|
|||
import { Renderer } from 'sdf-2d';
|
||||
import {
|
||||
Command,
|
||||
CommandExecutors,
|
||||
CommandReceiver,
|
||||
CreateObjectsCommand,
|
||||
CreatePlayerCommand,
|
||||
DeleteObjectsCommand,
|
||||
GameObject,
|
||||
Id,
|
||||
StepCommand,
|
||||
UpdateObjectsCommand,
|
||||
} from 'shared';
|
||||
import { Game } from '../game';
|
||||
import { Camera } from './camera';
|
||||
import { CharacterView } from './character-view';
|
||||
import { ViewObject } from './view-object';
|
||||
|
||||
export class GameObjectContainer extends CommandReceiver {
|
||||
protected objects: Map<Id, GameObject> = new Map();
|
||||
public player: CharacterView;
|
||||
public camera: Camera;
|
||||
protected objects: Map<Id, ViewObject> = new Map();
|
||||
public player!: CharacterView;
|
||||
public camera!: Camera;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[CreatePlayerCommand.type]: (c: CreatePlayerCommand) => {
|
||||
|
|
@ -27,14 +26,8 @@ export class GameObjectContainer extends CommandReceiver {
|
|||
this.addObject(this.camera);
|
||||
},
|
||||
|
||||
[StepCommand.type]: (_: StepCommand) => {
|
||||
if (this.player) {
|
||||
this.camera.center = this.player.position;
|
||||
}
|
||||
},
|
||||
|
||||
[CreateObjectsCommand.type]: (c: CreateObjectsCommand) =>
|
||||
c.objects.forEach((o) => this.addObject(o)),
|
||||
c.objects.forEach((o) => this.addObject(o as ViewObject)),
|
||||
|
||||
[DeleteObjectsCommand.type]: (c: DeleteObjectsCommand) =>
|
||||
c.ids.forEach((id: Id) => this.objects.delete(id)),
|
||||
|
|
@ -42,7 +35,7 @@ export class GameObjectContainer extends CommandReceiver {
|
|||
[UpdateObjectsCommand.type]: (c: UpdateObjectsCommand) => {
|
||||
c.objects.forEach((o) => {
|
||||
this.objects.delete(o.id);
|
||||
this.addObject(o);
|
||||
this.addObject(o as ViewObject);
|
||||
if (o.id === this.player.id) {
|
||||
this.player = o as CharacterView;
|
||||
}
|
||||
|
|
@ -54,15 +47,19 @@ export class GameObjectContainer extends CommandReceiver {
|
|||
super();
|
||||
}
|
||||
|
||||
protected defaultCommandExecutor(c: Command) {
|
||||
this.objects.forEach((o) => o.sendCommand(c));
|
||||
public stepObjects(delta: number) {
|
||||
if (this.player) {
|
||||
this.camera.center = this.player.position;
|
||||
}
|
||||
|
||||
this.objects.forEach((o) => o.step(delta));
|
||||
}
|
||||
|
||||
public sendCommandToSingleObject(id: Id, e: Command) {
|
||||
this.objects.get(id)!.sendCommand(e);
|
||||
public drawObjects(renderer: Renderer) {
|
||||
this.objects.forEach((o) => o.draw(renderer));
|
||||
}
|
||||
|
||||
private addObject(object: GameObject) {
|
||||
private addObject(object: ViewObject) {
|
||||
this.objects.set(object.id, object);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,24 @@
|
|||
import { vec2, vec3 } from 'gl-matrix';
|
||||
import { CircleLight } from 'sdf-2d';
|
||||
import { CircleLight, Renderer } from 'sdf-2d';
|
||||
import { CommandExecutors, Id, LampBase } from 'shared';
|
||||
import { RenderCommand } from '../commands/types/render';
|
||||
import { ViewObject } from './view-object';
|
||||
|
||||
export class LampView extends LampBase {
|
||||
export class LampView extends LampBase implements ViewObject {
|
||||
private light: CircleLight;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[RenderCommand.type]: (c: RenderCommand) => c.renderer.addDrawable(this.light),
|
||||
} as any;
|
||||
};
|
||||
|
||||
constructor(id: Id, center: vec2, color: vec3, lightness: number) {
|
||||
super(id, center, color, lightness);
|
||||
this.light = new CircleLight(center, color, lightness);
|
||||
}
|
||||
|
||||
public step(deltaTimeInMilliseconds: number): void {}
|
||||
|
||||
public draw(renderer: Renderer): void {
|
||||
renderer.addDrawable(this.light);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
frontend/src/scripts/objects/projectile-view.ts
Normal file
19
frontend/src/scripts/objects/projectile-view.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { Circle, Renderer } from 'sdf-2d';
|
||||
import { Id, ProjectileBase } from 'shared';
|
||||
import { ViewObject } from './view-object';
|
||||
|
||||
export class ProjectileView extends ProjectileBase implements ViewObject {
|
||||
private circle: Circle;
|
||||
|
||||
constructor(id: Id, center: vec2, radius: number) {
|
||||
super(id, center, radius);
|
||||
this.circle = new Circle(center, radius);
|
||||
}
|
||||
|
||||
public step(deltaTimeInMilliseconds: number): void {}
|
||||
|
||||
public draw(renderer: Renderer): void {
|
||||
renderer.addDrawable(this.circle);
|
||||
}
|
||||
}
|
||||
25
frontend/src/scripts/objects/stone-view.ts
Normal file
25
frontend/src/scripts/objects/stone-view.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { Drawable, Renderer } from 'sdf-2d';
|
||||
import { CommandExecutors, Id, StoneBase } from 'shared';
|
||||
import { RenderCommand } from '../commands/types/render';
|
||||
import { Polygon } from '../shapes/polygon';
|
||||
import { ViewObject } from './view-object';
|
||||
|
||||
export class StoneView extends StoneBase implements ViewObject {
|
||||
private shape: Drawable;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[RenderCommand.type]: (c: RenderCommand) => c.renderer.addDrawable(this.shape),
|
||||
};
|
||||
|
||||
constructor(id: Id, vertices: Array<vec2>) {
|
||||
super(id, vertices);
|
||||
this.shape = new Polygon(vertices);
|
||||
}
|
||||
|
||||
public step(deltaTimeInMilliseconds: number): void {}
|
||||
|
||||
public draw(renderer: Renderer): void {
|
||||
renderer.addDrawable(this.shape);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { InvertedTunnel } from 'sdf-2d';
|
||||
import { CommandExecutors, Id, TunnelBase } from 'shared';
|
||||
import { RenderCommand } from '../commands/types/render';
|
||||
|
||||
export class TunnelView extends TunnelBase {
|
||||
private shape: InvertedTunnel;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[RenderCommand.type]: (c: RenderCommand) => c.renderer.addDrawable(this.shape),
|
||||
} as any;
|
||||
|
||||
constructor(id: Id, from: vec2, to: vec2, fromRadius: number, toRadius: number) {
|
||||
super(id, from, to, fromRadius, toRadius);
|
||||
this.shape = new InvertedTunnel(from, to, fromRadius, toRadius);
|
||||
}
|
||||
}
|
||||
7
frontend/src/scripts/objects/view-object.ts
Normal file
7
frontend/src/scripts/objects/view-object.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { Renderer } from 'sdf-2d';
|
||||
import { GameObject } from 'shared';
|
||||
|
||||
export interface ViewObject extends GameObject {
|
||||
step(deltaTimeInMilliseconds: number): void;
|
||||
draw(renderer: Renderer): void;
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ export class BlobShape extends Drawable {
|
|||
uniform vec2 rightFootCenters[BLOB_COUNT];
|
||||
uniform float headRadii[BLOB_COUNT];
|
||||
uniform float footRadii[BLOB_COUNT];
|
||||
uniform float blobColors[BLOB_COUNT];
|
||||
|
||||
float blobSmoothMin(float a, float b)
|
||||
{
|
||||
|
|
@ -25,7 +26,6 @@ export class BlobShape extends Drawable {
|
|||
|
||||
float blobMinDistance(vec2 target, out float colorIndex) {
|
||||
float minDistance = 1000.0;
|
||||
colorIndex = 3.0;
|
||||
|
||||
for (int i = 0; i < BLOB_COUNT; i++) {
|
||||
float headDistance = circleDistance(headCenters[i], headRadii[i], target);
|
||||
|
|
@ -61,6 +61,10 @@ export class BlobShape extends Drawable {
|
|||
);
|
||||
|
||||
minDistance = min(minDistance, res);
|
||||
|
||||
if (res < 0.0) {
|
||||
colorIndex = blobColors[i];
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
|
|
@ -74,17 +78,18 @@ export class BlobShape extends Drawable {
|
|||
rightFootCenter: 'rightFootCenters',
|
||||
leftFootCenter: 'leftFootCenters',
|
||||
headCenter: 'headCenters',
|
||||
color: 'blobColors',
|
||||
},
|
||||
uniformCountMacroName: 'BLOB_COUNT',
|
||||
shaderCombinationSteps: [0, 1, 10],
|
||||
empty: new BlobShape(),
|
||||
shaderCombinationSteps: [],
|
||||
empty: new BlobShape(0),
|
||||
};
|
||||
|
||||
protected head: Circle;
|
||||
protected leftFoot: Circle;
|
||||
protected rightFoot: Circle;
|
||||
protected head!: Circle;
|
||||
protected leftFoot!: Circle;
|
||||
protected rightFoot!: Circle;
|
||||
|
||||
public constructor() {
|
||||
public constructor(private readonly color: number) {
|
||||
super();
|
||||
|
||||
const circle = new Circle(vec2.create(), 200);
|
||||
|
|
@ -120,6 +125,7 @@ export class BlobShape extends Drawable {
|
|||
),
|
||||
headRadius: this.head.radius * transform1d,
|
||||
footRadius: this.leftFoot.radius * transform1d,
|
||||
color: this.color,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
frontend/src/scripts/shapes/polygon.ts
Normal file
4
frontend/src/scripts/shapes/polygon.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { PolygonFactory } from 'sdf-2d';
|
||||
import { settings } from 'shared';
|
||||
|
||||
export const Polygon = PolygonFactory(settings.polygonEdgeCount);
|
||||
Loading…
Add table
Add a link
Reference in a new issue