Copilot made this in less than a minute. Save test.html and script.js in the same directory, then open test.html with your browser.
There are two script.js versions.
I don't know which is more efficient because it's impossible to profile in Javascript but theoretically applying rotation matrix may be more efficient.
It also avoids using the built-in Math.cos() and Math.sin() functions using simplified, less precise implementations for efficiency.
Again can't vouch for that since there's no way to profile that, JavaScript sucks for game dev.
test.html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sprite Rotation Demo</title>
<style>
#canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<div>
<h1>Current Angle: <span id="angle">0</span>°</h1>
<h2>Current Sprite: <span id="sprite">DOWN</span></h2>
</div>
<canvas id="canvas" width="500" height="500"></canvas>
<script src="script.js"></script>
</body>
</html>
script.js (simple trigonometry version)const Direction = Object.freeze({
DOWN: 'DOWN',
DOWN_LEFT: 'DOWN_LEFT',
LEFT: 'LEFT',
UP_LEFT: 'UP_LEFT',
UP: 'UP',
UP_RIGHT: 'UP_RIGHT',
RIGHT: 'RIGHT',
DOWN_RIGHT: 'DOWN_RIGHT'
});
const spriteDirections = [
{ angle: 0, sprite: Direction.DOWN },
{ angle: 45, sprite: Direction.DOWN_LEFT },
{ angle: 90, sprite: Direction.LEFT },
{ angle: 135, sprite: Direction.UP_LEFT },
{ angle: 180, sprite: Direction.UP },
{ angle: 225, sprite: Direction.UP_RIGHT },
{ angle: 270, sprite: Direction.RIGHT },
{ angle: 315, sprite: Direction.DOWN_RIGHT }
];
let cosLUT = [];
let sinLUT = [];
for (let i = 0; i < 360; i++) {
cosLUT[i] = Math.cos(i * Math.PI / 180);
sinLUT[i] = Math.sin(i * Math.PI / 180);
}
function fastCos(angle) {
return cosLUT[Math.floor(angle) % 360];
}
function fastSin(angle) {
return sinLUT[Math.floor(angle) % 360];
}
let currentAngle = 0;
let thrust = 1;
let turningSpeed = 0;
let maxTurningSpeed = 5;
let decay = 0.95;
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
turningSpeed = Math.max(turningSpeed - thrust, -maxTurningSpeed);
}
if (e.key === 'ArrowRight') {
turningSpeed = Math.min(turningSpeed + thrust, maxTurningSpeed);
}
});
function getSprite(angle) {
for (let i = 0; i < spriteDirections.length; i++) {
if (angle >= spriteDirections[i].angle && angle < spriteDirections[(i + 1) % spriteDirections.length].angle) {
return spriteDirections[i].sprite;
}
}
return Direction.DOWN;
}
function update() {
currentAngle += turningSpeed;
currentAngle = (currentAngle + 360) % 360;
turningSpeed *= decay;
document.getElementById('angle').textContent = Math.floor(currentAngle);
document.getElementById('sprite').textContent = getSprite(currentAngle);
draw();
requestAnimationFrame(update);
}
function draw() {
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(currentAngle * Math.PI / 180);
ctx.fillStyle = 'red';
ctx.fillRect(-25, -25, 50, 50);
ctx.restore();
}
update();
script.js (rotation matrix version)const Direction = Object.freeze({
DOWN: 'DOWN',
DOWN_LEFT: 'DOWN_LEFT',
LEFT: 'LEFT',
UP_LEFT: 'UP_LEFT',
UP: 'UP',
UP_RIGHT: 'UP_RIGHT',
RIGHT: 'RIGHT',
DOWN_RIGHT: 'DOWN_RIGHT'
});
const spriteDirections = [
{ angle: 0, sprite: Direction.DOWN },
{ angle: 45, sprite: Direction.DOWN_LEFT },
{ angle: 90, sprite: Direction.LEFT },
{ angle: 135, sprite: Direction.UP_LEFT },
{ angle: 180, sprite: Direction.UP },
{ angle: 225, sprite: Direction.UP_RIGHT },
{ angle: 270, sprite: Direction.RIGHT },
{ angle: 315, sprite: Direction.DOWN_RIGHT }
];
let cosLUT = [];
let sinLUT = [];
for (let i = 0; i < 360; i++) {
cosLUT[i] = Math.cos(i * Math.PI / 180);
sinLUT[i] = Math.sin(i * Math.PI / 180);
}
function fastCos(angle) {
return cosLUT[Math.floor(angle) % 360];
}
function fastSin(angle) {
return sinLUT[Math.floor(angle) % 360];
}
function rotatePoint(x, y, angle) {
const cosTheta = fastCos(angle);
const sinTheta = fastSin(angle);
const xNew = x * cosTheta - y * sinTheta;
const yNew = x * sinTheta + y * cosTheta;
return { x: xNew, y: yNew };
}
let currentAngle = 0;
let thrust = 1;
let turningSpeed = 0;
let maxTurningSpeed = 5;
let decay = 0.95;
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
turningSpeed = Math.max(turningSpeed - thrust, -maxTurningSpeed);
}
if (e.key === 'ArrowRight') {
turningSpeed = Math.min(turningSpeed + thrust, maxTurningSpeed);
}
});
function getSprite(angle) {
for (let i = 0; i < spriteDirections.length; i++) {
if (angle >= spriteDirections[i].angle && angle < spriteDirections[(i + 1) % spriteDirections.length].angle) {
return spriteDirections[i].sprite;
}
}
return Direction.DOWN;
}
function update() {
currentAngle += turningSpeed;
currentAngle = (currentAngle + 360) % 360;
turningSpeed *= decay;
document.getElementById('angle').textContent = Math.floor(currentAngle);
document.getElementById('sprite').textContent = getSprite(currentAngle);
draw();
requestAnimationFrame(update);
}
function draw() {
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
// Correctly apply the rotation around the center
ctx.rotate(currentAngle * Math.PI / 180);
ctx.fillStyle = 'red';
ctx.fillRect(-25, -25, 50, 50);
ctx.restore();
}
update();