summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/GameCanvas.tsx2
-rw-r--r--src/engine/TheAbstractionEngine.ts2
-rw-r--r--src/engine/config/sprites.ts10
-rw-r--r--src/engine/entities/EntityNames.ts1
-rw-r--r--src/engine/entities/FunctionApplication.ts16
-rw-r--r--src/engine/entities/FunctionBox.ts11
-rw-r--r--src/engine/entities/Sign.ts49
-rw-r--r--src/engine/entities/index.ts1
-rw-r--r--src/engine/levels/Tutorial.ts6
-rw-r--r--src/interpreter/PeggyParser.js2
-rw-r--r--src/interpreter/parser.ts8
11 files changed, 93 insertions, 15 deletions
diff --git a/src/components/GameCanvas.tsx b/src/components/GameCanvas.tsx
index b6c585d..18dd52e 100644
--- a/src/components/GameCanvas.tsx
+++ b/src/components/GameCanvas.tsx
@@ -11,7 +11,7 @@ export interface GameCanvasProps {
export const GameCanvas = ({ width, height }: GameCanvasProps) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const [game, setGame] = useState<TheAbstractionEngine>();
- const [ready, setReady] = useState(false);
+ const [ready, setReady] = useState(true); // false);
const [loading, setLoading] = useState(true);
useEffect(() => {
diff --git a/src/engine/TheAbstractionEngine.ts b/src/engine/TheAbstractionEngine.ts
index 2c29406..4a0effa 100644
--- a/src/engine/TheAbstractionEngine.ts
+++ b/src/engine/TheAbstractionEngine.ts
@@ -33,7 +33,7 @@ export class TheAbstractionEngine {
const facingDirectionSystem = new FacingDirection(inputSystem);
[
- new Level(LevelNames.LevelSelection),
+ new Level(LevelNames.Tutorial),
inputSystem,
facingDirectionSystem,
new Grid(
diff --git a/src/engine/config/sprites.ts b/src/engine/config/sprites.ts
index f8912d5..481dbb9 100644
--- a/src/engine/config/sprites.ts
+++ b/src/engine/config/sprites.ts
@@ -11,6 +11,7 @@ export enum Sprites {
BUBBLE,
PORTAL,
GRASS,
+ SIGN,
}
export interface SpriteSpec {
@@ -126,3 +127,12 @@ const grassSpriteSpec = {
sheet: "/assets/grass.png",
};
SPRITE_SPECS.set(Sprites.GRASS, grassSpriteSpec);
+
+const signSpriteSpec = {
+ msPerFrame: 200,
+ width: 64,
+ height: 64,
+ frames: 3,
+ sheet: "/assets/sign.png",
+};
+SPRITE_SPECS.set(Sprites.SIGN, signSpriteSpec);
diff --git a/src/engine/entities/EntityNames.ts b/src/engine/entities/EntityNames.ts
index b4fbbb2..17b5519 100644
--- a/src/engine/entities/EntityNames.ts
+++ b/src/engine/entities/EntityNames.ts
@@ -10,4 +10,5 @@ export namespace EntityNames {
export const Particles = "Particles";
export const Portal = "Portal";
export const Grass = "Grass";
+ export const Sign = "Sign";
}
diff --git a/src/engine/entities/FunctionApplication.ts b/src/engine/entities/FunctionApplication.ts
index d907eca..175534c 100644
--- a/src/engine/entities/FunctionApplication.ts
+++ b/src/engine/entities/FunctionApplication.ts
@@ -34,6 +34,10 @@ import {
interpret,
} from "../../interpreter";
+const APPLICATION_RESULTS: Record<string, (gridPosition: Coord2D) => Entity> = {
+ _KEY: (gridPosition: Coord2D) => new Key(gridPosition),
+};
+
export class FunctionApplication extends Entity {
private static spriteSpec = SPRITE_SPECS.get(Sprites.BUBBLE) as SpriteSpec;
@@ -43,7 +47,9 @@ export class FunctionApplication extends Entity {
super(EntityNames.FunctionApplication);
this.symbolTable = new SymbolTable();
- this.symbolTable.add("key");
+ Object.keys(APPLICATION_RESULTS).forEach((key) => {
+ this.symbolTable.add(key);
+ });
const dimension = {
width: FunctionApplication.spriteSpec.width,
@@ -109,9 +115,10 @@ export class FunctionApplication extends Entity {
ComponentNames.LambdaTerm
);
const newCode = applicationTerm.code.replace("_INPUT", functionTerm.code);
+
let result: DebrujinifiedLambdaTerm | null = null;
try {
- result = interpret(newCode, this.symbolTable);
+ result = interpret(newCode, this.symbolTable, true);
} catch (e) {
console.error(e);
fail();
@@ -131,8 +138,9 @@ export class FunctionApplication extends Entity {
applicationResultingEntity = new FunctionBox(grid.gridPosition, code);
} else if ("name" in result) {
const { name } = result;
- if (name === "key") {
- applicationResultingEntity = new Key(grid.gridPosition);
+ const entityFactory = APPLICATION_RESULTS[name];
+ if (entityFactory) {
+ game.addEntity(entityFactory(nextPosition));
}
} else {
fail();
diff --git a/src/engine/entities/FunctionBox.ts b/src/engine/entities/FunctionBox.ts
index dac2174..7b70567 100644
--- a/src/engine/entities/FunctionBox.ts
+++ b/src/engine/entities/FunctionBox.ts
@@ -67,7 +67,10 @@ export class FunctionBox extends Entity {
}
}
-export const makeLambdaTermHighlightComponent = (entity: Entity) => {
+export const makeLambdaTermHighlightComponent = (
+ entity: Entity,
+ text?: string
+) => {
const onUnhighlight = () => {
closeModal();
entity.removeComponent(ComponentNames.Interactable);
@@ -87,9 +90,9 @@ export const makeLambdaTermHighlightComponent = (entity: Entity) => {
return;
}
- const code = entity.getComponent<LambdaTerm>(
- ComponentNames.LambdaTerm
- )!.code;
+ const code =
+ text ??
+ entity.getComponent<LambdaTerm>(ComponentNames.LambdaTerm)!.code;
openModal(
`<div style="text-align:center"><p>${code}</p> <br> <button id="close">Close</button></div>`
);
diff --git a/src/engine/entities/Sign.ts b/src/engine/entities/Sign.ts
new file mode 100644
index 0000000..a11fba6
--- /dev/null
+++ b/src/engine/entities/Sign.ts
@@ -0,0 +1,49 @@
+import { Entity, EntityNames, makeLambdaTermHighlightComponent } from ".";
+import { BoundingBox, Colliding, Grid, Sprite } from "../components";
+import { IMAGES, SPRITE_SPECS, SpriteSpec, Sprites } from "../config";
+import { Coord2D } from "../interfaces";
+
+export class Sign extends Entity {
+ private static spriteSpec: SpriteSpec = SPRITE_SPECS.get(
+ Sprites.SIGN
+ ) as SpriteSpec;
+
+ private text: string;
+
+ constructor(text: string, gridPosition: Coord2D) {
+ super(EntityNames.Sign);
+ this.text = text;
+
+ const dimension = {
+ width: Sign.spriteSpec.width,
+ height: Sign.spriteSpec.height,
+ };
+
+ this.addComponent(
+ new Sprite(
+ IMAGES.get(Sign.spriteSpec.sheet)!,
+ { x: 0, y: 0 },
+ dimension,
+ Sign.spriteSpec.msPerFrame,
+ Sign.spriteSpec.frames
+ )
+ );
+
+ this.addComponent(
+ new BoundingBox(
+ {
+ x: 0,
+ y: 0,
+ },
+ dimension,
+ 0
+ )
+ );
+
+ this.addComponent(new Grid(gridPosition));
+
+ this.addComponent(new Colliding());
+
+ this.addComponent(makeLambdaTermHighlightComponent(this, this.text));
+ }
+}
diff --git a/src/engine/entities/index.ts b/src/engine/entities/index.ts
index 260db5b..284a2bd 100644
--- a/src/engine/entities/index.ts
+++ b/src/engine/entities/index.ts
@@ -11,3 +11,4 @@ export * from "./FunctionApplication";
export * from "./Particles";
export * from "./Portal";
export * from "./Grass";
+export * from "./Sign";
diff --git a/src/engine/levels/Tutorial.ts b/src/engine/levels/Tutorial.ts
index 694c8ff..b720346 100644
--- a/src/engine/levels/Tutorial.ts
+++ b/src/engine/levels/Tutorial.ts
@@ -6,6 +6,7 @@ import {
LambdaFactory,
LockedDoor,
Player,
+ Sign,
Wall,
} from "../entities";
@@ -16,14 +17,15 @@ export class Tutorial extends Level {
public init(game: Game): void {
const entities = [
- new Player({ x: 2, y: 2 }),
+ new Sign("TODO: Explain entities", { x: 4, y: 3 }),
new Wall({ x: 10, y: 9 }),
new Wall({ x: 10, y: 11 }),
new Wall({ x: 11, y: 10 }),
new Curry({ x: 10, y: 10 }),
new LockedDoor({ x: 9, y: 10 }),
new LambdaFactory({ x: 6, y: 3 }, "// TODO: Remove line\n(λ (x) . x)", 3),
- new FunctionApplication({ x: 6, y: 6 }, "(_INPUT key)"),
+ new FunctionApplication({ x: 6, y: 6 }, "(_INPUT _KEY)"),
+ new Player({ x: 2, y: 2 }),
];
entities.forEach((entity) => game.addEntity(entity));
diff --git a/src/interpreter/PeggyParser.js b/src/interpreter/PeggyParser.js
index 121cf9d..f5376b3 100644
--- a/src/interpreter/PeggyParser.js
+++ b/src/interpreter/PeggyParser.js
@@ -215,7 +215,7 @@ export default (function () {
var peg$c2 = ".";
var peg$c3 = "\r\n";
- var peg$r0 = /^[a-zA-Z0-9]/;
+ var peg$r0 = options.allowUnderscores ? /^[a-zA-Z0-9_]/ : /^[a-zA-Z0-9]/;
var peg$r1 = /^[\\\u03BB]/;
var peg$r2 = /^[\t-\n ]/;
diff --git a/src/interpreter/parser.ts b/src/interpreter/parser.ts
index 5e3be0f..930b953 100644
--- a/src/interpreter/parser.ts
+++ b/src/interpreter/parser.ts
@@ -30,6 +30,10 @@ export const isVariable = (term: LambdaTerm): term is Variable => {
return typeof term === "string";
};
-export const parse = (term: string, library = false) => {
- return peggyParser.parse(term, { peg$library: library });
+export const parse = (
+ term: string,
+ allowUnderscores = false,
+ library = false
+) => {
+ return peggyParser.parse(term, { peg$library: library, allowUnderscores });
};