Rev 26 | Blame | Compare with Previous | Last modification | View Log | Download
const TILE_SIZE = 30;const FPS = 30;const SLEEP = 1000 / FPS;enum RawTile {AIR,FLUX,UNBREAKABLE,PLAYER,STONE, FALLING_STONE,BOX, FALLING_BOX,KEY1, LOCK1,KEY2, LOCK2}interface Tile {isAir(): boolean;//isFlux(): boolean;//isUnbreakable(): boolean;//isPlayer(): boolean;isStone(): boolean;isFallingStone(): boolean;isBox(): boolean;isFallingBox(): boolean;//isKey1(): boolean;isLock1(): boolean;//isKey2(): boolean;isLock2(): boolean;//color(g: CanvasRenderingContext2D): void;draw(g: CanvasRenderingContext2D, x: number, y: number): void;//isEdible(): boolean;//isPushable(): boolean;moveHorizontal(dx: number): void;moveVertical(dy: number): void;}class Air implements Tile {isAir(){ return true; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) { }draw(g: CanvasRenderingContext2D, x: number, y: number) { }isEdible() {return true;}isPushable() {return false;}moveHorizontal(dx: number) {moveToTile(playerx + dx, playery);}moveVertical(dy: number) {moveToTile(playerx, playery + dy);}}class Flux implements Tile {isAir(){ return false; }isFlux(){ return true; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#ccffcc";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#ccffcc";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return true;}isPushable() {return false;}moveHorizontal(dx: number) {moveToTile(playerx + dx, playery);}moveVertical(dy: number) {moveToTile(playerx, playery + dy);}}class Unbreakable implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return true; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#999999";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#999999";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return false;}moveHorizontal(dx: number) { }moveVertical(dy: number) { }}class Player implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return true; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) { }draw(g: CanvasRenderingContext2D, x: number, y: number) { }isEdible() {return false;}isPushable() {return false;}moveHorizontal(dx: number) { }moveVertical(dy: number) { }}class Stone implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return true; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#0000cc";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#0000cc";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return true;}moveHorizontal(dx: number) {if (map[playery][playerx + dx + dx].isAir()&& !map[playery + 1][playerx + dx].isAir()) {map[playery][playerx + dx + dx] = map[playery][playerx + dx];moveToTile(playerx + dx, playery);}}moveVertical(dy: number) { }}class FallingStone implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return true; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#0000cc";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#0000cc";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return false;}moveHorizontal(dx: number) { }moveVertical(dy: number) { }}class Box implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return true; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#8b4513";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#8b4513";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return true;}moveHorizontal(dx: number) {if (map[playery][playerx + dx + dx].isAir()&& !map[playery + 1][playerx + dx].isAir()) {map[playery][playerx + dx + dx] = map[playery][playerx + dx];moveToTile(playerx + dx, playery);}}moveVertical(dy: number) { }}class FallingBox implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return true; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#8b4513";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#8b4513";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return false;}moveHorizontal(dx: number) { }moveVertical(dy: number) { }}class Key1 implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return true; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#ffcc00";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#ffcc00";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return false;}moveHorizontal(dx: number) {removeLock1();moveToTile(playerx + dx, playery);}moveVertical(dy: number) {removeLock1();moveToTile(playerx, playery + dy);}}class Lock1 implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return true; }isKey2(){ return false; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#ffcc00";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#ffcc00";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return false;}moveHorizontal(dx: number) { }moveVertical(dy: number) { }}class Key2 implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return true; }isLock2(){ return false; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#00ccff";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#00ccff";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return false;}moveHorizontal(dx: number) {removeLock2();moveToTile(playerx + dx, playery);}moveVertical(dy: number) {removeLock2();moveToTile(playerx, playery + dy);}}class Lock2 implements Tile {isAir(){ return false; }isFlux(){ return false; }isUnbreakable(){ return false; }isPlayer(){ return false; }isStone(){ return false; }isFallingStone(){ return false; }isBox(){ return false; }isFallingBox(){ return false; }isKey1(){ return false; }isLock1(){ return false; }isKey2(){ return false; }isLock2(){ return true; }//color(g: CanvasRenderingContext2D) {g.fillStyle = "#00ccff";}draw(g: CanvasRenderingContext2D, x: number, y: number) {g.fillStyle = "#00ccff";g.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);}isEdible() {return false;}isPushable() {return false;}moveHorizontal(dx: number) { }moveVertical(dy: number) { }}//enum RawInput {// UP, DOWN, LEFT, RIGHT//}interface Input {isUp(): boolean;isDown(): boolean;isLeft(): boolean;isRight(): boolean;handle(): void;}class Up implements Input {isUp() { return true; }isDown() { return false; }isLeft() { return false; }isRight() { return false; }handle(){map[playery - 1][playerx].moveVertical(-1);}}class Down implements Input {isUp() { return false; }isDown() { return true; }isLeft() { return false; }isRight() { return false; }handle(){map[playery + 1][playerx].moveVertical(1);}}class Left implements Input {isUp() { return false; }isDown() { return false; }isLeft() { return true; }isRight() { return false; }handle(){//moveHorizontal(-1);map[playery][playerx - 1].moveHorizontal(-1);}}class Right implements Input {isUp() { return false; }isDown() { return false; }isLeft() { return false; }isRight() { return true; }handle(){//moveHorizontal(1);map[playery][playerx + 1].moveHorizontal(1);}}let playerx = 1;let playery = 1;let rawMap: RawTile[][] = [[2, 2, 2, 2, 2, 2, 2, 2],[2, 3, 0, 1, 1, 2, 0, 2],[2, 4, 2, 6, 1, 2, 0, 2],[2, 8, 4, 1, 1, 2, 0, 2],[2, 4, 1, 1, 1, 9, 0, 2],[2, 2, 2, 2, 2, 2, 2, 2],];let map: Tile[][];function assertExhausted(x: never): never {throw new Error("Unexpected object: " + x);}function transformTile(tile: RawTile) {switch(tile) {case RawTile.AIR: return new Air();case RawTile.PLAYER: return new Player();case RawTile.UNBREAKABLE: return new Unbreakable();case RawTile.STONE: return new Stone();case RawTile.FALLING_STONE: return new FallingStone();case RawTile.BOX: return new Box();case RawTile.FALLING_BOX: return new FallingBox();case RawTile.FLUX: return new Flux();case RawTile.KEY1: return new Key1();case RawTile.LOCK1: return new Lock1();case RawTile.KEY2: return new Key2();case RawTile.LOCK2: return new Lock2();default: assertExhausted(tile);}}function transformMap() {map = new Array(rawMap.length);for (let y = 0; y < rawMap.length; y++) {map[y] = new Array(rawMap[y].length);for (let x = 0; x < rawMap[y].length; x++) {map[y][x] = transformTile(rawMap[y][x]);}}}let inputs: Input[] = [];function removeLock1() {for (let y = 0; y < map.length; y++) {for (let x = 0; x < map[y].length; x++) {if (map[y][x].isLock1()) {map[y][x] = new Air();}}}}function removeLock2() {for (let y = 0; y < map.length; y++) {for (let x = 0; x < map[y].length; x++) {if (map[y][x].isLock2()) {map[y][x] = new Air();}}}}function moveToTile(newx: number, newy: number) {map[playery][playerx] = new Air();map[newy][newx] = new Player();playerx = newx;playery = newy;}//function moveHorizontal2(dx: number) {// map[playery][playerx + dx].moveHorizontal(dx);//}///\function moveVertical2(dy: number) {// map[playery + dy][playerx].moveVertical(dy);//}function update() {handleInputs();updateMap();}function handleInputs(){while (inputs.length > 0) {let input = inputs.pop();input.handle();}}function updateMap() {for (let y = map.length - 1; y >= 0; y--) {for (let x = 0; x < map[y].length; x++) {updateTile(x, y);}}}function updateTile(x: number, y: number){if ((map[y][x].isStone() || map[y][x].isFallingStone())&& map[y + 1][x].isAir()) {map[y + 1][x] = new FallingStone();map[y][x] = new Air();} else if ((map[y][x].isBox() || map[y][x] .isFallingBox())&& map[y + 1][x].isAir()) {map[y + 1][x] = new FallingBox();map[y][x] = new Air();} else if (map[y][x].isFallingStone()) {map[y][x] = new Stone();} else if (map[y][x].isFallingBox()) {map[y][x] = new Box();}}function createGraphics() {let canvas = document.getElementById("GameCanvas") as HTMLCanvasElement;let g = canvas.getContext("2d");g.clearRect(0, 0, canvas.width, canvas.height);return g;}function draw() {let g = createGraphics();drawMap(g);drawPlayer(g);}function drawMap(g: CanvasRenderingContext2D) {for (let y = 0; y < map.length; y++) {for (let x = 0; x < map[y].length; x++) {map[y][x].draw(g, x, y);}}}function drawPlayer(g: CanvasRenderingContext2D) {g.fillStyle = "#ff0000";g.fillRect(playerx * TILE_SIZE, playery * TILE_SIZE, TILE_SIZE, TILE_SIZE);}function gameLoop() {let before = Date.now();update();draw();let after = Date.now();let frameTime = after - before;let sleep = SLEEP - frameTime;setTimeout(() => gameLoop(), sleep);}window.onload = () => {transformMap();gameLoop();}const LEFT_KEY = "ArrowLeft";const UP_KEY = "ArrowUp";const RIGHT_KEY = "ArrowRight";const DOWN_KEY = "ArrowDown";window.addEventListener("keydown", e => {if (e.key === LEFT_KEY || e.key === "a") inputs.push(new Left());else if (e.key === UP_KEY || e.key === "w") inputs.push(new Up());else if (e.key === RIGHT_KEY || e.key === "d") inputs.push(new Right());else if (e.key === DOWN_KEY || e.key === "s") inputs.push(new Down());});