A lightweight JavaScript game engine
git clone git://soophie.de/game-engine
blob: b9b38f37e1db0123504be51a724b2a708be01d0b (3295 bytes)[doc][blame][raw]
1
import { scaleCanvas } from './canvas.js';2
import * as Collision from './collision.js';4
export class Game {5
constructor(width, height, { fps } = {}) {6
this.width = width || 900;7
this.height = height || 600;8
this.fps = 1000 / (fps || 60);9
this.then = Date.now();10
this.canvas = document.createElement('canvas');11
scaleCanvas(this.canvas, this.width, this.height);12
this.g = this.canvas.getContext('2d');13
this.events = [];14
}15
start() {16
requestAnimationFrame(this.loop.bind(this));17
this.update();18
this.render(this.g);19
}20
loop() {21
requestAnimationFrame(this.loop.bind(this));22
this.now = Date.now();23
this.elapsed = this.now - this.then;24
if(this.elapsed > this.fps) {25
this.then = this.now - (this.elapsed % this.fps);26
for(const event of this.events) {27
if(this['on' + event.type]) {28
this['on' + event.type](event);29
}30
}31
this.update();32
this.render(this.g);33
this.events.length = 0;34
}35
}36
update() {37
// nothing38
}39
render() {40
this.g.clearRect(0, 0, this.width, this.height);41
}42
resize(width, height) {43
this.width = width;44
this.height = height;45
scaleCanvas(this.canvas, this.width, this.height);46
}47
bindEvent(element, type) {48
element['on' + type] = event => this.events.push(event);49
}50
}52
export class Group {53
constructor() {54
this.items = [];55
}56
update() {57
for(let item of this.items) {58
item.update();59
}60
}61
render(g) {62
for(let item of this.items) {63
item.render(g);64
}65
}66
causeEvent(type, events) {67
for(let item of this.items) {68
item.causeEvent(type, events);69
}70
}71
collide() {72
const duplicate = [];73
for(const a of this.items) {74
for(const b of this.items) {75
if(!duplicate.includes(b)) {76
if(a !== b) {77
let collided = false;78
if(a.shape instanceof Shape.Rect && b.shape instanceof Shape.Rect) {79
collided = Collision.collideRect(a, b);80
}81
else if(a.shape instanceof Shape.Circle && b.shape instanceof Shape.Circle) {82
collided = Collision.collideCircle(a, b);83
}84
else {85
collided = Collision.collideRectAndCircle(a, b);86
}87
if(collided) {88
if(a.oncollide) {89
a.oncollide(b);90
}91
if(b.oncollide) {92
b.oncollide(a);93
}94
}95
}96
}97
}98
duplicate.push(a);99
}100
}101
add(item) {102
this.items.push(item);103
}104
remove(item) {105
const i = this.items.findIndex(n => n === item);106
if(i !== -1) {107
this.items.splice(i, 1);108
}109
}110
[Symbol.iterator]() {111
return this.items.values();112
}113
}115
export class Surface {116
constructor(x, y, shape) {117
this.x = x;118
this.y = y;119
this.shape = shape;120
}121
update() {122
// nothing123
}124
render(g) {125
if(this.shape instanceof Shape.Rect) {126
g.beginPath();127
g.rect(this.x, this.y, this.shape.width, this.shape.height);128
g.stroke();129
}130
if(this.shape instanceof Shape.Circle) {131
g.beginPath();132
g.arc(this.x, this.y, this.shape.radius, 2 * Math.PI, 0);133
g.stroke();134
}135
}136
causeEvent(type, events) {137
if(this['on' + type]) {138
for(const event of events) {139
if(event.type === type) {140
this['on' + type](event);141
}142
}143
}144
}145
}147
class Rect {148
constructor(width, height) {149
this.width = width;150
this.height = height;151
}152
}154
class Circle {155
constructor(radius) {156
this.radius = radius;157
}158
}