2
\$\begingroup\$

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;
 }
 }
Sᴀᴍ Onᴇᴌᴀ
29.6k16 gold badges45 silver badges203 bronze badges
asked Jan 27, 2023 at 18:15
\$\endgroup\$
2
  • \$\begingroup\$ Recommend you define a manifest constant "epoch" for that magic number of 28 November 2006. \$\endgroup\$ Commented Jan 27, 2023 at 19:21
  • \$\begingroup\$ That multiplayer class is huge, time to split it up into multiple classes? \$\endgroup\$ Commented Feb 15, 2023 at 10:40

1 Answer 1

1
\$\begingroup\$

That multiplayer class is huge, time to split it up into multiple classes!

For example you can add a Controller class that handles user input.

And you should definitely make the actual tank a class instead of an object. I would also give the tank properties readable names instead of "s", "a", etc.

Finally, you seem to be rewriting a lot of functionality that is already available in PIXI.

answered Feb 15, 2023 at 10:44
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.