| function random(min, max) { | function random(min, max) { | ||||
| return Math.random() * (max - min) + min; | return Math.random() * (max - min) + min; | ||||
| } | } | ||||
| function inRange(n, min, max) { | |||||
| return n >= min && n <= max; | |||||
| } | |||||
| class Vec2 { | class Vec2 { | ||||
| constructor(x, y) { | constructor(x, y) { | ||||
| } | } | ||||
| set(x, y) { | set(x, y) { | ||||
| if (x instanceof Vec2) | |||||
| return this.set(x.x, x.y); | |||||
| this.x = x; | this.x = x; | ||||
| this.y = y; | this.y = y; | ||||
| return this; | return this; | ||||
| } | } | ||||
| add(x, y) { | add(x, y) { | ||||
| if (x instanceof Vec2) | |||||
| return this.add(x.x, x.y); | |||||
| this.x += x; | this.x += x; | ||||
| this.y += y; | this.y += y; | ||||
| return this; | return this; | ||||
| } | } | ||||
| sub(x, y) { | |||||
| if (x instanceof Vec2) | |||||
| return this.sub(x.x, x.y); | |||||
| this.x -= x; | |||||
| this.y -= y; | |||||
| return this; | |||||
| } | |||||
| scale(num) { | scale(num) { | ||||
| this.x *= num; | this.x *= num; | ||||
| this.y *= num; | this.y *= num; | ||||
| this.width = width; | this.width = width; | ||||
| this.height = height; | this.height = height; | ||||
| } | } | ||||
| intersects(b) { | |||||
| let a = this; | |||||
| //console.log("if ("+a.x+", "+a.y+") intersects ("+b.x+", "+b.y+")"); | |||||
| return ( | |||||
| (inRange(a.x, b.x, b.x + b.width) || inRange(b.x, a.x, a.x + a.width)) && | |||||
| (inRange(a.y, b.y, b.y + b.height) || inRange(b.y, a.y, a.y + a.height)) | |||||
| ); | |||||
| } | |||||
| } | } | ||||
| class Entity { | class Entity { | ||||
| } | } | ||||
| get boundingRect() { | get boundingRect() { | ||||
| return new Rectangle(this.pos.x, this.pos.y, this.width, this.height); | |||||
| if (this.oundingRectCache) | |||||
| return this.boundingRectCache; | |||||
| this.boundingRectCache = new Rectangle(this.pos.x, this.pos.y, this.width, this.height); | |||||
| return this.boundingRectCache; | |||||
| } | |||||
| intersectsPoint(e) { | |||||
| let rect = this.boundingRect; | |||||
| let r = new Rectangle(e.pos.x, e.pos.y, 1, 1); | |||||
| return rect.intersects(r); | |||||
| } | } | ||||
| move(dt) { | move(dt) { | ||||
| this.vforce.scale(this.forceScalar * dt); | this.vforce.scale(this.forceScalar * dt); | ||||
| this.vel.add(this.vforce.x, this.vforce.y); | |||||
| this.pos.add(this.vel.x * dt, this.vel.y * dt); | |||||
| this.vel.add(this.vforce); | |||||
| this.pos.add(this.vel.clone().scale(dt)); | |||||
| this.vforce.set(0, 0); | this.vforce.set(0, 0); | ||||
| } | } | ||||
| send() {} | send() {} | ||||
| despawn() { | despawn() { | ||||
| delete this.game.entities[this.id]; | |||||
| delete this.game.players[this.id]; | |||||
| this.game.players.forEach((p) => p.sock.send("despawn", { | this.game.players.forEach((p) => p.sock.send("despawn", { | ||||
| id: this.id | id: this.id | ||||
| })); | })); | ||||
| delete this.game.entities[this.id]; | |||||
| delete this.game.players[this.id]; | |||||
| } | } | ||||
| } | } | ||||
| this.ownerId = ownerId; | this.ownerId = ownerId; | ||||
| this.vel = vel; | this.vel = vel; | ||||
| setTimeout(() => this.despawn(), 4000); | |||||
| setTimeout(() => this.despawn(), 1000); | |||||
| } | } | ||||
| send() { | |||||
| send(first) { | |||||
| if (!first) | |||||
| return; | |||||
| this.game.players.forEach((p) => p.sock.send("set", { | this.game.players.forEach((p) => p.sock.send("set", { | ||||
| type: "bullet", | type: "bullet", | ||||
| id: this.id, | id: this.id, | ||||
| this.rotForce = 0; | this.rotForce = 0; | ||||
| this.rotVel = 0; | this.rotVel = 0; | ||||
| this.canShoot = true; | this.canShoot = true; | ||||
| this.health = 100; | |||||
| sock.on("request", (req) => { | sock.on("request", (req) => { | ||||
| if (req.url == "get_id") { | if (req.url == "get_id") { | ||||
| } else if (req.url == "keydown") { | } else if (req.url == "keydown") { | ||||
| this.keys[req.data.key] = true; | this.keys[req.data.key] = true; | ||||
| } else if (req.url == "keyup") { | } else if (req.url == "keyup") { | ||||
| this.keys[req.data.key] = false; | |||||
| delete this.keys[req.data.key]; | |||||
| } | } | ||||
| }); | }); | ||||
| this.rotForce += 0.005; | this.rotForce += 0.005; | ||||
| if (this.keys.shoot && this.canShoot) { | if (this.keys.shoot && this.canShoot) { | ||||
| let vel = new Vec2(0, -1).rotate(this.rot); | |||||
| let b = new Bullet(this.pos, vel, this.id, this.game.id, this.game); | |||||
| let vel = new Vec2(0, -1).rotate(this.rot).add(this.vel); | |||||
| let posmod = new Vec2(0, -this.height/2).rotate(this.rot); | |||||
| let pos = this.pos.clone().add(posmod); | |||||
| let b = new Bullet(pos, vel, this.id, this.game.id, this.game); | |||||
| this.game.spawn(b); | this.game.spawn(b); | ||||
| this.canShoot = false; | this.canShoot = false; | ||||
| setTimeout(() => this.canShoot = true, 100); | |||||
| setTimeout(() => this.canShoot = true, 50); | |||||
| } | } | ||||
| f.rotate(this.rot); | f.rotate(this.rot); | ||||
| this.force(f.x, f.y); | this.force(f.x, f.y); | ||||
| //Detect collissions | |||||
| this.game.entities.forEach((e) => { | |||||
| if (e instanceof Bullet) { | |||||
| if (e.ownerId !== this.id && this.intersectsPoint(e)) { | |||||
| this.health -= 3; | |||||
| e.despawn(); | |||||
| if (this.health <= 0) | |||||
| this.despawn(); | |||||
| } | |||||
| } | |||||
| }); | |||||
| this.boundingRectCache = null; | |||||
| } | |||||
| get boundingRect() { | |||||
| if (this.boundingRectCache) | |||||
| return this.boundingRectCache; | |||||
| //0 1 | |||||
| // * | |||||
| //3 2 | |||||
| var rotated = [ | |||||
| new Vec2(-this.width/2, -this.height/2), | |||||
| new Vec2(this.width/2, -this.height/2), | |||||
| new Vec2(this.width/2, this.height/2), | |||||
| new Vec2(-this.width/2, this.height/2) | |||||
| ].map((p) => p.rotate(this.rot)); | |||||
| let tl = new Vec2(0, 0); | |||||
| let br = new Vec2(0, 0); | |||||
| rotated.forEach((p) => { | |||||
| if (p.x < tl.x) | |||||
| tl.x = p.x; | |||||
| if (p.y < tl.y) | |||||
| tl.y = p.y; | |||||
| if (p.x > br.x) | |||||
| br.x = p.x; | |||||
| if (p.y > br.y) | |||||
| br.y = p.y; | |||||
| }); | |||||
| this.boundingRectCache = new Rectangle( | |||||
| this.pos.x + tl.x, | |||||
| this.pos.y + tl.y, | |||||
| br.x - tl.x, | |||||
| br.y - tl.y | |||||
| ); | |||||
| return this.boundingRectCache; | |||||
| } | } | ||||
| move(dt) { | move(dt) { | ||||
| super.move(dt); | super.move(dt); | ||||
| this.rotForce *= this.forceScalar * dt; | this.rotForce *= this.forceScalar * dt; | ||||
| this.rotVel += this.rotForce; | this.rotVel += this.rotForce; | ||||
| this.rot += this.rotVel * dt; | |||||
| this.rot = (this.rot + this.rotVel * dt) % (Math.PI * 2); | |||||
| this.rotForce = 0; | this.rotForce = 0; | ||||
| } | } | ||||
| send() { | |||||
| this.game.players.forEach((p) => p.sock.send("set", { | |||||
| type: "player", | |||||
| send(first) { | |||||
| let obj = { | |||||
| id: this.id, | id: this.id, | ||||
| pos: this.pos, | pos: this.pos, | ||||
| vel: this.vel, | vel: this.vel, | ||||
| rot: this.rot, | rot: this.rot, | ||||
| rotVel: this.rotVel | |||||
| })); | |||||
| rotVel: this.rotVel, | |||||
| keys: this.keys, | |||||
| health: this.health | |||||
| } | |||||
| if (first) | |||||
| obj.type = "player"; | |||||
| this.game.players.forEach((p) => p.sock.send("set", obj)); | |||||
| } | } | ||||
| } | } | ||||
| spawn(ent) { | spawn(ent) { | ||||
| this.entities[this.id] = ent; | this.entities[this.id] = ent; | ||||
| this.id += 1; | this.id += 1; | ||||
| ent.send(true); | |||||
| } | } | ||||
| start() { | start() { |