A lightweight JavaScript game engine
git clone git://soophie.de/game-engine
blob: b1f9322f9ab6b764c318806f2ba75d9250ed4228 (3710 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 = new Proxy({}, {14
get: function(object, prop) {15
const val = object[prop];16
if(typeof val !== 'undefined') {17
delete object[prop];18
}19
return val;20
}21
});22
}23
start() {24
requestAnimationFrame(this.loop.bind(this));25
this.update();26
this.g.save();27
this.render(this.g);28
this.g.restore();29
}30
loop() {31
requestAnimationFrame(this.loop.bind(this));32
this.now = Date.now();33
this.elapsed = this.now - this.then;34
if(this.elapsed > this.fps) {35
this.then = this.now - (this.elapsed % this.fps);36
this.update();37
this.g.save();38
this.render(this.g);39
this.g.restore();40
}41
}42
update() {43
// empty44
}45
render() {46
this.g.clearRect(0, 0, this.width, this.height);47
}48
resize(width, height) {49
this.width = width;50
this.height = height;51
scaleCanvas(this.canvas, this.width, this.height);52
}53
bindEvent(element, event) {54
element[event] = event => {55
this.events[event.type] = this.populateEvent ? { type: event.type, ...this.populateEvent(event) } : event;56
}57
}58
}60
export class Group {61
constructor() {62
this.items = [];63
}64
update() {65
for(let item of this.items) {66
item.update();67
}68
}69
render(g) {70
for(let item of this.items) {71
g.save();72
item.render(g);73
g.restore();74
}75
}76
collide() {77
for(const i of this.items) {78
i.items = [];79
i.collided = false;80
}81
const duplicate = [];82
for(const a of this.items) {83
for(const b of this.items) {84
if(!duplicate.includes(b)) {85
if(a !== b) {86
let collided = false;87
if(a.shape instanceof Shape.Rect && b.shape instanceof Shape.Rect) {88
collided = Collision.collideRect(a, b);89
}90
else if(a.shape instanceof Shape.Circle && b.shape instanceof Shape.Circle) {91
collided = Collision.collideCircle(a, b);92
}93
else {94
collided = Collision.collideRectAndCircle(a, b);95
}96
if(!a.collided) {97
a.collided = collided;98
}99
if(!b.collided) {100
b.collided = collided;101
}102
if(collided) {103
if(!a.items.includes(b)) {104
a.items.push(b);105
}106
if(!b.items.includes(a)) {107
b.items.push(a);108
}109
}110
}111
}112
}113
duplicate.push(a);114
}115
}116
add(item) {117
this.items.push(item);118
}119
remove(item) {120
const i = this.items.findIndex(n => n === item);121
if(i !== -1) {122
this.items.splice(i, 1);123
}124
}125
[Symbol.iterator]() {126
return this.items.values();127
}128
}130
export class Surface {131
constructor(x, y, shape) {132
this.x = x;133
this.y = y;134
this.shape = shape;135
this.events = new Proxy({}, {136
get: function(object, prop) {137
const val = object[prop];138
if(typeof val !== 'undefined') {139
delete object[prop];140
}141
return val;142
}143
});144
}145
update() {146
// empty147
}148
render(g) {149
if(this.shape instanceof Shape.Rect) {150
g.beginPath();151
g.rect(this.x, this.y, this.shape.width, this.shape.height);152
g.stroke();153
}154
if(this.shape instanceof Shape.Circle) {155
g.beginPath();156
g.arc(this.x, this.y, this.shape.radius, 2 * Math.PI, 0);157
g.stroke();158
}159
}160
causeEvent(event) {161
this.events[event.type] = event;162
}163
}165
class Rect {166
constructor(width, height) {167
this.width = width;168
this.height = height;169
}170
}172
class Circle {173
constructor(radius) {174
this.radius = radius;175
}176
}