| { | |||||
| "presets": ["env"] | |||||
| } |
| public/bundle.js | |||||
| node_modules |
| import Rect from './Rect'; | |||||
| import Vec2 from './Vec2'; | |||||
| export class Trait { | |||||
| constructor(entity, name) { | |||||
| this.name = name; | |||||
| this.entity = entity; | |||||
| this.enabled = true; | |||||
| } | |||||
| init() {} | |||||
| update(dt) {} | |||||
| } | |||||
| export default class Entity { | |||||
| constructor(level) { | |||||
| this.level = level; | |||||
| this.bounds = new Rect(); | |||||
| this.velocity = new Vec2(); | |||||
| this.t = {}; | |||||
| this.traits = []; | |||||
| } | |||||
| init() { | |||||
| for (let trait of this.traits) { | |||||
| trait.init(); | |||||
| } | |||||
| } | |||||
| update(dt) { | |||||
| for (let trait of this.traits) { | |||||
| if (trait.enabled) | |||||
| trait.update(dt); | |||||
| } | |||||
| this.bounds.pos.x += this.velocity.x * dt; | |||||
| this.bounds.pos.y += this.velocity.y * dt; | |||||
| } | |||||
| draw(ctx) {} | |||||
| has(name) { | |||||
| let t = this.t[name]; | |||||
| return t != null && t.enabled; | |||||
| } | |||||
| addTrait(t) { | |||||
| this.t[t.name] = t; | |||||
| this.traits.push(t); | |||||
| } | |||||
| } |
| import Player from './entities/Player'; | |||||
| export default class Level { | |||||
| constructor(canvas) { | |||||
| this.step = 1 / 120; | |||||
| this.canvas = canvas; | |||||
| this.ctx = canvas.getContext("2d"); | |||||
| this.lastTime = null; | |||||
| this.raf = null; | |||||
| this.timeAcc = 0; | |||||
| this.entities = []; | |||||
| } | |||||
| spawn(ent, x, y) { | |||||
| ent.bounds.pos.set(x, y); | |||||
| this.entities.push(ent); | |||||
| ent.init(); | |||||
| } | |||||
| physics(dt) { | |||||
| this.entities.forEach(ent => | |||||
| ent.update(dt)); | |||||
| this.entities.forEach(ent => { | |||||
| ent.bounds.pos.x += ent.velocity.x * dt; | |||||
| ent.bounds.pos.y += ent.velocity.y * dt; | |||||
| }); | |||||
| } | |||||
| draw() { | |||||
| this.canvas.width = window.innerWidth; | |||||
| this.canvas.height = window.innerHeight; | |||||
| this.entities.forEach(ent => ent.draw(this.ctx)); | |||||
| } | |||||
| update(time) { | |||||
| if (this.lastTime != null) { | |||||
| let dt = (time - this.lastTime) / 1000; | |||||
| this.timeAcc += dt; | |||||
| while (this.timeAcc > this.step) { | |||||
| this.physics(this.step); | |||||
| this.timeAcc -= this.step; | |||||
| } | |||||
| this.draw(); | |||||
| } | |||||
| this.lastTime = time; | |||||
| this.raf = requestAnimationFrame(time => this.update(time)); | |||||
| } | |||||
| start() { | |||||
| this.stop(); | |||||
| this.lastTime = null; | |||||
| this.update(); | |||||
| } | |||||
| stop() { | |||||
| if (this.raf != null) { | |||||
| cancelAnimationFrame(this.raf); | |||||
| this.raf = null; | |||||
| } | |||||
| } | |||||
| } |
| import Vec2 from './Vec2'; | |||||
| export default class Rect { | |||||
| constructor(pos = new Vec2(), size = new Vec2()) { | |||||
| this.pos = pos; | |||||
| this.size = size; | |||||
| } | |||||
| draw(ctx) { | |||||
| ctx.moveTo(this.left, this.top); | |||||
| ctx.lineTo(this.right, this.top); | |||||
| ctx.lineTo(this.right, this.bottom); | |||||
| ctx.lineTo(this.left, this.bottom); | |||||
| ctx.closePath(); | |||||
| ctx.stroke(); | |||||
| } | |||||
| get top() { | |||||
| return this.pos.y; | |||||
| } | |||||
| set top(n) { | |||||
| this.pos.y = n; | |||||
| } | |||||
| get bottom() { | |||||
| return this.pos.y + this.size.y; | |||||
| } | |||||
| set bottom(n) { | |||||
| this.pos.y = n - this.size.y; | |||||
| } | |||||
| get left() { | |||||
| return this.pos.x; | |||||
| } | |||||
| set left(n) { | |||||
| this.pos.x = n; | |||||
| } | |||||
| get right() { | |||||
| return this.pos.x + this.size.x; | |||||
| } | |||||
| set right(n) { | |||||
| this.pos.x = n - this.size.x; | |||||
| } | |||||
| } |
| export default class Vec2 { | |||||
| constructor(x = 0, y = 0) { | |||||
| this.x = x; | |||||
| this.y = y; | |||||
| } | |||||
| set(x, y) { | |||||
| this.x = x; | |||||
| this.y = y; | |||||
| } | |||||
| } |
| import Entity from '../Entity'; | |||||
| import Vec2 from '../Vec2'; | |||||
| import KeyboardControls from '../traits/KeyboardControls'; | |||||
| export default class Player extends Entity { | |||||
| constructor(level) { | |||||
| super(level); | |||||
| this.bounds.size.set(20, 20); | |||||
| this.addTrait(new KeyboardControls(this)); | |||||
| } | |||||
| draw(ctx) { | |||||
| this.bounds.draw(ctx); | |||||
| } | |||||
| } |
| import Level from './Level'; | |||||
| import Player from './entities/Player'; | |||||
| import Vec2 from './Vec2'; | |||||
| let level = new Level(document.getElementById("canvas")); | |||||
| level.spawn(new Player(level), 20, 20); | |||||
| level.start(); |
| import {Trait} from '../Entity'; | |||||
| export default class KeyboardControls extends Trait { | |||||
| constructor(entity) { | |||||
| super(entity, "keyboardControls"); | |||||
| this.speed = 500; | |||||
| this.map = { | |||||
| KeyA: 'left', | |||||
| KeyD: 'right', | |||||
| }; | |||||
| this.pressed = {}; | |||||
| } | |||||
| onkey(evt) { | |||||
| let name = this.map[evt.code]; | |||||
| if (name == null) return; | |||||
| evt.preventDefault(); | |||||
| this.pressed[name] = evt.type === 'keydown'; | |||||
| } | |||||
| init() { | |||||
| window.addEventListener("keydown", e => this.onkey(e)); | |||||
| window.addEventListener("keyup", e => this.onkey(e)); | |||||
| } | |||||
| update(dt) { | |||||
| if (this.pressed.left) | |||||
| this.entity.velocity.x -= this.speed * dt; | |||||
| if (this.pressed.right) | |||||
| this.entity.velocity.x += this.speed * dt; | |||||
| } | |||||
| } |
| { | |||||
| "name": "smartgame", | |||||
| "version": "1.0.0", | |||||
| "description": "", | |||||
| "main": "index.js", | |||||
| "scripts": { | |||||
| "test": "echo \"Error: no test specified\" && exit 1", | |||||
| "build-dbg": "browserify js/main.js -t [ babelify --sourceMap ] --debug --outfile public/bundle.js", | |||||
| "build-prod": "browserify js/main.js -t [ babelify --sourceMap ] --outfile public/bundle.js" | |||||
| }, | |||||
| "author": "", | |||||
| "license": "ISC", | |||||
| "devDependencies": { | |||||
| "babel-core": "^6.26.0", | |||||
| "babel-preset-env": "^1.6.1", | |||||
| "babelify": "^8.0.0", | |||||
| "browserify": "^14.5.0" | |||||
| } | |||||
| } |
| <!DOCTYPE html> | |||||
| <html> | |||||
| <head> | |||||
| <meta charset="utf-8"> | |||||
| <title>Game</title> | |||||
| <style> | |||||
| body { | |||||
| margin: 0; | |||||
| } | |||||
| canvas { | |||||
| display: block; | |||||
| } | |||||
| </style> | |||||
| </head> | |||||
| <body> | |||||
| <canvas id="canvas"></canvas> | |||||
| <script src="bundle.js"></script> | |||||
| </body> | |||||
| </html> |