| @@ -6,7 +6,8 @@ export default class Level { | |||
| this.ctx = canvas.getContext("2d"); | |||
| this.lastTime = null; | |||
| this.raf = null; | |||
| this.minFPS = 10; | |||
| this.minPhysFPS = 30; | |||
| this.minFPS = 5; | |||
| this.backgroundColor = "#87CEFA"; | |||
| this.entities = []; | |||
| @@ -77,12 +78,26 @@ export default class Level { | |||
| if (this.lastTime != null) { | |||
| let dt = (time - this.lastTime) / 1000; | |||
| if (1 / dt > this.minFPS) { | |||
| this.physics(dt); | |||
| } else { | |||
| if (1 / dt < this.minFPS) { | |||
| console.log( | |||
| "Too long between updates ("+dt.toFixed(2)+"s, "+ | |||
| (1 / dt).toFixed(2)+"FPS). Skipping."); | |||
| } else { | |||
| // We accept really low FPSes, | |||
| // but if the FPS gets too low, we want to run multiple | |||
| // physics steps in the frame. | |||
| let nSteps = 1; | |||
| while (1 / dt < this.minPhysFPS) { | |||
| dt /= 2; | |||
| nSteps *= 2; | |||
| } | |||
| if (nSteps != 1) | |||
| console.log(nSteps); | |||
| for (let i = 0; i < nSteps; ++i) | |||
| this.physics(dt); | |||
| } | |||
| this.draw(); | |||
| @@ -6,15 +6,33 @@ export default class Tile { | |||
| } | |||
| } | |||
| Tile.createLine = function(width, name) { | |||
| Tile.createLine = function(width, name, x = 0, y = 0) { | |||
| if (width <= 1) { | |||
| return [ new Tile(0, 0, name+"-lr") ]; | |||
| return [ new Tile(x, y, name+"-lr") ]; | |||
| } else { | |||
| return [ | |||
| new Tile(0, 0, name+"-l"), | |||
| new Tile(x, y, name+"-l"), | |||
| Array.from({ length: width - 2 }, (_, i) => | |||
| new Tile(i + 1, 0, name)), | |||
| new Tile(width - 1, 0, name+"-r"), | |||
| new Tile(x + i + 1, y, name)), | |||
| new Tile(x + width - 1, y, name+"-r"), | |||
| ]; | |||
| } | |||
| } | |||
| Tile.createBox = function(width, height, nameTop, nameMid, nameBottom) { | |||
| if (height <= 1) { | |||
| return Tile.createLine(width, nameTop); | |||
| } else if (height <= 2) { | |||
| return [ | |||
| Tile.createLine(width, nameTop), | |||
| Tile.createLine(width, nameBottom), | |||
| ]; | |||
| } else { | |||
| return [ | |||
| Tile.createLine(width, nameTop), | |||
| Array.from({ length: height - 2 }, (_, i) => | |||
| Tile.createLine(width, nameMid, 0, i + 1)), | |||
| Tile.createLine(width, nameBottom, 0, height - 1), | |||
| ]; | |||
| } | |||
| } | |||
| @@ -3,11 +3,14 @@ import SpriteSheet from "./SpriteSheet.js"; | |||
| export default { | |||
| tiles: new SpriteSheet("assets/tiles.png", 32, 32, 1) | |||
| .defineTile("ground", 0, 0) | |||
| .defineTile("ground-l", 1, 0) | |||
| .defineTile("ground-r", 2, 0) | |||
| .defineTile("ground-lr", 3, 0) | |||
| .defineTile("grass", 0, 1) | |||
| .defineTile("grass-l", 1, 1) | |||
| .defineTile("grass-r", 2, 1) | |||
| .defineTile("grass-lr", 3, 1) | |||
| .defineTile("ground-top", 0, 1) | |||
| .defineTile("ground-top-l", 1, 1) | |||
| .defineTile("ground-top-r", 2, 1) | |||
| .defineTile("ground-top-lr", 3, 1) | |||
| .defineTile("platform", 0, 2) | |||
| .defineTile("platform-l", 1, 2) | |||
| @@ -0,0 +1,26 @@ | |||
| import Entity from "../Entity.js"; | |||
| import Texture from "../Texture.js"; | |||
| import Tile from "../Tile.js"; | |||
| import assets from "../assets.js"; | |||
| import TPlatform from "../traits/TPlatform.js"; | |||
| import TCollider from "../traits/TCollider.js"; | |||
| import TPhysics from "../traits/TPhysics.js"; | |||
| export default class Platform extends Entity { | |||
| constructor(level, width = 5) { | |||
| super(level); | |||
| this.bounds.size.set(width, 0.5); | |||
| this.addTrait(new TCollider(this)); | |||
| this.addTrait(new TPlatform(this)); | |||
| this.addTrait(new TPhysics(this)); | |||
| this.texture = new Texture(assets.tiles, | |||
| Tile.createLine(this.bounds.size.x, "platform")); | |||
| } | |||
| draw(ctx) { | |||
| this.texture.drawAt(ctx, this.bounds.pos); | |||
| } | |||
| } | |||
| @@ -8,10 +8,10 @@ import TCollider from "../traits/TCollider.js"; | |||
| import TPhysics from "../traits/TPhysics.js"; | |||
| export default class Platform extends Entity { | |||
| constructor(level) { | |||
| constructor(level, width = 5) { | |||
| super(level); | |||
| this.bounds.size.set(5, 0.5); | |||
| this.bounds.size.set(width, 0.5); | |||
| this.addTrait(new TCollider(this)); | |||
| this.addTrait(new TPlatform(this)); | |||
| this.addTrait(new TPhysics(this)); | |||
| @@ -19,6 +19,7 @@ export default class Platform extends Entity { | |||
| this.targetSpeed = 3; | |||
| this.accel = 5; | |||
| this.dir = 1; | |||
| this.movement = 5; | |||
| this.texture = new Texture(assets.tiles, | |||
| Tile.createLine(this.bounds.size.x, "platform")); | |||
| @@ -26,7 +27,7 @@ export default class Platform extends Entity { | |||
| init() { | |||
| this.targetTop = this.bounds.pos.y; | |||
| this.targetBottom = this.targetTop + 5; | |||
| this.targetBottom = this.targetTop + this.movement; | |||
| this.t.physics.gravity = 0; | |||
| this.t.physics.velocity.y = 0; | |||
| @@ -1,16 +1,19 @@ | |||
| import Level from "./Level.js"; | |||
| import Vec2 from "./Vec2.js"; | |||
| import Player from "./entities/Player.js"; | |||
| import Platform from "./entities/Platform.js"; | |||
| import FloatingPlatform from "./entities/FloatingPlatform.js"; | |||
| import FallingPlatform from "./entities/FallingPlatform.js"; | |||
| import structures from "./structures.js"; | |||
| import Vec2 from "./Vec2.js"; | |||
| let canvas = document.getElementById("canvas"); | |||
| let level = new Level(canvas); | |||
| level.spawnEntity(new Player(level), 10, 1); | |||
| level.spawnEntity(new Platform(level), 16, 4); | |||
| level.spawnStructure(structures.floor(8), 4, 4); | |||
| level.spawnEntity(new FloatingPlatform(level), 16, 4); | |||
| level.spawnEntity(new FallingPlatform(level), 20, 1); | |||
| level.spawnStructure(structures.floor(8, 6), 4, 4); | |||
| level.start(); | |||
| @@ -2,7 +2,7 @@ import Structure from "./Structure.js"; | |||
| import Tile from "./Tile.js"; | |||
| export default { | |||
| floor: width => new Structure( | |||
| floor: (width, height = 1)=> new Structure( | |||
| [ "wall" ], | |||
| Tile.createLine(width, "grass")), | |||
| Tile.createBox(width, height, "ground-top", "ground", "ground")), | |||
| }; | |||