Any improvement suggestions are welcome, as I'm not the best at making games lol. I have it structured like how Java would be because in the future I want to make it run on java and in the browser.
Graphics Class used to easily resize, draw, and crop images:
class GUI {
static resize() {
PixelTanks.resizer = window.innerHeight/1000;
GUI.root.height = window.innerHeight;
GUI.root.width = window.innerHeight*1.6;
GUI.root.position.set((window.innerWidth-window.innerHeight*1.6)/2, 0);
GUI.root.scale.set(PixelTanks.resizer);
GUI.draw.scale.set(PixelTanks.resizer);
GUI.draw.position.set((window.innerWidth-window.innerHeight*1.6)/2, 0);
GUI.sidebarA.width = Math.abs((window.innerWidth-window.innerHeight*1.6)/2);
GUI.sidebarA.height = window.innerHeight;
GUI.sidebarB.width = Math.abs((window.innerWidth-window.innerHeight*1.6)/2);
GUI.sidebarB.height = window.innerHeight;
GUI.sidebarB.x = window.innerWidth-GUI.sidebarB.width;
Menus.redraw();
}
static resetSpritePool() {
GUI.nextsprite = 0;
}
static resetTextPool() {
GUI.nexttext = 0;
}
static drawImage(image, x, y, w, h, a) {
var sprite = GUI.spritepool[GUI.nextsprite];
sprite.texture = image;
sprite.x = x;
sprite.y = y;
sprite.width = w;
sprite.height = h;
sprite.alpha = a;
sprite.pivot.x = 0;
sprite.pivot.y = 0;
sprite.angle = 0;
GUI.root.addChild(sprite);
GUI.nextsprite++;
if (GUI.nextsprite === GUI.spritepool.length) GUI.resetSpritePool();
}
static drawImageCrop(image, x, y, w, h, cx, cy, cw, ch, a) {
var sprite = GUI.spritepool[GUI.nextsprite];
// generating new textures and rectangles every frame could cause memory leak issues
sprite.texture = new PIXI.Texture(image.baseTexture, new PIXI.Rectangle(cx, cy, cw, ch), image.orig, image.trim);
sprite.x = x;
sprite.y = y;
sprite.width = w;
sprite.height = h;
sprite.alpha = a;
sprite.pivot.x = 0;
sprite.pivot.y = 0;
sprite.angle = 0;
GUI.root.addChild(sprite);
GUI.nextsprite++;
if (GUI.nextsprite === GUI.spritepool.length) GUI.resetSpritePool();
}
static drawImageRotate(image, x, y, w, h, px, py, r, a) {
var sprite = GUI.spritepool[GUI.nextsprite];
sprite.texture = image;
sprite.x = x;
sprite.y = y;
sprite.width = w;
sprite.height = h;
sprite.pivot.x = px;
sprite.pivot.y = py;
sprite.angle = r;
sprite.alpha = a;
GUI.root.addChild(sprite);
GUI.nextsprite++;
if (GUI.nextsprite === GUI.spritepool.length) GUI.resetSpritePool();
}
static drawText(message, x, y, size, color, anchor) {
var text = GUI.textpool[GUI.nexttext];
text.text = message;
text.style = {
fill: color,
fontFamily: 'Font',
fontWeight: 300,
fontSize: size,
};
text.anchor.set(anchor);
text.x = x;
text.y = y;
GUI.nexttext++;
GUI.root.addChild(text);
if (GUI.nexttext === GUI.textpool.length) GUI.resetTextPool();
}
static clear() {
while (GUI.root.children[0]) {
GUI.root.removeChild(GUI.root.children[0]);
}
GUI.draw.clear();
}
}
Setup for graphics, called on page load.
static setup() {
PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
PIXI.Assets.preferWorkers = false;
const ticker = PIXI.Ticker.shared;
ticker.autoStart = false;
ticker.stop();
GUI.spritepool = [];
GUI.textpool = [];
GUI.fontstyle = [];
GUI.fontstyle[30] = new PIXI.TextStyle({fontFamily: 'Font', fontSize: 30, align: 'center'});
GUI.fontstyle[50] = new PIXI.TextStyle({fontFamily: 'Font', fontSize: 50, align: 'center'});
var l = 0;
while (l<500) {
GUI.spritepool.push(new PIXI.Sprite());
l++;
}
l = 0;
while (l<100) {
GUI.textpool.push(new PIXI.Text());
l++;
}
GUI.nextsprite = 0;
GUI.nexttext = 0;
GUI.app = new PIXI.Application({
resizeTo: window,
backgroundColor: '#000000',
antialias: true,
});
document.body.appendChild(GUI.app.view);
PixelTanks.resizer = window.innerHeight/1000;
GUI.root = new PIXI.Container();
GUI.root.height = window.innerHeight;
GUI.root.width = window.innerHeight*1.6;
GUI.root.position.set((window.innerWidth-window.innerHeight*1.6)/2, 0);
GUI.root.scale.set(PixelTanks.resizer);
GUI.app.stage.addChild(GUI.root);
GUI.draw = new PIXI.Graphics();
GUI.draw.scale.set(PixelTanks.resizer);
GUI.draw.position.set((window.innerWidth-window.innerHeight*1.6)/2, 0);
GUI.app.stage.addChild(GUI.draw);
GUI.sidebarA = PIXI.Sprite.from(PIXI.Texture.WHITE);
GUI.sidebarA.width = Math.abs((window.innerWidth-window.innerHeight*1.6)/2);
GUI.sidebarA.height = window.innerHeight;
GUI.sidebarA.x = 0
GUI.sidebarA.y = 0;
GUI.sidebarA.zIndex = 1000;
GUI.sidebarA.tint = 0x000000;
GUI.app.stage.addChild(GUI.sidebarA);
GUI.sidebarB = PIXI.Sprite.from(PIXI.Texture.WHITE);
GUI.sidebarB.width = Math.abs((window.innerWidth-window.innerHeight*1.6)/2);
GUI.sidebarB.height = window.innerHeight;
GUI.sidebarB.x = window.innerWidth-GUI.sidebarB.width;
GUI.sidebarB.y = 0;
GUI.sidebarB.zIndex = 1000;
GUI.sidebarB.tint = 0x000000;
GUI.app.stage.addChild(GUI.sidebarB);
GUI.drawText('0%', 800, 500, 50, '#ffffff', 0.5);
window.oncontextmenu = () => {
return false;
}
window.addEventListener('resize', GUI.resize);
}
Actual Multiplayer class:
class MultiPlayerTank {
control(ip) {
this.SETTINGS = {
fps: false, // chromebooks cant handle this :(
}
this.timers = {
boost: new Date('Nov 28 2006'),
powermissle: new Date('Nov 28 2006'),
toolkit: new Date('Nov 28 2006'),
class: {
date: new Date('Nov 28 2006'),
cooldown: -1,
},
items: [{
date: new Date('Nov 28 2006'),
cooldown: -1,
}, {
date: new Date('Nov 28 2006'),
cooldown: -1,
}, {
date: new Date('Nov 28 2006'),
cooldown: -1,
}, {
date: new Date('Nov 28 2006'),
cooldown: -1,
}],
};
this.xp = 0;
this.crates = 0;
this.kills = 0;
this.coins = 0;
this.hostupdate = {};
this.fireType = 1;
this.halfSpeed = false;
this.canFire = true;
this.canBoost = true;
this.canToolkit = true;
this.canPowermissle = true;
this.canMegamissle = true;
this.canInvis = true;
this.canTurret = true;
this.canBuild = true;
this.canBuff = true;
this.canHeal = true;
this.canDynamite = true;
this.hasDynamite = false;
this.canItem0 = true;
this.canItem1 = true;
this.canItem2 = true;
this.canItem3 = true;
this.gamemode = 'ffa';
this.canChangePaused = true;
this.paused = false;
this.speed = 4;
this.helper = [];
this.intervals = []; // optimize rename to i
this.intervals2 = [];
this.left = null;
this.up = null;
this.grapples = 1;
this.canGrapple = true;
this.showChat = false;
this.msg = '';
this.tank = {
s: 0, // shields [U]
x: 0, // x [U, J]
y: 0, // y [U, J]
r: 0, // rotation [U, J]
e: null, // emote [U]
ra: PixelTanks.userData.stats[4], // rank [j]
br: true, // base rotation [J, U]
u: PixelTanks.user.username, // username [J]
to: false, // toolkit [U]
b: false, // place block [U]
ba: false, // base first -> false, second -> true
p: 0, // pushback [U, J]
pl: 0, // place scaffolding [U]
fl: false, // flashbang fired [U]
i: false, // immune [U]
in: false, // invis [U]
c: PixelTanks.userData.class, // class [J]
co: PixelTanks.userData.cosmetic, // cosmetic [J]
fi: [], // firing
a: false, // animations
mi: false, // place mine
};
this.tank.m = PixelTanks.userData.material;
this.socket = new MegaSocket('wss://'+ip, {
keepAlive: false,
reconnect: false,
autoconnect: true,
});
this.socket.on('message', function(data) {
this.ups++;
if (this.paused) return;
if (data.event == 'hostupdate') {
if (data.tanks) {
this.hostupdate.tanks = data.tanks;
}
if (data.ai) {
this.hostupdate.ai = data.ai;
}
if (data.blocks) {
this.hostupdate.blocks = data.blocks;
}
if (data.bullets) {
this.hostupdate.bullets = data.bullets;
}
if (data.explosions) {
this.hostupdate.explosions = data.explosions;
}
if (data.logs) {
this.hostupdate.logs = data.logs.reverse();
}
} else if (data.event == 'ded') {
this.halfSpeed = false;
this.canFire = true;
this.canBoost = true;
this.canToolkit = true;
this.canPowermissle = true;
this.canMegamissle = true;
this.canInvis = true;
this.canTurret = true;
this.canBuild = true;
this.canBuff = true;
this.canHeal = true;
this.canDynamite = true;
this.hasDynamite = false;
this.canItem0 = true;
this.canItem1 = true;
this.canItem2 = true;
this.canItem3 = true;
this.invis = false;
this.kills = 0;
this.timers = {
boost: new Date('Nov 28 2006'),
powermissle: new Date('Nov 28 2006'),
toolkit: new Date('Nov 28 2006'),
class: {
date: new Date('Nov 28 2006'),
cooldown: -1,
},
items: [{
date: new Date('Nov 28 2006'),
cooldown: -1,
}, {
date: new Date('Nov 28 2006'),
cooldown: -1,
}, {
date: new Date('Nov 28 2006'),
cooldown: -1,
}, {
date: new Date('Nov 28 2006'),
cooldown: -1,
}],
};
} else if (data.event == 'gameover') {
gameover(data.data);
} else if (data.event == 'override') {
var l = 0;
while (l < data.data.length) {
this.tank[data.data[l].key] = data.data[l].value;
l++;
}
} else if (data.event == 'kill') {
this.kills++;
var crates = Math.floor(Math.random() * (2) + 1);
var coins = Math.floor(Math.random()*1000);
this.xp += 10;
this.crates += crates;
this.coins += coins;
PixelTanks.userData.stats[1] += crates;
PixelTanks.userData.stats[3] += 10;
PixelTanks.userData.stats[0] += coins;
PixelTanks.save();
} else if (data.event == 'ping') {
this.ping = new Date().getTime() - this.pingStart;
}
}.bind(this));
this.socket.on('connect', function() {
this.socket.send({
username: PixelTanks.user.username,
token: sessionStorage.token,
type: 'join',
tank: {
x: 0, // x [U, J]
y: 0, // y [U, J]
r: 0, // rotation [U, J]
p: 0, // pushback [U, J]
ra: PixelTanks.userData.stats[4], // rank [J]
br: 0, // base rotation [J]
u: PixelTanks.user.username, // username [J]
ba: 0, // base image stage [U, J]
c: PixelTanks.userData.class, // class [J]
co: PixelTanks.userData.cosmetic, // cosmetic [J]
m: PixelTanks.userData.material,
col: PixelTanks.userData.color,
},
});
this.pingStart = new Date().getTime();
this.pingId = Math.random();
this.socket.send({
type: 'ping',
id: this.pingId,
})
if (!this.SETTINGS.fps) {
setInterval(this.send.bind(this), 1000/60);
requestAnimationFrame(this.frame.bind(this));
}
}.bind(this));
document.addEventListener('keydown', this.keydown.bind(this));
document.addEventListener('keyup', this.keyup.bind(this));
document.addEventListener('mousemove', this.mousemove.bind(this));
document.addEventListener('mousedown', this.mousedown.bind(this));
document.addEventListener('mouseup', this.mouseup.bind(this));
setInterval(function() {
this.pingId = Math.random();
this.pingStart = new Date().getTime();
this.socket.send({
type: 'ping',
id: this.pingId,
});
// use stats here
this.ops = 0;
this.ups = 0;
this.fps = 0;
}.bind(this), 1000);
}
drawBlock(b) {
var team = false, a = 1, l = 0;
while (l<this.hostupdate.tanks.length) {
if (this.hostupdate.tanks[l].t.split(':')[1].replace('@leader', '') === b.o.split(':')[1].replace('@leader', '') && this.hostupdate.tanks[l].u === PixelTanks.user.username) {
team = true;
}
l++;
}
if (b.t === 'mine' && !team) a = .03
GUI.drawImage(PixelTanks.images.blocks[PixelTanks.texturepack][b.t], b.x, b.y, b.t === 'airstrike' ? 200 : 100, b.t === 'airstrike' ? 200 : 100, a);
if (b.s) {
GUI.draw.beginFill(0x000000);
GUI.draw.drawRect(b.x-2, b.y+108, 104, 11);
GUI.draw.endFill();
GUI.draw.beginFill(0x0000FF);
GUI.draw.drawRect(b.x, b.y+110, 100*b.h/b.m, 5);
GUI.draw.endFill();
}
}
drawShot(s) {
if (s.t == 'bullet') {
GUI.draw.beginFill(0x000000);
GUI.draw.drawRect(s.x, s.y, 10, 10)//-2.5, -2.5, 5, 5);
GUI.draw.endFill();
} else if (s.t === 'powermissle' || s.t === 'healmissle') {
GUI.drawImageRotate(PixelTanks.images.bullets[PixelTanks.texturepack].powermissle, s.x, s.y, 20, 40, 5, 10, s.r+180, 1);
} else if (s.t == 'megamissle') {
GUI.drawImageRotate(PixelTanks.images.bullets[PixelTanks.texturepack].megamissle, s.x, s.y, 20, 40, 5, 10, s.r+180, 1); //-5, -10, 10, 20);
} else if (s.t == 'shotgun') {
GUI.drawImageRotate(PixelTanks.images.bullets[PixelTanks.texturepack].shotgun, s.x, s.y, 10, 10, 2.5, 2.5, s.r+180, 1); //-2.5, -2.5);
} else if (s.t == 'grapple') {
GUI.drawImageRotate(PixelTanks.images.bullets[PixelTanks.texturepack].grapple, s.x, s.y, 45, 45, 22.5, 22.5, s.r+180, 1); //-22.5, -22.5);
/*GUI.draw.strokeStyle = 'darkgray';
GUI.draw.rotate(-(s.r+180)*Math.PI/180);
GUI.draw.lineWidth = 5;
GUI.draw.beginPath();
GUI.draw.moveTo(-2.5, -2.5);
GUI.draw.lineTo(s.sx-s.x-2.5, s.sy-s.y-2.5);
GUI.draw.stroke();
GUI.draw.rotate((s.r+180)*Math.PI/180);*/
} else if (s.t === 'dynamite') {
GUI.drawImageRotate(PixelTanks.images.bullets[PixelTanks.texturepack].dynamite, s.x, s.y, 10, 40, 2.5, 2.5, s.r+180, 1);
}
}
drawExplosion(e) {
GUI.drawImageCrop(PixelTanks.images.bullets[PixelTanks.texturepack].explosion, e.x, e.y, e.w, e.h, e.f*50, 0, 50, 50, 1);
}
drawAi(a) {
GUI.drawImage(PixelTanks.images.tanks[PixelTanks.texturepack].other.base, a.x, a.y, 40, 50, 1);
GUI.drawImageRotate(PixelTanks.images.tanks[PixelTanks.texturepack].red.top, a.x, a.y, 80, 90, 40, 40+a.p, a.r, 1);
for (var cosmetic in PixelTanks.images.tanks[PixelTanks.texturepack].cosmetics) {
if (cosmetic === a.c) {
GUI.drawImageRotate(PixelTanks.images.tanks[PixelTanks.texturepack].cosmetics[cosmetic], a.x, a.y, 80, 90, 20, 20+a.p, a.r, 1);
}
}
GUI.draw.beginFill(0x000000);
GUI.draw.drawRect(a.x, a.y+100, 80, 10);
GUI.draw.endFill();
GUI.draw.beginFill(0x00FF00);
GUI.draw.drawRect(a.x+4, a.y+102, 72*a.hp/600, 6);
GUI.draw.endFill();
}
drawTank(t) {
var key = {
0: 'red',
1: 'steel',
2: 'crystal',
3: 'dark',
4: 'light',
};
var a = 1;
if (t.in && t.u.split(':')[0] !== PixelTanks.user.username) a = .03;
if ((t.in && t.u.split(':')[0] === PixelTanks.user.username) || t.ded) a = .5;
GUI.drawImageRotate(PixelTanks.images.tanks[PixelTanks.texturepack][key[t.m]].bottom[t.ba ? 0 : 1], t.x+40, t.y+40, 80, 80, PixelTanks.images.tanks[PixelTanks.texturepack][key[t.m]].bottom[t.ba ? 0 : 1].baseTexture.width/2, PixelTanks.images.tanks[PixelTanks.texturepack][key[t.m]].bottom[t.ba ? 0 : 1].baseTexture.height/2, t.br, a);
GUI.drawImageRotate(PixelTanks.images.tanks[PixelTanks.texturepack][key[t.m]].top, t.x+40, t.y+40, 80, 90, PixelTanks.images.tanks[PixelTanks.texturepack][key[t.m]].top.baseTexture.width/2, PixelTanks.images.tanks[PixelTanks.texturepack][key[t.m]].top.baseTexture.width/2-t.p, t.r, a);
if (t.co) {
for (var cosmetic in PixelTanks.images.tanks[PixelTanks.texturepack].cosmetics) {
if (t.co === cosmetic) {
GUI.drawImageRotate(PixelTanks.images.tanks[PixelTanks.texturepack].cosmetics[cosmetic], t.x+40, t.y+40, 80, 90, PixelTanks.images.tanks[PixelTanks.texturepack].cosmetics[cosmetic].baseTexture.width/2, PixelTanks.images.tanks[PixelTanks.texturepack].cosmetics[cosmetic].baseTexture.width/2-t.p, t.r, a);
}
}
}
if (t.in && t.u.split(':')[0] !== PixelTanks.user.username) return;
if (!t.ded) { // health bar
GUI.draw.beginFill(0x000000);
GUI.draw.drawRect(t.x-2, t.y+98, 84, 11);
GUI.draw.endFill();
GUI.draw.beginFill(0x90EE90);
GUI.draw.drawRect(t.x, t.y+100, 80*t.h/t.ma, 5);
GUI.draw.endFill();
}
var username = '['+t.ra+'] '+t.u;
if (t.t.split(':')[1].includes('@leader')) {
username += ' ['+t.t.split(':')[1].replace('@leader', '')+'] (Leader)'
} else if (t.t.split(':')[1].includes('@requestor#')) {
username += ' [Requesting...] ('+t.t.split(':')[1].split('@requestor#')[1]+')';
} else if (new Number(t.t.split(':')[1]) < 1) {} else {
username += ' ['+t.t.split(':')[1]+']';
}
var style = PIXI.TextMetrics.measureText(username, GUI.fontstyle[30]);
GUI.drawImage(PixelTanks.images.blocks[PixelTanks.texturepack].void, t.x-style.width/2+40, t.y-style.height/2-25, style.width, 50, 0.5);
GUI.drawText(username, t.x+40, t.y-25, 50, t.col, 0.5);
if (t.s > 0 && !t.in) {
GUI.draw.beginFill(0x7DF9FF, .2);
GUI.draw.drawCircle(t.x+40, t.y+40, 66);
GUI.draw.endFill();
}
if (t.buff) {
GUI.drawImage(PixelTanks.images.tanks.default.other.buff, t.x-5, t.y-5, 80, 80, .2);
}
if (t.d !== false) {
var msg = (Math.round(t.d.d) < 0) ? '+' : '-';
msg += Math.round(t.d.d);
if (PixelTanks.user.username === t.u) {
GUI.drawText(msg, t.d.x, t.d.y, Math.round(t.d.d/10)+20, '#FFFFFF', 0.5);
GUI.drawText(msg, t.d.x, t.d.y, Math.round(t.d.d/10)+18, '#FF0000', 0.5);
} else {
GUI.drawText(msg, t.d.x, t.d.y, Math.round(t.d.d/10)+20, '#FFFFFF', 0.5);
GUI.drawText(msg, t.d.x, t.d.y, Math.round(t.d.d/10)+18, '#0000FF', 0.5);
}
}
if (t.e) {
GUI.drawImage(PixelTanks.images.emotes.speech.image, t.x+45, t.y-15);
GUI.drawImageCrop(PixelTanks.images.emotes[t.e.a].image, t.x+45, t.y-15, 100, 100, t.e.f*50, 0, 50, 50, 1);
}
if (t.a) {
GUI.drawImageCrop(PixelTanks.images.animations[t.a.i].image, t.x, t.y, 80, 90, t.a.f*40, 0, 40, 45, 1);
}
}
frame() {
requestAnimationFrame(this.frame.bind(this));
GUI.clear();
GUI.resetSpritePool();
GUI.resetTextPool();
this.fps++;
var t = this.hostupdate.tanks, b = this.hostupdate.blocks, s = this.hostupdate.bullets, a = this.hostupdate.ai, e = this.hostupdate.explosions;
this.stats = '(' + this.ops + ', ' + this.ups + ', ' + this.fps + ') ping: ' + this.ping + ' ['+this.hostupdate.bullets.length+', '+this.hostupdate.blocks.length+', '+this.hostupdate.tanks.length+']';
var l = 0;
while (l<t.length) {
if (t[l].u == PixelTanks.user.username) {
t[l].x = this.tank.x;
t[l].y = this.tank.y;
t[l].r = this.tank.r;
t[l].br = this.tank.br; // player smoothing
GUI.root.pivot.set(t[l].x-760, t[l].y-460);
GUI.draw.pivot.set(t[l].x-760, t[l].y-460);
}
l++;
}
GUI.drawImage(PixelTanks.images.blocks[PixelTanks.texturepack].floor, 0, 0, 3000, 3000, 1);
var l = 0;
while (l<b.length) {
this.drawBlock(b[l]);
l++;
}
var l = 0;
while (l<s.length) {
this.drawShot(s[l]);
l++;
}
var l = 0;
while (l<a.length) {
this.drawAi(PixelTanks.user.joiner.hostupdate.ai[l]);
l++;
}
var l = 0;
while (l<t.length) {
this.drawTank(t[l]);
l++;
}
var l = 0;
while (l<e.length) {
this.drawExplosion(e[l]);
l++;
}
var l = 0;
while (l<t.length) {
if (t[l].u == PixelTanks.user.username) {
if (t[l].fb) {;
GUI.drawImage(PIXI.Texture.WHITE, GUI.root.pivot.x, GUI.root.pivot.y, 1600, 1000, 0);
}
}
l++;
}
GUI.drawImage(PixelTanks.images.menus[PixelTanks.texturepack].ui, GUI.root.pivot.x, GUI.root.pivot.y, 1600, 1000, 1);
GUI.drawImage(PixelTanks.images.items[PixelTanks.userData.items[0]], GUI.root.pivot.x+500, GUI.root.pivot.y+900, 100, 100, 1);
GUI.drawImage(PixelTanks.images.items[PixelTanks.userData.items[1]], GUI.root.pivot.x+666, GUI.root.pivot.y+900, 100, 100, 1);
GUI.drawImage(PixelTanks.images.items[PixelTanks.userData.items[2]], GUI.root.pivot.x+832, GUI.root.pivot.y+900, 100, 100, 1);
GUI.drawImage(PixelTanks.images.items[PixelTanks.userData.items[3]], GUI.root.pivot.x+998, GUI.root.pivot.y+900, 100, 100, 1);
GUI.draw.beginFill(PixelTanks.userData.color.replace('#', '0x'), .5);
GUI.draw.drawRect(GUI.root.pivot.x+500, GUI.root.pivot.y+900+(Math.min((Date.now()-this.timers.items[0].date.getTime())/this.timers.items[0].cooldown, 1))*100, 100, 100);
GUI.draw.drawRect(GUI.root.pivot.x+666, GUI.root.pivot.y+900+(Math.min((Date.now()-this.timers.items[1].date.getTime())/this.timers.items[1].cooldown, 1))*100, 100, 100);
GUI.draw.drawRect(GUI.root.pivot.x+832, GUI.root.pivot.y+900+(Math.min((Date.now()-this.timers.items[2].date.getTime()) / this.timers.items[2].cooldown, 1))*100, 100, 100);
GUI.draw.drawRect(GUI.root.pivot.x+998, GUI.root.pivot.y+900+(Math.min((Date.now()-this.timers.items[3].date.getTime()) / this.timers.items[3].cooldown, 1))*100, 100, 100);
GUI.draw.drawRect(GUI.root.pivot.x+358, GUI.root.pivot.y+900+(Math.min((Date.now()-this.timers.class.date.getTime())/this.timers.class.cooldown, 1))*100, 100, 100);
GUI.draw.drawRect(GUI.root.pivot.x+1142, GUI.root.pivot.y+900+(Math.min((Date.now()-this.timers.powermissle.getTime())/10000, 1))*100, 100, 100);
GUI.draw.endFill();
GUI.drawImage(PixelTanks.images.blocks[PixelTanks.texturepack].void, GUI.root.pivot.x, GUI.root.pivot.y, 180, 250, 0.5);
GUI.drawText('Kills Streak: ' + this.kills, GUI.root.pivot.x+10, GUI.root.pivot.y+50, 30, '#ffffff', 0);
GUI.drawText('Crates: ' + this.crates, GUI.root.pivot.x+10, GUI.root.pivot.y+100, 30, '#ffffff', 0);
GUI.drawText('Experience: ' + this.xp, GUI.root.pivot.x+10, GUI.root.pivot.y+150, 30, '#ffffff', 0);
GUI.drawText('Coins: '+this.coins, GUI.root.pivot.x+10, GUI.root.pivot.y+200, 30, '#ffffff', 0);
var style = PIXI.TextMetrics.measureText(this.stats, GUI.fontstyle[30]);
GUI.drawImage(PixelTanks.images.blocks[PixelTanks.texturepack].void, GUI.root.pivot.x+800-style.width/2, GUI.root.pivot.y+50-style.height/2, style.width, style.height, 0.5);
GUI.drawText(this.stats, GUI.root.pivot.x+800, GUI.root.pivot.y+50, 30, '#ffffff', 0.5);
var l = 0, len;
if (this.showChat || this.hostupdate.logs.length < 3) {
len = this.hostupdate.logs.length;
} else {
len = 3;
}
// possible memory leak with creating new objects every frame
while (l<Math.min(len, 30)) {
GUI.drawImage(PixelTanks.images.blocks[PixelTanks.texturepack].void, GUI.root.pivot.x, GUI.root.pivot.y+800-l*30, PIXI.TextMetrics.measureText(this.hostupdate.logs[l].m, GUI.fontstyle[30]).width, 30, .5);
GUI.drawText(this.hostupdate.logs[l].m, GUI.root.pivot.x, GUI.root.pivot.y+800-l*30, 30, this.hostupdate.logs[l].c, 0);
l++;
}
if (this.showChat) {
GUI.drawImage(PixelTanks.images.blocks[PixelTanks.texturepack].void, GUI.root.pivot.x, GUI.root.pivot.y+830, PIXI.TextMetrics.measureText(this.msg, GUI.fontstyle[30]).width, 30, .5);
GUI.drawText(this.msg, GUI.root.pivot.x, GUI.root.pivot.y+830, 30, '#ffffff', 0);
}
}
chat(e) {
if (e.key.length === 1) {
this.msg += e.key;
} else if (e.keyCode === 8) {
this.msg = this.msg.slice(0, -1);
} else if (e.keyCode === 13) {
if (this.msg !== '') {
if (this.msg.split('')[0] === '/') {
var command = this.msg.split(' ')[0]
if (command === '/emote') {
if (this.msg.split(' ')[1] === 'set') {
var data = this.msg.split(' ')[2];
data = data.split('~');
if ((new Number(data[1]) >= 5 && new Number(data[1]) <= 9) || data[1] == 0) {
if (data[1] == 0) {
data[1] = 10;
}
PixelTanks.userData['emote' + (data[1] - 4)] = data[0];
} else {
alert('invalid everything. bad idot.')
}
} else {
this.emote(this.msg.split(' ')[1])
}
} else if (['/createteam', '/join', '/leave', '/accept', '/ban', '/unban', '/kick', '/kill', '/target'].includes(command)) {
this.socket.send({
type: 'command',
data: this.msg.split(' '),
});
} else {
alert('Command nonexistant. Use /emote emotename');
}
} else {
this.socket.send({
type: 'chat',
msg: this.msg,
});
}
this.msg = '';
}
this.showChat = false;
}
}
keydown(e) {
e.preventDefault();
if (this.helper[e.keyCode] !== 'pressed') {
if (this.showChat) {
this.chat(e);
return;
}
var cooldown = this.tank.in ? 12 : 15;
this.keyStart(e);
this.keyLoop(e);
this.intervals2[e.keyCode] = setInterval(function() {
this.tank.ba = !this.tank.ba;
var left = this.left;
var up = this.up;
if (left === null) {
if (up === null) {} else if (up) {
this.tank.br = 180;
} else if (!up) {
this.tank.br = 0;
}
} else if (left) {
if (up === null) {
this.tank.br = 90;
} else if (up) {
this.tank.br = 135;
} else if (!up) {
this.tank.br = 45;
}
} else if (!left) {
if (up === null) {
this.tank.br = 270;
} else if (up) {
this.tank.br = 225;
} else if (!up) {
this.tank.br = 315;
}
}
}.bind(this), 100);
this.intervals[e.keyCode] = setInterval(this.keyLoop.bind(this), cooldown, e);
}
this.helper[e.keyCode] = 'pressed';
}
keyup(e) {
if (this.paused) return;
e.preventDefault();
clearInterval(this.intervals[e.keyCode]);
clearInterval(this.intervals2[e.keyCode]);
if (e.keyCode == 65 || e.keyCode == 68) {
this.left = null;
}
if (e.keyCode == 87 || e.keyCode == 83) {
this.up = null;
}
this.helper[e.keyCode] = false;
}
mousemove(e) {
var x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
var y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
var targetX = x - window.innerWidth/2, targetY = y - window.innerHeight/2;
var rotation = this.toAngle(targetX, targetY);
this.tank.r = Math.round(rotation);
this.mouse = {
x: targetX,
y: targetY,
}
if (this.SETTINGS.fps) {
this.send();
}
}
toAngle(x, y) {
var angle = Math.atan2(x, y) * 180 / Math.PI
angle = -angle //-90;
if (angle < 0) {
angle += 360;
}
if (angle >= 360) {
angle -= 360;
}
return angle;
}
toPoint(angle) {
var theta = (-angle) * Math.PI / 180;
var y = Math.cos(theta);
var x = Math.sin(theta);
if (x < 0) {
if (y < 0) {
return {
x: -1,
y: Math.round(-Math.abs(y / x) * 1000) / 1000,
};
} else {
return {
x: -1,
y: Math.round(Math.abs(y / x) * 1000) / 1000,
};
}
} else {
if (y < 0) {
return {
x: 1,
y: Math.round(-Math.abs(y / x) * 1000) / 1000,
};
} else {
return {
x: 1,
y: Math.round(Math.abs(y / x) * 1000) / 1000,
};
}
}
}
mousedown(e) {
var cooldown = this.fireType === 1 ? 200 : 600;
if (this.canFire) {
this.fire(e.button);
this.canFire = false;
setTimeout(function() {
this.canFire = true;
}.bind(this), cooldown);
}
clearInterval(this.fireInterval);
this.fireInterval = setInterval(this.fire.bind(this), cooldown, e.button);
}
mouseup() {
clearInterval(this.fireInterval);
}
fire(type) {
var fireType = this.fireType;
if (type === 'grapple' || type === 'megamissle') {
fireType = 1;
} else if (type === 'dynamite') {
fireType = 1;
} else if (type == 2) {
if (this.canPowermissle) {
type = 'powermissle';
fireType = 1;
this.canPowermissle = false;
this.timers.powermissle = new Date();
var cooldown = 10000;
setTimeout(function() {
this.canPowermissle = true;
}.bind(this), cooldown);
} else {
if (this.fireType == 1) {
type = 'bullet';
} else if (this.fireType == 2) {
type = 'shotgun';
}
}
} else {
if (this.fireType == 1) {
type = 'bullet';
} else if (this.fireType == 2) {
type = 'shotgun';
}
}
if (PixelTanks.userData.class === 'medic' && type === 'powermissle') type = 'healmissle';
if (fireType == 1) {
var bullet = this.toPoint(this.tank.r);
bullet.t = type;
bullet.r = this.tank.r;
this.tank.fi.push(bullet);
} else if (fireType == 2) { // REVISE with while loop
var l = -10;
while (l < 15) {
var bullet = this.toPoint(this.tank.r + l);
bullet.t = type;
bullet.r = this.tank.r + l;
this.tank.fi.push(bullet);
l += 5;
}
}
if (this.SETTINGS.fps) {
this.send();
}
}
collision(x, y) {
var l = 0, team;
while (l < this.hostupdate.tanks.length) {
if (this.hostupdate.tanks[l].u === PixelTanks.user.username) {
team = this.hostupdate.tanks[l].t.split(':')[1].replace('@leader', '').replace('@requestor#', '');
if (this.hostupdate.tanks[l].ded) return true;
}
l++;
}
if (x < 0 || y < 0 || x + 80 > 3000 || y + 80 > 3000) {
return false;
}
if (this.tank.in && this.tank.i) return true;
var l = 0,
blocks = this.hostupdate.blocks,
len = blocks.length;
while (l < len) {
if ((x > blocks[l].x || x + 80 > blocks[l].x) && (x < blocks[l].x + 100 || x + 80 < blocks[l].x + 100) && (y > blocks[l].y || y + 80 > blocks[l].y) && (y < blocks[l].y + 100 || y + 80 < blocks[l].y + 100)) {
if ((blocks[l].t === 'fortress' && blocks[l].o.split(':')[1] === team) || blocks[l].t === 'heal') {} else if (blocks[l].c) {
return false;
}
}
l++;
}
return true;
}
playAnimation(id) {
this.tank.a = {
i: id,
f: 0,
};
clearInterval(this.animationInterval);
this.animationInterval = setInterval(function() {
if (this.tank.a.f === PixelTanks.images.animations[id].frames) {
clearInterval(this.animationInterval);
setTimeout(function() {
this.tank.a = false;
}.bind(this), PixelTanks.images.animations[id].speed);
} else {
this.tank.a.f++;
}
}.bind(this), PixelTanks.images.animations[id].speed);
}
item(id, slot) {
/*
case 32:
if (this.canBlock) {
if (PixelTanks.userData.blocks > 0) {
this.canBlock = false;
this.timers.block = new Date();
PixelTanks.userData.blocks -= 1;
this.tank.pl = true; // place scaffolding
if (PixelTanks.userData.class == 'builder') {
this.tank.st = 'gold';
} else {
this.tank.st = 'weak';
}
var cooldown = 5000;
if (PixelTanks.userData.kit == 'cooldown') {
cooldown *= .9;
}
setTimeout(function() {
this.canBlock = true;
}.bind(this), cooldown);
}
}
break;
case 69:
if (PixelTanks.userData.flashbangs > 0) {
if (this.canFlashbang) {
PixelTanks.userData.flashbangs -= 1;
this.tank.fl = true;
this.canFlashbang = false;
this.timers.flashbang = new Date();
var cooldown = 40000;
if (PixelTanks.userData.kit == 'cooldown') {
cooldown *= .9;
}
setTimeout(function() {
this.canFlashbang = true;
}.bind(this), cooldown);
}
}
*/
var key = {
duck_tape: [function() {
this.tank.ta = true;
this.playAnimation('tape');
}, 30000, false],
super_glu: [function() {
this.tank.gl = true;
}, 40000, false],
shield: [function() {
this.tank.sh = true;
}, 30000, false],
weak: [function() {
this.tank.pl = true; // place scaffolding
this.tank.st = PixelTanks.userData.class === 'builder' ? 'gold' : 'weak';
}, 3000, false],
strong: [function() {
this.tank.pl = true;
this.tank.st = PixelTanks.userData.class === 'builder' ? 'gold' : 'strong';
}, 7000, false],
spike: [function() {
this.tank.pl = true;
this.tank.st = 'spike';
}, 10000, false],
flashbang: [function() {
this.tank.fl = true;
}, 20000, false],
bomb: [function() {
this.tank.bo = true;
}, 10000, false],
power_bomb: [function() {
this.tank.po = true;
}, 10000, false],
mine: [function() {
this.tank.pl = true;
this.tank.st = 'mine';
}, 5000, false],
dynamite: [function() {
if (!this['canItem'+slot]) {
this.tank.dy = true;
} else {
this.fire('dynamite');
this['canItem'+slot] = false;
this.timers.items[slot].cooldown = 25000;
this.timers.items[slot].date = new Date();
setTimeout(function() {
this['canItem'+slot] = true;
}.bind(this), 25000);
}
}, 25000, true],
airstrike: [function() {
this.tank.as = {
x: this.mouse.x/PixelTanks.resizer+GUI.root.pivot.x+700,
y: this.mouse.y/PixelTanks.resizer+GUI.root.pivot.y+400,
};
}, 40000, false],
fortress: [function() {
this.tank.pl = true;
this.tank.st = 'fortress';
}, 30000, false],
}
this.useItem(key[id][0], key[id][1], slot, key[id][2]);
}
useItem(enable, cooldown, slot, c) {
if (c) {
enable = enable.bind(this);
enable();
return;
}
if (this['canItem'+slot]) {
enable = enable.bind(this);
enable();
this.timers.items[slot].cooldown = cooldown;
this.timers.items[slot].date = new Date();
this['canItem'+slot] = false;
setTimeout(function() {
this['canItem'+slot] = true;
}.bind(this), cooldown);
}
}
keyStart(e) {
if (this.paused && e.keyCode !== 22) return;
switch (e.keyCode) {
case PixelTanks.userData.keybinds.items[0]:
this.item(PixelTanks.userData.items[0], 0);
break;
case PixelTanks.userData.keybinds.items[1]:
this.item(PixelTanks.userData.items[1], 1);
break;
case PixelTanks.userData.keybinds.items[2]:
this.item(PixelTanks.userData.items[2], 2);
break;
case PixelTanks.userData.keybinds.items[3]:
this.item(PixelTanks.userData.items[3], 3);
break;
case 53:
this.emote(PixelTanks.userData.emote1);
break;
case 54:
this.emote(PixelTanks.userData.emote2);
break;
case 55:
this.emote(PixelTanks.userData.emote3);
break;
case 56:
this.emote(PixelTanks.userData.emote4);
break;
case 57:
this.emote(PixelTanks.userData.emote5)
break;
case 48:
this.emote(PixelTanks.userData.emote6)
break;
case 13:
this.showChat = true;
break;
case false: //PixelTanks.userData.settings.fire1:
this.fireType = 1;
clearInterval(this.fireInterval);
break;
case false: //PixelTanks.userData.settings.fire2:
this.fireType = 2;
clearInterval(this.fireInterval);
break;
case 9:
if (this.fireType === 2) {
this.fireType = 1;
} else {
this.fireType++;
}
clearInterval(this.fireInterval);
break;
case 82:
if (this.grapples > 0) {
this.fire('grapple');
this.grapples--;
this.canGrapple = false;
setTimeout(function() {
this.canGrapple = true;
}.bind(this), 200)
if (this.grapples === 0) {
setTimeout(function() {
this.grapples = 1;
}.bind(this), 5000);
}
}
break;
case 81:
if (this.canToolkit) {
if (this.halfSpeed) {
this.tank.to = true;
this.halfSpeed = false;
} else {
if (PixelTanks.userData.class !== 'medic') {
this.halfSpeed = true;
setTimeout(function() {
this.halfSpeed = false;
}.bind(this), 7500);
}
this.tank.to = true;
this.canToolkit = false;
this.timers.toolkit = new Date();
setTimeout(function() {
this.canToolkit = true;
}.bind(this), 30000);
this.playAnimation('toolkit');
}
}
break;
case 70:
if (PixelTanks.userData.class === 'stealth') {
if (this.canInvis && !this.tank.in) {
this.tank.in = true;
this.canInvis = false;
this.timers.class.date = new Date();
this.timers.class.cooldown = 20000;
clearTimeout(this.invis);
this.invis = setTimeout(function() {
this.tank.in = false;
this.invis = setTimeout(function() {
this.canInvis = true;
}.bind(this), 20000);
}.bind(this), 20000);
} else if (this.tank.in) {
this.tank.in = false;
this.canInvis = true;
}
} else if (PixelTanks.userData.class === 'normal') {
// add sheidls ehre for idots
} else if (PixelTanks.userData.class == 'tactical') {
if (this.canMegamissle) {
this.fire('megamissle');
this.canMegamissle = false;
this.timers.class.date = new Date();
this.timers.class.cooldown = 20000
setTimeout(function() {
this.canMegamissle = true;
}.bind(this), 30000);
}
} else if (PixelTanks.userData.class == 'builder') {
if (this.canTurret) {
this.canTurret = false;
this.tank.tu = true;
this.timers.class.date = new Date();
this.timers.class.cooldown = 40000;
setTimeout(function() {
this.canTurret = true;
}.bind(this), 40000);
}
} else if (PixelTanks.userData.class === 'warrior') {
if (this.canBuff) {
this.canBuff = false;
this.tank.bu = true;
this.tank.to = false;
this.timers.class.date = new Date();
this.timers.class.cooldown = 30000;
setTimeout(function() {
this.canBuff = true;
}.bind(this), 30000);
}
} else if (PixelTanks.userData.class === 'medic') {
if (this.canHeal) {
this.canHeal = false;
this.tank.pl = true;
this.tank.st = 'heal';
this.timers.class.date = new Date();
this.timers.class.cooldown = 30000;
setTimeout(function() {
this.canHeal = true;
}.bind(this), 30000);
}
}
break;
case 27:
this.paused = !this.paused;
if (this.paused) {
GUI.draw.fillStyle = '#000000';
GUI.draw.fillRect(0, 0, 1600, 1000);
} else {
Menus.removeListeners();
}
break;
case 18:
document.write(JSON.stringify(this.hostupdate));
break;
}
}
keyLoop(e) {
switch (e.keyCode) {
case 68:
if (this.collision(this.tank.x + this.speed, this.tank.y) && !this.tank.to) {
this.tank.x += (this.halfSpeed) ? this.speed / 2 : this.speed;
this.left = false;
} else {
this.left = null;
}
break;
case 87:
if (this.collision(this.tank.x, this.tank.y - this.speed) && !this.tank.to) {
this.tank.y -= (this.halfSpeed) ? this.speed / 2 : this.speed;
this.up = true;
} else {
this.up = null;
}
break;
case 65:
if (this.collision(this.tank.x - this.speed, this.tank.y) && !this.tank.to) {
this.tank.x -= (this.halfSpeed) ? this.speed / 2 : this.speed;
this.left = true;
} else {
this.left = null;
}
break;
case 83:
if (this.collision(this.tank.x, this.tank.y + this.speed) && !this.tank.to) {
this.tank.y += (this.halfSpeed) ? this.speed / 2 : this.speed;
this.up = false;
} else {
this.up = null;
}
break;
case 16:
if (this.canBoost) {
this.speed = 16;
this.canBoost = false;
this.tank.i = true;
setTimeout(function() {
this.speed = 4;
this.tank.i = false;
}.bind(this), 500);
var cooldown = 5000;
if (PixelTanks.userData.kit == 'cooldown') {
cooldown *= .9;
}
setTimeout(function() {
this.canBoost = true;
}.bind(this), cooldown);
}
break;
}
if (this.SETTINGS.fps) {
this.send();
}
}
emote(id) {
clearInterval(this.emoteAnimation);
clearTimeout(this.emoteTimeout);
if (PixelTanks.images.emotes[id].type === 0) { // loop emote
this.tank.e = {
a: id,
f: 0,
};
this.emoteAnimation = setInterval(function() {
if (this.tank.e.f != PixelTanks.images.emotes[id].frames) {
this.tank.e.f++;
} else {
this.tank.e.f = 0;
}
}.bind(this), 50);
this.emoteTimeout = setTimeout(function() {
clearInterval(this.emoteAnimation);
this.tank.e = null;
}.bind(this), 5000);
} else if (PixelTanks.images.emotes[id].type === 1) { // single run emote
this.tank.e = {
a: id,
f: 0,
};
this.emoteAnimation = setInterval(function() {
if (this.tank.e.f != PixelTanks.images.emotes[id].frames) {
this.tank.e.f++;
} else {
clearInterval(this.emoteAnimation);
setTimeout(function() {
this.tank.e = null;
}.bind(this), 1500);
}
}.bind(this), 50);
} else {
this.tank.e = {
a: id,
f: 0,
}
this.emoteTimeout = setTimeout(function() {
this.tank.e = null;
}.bind(this), 5000);
}
}
send() {
this.ops++;
this.socket.send({
username: sessionStorage.username,
type: 'update',
data: {
x: this.tank.x, // x [U, J]
y: this.tank.y, // y [U, J]
e: this.tank.e, // [U]
br: this.tank.br, // leftright [U, J]
r: this.tank.r, // rotation [U, J]
to: this.tank.to, // toolkit [U]
ta: this.tank.ta, // duck tape [U]
gl: this.tank.gl, // glu [U]
pl: this.tank.pl, // place scaffolding [U]
st: this.tank.st, // scaffolding type
ba: this.tank.ba, // base image stage [U, J]
fl: this.tank.fl, // flashbang fired [U]
bo: this.tank.bo, // bumb fired [U]
po: this.tank.po, // power-bumb fired [U]
i: this.tank.i, // immune [U]
in: this.tank.in, // invis [U]
fi: this.tank.fi, // fire or not
tu: this.tank.tu, // summoner turret
bui: this.tank.bui, // builder block
a: this.tank.a, // animation to play on tank :D
bu: this.tank.bu, // warrior buff
mi: this.tank.mi, // mines while boost TEMP DISABLED
dy: this.tank.dy, // dynamite
sh: this.tank.sh, // shields :D
as: this.tank.as, // airstrike
},
});
this.tank.st = null;
this.tank.blockShield = false;
this.tank.fi = [];
this.tank.mi = false;
this.tank.to = false;
this.tank.ta = false;
this.tank.pl = false;
this.tank.tu = false;
this.tank.fl = false;
this.tank.bo = false;
this.tank.po = false;
this.tank.bu = false;
this.tank.bui = false;
this.tank.dy = false;
this.tank.gl = false;
this.tank.sh = false;
this.tank.as = false;
}
}