| window.addEventListener("resize", () => background.cache = null); | window.addEventListener("resize", () => background.cache = null); | ||||
| class Animation { | 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.img = img; | ||||
| this.x = x; | this.x = x; | ||||
| this.y = y; | this.y = y; | ||||
| this.offsetX = offsetX; | |||||
| this.offsetY = offsetY; | |||||
| this.rot = rot; | |||||
| this.width = width; | this.width = width; | ||||
| this.height = height; | 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.step = 0; | ||||
| this.nsteps = nsteps; | |||||
| this.loop = loop; | |||||
| this.visible = true; | |||||
| this.onend = function(){}; | this.onend = function(){}; | ||||
| let interval = setInterval(() => { | let interval = setInterval(() => { | ||||
| this.step += 1; | this.step += 1; | ||||
| if (this.step > this.nsteps) { | |||||
| if (this.step >= this.nsteps) { | |||||
| this.step = 0; | this.step = 0; | ||||
| this.wstep = 0; | |||||
| this.hstep = 0; | |||||
| if (!loop) | |||||
| if (!this.loop) { | |||||
| clearInterval(interval); | |||||
| this.onend(); | this.onend(); | ||||
| } | |||||
| return; | |||||
| } | |||||
| this.wstep += 1; | |||||
| if (this.wstep >= this.wsteps) { | |||||
| this.wstep = 0; | |||||
| this.hstep += 1; | |||||
| } | } | ||||
| }, 1000/fps); | }, 1000/fps); | ||||
| } | } | ||||
| animate(ctx) { | animate(ctx) { | ||||
| if (!this.visible) | |||||
| return; | |||||
| ctx.translate(this.x, this.y); | |||||
| if (this.rot) | |||||
| ctx.rotate(this.rot); | |||||
| ctx.drawImage( | ctx.drawImage( | ||||
| this.img, | this.img, | ||||
| this.step * this.width, | |||||
| 0, | |||||
| this.wstep * this.width, | |||||
| this.hstep * this.width, | |||||
| this.width, | this.width, | ||||
| this.height, | 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); | |||||
| } | } | ||||
| } | } | ||||
| let BulletImgs = { | let BulletImgs = { | ||||
| despawn: createImage("imgs/bullet_despawn.png") | despawn: createImage("imgs/bullet_despawn.png") | ||||
| } | |||||
| }; | |||||
| class Bullet extends Entity { | 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); | super(x, y, 5, 5, id, game); | ||||
| this.imgs = BulletImgs; | this.imgs = BulletImgs; | ||||
| this.vel.set(vel.x, vel.y); | this.vel.set(vel.x, vel.y); | ||||
| this.game.animate(new Animation({ | this.game.animate(new Animation({ | ||||
| img: this.imgs.despawn, | img: this.imgs.despawn, | ||||
| x: this.pos.x, | 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 = { | let PlayerImgs = { | ||||
| thrust_back: createImage("imgs/player_thrust_back.png"), | thrust_back: createImage("imgs/player_thrust_back.png"), | ||||
| explosion: createImage("imgs/player_explosion.png") | |||||
| } | |||||
| despawn: createImage("imgs/player_despawn.png") | |||||
| }; | |||||
| class Player extends Entity { | class Player extends Entity { | ||||
| constructor(x, y, id, rot, game) { | constructor(x, y, id, rot, game) { | ||||
| this.rotVel = 0; | this.rotVel = 0; | ||||
| this.keys = {}; | this.keys = {}; | ||||
| this.health = 0; | 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) { | draw(ctx, selfId) { | ||||
| let h = 255-((100-this.health) * 2) | |||||
| let h = 255-((100-this.health) * 2); | |||||
| if (selfId == this.id) { | if (selfId == this.id) { | ||||
| ctx.fillStyle = "rgb("+h+", "+h+", "+h+")"; | ctx.fillStyle = "rgb("+h+", "+h+", "+h+")"; | ||||
| ctx.rotate(this.rot); | ctx.rotate(this.rot); | ||||
| if (this.keys.up) { | 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(); | ctx.beginPath(); | ||||
| let pos = e.pos.clone().sub(this.pos).normalize().scale(100); | let pos = e.pos.clone().sub(this.pos).normalize().scale(100); | ||||
| console.log(pos); | |||||
| ctx.fillStyle = "rgb(255, 0, 0)"; | ctx.fillStyle = "rgb(255, 0, 0)"; | ||||
| ctx.beginPath(); | ctx.beginPath(); | ||||
| ctx.arc(pos.x, pos.y, 10, 0, 2*Math.PI); | ctx.arc(pos.x, pos.y, 10, 0, 2*Math.PI); | ||||
| update(dt) { | update(dt) { | ||||
| super.update(dt); | super.update(dt); | ||||
| this.rot += this.rotVel * 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 | |||||
| })); | |||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||
| sock.on("despawn", (msg) => { | sock.on("despawn", (msg) => { | ||||
| if (!this.entities[msg.id]) | |||||
| return; | |||||
| this.entities[msg.id].despawn(); | |||||
| delete this.entities[msg.id]; | delete this.entities[msg.id]; | ||||
| if (msg.id == this.id) { | if (msg.id == this.id) { | ||||
| alert("You died."); | alert("You died."); | ||||
| ent.update(dt); | 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.ctx.translate(cam.x, cam.y); | ||||
| this.raf = window.requestAnimationFrame(this.update.bind(this)); | this.raf = window.requestAnimationFrame(this.update.bind(this)); | ||||
| animate(animation) { | animate(animation) { | ||||
| let i = this.animations.length; | let i = this.animations.length; | ||||
| this.animations.add(animation); | |||||
| this.animations.push(animation); | |||||
| animation.onend = () => { | animation.onend = () => { | ||||
| delete this.animations[i]; | delete this.animations[i]; | ||||
| } | |||||
| }; | |||||
| } | } | ||||
| } | } |