| this.ctx = canvas.getContext("2d"); | this.ctx = canvas.getContext("2d"); | ||||
| this.lastTime = null; | this.lastTime = null; | ||||
| this.raf = null; | this.raf = null; | ||||
| this.minFPS = 10; | |||||
| this.minPhysFPS = 30; | |||||
| this.minFPS = 5; | |||||
| this.backgroundColor = "#87CEFA"; | this.backgroundColor = "#87CEFA"; | ||||
| this.entities = []; | this.entities = []; | ||||
| if (this.lastTime != null) { | if (this.lastTime != null) { | ||||
| let dt = (time - this.lastTime) / 1000; | let dt = (time - this.lastTime) / 1000; | ||||
| if (1 / dt > this.minFPS) { | |||||
| this.physics(dt); | |||||
| } else { | |||||
| if (1 / dt < this.minFPS) { | |||||
| console.log( | console.log( | ||||
| "Too long between updates ("+dt.toFixed(2)+"s, "+ | "Too long between updates ("+dt.toFixed(2)+"s, "+ | ||||
| (1 / dt).toFixed(2)+"FPS). Skipping."); | (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(); | this.draw(); |
| } | } | ||||
| } | } | ||||
| Tile.createLine = function(width, name) { | |||||
| Tile.createLine = function(width, name, x = 0, y = 0) { | |||||
| if (width <= 1) { | if (width <= 1) { | ||||
| return [ new Tile(0, 0, name+"-lr") ]; | |||||
| return [ new Tile(x, y, name+"-lr") ]; | |||||
| } else { | } else { | ||||
| return [ | return [ | ||||
| new Tile(0, 0, name+"-l"), | |||||
| new Tile(x, y, name+"-l"), | |||||
| Array.from({ length: width - 2 }, (_, i) => | 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), | |||||
| ]; | ]; | ||||
| } | } | ||||
| } | } |
| export default { | export default { | ||||
| tiles: new SpriteSheet("assets/tiles.png", 32, 32, 1) | tiles: new SpriteSheet("assets/tiles.png", 32, 32, 1) | ||||
| .defineTile("ground", 0, 0) | .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", 0, 2) | ||||
| .defineTile("platform-l", 1, 2) | .defineTile("platform-l", 1, 2) |
| 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); | |||||
| } | |||||
| } |
| import TPhysics from "../traits/TPhysics.js"; | import TPhysics from "../traits/TPhysics.js"; | ||||
| export default class Platform extends Entity { | export default class Platform extends Entity { | ||||
| constructor(level) { | |||||
| constructor(level, width = 5) { | |||||
| super(level); | super(level); | ||||
| this.bounds.size.set(5, 0.5); | |||||
| this.bounds.size.set(width, 0.5); | |||||
| this.addTrait(new TCollider(this)); | this.addTrait(new TCollider(this)); | ||||
| this.addTrait(new TPlatform(this)); | this.addTrait(new TPlatform(this)); | ||||
| this.addTrait(new TPhysics(this)); | this.addTrait(new TPhysics(this)); | ||||
| this.targetSpeed = 3; | this.targetSpeed = 3; | ||||
| this.accel = 5; | this.accel = 5; | ||||
| this.dir = 1; | this.dir = 1; | ||||
| this.movement = 5; | |||||
| this.texture = new Texture(assets.tiles, | this.texture = new Texture(assets.tiles, | ||||
| Tile.createLine(this.bounds.size.x, "platform")); | Tile.createLine(this.bounds.size.x, "platform")); | ||||
| init() { | init() { | ||||
| this.targetTop = this.bounds.pos.y; | 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.gravity = 0; | ||||
| this.t.physics.velocity.y = 0; | this.t.physics.velocity.y = 0; |
| import Level from "./Level.js"; | import Level from "./Level.js"; | ||||
| import Vec2 from "./Vec2.js"; | |||||
| import Player from "./entities/Player.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 structures from "./structures.js"; | ||||
| import Vec2 from "./Vec2.js"; | |||||
| let canvas = document.getElementById("canvas"); | let canvas = document.getElementById("canvas"); | ||||
| let level = new Level(canvas); | let level = new Level(canvas); | ||||
| level.spawnEntity(new Player(level), 10, 1); | 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(); | level.start(); | ||||
| import Tile from "./Tile.js"; | import Tile from "./Tile.js"; | ||||
| export default { | export default { | ||||
| floor: width => new Structure( | |||||
| floor: (width, height = 1)=> new Structure( | |||||
| [ "wall" ], | [ "wall" ], | ||||
| Tile.createLine(width, "grass")), | |||||
| Tile.createBox(width, height, "ground-top", "ground", "ground")), | |||||
| }; | }; |