AI Code Test
Subway Surfers (with cars)
Review the original prompt, inspect the generated code, and compare how different AI models handled the same coding task.
Back to All Tests
Subway Surfers (with cars)
I want you to code a infinite runner game. It will be inspired by subway sufers where you have to move left right or stay in the center. You are moiving upwards and need to avoid stuff. For now don't use any fancy assets. Just make a working game with the ability to restart. Include a menu screen. Also make it look like cars with a road and roadblocks in the way as the things that are what stops the car. Update the name and make the main screen nicer. use three.js and make it 3d. I want to have clouds, a 3d car and make it look very epic. Make the road not just straight. So it is more interesting
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>Curve Rider 3D</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #050510;
user-select: none;
}
#canvas-container {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
/* UI Overlays */
.ui-layer {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 10;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
text-shadow: 0 4px 8px rgba(0,0,0,0.7);
transition: opacity 0.3s ease;
}
.hidden {
opacity: 0;
pointer-events: none;
display: none !important;
}
/* Screen Stylings */
#menu-screen {
background: linear-gradient(to bottom, rgba(5, 5, 20, 0.45), rgba(15, 10, 35, 0.85));
}
#gameover-screen {
background: rgba(15, 0, 0, 0.75);
backdrop-filter: blur(4px);
}
#hud {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 5;
display: flex;
gap: 40px;
font-size: 24px;
font-weight: bold;
letter-spacing: 2px;
background: rgba(0, 0, 0, 0.4);
padding: 10px 30px;
border-radius: 30px;
border: 1px solid rgba(255, 255, 255, 0.1);
pointer-events: none;
}
/* Typography & Buttons */
h1 {
font-size: 64px;
margin-bottom: 10px;
letter-spacing: 6px;
text-transform: uppercase;
background: linear-gradient(45deg, #ff007f, #00f0ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 2px 10px rgba(0,240,255,0.3));
}
p {
font-size: 18px;
margin-bottom: 30px;
color: #ccc;
}
.btn {
padding: 15px 40px;
font-size: 20px;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 2px;
color: white;
background: linear-gradient(90deg, #ff0055, #9900ff);
border: none;
border-radius: 5px;
cursor: pointer;
box-shadow: 0 5px 15px rgba(255, 0, 85, 0.4);
transition: transform 0.1s, box-shadow 0.2s;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(255, 0, 85, 0.6);
}
.btn:active {
transform: translateY(1px);
}
.controls-hint {
margin-top: 40px;
font-size: 14px;
color: #888;
background: rgba(0,0,0,0.3);
padding: 10px 20px;
border-radius: 5px;
}
</style>
<!-- Include Three.js via CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
</head>
<body>
<div id="canvas-container"></div>
<!-- HUD -->
<div id="hud" class="hidden">
<div>SCORE: <span id="score-val">0</span></div>
<div>SPEED: <span id="speed-val">0</span> MPH</div>
</div>
<!-- Main Menu Screen -->
<div id="menu-screen" class="ui-layer">
<h1>NEON DRIVE 3D</h1>
<p>Race down the winding cyber highway. Avoid the structural barriers.</p>
<button class="btn" id="start-btn">Start Race</button>
<div class="controls-hint">Use LEFT / RIGHT Arrows or A / D keys to switch lanes</div>
</div>
<!-- Game Over Screen -->
<div id="gameover-screen" class="ui-layer hidden">
<h1 style="background: linear-gradient(45deg, #ff3333, #ff8800); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">CRASHED!</h1>
<p>Your vehicle sustained catastrophic damage.</p>
<p style="font-size: 28px; margin-top: -15px;">Final Score: <span id="final-score">0</span></p>
<button class="btn" id="restart-btn" style="background: linear-gradient(90deg, #ff4400, #ffaa00); box-shadow: 0 5px 15px rgba(255, 68, 0, 0.4);">Restart</button>
</div>
<script>
// --- GAME CONFIG & STATE ---
const CONFIG = {
laneWidth: 4.5,
laneSwitchSpeed: 12,
initialSpeed: 45,
maxSpeed: 120,
acceleration: 1.5,
roadSegmentLength: 4,
visibleSegments: 45,
curveIntensity: 18, // How far left/right the road snakes
curveFrequency: 0.015 // Wavelength of the road curves
};
let gameState = 'MENU'; // MENU, PLAYING, GAMEOVER
let score = 0;
let currentSpeed = CONFIG.initialSpeed;
let distanceTraveled = 0;
let currentLane = 0; // -1: Left, 0: Center, 1: Right
let targetX = 0; // Target X coord for smooth lane changing
let playerX = 0; // Actual physical X coordinate of player car
// --- THREE.JS GLOBALS ---
let scene, camera, renderer;
let playerCar, roadGroup, obstacleGroup, cloudGroup;
let roadSegments = [];
let obstacles = [];
// --- INITIALIZATION ---
function init() {
const container = document.getElementById('canvas-container');
// Scene Setup
scene = new THREE.Scene();
scene.background = new THREE.Color(0x050512);
scene.fog = new THREE.FogExp2(0x050512, 0.007);
// Camera Setup
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
// Angle camera down at the car slightly
camera.position.set(0, 6, -11);
camera.lookAt(new THREE.Vector3(0, 2, 20));
// Renderer Setup
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
// Groups
roadGroup = new THREE.Group();
obstacleGroup = new THREE.Group();
cloudGroup = new THREE.Group();
scene.add(roadGroup);
scene.add(obstacleGroup);
scene.add(cloudGroup);
// Lighting
setupLighting();
// Build Static Environment / Objects
createPlayerCar();
buildInitialRoad();
generateClouds();
// Event Listeners
window.addEventListener('resize', onWindowResize);
window.addEventListener('keydown', handleKeyDown);
document.getElementById('start-btn').addEventListener('click', startGame);
document.getElementById('restart-btn').addEventListener('click', restartGame);
// Kick off game animation loop
animate();
}
// --- LIGHTING ---
function setupLighting() {
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(20, 40, -20);
directionalLight.castShadow = true;
scene.add(directionalLight);
// Subtle neon glow from bottom up
const skyLight = new THREE.HemisphereLight(0x00ffff, 0xff00ff, 0.3);
scene.add(skyLight);
}
// --- PROCEDURAL GENERATION HELPERS ---
// Math formula that determines how the road curves based on total Z distance
function getRoadCenterAtZ(zCoordinate) {
return Math.sin(zCoordinate * CONFIG.curveFrequency) * CONFIG.curveIntensity;
}
function createPlayerCar() {
playerCar = new THREE.Group();
// Main Chassis (Lower Body)
const bodyGeom = new THREE.BoxGeometry(2, 0.6, 4.2);
const bodyMat = new THREE.MeshStandardMaterial({ color: 0xff0055, roughness: 0.2, metalness: 0.8 });
const body = new THREE.Mesh(bodyGeom, bodyMat);
body.position.y = 0.5;
body.castShadow = true;
playerCar.add(body);
// Cabin (Upper glass/roof)
const cabinGeom = new THREE.BoxGeometry(1.6, 0.6, 2);
const cabinMat = new THREE.MeshStandardMaterial({ color: 0x111122, roughness: 0.1, transparent: true, opacity: 0.7 });
const cabin = new THREE.Mesh(cabinGeom, cabinMat);
cabin.position.set(0, 1.1, -0.3);
playerCar.add(cabin);
// Wheels (Cylinders)
const wheelGeom = new THREE.CylinderGeometry(0.4, 0.4, 0.4, 16);
const wheelMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.8 });
const wheelPositions = [
[-1.05, 0.4, 1.3], // Front Left
[1.05, 0.4, 1.3], // Front Right
[-1.05, 0.4, -1.3], // Rear Left
[1.05, 0.4, -1.3] // Rear Right
];
wheelPositions.forEach(pos => {
const wheel = new THREE.Mesh(wheelGeom, wheelMat);
wheel.position.set(pos[0], pos[1], pos[2]);
wheel.rotation.z = Math.PI / 2; // Flip cylinder sideways
playerCar.add(wheel);
});
// Headlights (Neon visual indicators)
const lightGeom = new THREE.BoxGeometry(0.4, 0.15, 0.1);
const lightMat = new THREE.MeshBasicMaterial({ color: 0x00ffff });
const leftLight = new THREE.Mesh(lightGeom, lightMat);
leftLight.position.set(-0.7, 0.6, 2.1);
const rightLight = leftLight.clone();
rightLight.position.x = 0.7;
playerCar.add(leftLight, rightLight);
scene.add(playerCar);
}
function createRoadSegment(zPos) {
const segmentGroup = new THREE.Group();
const roadWidth = CONFIG.laneWidth * 3;
// Main Asphalt
const roadGeom = new THREE.BoxGeometry(roadWidth, 0.2, CONFIG.roadSegmentLength);
const roadMat = new THREE.MeshStandardMaterial({ color: 0x1a1a24, roughness: 0.7 });
const road = new THREE.Mesh(roadGeom, roadMat);
road.receiveShadow = true;
segmentGroup.add(road);
// Side Railings / Neon borders
const railGeom = new THREE.BoxGeometry(0.3, 0.4, CONFIG.roadSegmentLength);
const railMat = new THREE.MeshStandardMaterial({ color: 0x9900ff, emissive: 0x330066 });
const leftRail = new THREE.Mesh(railGeom, railMat);
leftRail.position.set(-roadWidth/2 - 0.15, 0.2, 0);
const rightRail = leftRail.clone();
rightRail.position.x = roadWidth/2 + 0.15;
segmentGroup.add(leftRail, rightRail);
// Lane Dividers (Dashed Center Lines)
if (Math.floor(zPos / CONFIG.roadSegmentLength) % 2 === 0) {
const lineGeom = new THREE.BoxGeometry(0.15, 0.22, CONFIG.roadSegmentLength * 0.6);
const lineMat = new THREE.MeshBasicMaterial({ color: 0xffffff });
const line1 = new THREE.Mesh(lineGeom, lineMat);
line1.position.set(-CONFIG.laneWidth / 2, 0, 0);
const line2 = line1.clone();
line2.position.x = CONFIG.laneWidth / 2;
segmentGroup.add(line1, line2);
}
// Curve positioning alignment
const targetCenterX = getRoadCenterAtZ(zPos);
segmentGroup.position.set(targetCenterX, 0, zPos);
roadGroup.add(segmentGroup);
return {
mesh: segmentGroup,
z: zPos,
centerX: targetCenterX
};
}
function buildInitialRoad() {
for (let i = 0; i < CONFIG.visibleSegments; i++) {
const zPos = i * CONFIG.roadSegmentLength;
roadSegments.push(createRoadSegment(zPos));
}
}
function createObstacle(zPos, lane) {
// Lane mapping calculations
const baseCenterX = getRoadCenterAtZ(zPos);
const laneXOffset = lane * CONFIG.laneWidth;
const absoluteX = baseCenterX + laneXOffset;
const obstacleMesh = new THREE.Group();
// Main Barrier beam
const barrierGeom = new THREE.BoxGeometry(3.6, 0.5, 0.8);
const barrierMat = new THREE.MeshStandardMaterial({ color: 0xff7700, roughness: 0.5 });
const barrier = new THREE.Mesh(barrierGeom, barrierMat);
barrier.position.y = 0.8;
barrier.castShadow = true;
obstacleMesh.add(barrier);
// Support pillars
const legGeom = new THREE.BoxGeometry(0.4, 0.8, 0.8);
const legMat = new THREE.MeshStandardMaterial({ color: 0x333333 });
const leftLeg = new THREE.Mesh(legGeom, legMat);
leftLeg.position.set(-1.4, 0.4, 0);
const rightLeg = leftLeg.clone();
rightLeg.position.x = 1.4;
obstacleMesh.add(leftLeg, rightLeg);
// Neon warning strip
const stripeGeom = new THREE.BoxGeometry(3.62, 0.2, 0.82);
const stripeMat = new THREE.MeshBasicMaterial({ color: 0xffaa00 });
const stripe = new THREE.Mesh(stripeGeom, stripeMat);
stripe.position.y = 0.8;
obstacleMesh.add(stripe);
obstacleMesh.position.set(absoluteX, 0, zPos);
obstacleGroup.add(obstacleMesh);
obstacles.push({
mesh: obstacleMesh,
z: zPos,
lane: lane,
boundingBox: new THREE.Box3(new THREE.Vector3(), new THREE.Vector3())
});
}
function generateClouds() {
const cloudMat = new THREE.MeshStandardMaterial({ color: 0x222244, roughness: 0.9, flatShading: true });
for(let i=0; i<25; i++) {
const cloud = new THREE.Group();
const numSpheres = 3 + Math.floor(Math.random() * 4);
for(let j=0; j<numSpheres; j++) {
const radius = 3 + Math.random() * 5;
const sphereGeom = new THREE.SphereGeometry(radius, 6, 6);
const sphere = new THREE.Mesh(sphereGeom, cloudMat);
sphere.position.set(
(j * 3) - (numSpheres * 1.5),
(Math.random() * 2) - 1,
(Math.random() * 2) - 1
);
cloud.add(sphere);
}
// Disperse widely over horizon skybox
cloud.position.set(
(Math.random() - 0.5) * 300,
15 + Math.random() * 25,
40 + Math.random() * 160
);
cloudGroup.add(cloud);
}
}
// --- PROCEDURAL RECYCLING LOOP ---
function updateInfiniteWorld(delta) {
// Calculate how far we traveled inside this tick frame
const speedFactor = currentSpeed * 0.44704; // Conversion framework to M/S
const frameDistance = speedFactor * delta;
distanceTraveled += frameDistance;
if (gameState === 'PLAYING') {
score = Math.floor(distanceTraveled / 3);
document.getElementById('score-val').innerText = score;
document.getElementById('speed-val').innerText = Math.floor(currentSpeed);
// Accelerate gently over time
if (currentSpeed < CONFIG.maxSpeed) {
currentSpeed += CONFIG.acceleration * delta;
}
}
// Move the obstacle meshes and clouds backward towards player
obstacleGroup.position.z -= frameDistance;
cloudGroup.children.forEach(cloud => {
cloud.position.z -= frameDistance * 0.1; // Cloud drift looks slower (parallax effect)
if (cloud.position.z < -20) {
cloud.position.z = 150 + Math.random() * 50;
cloud.position.x = (Math.random() - 0.5) * 300;
}
});
// Adjust road segments track
roadSegments.forEach(seg => {
seg.z -= frameDistance;
// Recycle chunk index to horizon when it leaves player camera range
if (seg.z < -CONFIG.roadSegmentLength * 3) {
const highestZ = Math.max(...roadSegments.map(s => s.z));
seg.z = highestZ + CONFIG.roadSegmentLength;
seg.centerX = getRoadCenterAtZ(distanceTraveled + seg.z);
}
seg.mesh.position.set(seg.centerX, 0, seg.z);
});
// Handle Obstacle spawning logic rules
obstacles.forEach((obs, index) => {
obs.z -= frameDistance;
// Track dynamic curves adjustments as barriers move closer
const absoluteRoadCenter = getRoadCenterAtZ(distanceTraveled + obs.z);
obs.mesh.position.set(absoluteRoadCenter + (obs.lane * CONFIG.laneWidth), 0, obs.z);
// Update physical bounding box matrices targets
if (obs.mesh.children[0]) {
obs.boundingBox.setFromObject(obs.mesh);
}
// Clear barriers safely when behind player cockpit
if (obs.z < -5) {
obstacleGroup.remove(obs.mesh);
obstacles.splice(index, 1);
}
});
// Continuous spawn stream triggers
if (gameState === 'PLAYING' && obstacles.length < 8) {
const furthestZ = obstacles.length > 0 ? Math.max(...obstacles.map(o => o.z)) : 40;
// Spawn spacing gaps dynamically based on speed thresholds
const spawnGap = 35 + (currentSpeed * 0.2);
if (furthestZ < 140) {
const targetSpawnZ = furthestZ + spawnGap;
const choicePattern = Math.random();
if (choicePattern < 0.40) {
// Single random barrier
createObstacle(targetSpawnZ, Math.floor(Math.random() * 3) - 1);
} else if (choicePattern < 0.75) {
// Double barrier blockade combo (Forces clean swift lane skips)
const emptyLane = Math.floor(Math.random() * 3) - 1;
[-1, 0, 1].forEach(lane => {
if (lane !== emptyLane) createObstacle(targetSpawnZ, lane);
});
}
}
}
}
// --- PLAYER INTERACTION INTERPOLATION ---
function updatePlayerMovement(delta) {
// Find current alignment profile anchor directly underneath the vehicle
const currentRoadCenter = getRoadCenterAtZ(distanceTraveled);
// Map lateral lane selections values targets
targetX = currentRoadCenter + (currentLane * CONFIG.laneWidth);
// Interpolate vehicle physics position across curves tracks safely
playerX += (targetX - playerX) * CONFIG.laneSwitchSpeed * delta;
playerCar.position.set(playerX, 0, 0);
// Tilt/Lean effects calculations based on steering targets tracking gaps delta
const lateralDeflection = targetX - playerX;
playerCar.rotation.y = lateralDeflection * 0.08;
playerCar.rotation.z = -lateralDeflection * 0.05;
}
// --- COLLISION LOGIC DETECTOR ---
function checkCollisions() {
if (gameState !== 'PLAYING') return;
// Generate Bounding box wrapping system calculations cleanly around car frame
const carBox = new THREE.Box3().setFromObject(playerCar);
// Add margin reduction profile to ease visual tolerances safely
carBox.min.x += 0.15;
carBox.max.x -= 0.15;
carBox.min.z += 0.2;
carBox.max.z -= 0.2;
for (let i = 0; i < obstacles.length; i++) {
const obs = obstacles[i];
// Only evaluate intersections strictly near tracking range parameters
if (obs.z > -2 && obs.z < 3) {
if (carBox.intersectsBox(obs.boundingBox)) {
endGame();
break;
}
}
}
}
// --- STATE ACTIONS ---
function startGame() {
document.getElementById('menu-screen').classList.add('hidden');
document.getElementById('hud').classList.remove('hidden');
gameState = 'PLAYING';
}
function endGame() {
gameState = 'GAMEOVER';
document.getElementById('hud').classList.add('hidden');
document.getElementById('final-score').innerText = score;
document.getElementById('gameover-screen').classList.remove('hidden');
}
function restartGame() {
document.getElementById('gameover-screen').classList.add('hidden');
document.getElementById('hud').classList.remove('hidden');
// Reset variable loops
score = 0;
distanceTraveled = 0;
currentSpeed = CONFIG.initialSpeed;
currentLane = 0;
playerX = 0;
targetX = 0;
// Purge existing barriers from runtime context cache safely
obstacles.forEach(obs => obstacleGroup.remove(obs.mesh));
obstacles = [];
gameState = 'PLAYING';
}
// --- CORE LOOPS CONTROLLER ---
let clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
// Fetch structural Delta framework steps safely capped to prevent lag spikes
let delta = clock.getDelta();
if (delta > 0.1) delta = 0.1;
// Environment transformations ticks executed continuously
updateInfiniteWorld(delta);
updatePlayerMovement(delta);
checkCollisions();
renderer.render(scene, camera);
}
// --- CONTROL MAPS ---
function handleKeyDown(e) {
if (gameState !== 'PLAYING') return;
if ((e.key === 'ArrowLeft' || e.key.toLowerCase() === 'a') && currentLane > -1) {
currentLane--;
}
if ((e.key === 'ArrowRight' || e.key.toLowerCase() === 'd') && currentLane < 1) {
currentLane++;
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// Boot system core runtime directly on finish loading document context safely
window.onload = init;
</script>
</body>
</html>