JSFiddle - React, Tailwind, and code Playground

by Calumks

HTML

<canvas id="canvas" width="500px" height="500px">

JavaScript

class Creature {
  x = 0;
  y = 0;
  speed = 2;
  colour = 'blue';

  // The direction we are traveling to
  xDirection = 0;
  yDirection = 0;
  directionAngle = 0;

  // How long we should go in a given direction
  directionIntvl = 0;

  radius = 4;
  health = 500;
}


// Generate creature
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');

for (let x = 0; x < 20; x++) {
  let creature = new Creature();
  creature.x = Math.round(Math.random() * canvas.width);
  creature.y = Math.round(Math.random() * canvas.height);
  eachFrame(creature);
}

function eachFrame(creature) {

  // Clear last frame
  ctx.clearRect(creature.x, creature.y, 4, 4);

  // Generate new direction
  if (creature.directionIntvl <= 0) {
    genDirection(creature);
  } else {
    creature.directionIntvl--;
  }

  // Move in direction
  creature.x += Math.round(creature.xDirection);
  creature.y += Math.round(creature.yDirection);

  rangeCheck(creature);

  // Draw creature
  ctx.fillStyle = creature.colour;
  ctx.fillRect(creature.x, creature.y, 4, 4);

  window.requestAnimationFrame(() => eachFrame(creature));
}


// Generate new direction
function genDirection(creature) {
  // Calculate new angle 45 degrees ether side of direction
  creature.directionAngle += (Math.random() - 0.5) * Math.PI / 2;

  // Calculate new direction at speed (radius)
  creature.xDirection = Math.cos(creature.directionAngle) * creature.speed;
  creature.yDirection = Math.sin(creature.directionAngle) * creature.speed;

  // Generate random interval up to 10 frames
  creature.directionIntvl = Math.random() * 10;
}

// Check creature is within the canvas
function rangeCheck(creature) {

  if (creature.x < 0) {
    creature.x = canvas.width;
  } else if (creature.x > canvas.width) {
    creature.x = 0;
  }
  if (creature.y < 0) {
    creature.y = canvas.height;
  } else if (creature.y > canvas.height) {
    creature.y = 0;
  }
}