summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-03-02 02:22:46 -0700
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-03-02 02:24:18 -0700
commit06bb4177202b432d5f42141975ec82b5a8837f0e (patch)
tree7a9cb1e4177684848a3fcca91eed2ec703c787fb
parentcd6a3a56b0a9f27dd7250c7641776fe1bd184888 (diff)
downloadthe-abstraction-engine-06bb4177202b432d5f42141975ec82b5a8837f0e.tar.gz
the-abstraction-engine-06bb4177202b432d5f42141975ec82b5a8837f0e.zip
slight refactor in collision behavior
-rw-r--r--src/css/modal.css36
-rw-r--r--src/engine/TheAbstractionEngine.ts10
-rw-r--r--src/engine/components/Colliding.ts7
-rw-r--r--src/engine/components/ComponentNames.ts2
-rw-r--r--src/engine/components/Grid.ts5
-rw-r--r--src/engine/components/Highlight.ts28
-rw-r--r--src/engine/components/Pushable.ts11
-rw-r--r--src/engine/components/index.ts2
-rw-r--r--src/engine/config/sprites.ts10
-rw-r--r--src/engine/entities/EntityNames.ts1
-rw-r--r--src/engine/entities/FunctionBox.ts48
-rw-r--r--src/engine/entities/Wall.ts45
-rw-r--r--src/engine/entities/index.ts1
-rw-r--r--src/engine/systems/Grid.ts55
-rw-r--r--src/engine/systems/Render.ts9
-rw-r--r--src/engine/systems/index.ts1
16 files changed, 209 insertions, 62 deletions
diff --git a/src/css/modal.css b/src/css/modal.css
index bd6f2a3..a609ef9 100644
--- a/src/css/modal.css
+++ b/src/css/modal.css
@@ -1,32 +1,30 @@
-/* The Modal (background) */
.modal {
- display: none; /* Hidden by default */
- position: fixed; /* Stay in place */
- z-index: 1; /* Sit on top */
+ display: none;
+ position: fixed;
+ z-index: 1;
left: 0;
top: 0;
- width: 100%; /* Full width */
- height: 100%; /* Full height */
- justify-content: center; /* Center horizontally */
- align-items: center; /* Center vertically */
- background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
- overflow: auto; /* Enable scroll if needed */
- animation: fadeIn 0.25s; /* Fade in the background */
+ width: 100%;
+ height: 100%;
+ justify-content: center;
+ align-items: center;
+ background-color: rgba(0, 0, 0, 0.4);
+ overflow: auto;
+ animation: fadeIn 0.25s;
}
-/* Modal Content */
.modal-content {
display: flex;
- background-color: #282828; /* Gruvbox background */
- color: #ebdbb2; /* Gruvbox foreground */
+ background-color: #282828;
+ color: #ebdbb2;
margin: auto;
padding: 20px;
- border: 1px solid #928374; /* Gruvbox grey */
- width: 40%; /* Adjust as needed */
+ border: 1px solid #928374;
+ width: 40%;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- animation: scaleUp 0.25s; /* Scale animation */
- border-radius: 8px; /* Rounded corners */
- justify-content: center; /* Center horizontally */
+ animation: scaleUp 0.25s;
+ border-radius: 8px;
+ justify-content: center;
}
/* Animations */
diff --git a/src/engine/TheAbstractionEngine.ts b/src/engine/TheAbstractionEngine.ts
index 15ef011..2db599b 100644
--- a/src/engine/TheAbstractionEngine.ts
+++ b/src/engine/TheAbstractionEngine.ts
@@ -1,8 +1,7 @@
import { Game } from ".";
import { Miscellaneous, loadAssets } from "./config";
-import { Player, FunctionBox } from "./entities";
-import { FacingDirection, Input, Render } from "./systems";
-import { Grid } from "./systems/Grid";
+import { Player, FunctionBox, Wall } from "./entities";
+import { Grid, FacingDirection, Input, Render } from "./systems";
export class TheAbstractionEngine {
private game: Game;
@@ -24,7 +23,6 @@ export class TheAbstractionEngine {
const facingDirectionSystem = new FacingDirection(inputSystem);
[
- new Render(this.ctx),
inputSystem,
facingDirectionSystem,
new Grid(
@@ -34,6 +32,7 @@ export class TheAbstractionEngine {
height: Miscellaneous.GRID_CELL_HEIGHT,
},
),
+ new Render(this.ctx),
].forEach((system) => this.game.addSystem(system));
const player = new Player();
@@ -43,6 +42,9 @@ export class TheAbstractionEngine {
this.game.addEntity(box);
const box2 = new FunctionBox({ x: 4, y: 1 }, "λ x . (x)");
this.game.addEntity(box2);
+
+ const wall = new Wall({ x: 5, y: 3 });
+ this.game.addEntity(wall);
}
public play() {
diff --git a/src/engine/components/Colliding.ts b/src/engine/components/Colliding.ts
new file mode 100644
index 0000000..4027c3d
--- /dev/null
+++ b/src/engine/components/Colliding.ts
@@ -0,0 +1,7 @@
+import { Component, ComponentNames } from ".";
+
+export class Colliding extends Component {
+ constructor() {
+ super(ComponentNames.Colliding);
+ }
+}
diff --git a/src/engine/components/ComponentNames.ts b/src/engine/components/ComponentNames.ts
index da6c37a..5e9b589 100644
--- a/src/engine/components/ComponentNames.ts
+++ b/src/engine/components/ComponentNames.ts
@@ -6,4 +6,6 @@ export namespace ComponentNames {
export const Control = "Control";
export const Highlight = "Highlight";
export const Interactable = "Interactable";
+ export const Pushable = "Pushable";
+ export const Colliding = "Colliding";
}
diff --git a/src/engine/components/Grid.ts b/src/engine/components/Grid.ts
index 0c18a65..a62cc7b 100644
--- a/src/engine/components/Grid.ts
+++ b/src/engine/components/Grid.ts
@@ -6,15 +6,12 @@ export class Grid extends Component {
public gridPosition: Coord2D;
public movingDirection: Direction;
- public pushable: boolean = false;
- constructor(pushable: boolean = false, position: Coord2D = { x: 0, y: 0 }) {
+ constructor(position: Coord2D = { x: 0, y: 0 }) {
super(ComponentNames.Grid);
this.initialized = false;
-
this.gridPosition = position;
this.movingDirection = Direction.NONE;
- this.pushable = pushable;
}
}
diff --git a/src/engine/components/Highlight.ts b/src/engine/components/Highlight.ts
index 49d9f96..5875057 100644
--- a/src/engine/components/Highlight.ts
+++ b/src/engine/components/Highlight.ts
@@ -1,7 +1,33 @@
import { Component, ComponentNames } from ".";
export class Highlight extends Component {
- constructor() {
+ public isHighlighted: boolean;
+ private onHighlight: Function;
+ private onUnhighlight: Function;
+
+ constructor(
+ onHighlight: Function,
+ onUnhighlight: Function,
+ isHighlighted: boolean = false,
+ ) {
super(ComponentNames.Highlight);
+
+ this.isHighlighted = isHighlighted;
+ this.onHighlight = onHighlight;
+ this.onUnhighlight = onUnhighlight;
+ }
+
+ public highlight() {
+ if (!this.isHighlighted) {
+ this.isHighlighted = true;
+ this.onHighlight();
+ }
+ }
+
+ public unhighlight() {
+ if (this.isHighlighted) {
+ this.isHighlighted = false;
+ this.onUnhighlight();
+ }
}
}
diff --git a/src/engine/components/Pushable.ts b/src/engine/components/Pushable.ts
new file mode 100644
index 0000000..b3d0dc4
--- /dev/null
+++ b/src/engine/components/Pushable.ts
@@ -0,0 +1,11 @@
+import { Component, ComponentNames } from ".";
+
+export class Pushable extends Component {
+ public pushable: boolean;
+
+ constructor(pushable = false) {
+ super(ComponentNames.Pushable);
+
+ this.pushable = pushable;
+ }
+}
diff --git a/src/engine/components/index.ts b/src/engine/components/index.ts
index c470eff..4ae886a 100644
--- a/src/engine/components/index.ts
+++ b/src/engine/components/index.ts
@@ -7,3 +7,5 @@ export * from "./BoundingBox";
export * from "./Control";
export * from "./Highlight";
export * from "./Interactable";
+export * from "./Pushable";
+export * from "./Colliding";
diff --git a/src/engine/config/sprites.ts b/src/engine/config/sprites.ts
index eab65fd..7cb8adf 100644
--- a/src/engine/config/sprites.ts
+++ b/src/engine/config/sprites.ts
@@ -3,6 +3,7 @@ import { Direction } from "../interfaces/Direction";
export enum Sprites {
PLAYER,
FUNCTION_BOX,
+ WALL,
}
export interface SpriteSpec {
@@ -46,3 +47,12 @@ const functionBoxSpriteSpec = {
sheet: "/assets/function_block.png",
};
SPRITE_SPECS.set(Sprites.FUNCTION_BOX, functionBoxSpriteSpec);
+
+const wallSpriteSpec = {
+ msPerFrame: 200,
+ width: 64,
+ height: 64,
+ frames: 3,
+ sheet: "/assets/wall.png",
+};
+SPRITE_SPECS.set(Sprites.WALL, wallSpriteSpec);
diff --git a/src/engine/entities/EntityNames.ts b/src/engine/entities/EntityNames.ts
index 1a4c1ed..ffcc937 100644
--- a/src/engine/entities/EntityNames.ts
+++ b/src/engine/entities/EntityNames.ts
@@ -1,4 +1,5 @@
export namespace EntityNames {
export const Player = "Player";
export const FunctionBox = "FunctionBox";
+ export const Wall = "Wall";
}
diff --git a/src/engine/entities/FunctionBox.ts b/src/engine/entities/FunctionBox.ts
index 57eeedb..e5d031a 100644
--- a/src/engine/entities/FunctionBox.ts
+++ b/src/engine/entities/FunctionBox.ts
@@ -4,7 +4,9 @@ import {
BoundingBox,
ComponentNames,
Grid,
+ Highlight,
Interactable,
+ Pushable,
Sprite,
} from "../components";
import { Coord2D } from "../interfaces";
@@ -36,7 +38,9 @@ export class FunctionBox extends Entity {
),
);
- this.addComponent(new Grid(true, gridPosition));
+ this.addComponent(new Pushable());
+
+ this.addComponent(new Grid(gridPosition));
this.addComponent(
new Sprite(
@@ -51,25 +55,31 @@ export class FunctionBox extends Entity {
),
);
- this.hooks.set(ComponentNames.Highlight, {
- add: () => {
- let modalOpen = false;
- const interaction = () => {
- if (modalOpen) {
- modalOpen = false;
- closeModal();
- return;
- }
- modalOpen = true;
- openModal(this.code);
- };
+ this.addComponent(
+ new Highlight(
+ () => this.onHighlight(),
+ () => this.onUnhighlight(),
+ ),
+ );
+ }
+
+ private onUnhighlight() {
+ closeModal();
+ this.removeComponent(ComponentNames.Interactable);
+ }
- this.addComponent(new Interactable(interaction));
- },
- remove: () => {
+ private onHighlight() {
+ let modalOpen = false;
+ const interaction = () => {
+ if (modalOpen) {
+ modalOpen = false;
closeModal();
- this.removeComponent(ComponentNames.Interactable);
- },
- });
+ return;
+ }
+ modalOpen = true;
+ openModal(this.code);
+ };
+
+ this.addComponent(new Interactable(interaction));
}
}
diff --git a/src/engine/entities/Wall.ts b/src/engine/entities/Wall.ts
new file mode 100644
index 0000000..621a569
--- /dev/null
+++ b/src/engine/entities/Wall.ts
@@ -0,0 +1,45 @@
+import { Entity, EntityNames } from ".";
+import { BoundingBox, Colliding, Grid, Sprite } from "../components";
+import { IMAGES, SPRITE_SPECS, SpriteSpec, Sprites } from "../config";
+import { Coord2D } from "../interfaces";
+
+export class Wall extends Entity {
+ private static spriteSpec: SpriteSpec = SPRITE_SPECS.get(
+ Sprites.WALL,
+ ) as SpriteSpec;
+
+ constructor(gridPosition: Coord2D) {
+ super(EntityNames.Wall);
+
+ this.addComponent(new Grid(gridPosition));
+
+ this.addComponent(new Colliding());
+
+ this.addComponent(
+ new BoundingBox(
+ {
+ x: 0,
+ y: 0,
+ },
+ {
+ width: Wall.spriteSpec.width,
+ height: Wall.spriteSpec.height,
+ },
+ 0,
+ ),
+ );
+
+ this.addComponent(
+ new Sprite(
+ IMAGES.get(Wall.spriteSpec.sheet)!,
+ { x: 0, y: 0 },
+ {
+ width: Wall.spriteSpec.width,
+ height: Wall.spriteSpec.height,
+ },
+ Wall.spriteSpec.msPerFrame,
+ Wall.spriteSpec.frames,
+ ),
+ );
+ }
+}
diff --git a/src/engine/entities/index.ts b/src/engine/entities/index.ts
index d6a8aed..e63b272 100644
--- a/src/engine/entities/index.ts
+++ b/src/engine/entities/index.ts
@@ -2,3 +2,4 @@ export * from "./Entity";
export * from "./EntityNames";
export * from "./Player";
export * from "./FunctionBox";
+export * from "./Wall";
diff --git a/src/engine/systems/Grid.ts b/src/engine/systems/Grid.ts
index c9cab6b..28ca5ea 100644
--- a/src/engine/systems/Grid.ts
+++ b/src/engine/systems/Grid.ts
@@ -71,14 +71,20 @@ export class Grid extends System {
highlightableEntities.forEach((id) => {
const entity = game.getEntity(id)!;
- if (!entity.hasComponent(ComponentNames.Highlight)) {
- entity.addComponent(new Highlight());
+ if (entity.hasComponent(ComponentNames.Highlight)) {
+ const highlight = entity.getComponent<Highlight>(
+ ComponentNames.Highlight,
+ )!;
+ highlight.highlight();
}
});
game.forEachEntityWithComponent(ComponentNames.Highlight, (entity) => {
if (!highlightableEntities.has(entity.id)) {
- entity.removeComponent(ComponentNames.Highlight);
+ const highlight = entity.getComponent<Highlight>(
+ ComponentNames.Highlight,
+ )!;
+ highlight.unhighlight();
}
});
}
@@ -97,21 +103,41 @@ export class Grid extends System {
// continue until no more pushable entities are found
for (const entity of movingEntities) {
const grid = entity.getComponent<GridComponent>(ComponentNames.Grid)!;
+ const { gridPosition, movingDirection } = grid;
+
+ grid.movingDirection = Direction.NONE;
+ entity.addComponent(grid); // default to not moving
+
let nextGridPosition = this.getNewGridPosition(
- grid.gridPosition,
- grid.movingDirection,
+ gridPosition,
+ movingDirection,
);
+
+ const moving = new Set<string>();
+ moving.add(entity.id);
+
while (!this.isOutOfBounds(nextGridPosition)) {
const { x, y } = nextGridPosition;
const entities = Array.from(this.grid[y][x]).map(
(id) => game.getEntity(id)!,
);
+ if (
+ entities.some((entity) =>
+ entity.hasComponent(ComponentNames.Colliding),
+ )
+ ) {
+ moving.clear();
+ break;
+ }
+
const pushableEntities = entities.filter((entity) => {
if (!entity.hasComponent(ComponentNames.Grid)) return false;
- const { pushable, movingDirection } =
- entity.getComponent<GridComponent>(ComponentNames.Grid)!;
+ const { movingDirection } = entity.getComponent<GridComponent>(
+ ComponentNames.Grid,
+ )!;
+ const pushable = entity.hasComponent(ComponentNames.Pushable);
return movingDirection === Direction.NONE && pushable;
});
if (pushableEntities.length === 0) {
@@ -119,18 +145,21 @@ export class Grid extends System {
}
for (const pushableEntity of pushableEntities) {
- const pushableGrid = pushableEntity.getComponent<GridComponent>(
- ComponentNames.Grid,
- )!;
- pushableGrid.movingDirection = grid.movingDirection;
- pushableEntity.addComponent(pushableEntity);
+ moving.add(pushableEntity.id);
}
nextGridPosition = this.getNewGridPosition(
nextGridPosition,
- grid.movingDirection,
+ movingDirection,
);
}
+
+ for (const id of moving) {
+ const entity = game.getEntity(id)!;
+ const grid = entity.getComponent<GridComponent>(ComponentNames.Grid)!;
+ grid.movingDirection = movingDirection;
+ entity.addComponent(grid);
+ }
}
}
diff --git a/src/engine/systems/Render.ts b/src/engine/systems/Render.ts
index 7cb5d81..83daa52 100644
--- a/src/engine/systems/Render.ts
+++ b/src/engine/systems/Render.ts
@@ -1,5 +1,5 @@
import { System, SystemNames } from ".";
-import { BoundingBox, ComponentNames, Sprite } from "../components";
+import { BoundingBox, ComponentNames, Highlight, Sprite } from "../components";
import { Game } from "..";
import { clamp } from "../utils";
import { DrawArgs } from "../interfaces";
@@ -43,8 +43,13 @@ export class Render extends System {
center: boundingBox.center,
dimension: boundingBox.dimension,
rotation: boundingBox.rotation,
- tint: entity.hasComponent(ComponentNames.Highlight) ? "red" : undefined,
};
+ if (entity.hasComponent(ComponentNames.Highlight)) {
+ const highlight = entity.getComponent<Highlight>(
+ ComponentNames.Highlight,
+ );
+ drawArgs.tint = highlight.isHighlighted ? "red" : undefined;
+ }
sprite.draw(this.ctx, drawArgs);
});
diff --git a/src/engine/systems/index.ts b/src/engine/systems/index.ts
index 31c98ac..18ffa2e 100644
--- a/src/engine/systems/index.ts
+++ b/src/engine/systems/index.ts
@@ -3,3 +3,4 @@ export * from "./System";
export * from "./Render";
export * from "./Input";
export * from "./FacingDirection";
+export * from "./Grid";