AI Code Test
Sonic
Review the original prompt, inspect the generated code, and compare how different AI models handled the same coding task.
Back to All Tests
Sonic
can you make me a simple sonic 1 inspired game. for now just use simple blocks
Gemini Flash 3.5 (Standard)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sonic-Inspired Physics Block Test</title>
<style>
body {
margin: 0;
background: #111;
color: #fff;
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
overflow: hidden;
}
canvas {
border: 4px solid #333;
background: #223355;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.ui {
margin-top: 10px;
font-size: 14px;
text-align: center;
line-height: 1.5;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="800" height="480"></canvas>
<div class="ui">
<strong>Controls:</strong> Left/Right Arrow = Run | Space = Jump | Down Arrow = Roll <br>
<span id="stats">Speed: 0 | Rolling: False</span>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const stats = document.getElementById('stats');
// --- Physics Constants (Inspired by Sonic 1 Specs) ---
const ACCEL = 0.08;
const DECEL = 0.5;
const FRICTION = 0.046;
const MAX_SPEED = 8;
const JUMP_FORCE = -8.5;
const GRAVITY = 0.35;
const ROLL_FRICTION = 0.023;
const ROLL_DECEL = 0.25;
// --- Player Object ---
const player = {
x: 100,
y: 300,
w: 24,
h: 36,
vx: 0,
vy: 0,
isGrounded: false,
isRolling: false,
color: '#0055ff' // Sonic Blue
};
// --- Level Data (Simple Blocks/Platforms) ---
const platforms = [
// Main Floor
{ x: 0, y: 420, w: 1200, h: 60, color: '#33aa33' },
// Step Blocks
{ x: 300, y: 360, w: 80, h: 60, color: '#aa6633' },
{ x: 380, y: 300, w: 80, h: 120, color: '#aa6633' },
// High Platform to jump off of
{ x: 550, y: 220, w: 200, h: 20, color: '#aa6633' },
// Long flat stretch for building top speed
{ x: 850, y: 320, w: 400, h: 100, color: '#33aa33' }
];
// --- Input Tracking ---
const keys = { Left: false, Right: false, Down: false };
window.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft' || e.key === 'a') keys.Left = true;
if (e.key === 'ArrowRight' || e.key === 'd') keys.Right = true;
if (e.key === 'ArrowDown' || e.key === 's') keys.Down = true;
if (e.key === ' ' && player.isGrounded) {
player.vy = JUMP_FORCE;
player.isGrounded = false;
if (player.isRolling) {
// Keep rolling size if already rolling
}
}
});
window.addEventListener('keyup', (e) => {
if (e.key === 'ArrowLeft' || e.key === 'a') keys.Left = false;
if (e.key === 'ArrowRight' || e.key === 'd') keys.Right = false;
if (e.key === 'ArrowDown' || e.key === 's') keys.Down = false;
});
// --- Simple AABB Collision Detection & Resolution ---
function checkCollision(p, plat) {
return p.x < plat.x + plat.w &&
p.x + p.w > plat.x &&
p.y < plat.y + plat.h &&
p.y + p.h > plat.y;
}
// --- Main Game Loop ---
function update() {
// 1. Handle Rolling State Changes
if (keys.Down && player.isGrounded && Math.abs(player.vx) > 1.0 && !player.isRolling) {
player.isRolling = true;
player.h = 24; // Compress hitbox into a "ball"
player.y += 12;
player.color = '#00bbff'; // Lighter spin blue
}
if (player.isRolling && (Math.abs(player.vx) < 0.2 || !player.isGrounded || (!keys.Down && Math.abs(player.vx) < 1.0))) {
// Unroll if stopped, airborne, or letting go of down at slow speeds
if (player.isRolling && player.isGrounded) {
player.isRolling = false;
player.h = 36;
player.y -= 12;
player.color = '#0055ff';
}
}
// 2. Horizontal Movement Mechanics (Acceleration, Deceleration, Friction)
let currentDrag = player.isRolling ? ROLL_FRICTION : FRICTION;
if (keys.Left) {
if (player.vx > 0) {
player.vx -= player.isRolling ? ROLL_DECEL : DECEL;
} else if (player.vx > -MAX_SPEED) {
player.vx -= player.isRolling ? 0 : ACCEL; // Sonic can't actively accelerate well while rolling
}
} else if (keys.Right) {
if (player.vx < 0) {
player.vx += player.isRolling ? ROLL_DECEL : DECEL;
} else if (player.vx < MAX_SPEED) {
player.vx += player.isRolling ? 0 : ACCEL;
}
} else {
// Apply friction when no direction is pressed
if (player.vx > 0) player.vx = Math.max(0, player.vx - currentDrag);
if (player.vx < 0) player.vx = Math.min(0, player.vx + currentDrag);
}
// Apply X position
player.x += player.vx;
// Handle X collision resolution
for (let plat of platforms) {
if (checkCollision(player, plat)) {
if (player.vx > 0) {
player.x = plat.x - player.w;
player.vx = 0; // Wall bonk
} else if (player.vx < 0) {
player.x = plat.x + plat.w;
player.vx = 0;
}
}
}
// 3. Vertical Movement Mechanics (Gravity & Jumping)
if (!player.isGrounded) {
player.vy += GRAVITY;
}
// Apply Y position
player.y += player.vy;
player.isGrounded = false;
// Handle Y collision resolution
for (let plat of platforms) {
if (checkCollision(player, plat)) {
// Landing on top of a platform
if (player.vy > 0 && (player.y + player.h - player.vy) <= plat.y + 4) {
player.y = plat.y - player.h;
player.vy = 0;
player.isGrounded = true;
}
// Bonking ceiling
else if (player.vy < 0) {
player.y = plat.y + plat.h;
player.vy = 0;
}
}
}
// Update debug text
stats.innerText = `Speed: ${Math.abs(player.vx).toFixed(2)} | Rolling: ${player.isRolling} | Grounded: ${player.isGrounded}`;
}
function draw() {
// Clear Screen & Apply Camera Tracking (Offsets view based on player x)
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
// Simple camera tracking centered around player X
let cameraX = -player.x + canvas.width / 2 - player.w / 2;
// Constrain camera boundary to level width
cameraX = Math.min(0, cameraX);
ctx.translate(cameraX, 0);
// Draw Platforms
for (let plat of platforms) {
ctx.fillStyle = plat.color;
ctx.fillRect(plat.x, plat.y, plat.w, plat.h);
// Simple checkered grid look on platforms to show movement speed
ctx.fillStyle = 'rgba(0,0,0,0.05)';
for (let i = 0; i < plat.w; i += 20) {
if ((i / 20) % 2 === 0) {
ctx.fillRect(plat.x + i, plat.y, 20, plat.h);
}
}
}
// Draw Player
ctx.fillStyle = player.color;
if (player.isRolling) {
// Draw spinning ball block approximation
ctx.fillRect(player.x, player.y, player.w, player.h);
ctx.fillStyle = '#fff';
ctx.fillRect(player.x + 4, player.y + 4, 6, 6); // Core spin accent
} else {
// Normal running block
ctx.fillRect(player.x, player.y, player.w, player.h);
// "Shoes" accent line
ctx.fillStyle = '#ff0000';
ctx.fillRect(player.x, player.y + player.h - 4, player.w, 4);
}
ctx.restore();
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
// Start the game loop
loop();
</script>
</body>
</html>