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;
    }

  }

\$\endgroup\$
2
  • \$\begingroup\$ Recommend you define a manifest constant “epoch” for that magic number of 28 November 2006. \$\endgroup\$
    – J_H
    Jan 27, 2023 at 19:21
  • \$\begingroup\$ That multiplayer class is huge, time to split it up into multiple classes? \$\endgroup\$
    – Kokodoko
    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.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.