Как оптимизировать игру на Canvas JS

Появились трудности с созданием игры на чистом JS. Реализую собственную змейку) Да, я старомодный, но для меня это уже достижение.

В чем вопрос, я в массив добавляю хвост и первым элементом массива змейки является голова змейки. Когда я отрисовываю змейку, будь то через setInterval, или же через requestAnimation, при большом количестве точек хвоста, фпс значительно падает. Ребят, я хочу максимальную оптимизацию, спасайте )))

Код:

const c = document.getElementById("ctx");

c.width = 700;
c.height = 500;

const ctx = c.getContext("2d");


function random(max, v = 0, ) {

  let r = Math.floor(Math.random() * max);
  if (v === 1 && r % 5 !== 0 || r % 10 === 0 && v === 1) {
    r = random(max, 1)
  }

  return r;
}

function Snake() {
  this.Ox = 10, // Направление змейки
    this.Oy = 0;


  this.speed = 10;

  this.r = 5, // Радиус и длина змейки
    this.length = [{
      "x": 5,
      "y": 5,
      "color": "black"
    }];

  this.lastX,
    this.lastY;

  this.head = null;
}

Snake.prototype.add = function() {
  let num = this.length.length;
  this.length[num] = {
    "x": 0,
    "y": 0,
    "color": "silver"
  }
}

Snake.prototype.move = function() {

  if (this.length[0].x === c.width - this.r && this.Ox === this.speed) {
    this.Ox = 0;
  } else if (this.length[0].x === 0 + this.r && this.Ox === -this.speed) {
    this.Ox = 0;
  } else if (this.length[0].y === c.height - this.r && this.Oy === this.speed) {
    this.Oy = 0;
  } else if (this.length[0].y === 0 + this.r && this.Oy === -this.speed) {
    this.Oy = 0;
  }
  // for (let i = 0; i < this.length.length; i++) {
  //     if (i !== 0) {
  //         if (this.length[0].x === this.length[i].x && this.length[0].y === this.length[i].y) {
  //             this.Oy = 0;
  //             this.Ox = 0;
  //         }
  //     }
  // }
  for (let i = this.length.length - 1; i >= 0; --i) {
    if (i === 0) {
      this.length[i].x += this.Ox;
      this.length[i].y += this.Oy;
    } else {
      this.length[i].x = this.length[i - 1].x;
      this.length[i].y = this.length[i - 1].y;
    }

    ctx.fillStyle = this.length[i].color;
    ctx.beginPath();
    ctx.arc(this.length[i].x, this.length[i].y, this.r, 0, 2 * Math.PI)
    ctx.fill();
  }
}



let s = new Snake();

let x = random(c.width, 1, s.length),
  y = random(c.height, 1, s.length);

function direction(l = 0, r = 0, u = 0, d = 0) {
  if (l === 1) {
    if (s.Ox === 0) {
      s.Ox = -s.speed;
    }
    s.Oy = 0;
  } else if (r === 1) {
    if (s.Ox === 0) {
      s.Ox = s.speed;
    }
    s.Oy = 0;
  } else if (u === 1) {
    if (s.Oy === 0) {
      s.Oy = -s.speed;
    }
    s.Ox = 0;
  } else if (d === 1) {
    if (s.Oy === 0) {
      s.Oy = s.speed;
    }
    s.Ox = 0;
  }
}

document.addEventListener("keydown", (e) => {
  switch (e.keyCode) {
    case 83:
      direction(0, 0, 0, 1);
      break;
    case 87:
      direction(0, 0, 1, 0);
      break;
    case 65:
      direction(1, 0, 0, 0);
      break;
    case 68:
      direction(0, 1, 0, 0);
      break;
    case 82:
      for (let i = 0; i < 1000; i++) {
        s.add()
      }
  }
})

function bot() {
  if (s.length[0].x < x) {
    if (s.Ox === -s.speed) {
      direction(0, 0, 1, 0);
    }

    direction(0, 1, 0, 0);
  }
  if (s.length[0].x > x) {
    if (s.Ox === s.speed) {
      direction(0, 0, 1, 0);
    }
    direction(1, 0, 0, 0);
  }
  if (s.length[0].y > y) {
    if (s.Oy === -s.speed) {
      direction(0, 1, 0, 0);
    }
    direction(0, 0, 1, 0);
  }
  if (s.length[0].y < y) {
    if (s.Ox === s.speed) {
      direction(0, 1, 0, 0);
    }
    direction(0, 0, 0, 1);
  }
}


function apple() {
  if (s.length[0].x === x && s.length[0].y === y) {
    x = random(c.width, 1);
    y = random(c.height, 1);

    s.add();
  }
  for (let i = 0; i < s.length.length; i++) {
    if (s.length[0].y === x && s.length[0].x === y) {
      x = random(max, 1);
      y = random(c.height, 1);
    }
  }
  ctx.fillStyle = "black";
  ctx.beginPath();
  ctx.arc(x, y, 5, 0, 2 * Math.PI)
  ctx.fill();
}

// setInterval(() => {
//     ctx.fillStyle = "white";
//     ctx.fillRect(0, 0, c.width, c.height);
//     apple()
//     bot();
//     s.move();
// }, 40);

function anim() {
  window.requestAnimationFrame(() => {
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, c.width, c.height);
    apple()
    bot();
    s.move();
    anim();
  });

}
anim();
<canvas id="ctx"></canvas>


Ответы (0 шт):