diff --git a/src/engine/TheAbstractionEngine.ts b/src/engine/TheAbstractionEngine.ts index 09419ff..d7dd28b 100644 --- a/src/engine/TheAbstractionEngine.ts +++ b/src/engine/TheAbstractionEngine.ts @@ -2,7 +2,6 @@ import { Game } from "."; import { Miscellaneous, loadAssets } from "./config"; import { Player, - FunctionBox, Wall, LambdaFactory, Key, @@ -14,8 +13,8 @@ import { FacingDirection, Input, Render, - LambdaFactory as LambdaFactorySpawnSystem, Collision, + GridSpawner, } from "./systems"; export class TheAbstractionEngine { @@ -47,7 +46,7 @@ export class TheAbstractionEngine { height: Miscellaneous.GRID_CELL_HEIGHT, }, ), - new LambdaFactorySpawnSystem(), + new GridSpawner(), new Collision(), new Render(this.ctx), ].forEach((system) => this.game.addSystem(system)); diff --git a/src/engine/components/ComponentNames.ts b/src/engine/components/ComponentNames.ts index 1f41d18..a9f0c15 100644 --- a/src/engine/components/ComponentNames.ts +++ b/src/engine/components/ComponentNames.ts @@ -8,6 +8,7 @@ export namespace ComponentNames { export const Interactable = "Interactable"; export const Pushable = "Pushable"; export const Colliding = "Colliding"; - export const LambdaSpawn = "LambdaSpawn"; + export const GridSpawn = "GridSpawn"; export const Text = "Text"; + export const LambdaTerm = "LambdaTerm"; } diff --git a/src/engine/components/GridSpawn.ts b/src/engine/components/GridSpawn.ts new file mode 100644 index 0000000..d2ec898 --- /dev/null +++ b/src/engine/components/GridSpawn.ts @@ -0,0 +1,30 @@ +import { Component, ComponentNames } from "."; +import { Entity } from "../entities"; +import { Direction } from "../interfaces"; + +export class GridSpawn extends Component { + public direction: Direction; + public spawnsLeft: number; + public spawner: () => Entity; + + constructor( + spawnsLeft: number, + spawner: () => Entity, + direction = Direction.NONE, + ) { + super(ComponentNames.GridSpawn); + + this.spawnsLeft = spawnsLeft; + this.direction = direction; + this.spawner = spawner; + } + + public spawnEntity(direction: Direction): Entity | undefined { + if (this.spawnsLeft === 0) { + return; + } + + this.direction = direction; + this.spawnsLeft -= 1; + } +} diff --git a/src/engine/components/LambdaSpawn.ts b/src/engine/components/LambdaSpawn.ts deleted file mode 100644 index c45092a..0000000 --- a/src/engine/components/LambdaSpawn.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Component, ComponentNames } from "."; -import { Direction } from "../interfaces"; - -export class LambdaSpawn extends Component { - public direction: Direction | null; - public spawnsLeft: number; - public code: string = ""; - - constructor( - spawnsLeft: number, - code: string, - direction: Direction | null = null, - ) { - super(ComponentNames.LambdaSpawn); - - this.spawnsLeft = spawnsLeft; - this.direction = direction; - this.code = code; - } - - public spawn(direction: Direction) { - if (this.spawnsLeft <= 0) { - return; - } - - this.direction = direction; - this.spawnsLeft -= 1; - } -} diff --git a/src/engine/components/LambdaTerm.ts b/src/engine/components/LambdaTerm.ts new file mode 100644 index 0000000..63e9889 --- /dev/null +++ b/src/engine/components/LambdaTerm.ts @@ -0,0 +1,11 @@ +import { Component, ComponentNames } from "."; + +export class LambdaTerm extends Component { + public code: string; + + constructor(code: string) { + super(ComponentNames.LambdaTerm); + + this.code = code; + } +} diff --git a/src/engine/components/index.ts b/src/engine/components/index.ts index 104ba2d..a7a3cf1 100644 --- a/src/engine/components/index.ts +++ b/src/engine/components/index.ts @@ -9,5 +9,6 @@ export * from "./Highlight"; export * from "./Interactable"; export * from "./Pushable"; export * from "./Colliding"; -export * from "./LambdaSpawn"; +export * from "./GridSpawn"; export * from "./Text"; +export * from "./LambdaTerm"; diff --git a/src/engine/entities/EntityNames.ts b/src/engine/entities/EntityNames.ts index 7fc69c6..3f6d26f 100644 --- a/src/engine/entities/EntityNames.ts +++ b/src/engine/entities/EntityNames.ts @@ -6,4 +6,5 @@ export namespace EntityNames { export const Key = "Key"; export const LockedDoor = "LockedDoor"; export const Curry = "Curry"; + export const FunctionApplication = "FunctionApplication"; } diff --git a/src/engine/entities/FunctionApplication.ts b/src/engine/entities/FunctionApplication.ts new file mode 100644 index 0000000..31e3490 --- /dev/null +++ b/src/engine/entities/FunctionApplication.ts @@ -0,0 +1,7 @@ +import { Entity, EntityNames } from "."; + +export class FunctionApplication extends Entity { + constructor() { + super(EntityNames.FunctionApplication); + } +} diff --git a/src/engine/entities/FunctionBox.ts b/src/engine/entities/FunctionBox.ts index e51eb2b..92f1908 100644 --- a/src/engine/entities/FunctionBox.ts +++ b/src/engine/entities/FunctionBox.ts @@ -12,6 +12,7 @@ import { Grid, Highlight, Interactable, + LambdaTerm, Pushable, Sprite, } from "../components"; @@ -23,13 +24,9 @@ export class FunctionBox extends Entity { Sprites.FUNCTION_BOX, ) as SpriteSpec; - private code: string; - constructor(gridPosition: Coord2D, code: string) { super(EntityNames.FunctionBox); - this.code = code; - this.addComponent( new BoundingBox( { @@ -61,20 +58,19 @@ export class FunctionBox extends Entity { ), ); - this.addComponent( - new Highlight( - (_direction) => this.onHighlight(), - () => this.onUnhighlight(), - ), - ); - } + this.addComponent(new LambdaTerm(code)); - private onUnhighlight() { + this.addComponent(makeLambdaTermHighlightComponent(this)); + } +} + +export const makeLambdaTermHighlightComponent = (entity: Entity) => { + const onUnhighlight = () => { closeModal(); - this.removeComponent(ComponentNames.Interactable); - } + entity.removeComponent(ComponentNames.Interactable); + }; - private onHighlight() { + const onHighlight = () => { let modalOpen = false; const interaction = () => { if (modalOpen) { @@ -82,10 +78,14 @@ export class FunctionBox extends Entity { closeModal(); return; } - modalOpen = true; + + const code = entity.getComponent( + ComponentNames.LambdaTerm, + )!.code; openModal( - `

${this.code}


`, + `

${code}


`, ); + modalOpen = true; document.getElementById("close")!.addEventListener("click", () => { closeModal(); @@ -93,6 +93,8 @@ export class FunctionBox extends Entity { }); }; - this.addComponent(new Interactable(interaction)); - } -} + entity.addComponent(new Interactable(interaction)); + }; + + return new Highlight(onHighlight, onUnhighlight); +}; diff --git a/src/engine/entities/LambdaFactory.ts b/src/engine/entities/LambdaFactory.ts index 1c897eb..a0f5749 100644 --- a/src/engine/entities/LambdaFactory.ts +++ b/src/engine/entities/LambdaFactory.ts @@ -5,15 +5,15 @@ import { SpriteSpec, Sprites, } from "../config"; -import { Entity, EntityNames } from "."; +import { Entity, EntityNames, FunctionBox } from "."; import { BoundingBox, Colliding, ComponentNames, Grid, + GridSpawn, Highlight, Interactable, - LambdaSpawn, Sprite, Text, } from "../components"; @@ -75,11 +75,13 @@ export class LambdaFactory extends Entity { private codeEditorState: CodeEditorState | null; private spawns: number; + private code: string; constructor(gridPosition: Coord2D, code: string, spawns: number) { super(EntityNames.LambdaFactory); this.spawns = spawns; + this.code = code; this.codeEditorState = null; this.addComponent( @@ -100,7 +102,12 @@ export class LambdaFactory extends Entity { this.addComponent(new Colliding()); - this.addComponent(new LambdaSpawn(this.spawns, code)); + this.addComponent( + new GridSpawn( + this.spawns, + () => new FunctionBox({ x: 0, y: 0 }, this.code), + ), + ); this.addComponent(new Grid(gridPosition)); @@ -131,8 +138,8 @@ export class LambdaFactory extends Entity { } private spawnNewLambda(direction: Direction) { - const spawner = this.getComponent(ComponentNames.LambdaSpawn); - spawner.spawn(direction); + const spawner = this.getComponent(ComponentNames.GridSpawn); + spawner.spawnEntity(direction); const text = this.getComponent(ComponentNames.Text); text.text = spawner.spawnsLeft.toString(); @@ -144,9 +151,8 @@ export class LambdaFactory extends Entity { "

"; openModal(modalContent); - const { code } = this.getComponent(ComponentNames.LambdaSpawn); const startState = EditorState.create({ - doc: code, + doc: this.code, extensions: [ basicSetup, keymap.of(defaultKeymap), @@ -236,9 +242,7 @@ export class LambdaFactory extends Entity { return; } - const spawner = this.getComponent(ComponentNames.LambdaSpawn); - spawner.code = text; - this.addComponent(spawner); + this.code = text; view.destroy(); editorElement.innerHTML = ""; diff --git a/src/engine/systems/GridSpawner.ts b/src/engine/systems/GridSpawner.ts new file mode 100644 index 0000000..c566444 --- /dev/null +++ b/src/engine/systems/GridSpawner.ts @@ -0,0 +1,39 @@ +import { System, SystemNames } from "."; +import { Game } from ".."; +import { ComponentNames, Grid, GridSpawn } from "../components"; +import { Direction } from "../interfaces"; + +export class GridSpawner extends System { + constructor() { + super(SystemNames.GridSpawner); + } + + public update(_dt: number, game: Game) { + game.forEachEntityWithComponent(ComponentNames.GridSpawn, (entity) => { + const spawn = entity.getComponent(ComponentNames.GridSpawn)!; + const hasGrid = entity.hasComponent(SystemNames.Grid); + + if (spawn.direction === Direction.NONE || !hasGrid) { + return; + } + + const grid = entity.getComponent(SystemNames.Grid)!; + + const direction = spawn.direction; + const spawned = spawn.spawner(); + if (!spawned) { + return; + } + spawn.direction = Direction.NONE; + entity.addComponent(spawn); + + const spawnedGrid = spawned.getComponent(SystemNames.Grid)!; + spawnedGrid.gridPosition = grid.gridPosition; + spawnedGrid.movingDirection = direction; + spawned.addComponent(spawnedGrid); + + game.addEntity(spawned); + entity.addComponent(spawned); + }); + } +} diff --git a/src/engine/systems/LambdaFactory.ts b/src/engine/systems/Spawner.ts similarity index 69% rename from src/engine/systems/LambdaFactory.ts rename to src/engine/systems/Spawner.ts index 1263eae..6a4d382 100644 --- a/src/engine/systems/LambdaFactory.ts +++ b/src/engine/systems/Spawner.ts @@ -1,17 +1,17 @@ import { System, SystemNames } from "."; import { Game } from ".."; -import { ComponentNames, Grid, LambdaSpawn } from "../components"; +import { ComponentNames, Grid, GridSpawn } from "../components"; import { FunctionBox } from "../entities"; -export class LambdaFactory extends System { +export class GridSpawner extends System { constructor() { - super(SystemNames.LambdaFactory); + super(SystemNames.GridSpawner); } public update(_dt: number, game: Game) { - game.forEachEntityWithComponent(ComponentNames.LambdaSpawn, (entity) => { - const lambdaSpawn = entity.getComponent( - ComponentNames.LambdaSpawn, + game.forEachEntityWithComponent(ComponentNames.GridSpawn, (entity) => { + const lambdaSpawn = entity.getComponent( + ComponentNames.GridSpawn, )!; const hasGrid = entity.hasComponent(SystemNames.Grid); diff --git a/src/engine/systems/SystemNames.ts b/src/engine/systems/SystemNames.ts index c96dc48..555746c 100644 --- a/src/engine/systems/SystemNames.ts +++ b/src/engine/systems/SystemNames.ts @@ -3,6 +3,6 @@ export namespace SystemNames { export const Input = "Input"; export const FacingDirection = "FacingDirection"; export const Grid = "Grid"; - export const LambdaFactory = "LambdaFactory"; + export const GridSpawner = "GridSpawner"; export const Collision = "Collision"; } diff --git a/src/engine/systems/index.ts b/src/engine/systems/index.ts index 6ee5392..34b369c 100644 --- a/src/engine/systems/index.ts +++ b/src/engine/systems/index.ts @@ -4,5 +4,5 @@ export * from "./Render"; export * from "./Input"; export * from "./FacingDirection"; export * from "./Grid"; -export * from "./LambdaFactory"; +export * from "./GridSpawner"; export * from "./Collision";