|
|
@@ -53,39 +53,83 @@ function background(ctx, camera, offset) { |
|
|
|
window.addEventListener("resize", () => background.cache = null); |
|
|
|
|
|
|
|
class Animation { |
|
|
|
constructor({img, x, y, width, height, nsteps, loop = false, fps = 10}) { |
|
|
|
constructor({img, x, y, width, height, dwidth, dheight, wsteps, hsteps, nsteps, loop, fps, rot, offsetX, offsetY}) { |
|
|
|
loop = loop || false; |
|
|
|
fps = fps || 30; |
|
|
|
nsteps = nsteps || wsteps * hsteps; |
|
|
|
dwidth = dwidth || width; |
|
|
|
dheight = dheight || height; |
|
|
|
rot = rot || 0; |
|
|
|
offsetX = offsetX || 0; |
|
|
|
offsetY = offsetY || 0; |
|
|
|
|
|
|
|
this.img = img; |
|
|
|
this.x = x; |
|
|
|
this.y = y; |
|
|
|
this.offsetX = offsetX; |
|
|
|
this.offsetY = offsetY; |
|
|
|
this.rot = rot; |
|
|
|
this.width = width; |
|
|
|
this.height = height; |
|
|
|
this.nsteps = nsteps; |
|
|
|
this.dwidth = dwidth; |
|
|
|
this.dheight = dheight; |
|
|
|
this.wsteps = wsteps; |
|
|
|
this.hsteps = hsteps; |
|
|
|
this.wstep = 0; |
|
|
|
this.hstep = 0; |
|
|
|
this.step = 0; |
|
|
|
this.nsteps = nsteps; |
|
|
|
this.loop = loop; |
|
|
|
this.visible = true; |
|
|
|
this.onend = function(){}; |
|
|
|
|
|
|
|
let interval = setInterval(() => { |
|
|
|
this.step += 1; |
|
|
|
if (this.step > this.nsteps) { |
|
|
|
if (this.step >= this.nsteps) { |
|
|
|
this.step = 0; |
|
|
|
this.wstep = 0; |
|
|
|
this.hstep = 0; |
|
|
|
|
|
|
|
if (!loop) |
|
|
|
if (!this.loop) { |
|
|
|
clearInterval(interval); |
|
|
|
this.onend(); |
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
this.wstep += 1; |
|
|
|
if (this.wstep >= this.wsteps) { |
|
|
|
this.wstep = 0; |
|
|
|
this.hstep += 1; |
|
|
|
} |
|
|
|
|
|
|
|
}, 1000/fps); |
|
|
|
} |
|
|
|
|
|
|
|
animate(ctx) { |
|
|
|
if (!this.visible) |
|
|
|
return; |
|
|
|
|
|
|
|
ctx.translate(this.x, this.y); |
|
|
|
|
|
|
|
if (this.rot) |
|
|
|
ctx.rotate(this.rot); |
|
|
|
|
|
|
|
ctx.drawImage( |
|
|
|
this.img, |
|
|
|
this.step * this.width, |
|
|
|
0, |
|
|
|
this.wstep * this.width, |
|
|
|
this.hstep * this.width, |
|
|
|
this.width, |
|
|
|
this.height, |
|
|
|
this.x, |
|
|
|
this.y, |
|
|
|
this.width, |
|
|
|
this.height |
|
|
|
this.offsetX, |
|
|
|
this.offsetY, |
|
|
|
this.dwidth, |
|
|
|
this.dheight |
|
|
|
); |
|
|
|
|
|
|
|
if (this.rot) |
|
|
|
ctx.rotate(-this.rot); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -117,10 +161,10 @@ class Entity { |
|
|
|
|
|
|
|
let BulletImgs = { |
|
|
|
despawn: createImage("imgs/bullet_despawn.png") |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
class Bullet extends Entity { |
|
|
|
constructor(x: 0, y: 0, vel, id, ownerId, game) { |
|
|
|
constructor(x, y, vel, id, ownerId, game) { |
|
|
|
super(x, y, 5, 5, id, game); |
|
|
|
this.imgs = BulletImgs; |
|
|
|
this.vel.set(vel.x, vel.y); |
|
|
@@ -151,15 +195,21 @@ class Bullet extends Entity { |
|
|
|
this.game.animate(new Animation({ |
|
|
|
img: this.imgs.despawn, |
|
|
|
x: this.pos.x, |
|
|
|
y: this.pos.y |
|
|
|
y: this.pos.y, |
|
|
|
width: 64, |
|
|
|
height: 64, |
|
|
|
dwidth: 16, |
|
|
|
dheight: 16, |
|
|
|
wsteps: 5, |
|
|
|
hsteps: 5 |
|
|
|
})); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
let PlayerImgs = { |
|
|
|
thrust_back: createImage("imgs/player_thrust_back.png"), |
|
|
|
explosion: createImage("imgs/player_explosion.png") |
|
|
|
} |
|
|
|
despawn: createImage("imgs/player_despawn.png") |
|
|
|
}; |
|
|
|
|
|
|
|
class Player extends Entity { |
|
|
|
constructor(x, y, id, rot, game) { |
|
|
@@ -169,10 +219,26 @@ class Player extends Entity { |
|
|
|
this.rotVel = 0; |
|
|
|
this.keys = {}; |
|
|
|
this.health = 0; |
|
|
|
|
|
|
|
this.thrustAnim = new Animation({ |
|
|
|
img: this.imgs.thrust_back, |
|
|
|
x: this.pos.x, |
|
|
|
y: this.pos.y, |
|
|
|
width: 128, |
|
|
|
height: 128, |
|
|
|
dwidth: 64, |
|
|
|
dheight: 64, |
|
|
|
wsteps: 4, |
|
|
|
hsteps: 4, |
|
|
|
fps: 60, |
|
|
|
loop: true |
|
|
|
}); |
|
|
|
this.thrustAnim.visible = false; |
|
|
|
game.animate(this.thrustAnim); |
|
|
|
} |
|
|
|
|
|
|
|
draw(ctx, selfId) { |
|
|
|
let h = 255-((100-this.health) * 2) |
|
|
|
let h = 255-((100-this.health) * 2); |
|
|
|
|
|
|
|
if (selfId == this.id) { |
|
|
|
ctx.fillStyle = "rgb("+h+", "+h+", "+h+")"; |
|
|
@@ -183,13 +249,11 @@ class Player extends Entity { |
|
|
|
ctx.rotate(this.rot); |
|
|
|
|
|
|
|
if (this.keys.up) { |
|
|
|
ctx.drawImage( |
|
|
|
this.imgs.thrust_back, |
|
|
|
-this.width, |
|
|
|
this.height/2, |
|
|
|
this.width*2, |
|
|
|
this.height*2 |
|
|
|
); |
|
|
|
this.thrustAnim.rot = this.rot; |
|
|
|
this.thrustAnim.x = this.pos.x; |
|
|
|
this.thrustAnim.y = this.pos.y; |
|
|
|
this.thrustAnim.offsetX = -this.thrustAnim.dwidth/2; |
|
|
|
this.thrustAnim.offsetY = this.thrustAnim.dwidth/2; |
|
|
|
} |
|
|
|
|
|
|
|
ctx.beginPath(); |
|
|
@@ -219,8 +283,6 @@ class Player extends Entity { |
|
|
|
|
|
|
|
let pos = e.pos.clone().sub(this.pos).normalize().scale(100); |
|
|
|
|
|
|
|
console.log(pos); |
|
|
|
|
|
|
|
ctx.fillStyle = "rgb(255, 0, 0)"; |
|
|
|
ctx.beginPath(); |
|
|
|
ctx.arc(pos.x, pos.y, 10, 0, 2*Math.PI); |
|
|
@@ -247,6 +309,27 @@ class Player extends Entity { |
|
|
|
update(dt) { |
|
|
|
super.update(dt); |
|
|
|
this.rot += this.rotVel * dt; |
|
|
|
|
|
|
|
if (this.keys.up) |
|
|
|
this.thrustAnim.visible = true; |
|
|
|
else |
|
|
|
this.thrustAnim.visible = false; |
|
|
|
} |
|
|
|
|
|
|
|
despawn() { |
|
|
|
this.game.animate(new Animation({ |
|
|
|
img: this.imgs.despawn, |
|
|
|
x: this.pos.x, |
|
|
|
y: this.pos.y, |
|
|
|
width: 64, |
|
|
|
height: 64, |
|
|
|
dwidth: 128, |
|
|
|
dheight: 128, |
|
|
|
offsetX: -64, |
|
|
|
offsetY: -64, |
|
|
|
wsteps: 5, |
|
|
|
hsteps: 5 |
|
|
|
})); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -308,6 +391,10 @@ export default class Game { |
|
|
|
}); |
|
|
|
|
|
|
|
sock.on("despawn", (msg) => { |
|
|
|
if (!this.entities[msg.id]) |
|
|
|
return; |
|
|
|
|
|
|
|
this.entities[msg.id].despawn(); |
|
|
|
delete this.entities[msg.id]; |
|
|
|
if (msg.id == this.id) { |
|
|
|
alert("You died."); |
|
|
@@ -374,7 +461,11 @@ export default class Game { |
|
|
|
|
|
|
|
ent.update(dt); |
|
|
|
}); |
|
|
|
this.animations.forEach((a) => a.animate()); |
|
|
|
this.animations.forEach((a) => { |
|
|
|
this.ctx.save(); |
|
|
|
a.animate(this.ctx); |
|
|
|
this.ctx.restore(); |
|
|
|
}); |
|
|
|
this.ctx.translate(cam.x, cam.y); |
|
|
|
|
|
|
|
this.raf = window.requestAnimationFrame(this.update.bind(this)); |
|
|
@@ -391,9 +482,9 @@ export default class Game { |
|
|
|
|
|
|
|
animate(animation) { |
|
|
|
let i = this.animations.length; |
|
|
|
this.animations.add(animation); |
|
|
|
this.animations.push(animation); |
|
|
|
animation.onend = () => { |
|
|
|
delete this.animations[i]; |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
} |