Bläddra i källkod

improvements and things

master
mort 8 år sedan
förälder
incheckning
6f74b8795a
4 ändrade filer med 239 tillägg och 35 borttagningar
  1. 170
    34
      es/game.js
  2. 1
    1
      es/script.js
  3. 68
    0
      es/vec2.js
  4. Binär
      imgs/explosion.png

+ 170
- 34
es/game.js Visa fil

let Vec2 = require("./vec2");

function randint(min, max) { function randint(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
} }
return Math.random() * (max - min + 1) + min; return Math.random() * (max - min + 1) + min;
} }


function background(ctx, camera) {
function diff(n1, n2) {
return Math.abs(n1 - n2);
}

function background(ctx, camera, offset) {
if (!background.cache) { if (!background.cache) {
let cache = []; let cache = [];
let n = 1000; let n = 1000;
ctx.fillStyle = "#FFFFFF"; ctx.fillStyle = "#FFFFFF";
for (let i = 0, len = cache.length; i < len; ++i) { for (let i = 0, len = cache.length; i < len; ++i) {
let p = cache[i]; let p = cache[i];
let x = ((p.x - cx) / p.p) % window.innerWidth;
let y = ((p.y - cy) / p.p) % window.innerHeight;
let x = (((p.x - cx) / p.p) + offset.x) % window.innerWidth;
let y = (((p.y - cy) / p.p) + offset.y) % window.innerHeight;
if (x < 0) if (x < 0)
x += window.innerWidth; x += window.innerWidth;
if (y < 0) if (y < 0)


window.addEventListener("resize", () => background.cache = null); window.addEventListener("resize", () => background.cache = null);


class Animation {
constructor({img, x, y, width, height, nsteps, loop = false, fps = 10}) {
this.img = img;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.nsteps = nsteps;
this.step = 0;
this.onend = function(){};

let interval = setInterval(() => {
this.step += 1;
if (this.step > this.nsteps) {
this.step = 0;

if (!loop)
this.onend();
}
}, 1000/fps);
}

animate(ctx) {
ctx.drawImage(
this.img,
this.step * this.width,
0,
this.width,
this.height,
this.x,
this.y,
this.width,
this.height
);
}
}

class Entity { class Entity {
constructor(x, y, width, height, id) {
this.pos = {x: x, y: y};
this.vel = {x: 0, y: 0};
constructor(x, y, width, height, id, game) {
this.pos = new Vec2(x, y);
this.vel = new Vec2(0, 0);
this.width = width; this.width = width;
this.height = height; this.height = height;
this.game = game;


this.id = id; this.id = id;
} }
draw(ctx) {} draw(ctx) {}


set(obj) { set(obj) {
this.pos = obj.pos;
this.vel = obj.vel;
this.pos.set(obj.pos.x, obj.pos.y);
this.vel.set(obj.vel.x, obj.vel.y);
} }


update(dt) { update(dt) {
this.pos.x += this.vel.x * dt; this.pos.x += this.vel.x * dt;
this.pos.y += this.vel.y * dt; this.pos.y += this.vel.y * dt;
} }

despawn() {}
}

let BulletImgs = {
despawn: createImage("imgs/bullet_despawn.png")
} }


class Bullet extends Entity { class Bullet extends Entity {
constructor(x, y, vel, id, ownerId) {
super(x, y, 5, 5, id);
this.vel = vel;
constructor(x: 0, y: 0, vel, id, ownerId, game) {
super(x, y, 5, 5, id, game);
this.imgs = BulletImgs;
this.vel.set(vel.x, vel.y);
this.ownerId = ownerId; this.ownerId = ownerId;

if (ownerId == game.id)
game.screenShake(10, 0);
} }


draw(ctx, selfId) { draw(ctx, selfId) {
set(obj) { set(obj) {
super.set(obj); super.set(obj);
} }

despawn() {
this.game.animate(new Animation({
img: this.imgs.despawn,
x: this.pos.x,
y: this.pos.y
}));
}
} }


let PlayerImgs = { let PlayerImgs = {
thrust_back: createImage("imgs/thrust_back.png")
thrust_back: createImage("imgs/player_thrust_back.png"),
explosion: createImage("imgs/player_explosion.png")
} }


class Player extends Entity { class Player extends Entity {
constructor(x, y, id, rot) {
super(x, y, 25, 60, id);
constructor(x, y, id, rot, game) {
super(x, y, 25, 60, id, game);
this.imgs = PlayerImgs;
this.rot = rot; this.rot = rot;
this.rotVel = 0; this.rotVel = 0;
this.keys = {}; this.keys = {};
this.imgs = PlayerImgs;
this.health = 0; this.health = 0;
} }


let h = 255-((100-this.health) * 2) let h = 255-((100-this.health) * 2)


if (selfId == this.id) { if (selfId == this.id) {
ctx.fillStyle = "rgba("+h+", "+h+", "+h+", 1)";
ctx.fillStyle = "rgb("+h+", "+h+", "+h+")";
} else { } else {
ctx.fillStyle = "rgba("+h+", 0, 0, 1)";
ctx.fillStyle = "rgb("+h+", 0, 0)";
} }


ctx.rotate(this.rot); ctx.rotate(this.rot);
ctx.lineTo(this.width, this.height/2); ctx.lineTo(this.width, this.height/2);
ctx.closePath(); ctx.closePath();
ctx.fill(); ctx.fill();

ctx.rotate(-this.rot);

//Draw pointers to far away players
if (selfId == this.id) {
this.game.entities.forEach((e) => {

//Only draw players
if (!(e instanceof Player))
return;

//Only draw far away players
if (
diff(e.pos.x, this.pos.x) < window.innerWidth / 2 &&
diff(e.pos.y, this.pos.y) < window.innerHeight / 2
) {
return;
}

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);
ctx.closePath();
ctx.fill();
});
}
} }


set(obj) { set(obj) {
super.set(obj); super.set(obj);
let lastHealth = this.health;

this.rot = obj.rot; this.rot = obj.rot;
this.rotVel = obj.rotVel; this.rotVel = obj.rotVel;
this.keys = obj.keys; this.keys = obj.keys;
this.health = obj.health; this.health = obj.health;

if (this.id == this.game.id && lastHealth > obj.health) {
this.game.screenShake(200);
}
} }


update(dt) { update(dt) {
} }
} }


function createEntity(obj) {
function createEntity(obj, game) {
if (obj.type == "player") { if (obj.type == "player") {
return new Player(obj.pos.x, obj.pos.y, obj.id, obj.rot);
return new Player(obj.pos.x, obj.pos.y, obj.id, obj.rot, game);
} else if (obj.type == "bullet") { } else if (obj.type == "bullet") {
return new Bullet(obj.pos.x, obj.pos.y, obj.vel, obj.id, obj.ownerId);
return new Bullet(obj.pos.x, obj.pos.y, obj.vel, obj.id, obj.ownerId, game);
} else { } else {
throw new Error("Unknown entity type: "+obj.type);
console.log("Unknown entity type: "+obj.type);
return false;
} }
} }


this.canvas = canvas; this.canvas = canvas;
this.ctx = canvas.getContext("2d"); this.ctx = canvas.getContext("2d");
this.id = null; this.id = null;
this.camera = {x: 0, y: 0};
this.camera = new Vec2(0, 0);
this.raf = null; this.raf = null;
this.prevTime = new Date().getTime(); this.prevTime = new Date().getTime();
this.player = null; this.player = null;


this.shake = 0;
this.shakedec = 0.5;

this.keymap = []; this.keymap = [];
this.keymap[87] = "up"; this.keymap[87] = "up";
this.keymap[83] = "down"; this.keymap[83] = "down";
this.keymap[32] = "shoot"; this.keymap[32] = "shoot";


this.entities = []; this.entities = [];
this.animations = [];


sock.on("ready", () => { sock.on("ready", () => {
sock.send("get_id", {}, (err, res) => { sock.send("get_id", {}, (err, res) => {
}); });


sock.on("set", (msg) => { sock.on("set", (msg) => {
if (!this.entities[msg.id])
this.entities[msg.id] = createEntity(msg);
else
if (!this.entities[msg.id]) {
let ent = createEntity(msg, this);
if (ent)
this.entities[msg.id] = ent;
} else {
this.entities[msg.id].set(msg); this.entities[msg.id].set(msg);
}
}); });


sock.on("despawn", (msg) => { sock.on("despawn", (msg) => {
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.");
this.stop();
}
}); });


window.addEventListener("keydown", (evt) => { window.addEventListener("keydown", (evt) => {
this.canvas.width = window.innerWidth; this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight; this.canvas.height = window.innerHeight;


background(this.ctx, this.camera);

let player = this.entities[this.id]; let player = this.entities[this.id];
if (player) { if (player) {
this.camera = {
x: player.pos.x - (window.innerWidth / 2),
y: player.pos.y - (window.innerHeight / 2)
};
this.camera.set(
player.pos.x - (window.innerWidth / 2),
player.pos.y - (window.innerHeight / 2)
);
}

let shakeOffset = new Vec2(0, 0);
if (this.shake > 0) {
shakeOffset.set(
(Math.random() - 0.5) * this.shake,
(Math.random() - 0.5) * this.shake
);
this.shake -= dt * this.shakedec;
} else {
shakeOffset.set(0, 0);
} }


this.ctx.translate(-this.camera.x, -this.camera.y);
let cam = this.camera.clone().add(shakeOffset);

background(this.ctx, this.camera, shakeOffset);

this.ctx.translate(-cam.x, -cam.y);
this.entities.forEach((ent) => { this.entities.forEach((ent) => {
this.ctx.save(); this.ctx.save();
this.ctx.translate(ent.pos.x, ent.pos.y); this.ctx.translate(ent.pos.x, ent.pos.y);


ent.update(dt); ent.update(dt);
}); });
this.ctx.translate(this.camera.x, this.camera.y);
this.animations.forEach((a) => a.animate());
this.ctx.translate(cam.x, cam.y);


this.raf = window.requestAnimationFrame(this.update.bind(this)); this.raf = window.requestAnimationFrame(this.update.bind(this));
} }
stop() { stop() {
window.cancelAnimationFrame(this.raf); window.cancelAnimationFrame(this.raf);
} }

screenShake(n) {
if (this.shake < n)
this.shake = n;
}

animate(animation) {
let i = this.animations.length;
this.animations.add(animation);
animation.onend = () => {
delete this.animations[i];
}
}
} }

+ 1
- 1
es/script.js Visa fil

let Game = require("./game.js");
let Game = require("./game");


document.querySelector("#startGameBtn").addEventListener("click", () => { document.querySelector("#startGameBtn").addEventListener("click", () => {
view("game"); view("game");

+ 68
- 0
es/vec2.js Visa fil

export default class Vec2 {
constructor(x, y) {
this.x = x;
this.y = y;
}

length() {
return Math.sqrt((this.x * this.x) + (this.y * this.y));
}

clone() {
return new Vec2(this.x, this.y);
}

set(x, y) {
if (x instanceof Vec2)
return this.set(x.x, x.y);

this.x = x;
this.y = y;
return this;
}

add(x, y) {
if (x instanceof Vec2)
return this.add(x.x, x.y);

this.x += x;
this.y += y;
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) {
this.x *= num;
this.y *= num;
return this;
}

normalize() {
var len = this.length();

if (len === 0) {
this.x = 1;
this.y = 0;
} else {
this.scale(1 / len);
}

return this;
}

rotate(rad) {
let x = this.x;
let y = this.y;
this.x = x * Math.cos(rad) - y * Math.sin(rad);
this.y = y * Math.cos(rad) + x * Math.sin(rad);
return this;
}
}

Binär
imgs/explosion.png Visa fil


Laddar…
Avbryt
Spara