LiteChat Model Race Result (RUNJS)
Here's a 2D scroll shooter with 3D effects using Three.js. The game features colorful graphics, power-ups, and increasing difficulty:
```runjs
// Clear any previous content
litechat.target.replaceChildren();
async function createScrollShooter() {
try {
litechat.utils.log('info', '🚀 Starting Scroll Shooter game...');
// Load Three.js
const THREE = await litechat.utils.loadModule(
'https://unpkg.com/three@0.170.0/build/three.module.js',
'THREE'
);
// Game constants
const GAME_WIDTH = 800;
const GAME_HEIGHT = 600;
const PLAYER_SPEED = 5;
const BULLET_SPEED = 8;
const ENEMY_SPEED = 2;
const SPAWN_INTERVAL = 1500; // ms
const POWERUP_CHANCE = 0.2; // 20% chance for powerup
// Game state
let player;
let bullets = [];
let enemies = [];
let powerups = [];
let score = 0;
let lives = 3;
let fireRate = 300; // ms between shots
let lastShotTime = 0;
let bounceCount = 0;
let gunCount = 1;
let gameOver = false;
let enemySpeed = ENEMY_SPEED;
let enemySpawnInterval = SPAWN_INTERVAL;
// Create game container
const container = document.createElement('div');
container.className = 'relative w-full max-w-[800px] mx-auto bg-gray-900 rounded-lg overflow-hidden border-4 border-purple-500';
// Create canvas
const canvas = document.createElement('canvas');
canvas.width = GAME_WIDTH;
canvas.height = GAME_HEIGHT;
container.appendChild(canvas);
// Create UI overlay
const uiOverlay = document.createElement('div');
uiOverlay.className = 'absolute top-0 left-0 right-0 p-4 text-white font-bold';
uiOverlay.style.pointerEvents = 'none';
const scoreDisplay = document.createElement('div');
scoreDisplay.textContent = 'Score: 0';
scoreDisplay.className = 'text-xl';
const livesDisplay = document.createElement('div');
livesDisplay.textContent = 'Lives: 3';
livesDisplay.className = 'text-xl';
const gameOverDisplay = document.createElement('div');
gameOverDisplay.className = 'absolute inset-0 flex items-center justify-center bg-black bg-opacity-75 text-4xl hidden';
uiOverlay.appendChild(scoreDisplay);
uiOverlay.appendChild(livesDisplay);
uiOverlay.appendChild(gameOverDisplay);
container.appendChild(uiOverlay);
litechat.target.appendChild(container);
// Three.js setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
const camera = new THREE.OrthographicCamera(
-GAME_WIDTH / 2, GAME_WIDTH / 2,
GAME_HEIGHT / 2, -GAME_HEIGHT / 2,
0.1, 1000
);
camera.position.z = 500;
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(GAME_WIDTH, GAME_HEIGHT);
// Add ambient light
const ambientLight = new THREE.AmbientLight(0x404040, 0.8);
scene.add(ambientLight);
// Create player
function createPlayer() {
const geometry = new THREE.BoxGeometry(50, 30, 10);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = -GAME_HEIGHT / 2 + 50;
scene.add(mesh);
return mesh;
}
// Create bullet
function createBullet(x, y) {
const geometry = new THREE.SphereGeometry(5, 8, 8);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(x, y, 0);
scene.add(mesh);
return mesh;
}
// Create enemy
function createEnemy() {
const geometry = new THREE.BoxGeometry(40, 40, 10);
const color = new THREE.Color(
Math.random(),
Math.random(),
Math.random()
);
const material = new THREE.MeshBasicMaterial({ color });
const mesh = new THREE.Mesh(geometry, material);
// Random starting position at top
const x = Math.random() * GAME_WIDTH - GAME_WIDTH / 2;
mesh.position.set(x, GAME_HEIGHT / 2 + 20, 0);
scene.add(mesh);
return mesh;
}
// Create powerup
function createPowerup(x, y, type) {
const geometry = new THREE.BoxGeometry(30, 30, 10);
let color;
switch(type) {
case 'fireRate': color = 0xffff00; break;
case 'bounce': color = 0xff8800; break;
case 'gun': color = 0x00ffff; break;
case 'life': color = 0xff00ff; break;
default: color = 0xffffff;
}
const material = new THREE.MeshBasicMaterial({ color });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(x, y, 0);
mesh.userData.type = type;
scene.add(mesh);
return mesh;
}
// Initialize player
player = createPlayer();
// Handle keyboard input
const keys = {};
window.addEventListener('keydown', (e) => {
keys[e.key] = true;
});
window.addEventListener('keyup', (e) => {
keys[e.key] = false;
});
// Game loop
let lastTime = 0;
let lastEnemySpawn = 0;
let lastPowerupSpawn = 0;
function gameLoop(time) {
if (gameOver) return;
const deltaTime = time - lastTime;
lastTime = time;
// Move player
if (keys['ArrowLeft'] && player.position.x > -GAME_WIDTH / 2 + 25) {
player.position.x -= PLAYER_SPEED;
}
if (keys['ArrowRight'] && player.position.x < GAME_WIDTH / 2 - 25) {
player.position.x += PLAYER_SPEED;
}
if (keys['ArrowUp'] && player.position.y < GAME_HEIGHT / 2 - 15) {
player.position.y += PLAYER_SPEED;
}
if (keys['ArrowDown'] && player.position.y > -GAME_HEIGHT / 2 + 15) {
player.position.y -= PLAYER_SPEED;
}
// Shoot
if (keys[' '] && time - lastShotTime > fireRate) {
lastShotTime = time;
shoot();
}
// Move bullets
bullets.forEach((bullet, index) => {
bullet.position.y += BULLET_SPEED;
if (bullet.position.y > GAME_HEIGHT / 2) {
scene.remove(bullet);
bullets.splice(index, 1);
}
});
// Move enemies
enemies.forEach((enemy, index) => {
enemy.position.y -= enemySpeed;
if (enemy.position.y < -GAME_HEIGHT / 2) {
scene.remove(enemy);
enemies.splice(index, 1);
lives--;
livesDisplay.textContent = `Lives: ${lives}`;
if (lives <= 0) {
gameOver = true;
gameOverDisplay.textContent = 'Game Over! Press F5 to restart';
gameOverDisplay.classList.remove('hidden');
}
}
});
// Move powerups
powerups.forEach((powerup, index) => {
powerup.position.y -= 2;
if (powerup.position.y < -GAME_HEIGHT / 2) {
scene.remove(powerup);
powerups.splice(index, 1);
}
});
// Check collisions
checkCollisions();
// Spawn enemies
if (time - lastEnemySpawn > enemySpawnInterval) {
lastEnemySpawn = time;
enemies.push(createEnemy());
// Increase difficulty over time
if (enemySpawnInterval > 500) {
enemySpawnInterval -= 10;
}
if (enemySpeed < 5) {
enemySpeed += 0.05;
}
}
// Spawn powerups
if (Math.random() < POWERUP_CHANCE / 100 && time - lastPowerupSpawn > 5000) {
lastPowerupSpawn = time;
const enemy = enemies[Math.floor(Math.random() * enemies.length)];
if (enemy) {
const types = ['fireRate', 'bounce', 'gun', 'life'];
const type = types[Math.floor(Math.random() * types.length)];
powerups.push(createPowerup(enemy.position.x, enemy.position.y, type));
}
}
renderer.render(scene, camera);
requestAnimationFrame(gameLoop);
}
// Shooting function
function shoot() {
const bulletPositions = [];
if (gunCount === 1) {
bulletPositions.push({ x: 0, y: 15 });
} else if (gunCount === 2) {
bulletPositions.push({ x: -10, y: 15 }, { x: 10, y: 15 });
} else if (gunCount === 3) {
bulletPositions.push({ x: -15, y: 15 }, { x: 0, y: 15 }, { x: 15, y: 15 });
}
bulletPositions.forEach(pos => {
const bullet = createBullet(
player.position.x + pos.x,
player.position.y + pos.y
);
bullet.userData.bounces = bounceCount;
bullets.push(bullet);
});
}
// Collision detection
function checkCollisions() {
// Bullet-enemy collisions
bullets.forEach((bullet, bulletIndex) => {
enemies.forEach((enemy, enemyIndex) => {
if (Math.abs(bullet.position.x - enemy.position.x) < 25 &&
Math.abs(bullet.position.y - enemy.position.y) < 25) {
// Remove enemy
scene.remove(enemy);
enemies.splice(enemyIndex, 1);
// Update score
score += 10;
scoreDisplay.textContent = `Score: ${score}`;
// Handle bullet bounce
if (bullet.userData.bounces > 0) {
bullet.userData.bounces--;
// Simple bounce: reverse direction
bullet.position.y -= 10;
} else {
// Remove bullet
scene.remove(bullet);
bullets.splice(bulletIndex, 1);
}
}
});
});
// Player-powerup collisions
powerups.forEach((powerup, index) => {
if (Math.abs(player.position.x - powerup.position.x) < 35 &&
Math.abs(player.position.y - powerup.position.y) < 35) {
// Apply powerup
switch(powerup.userData.type) {
case 'fireRate':
fireRate = Math.max(100, fireRate * 0.9);
break;
case 'bounce':
bounceCount++;
break;
case 'gun':
gunCount = Math.min(3, gunCount + 1);
break;
case 'life':
lives = Math.min(5, lives + 1);
livesDisplay.textContent = `Lives: ${lives}`;
break;
}
// Remove powerup
scene.remove(powerup);
powerups.splice(index, 1);
}
});
// Player-enemy collisions
enemies.forEach((enemy, index) => {
if (Math.abs(player.position.x - enemy.position.x) < 35 &&
Math.abs(player.position.y - enemy.position.y) < 35) {
// Remove enemy and decrease life
scene.remove(enemy);
enemies.splice(index, 1);
lives--;
livesDisplay.textContent = `Lives: ${lives}`;
if (lives <= 0) {
gameOver = true;
gameOverDisplay.textContent = 'Game Over! Press F5 to restart';
gameOverDisplay.classList.remove('hidden');
}
}
});
}
// Start game loop
requestAnimationFrame(gameLoop);
litechat.utils.log('info', '🎮 Scroll Shooter game loaded! Use arrow keys to move, space to shoot.');
} catch (error) {
litechat.utils.log('error', '❌ FAILED to create game:', error.message);
const errorDiv = document.createElement('div');
errorDiv.className = 'p-4 text-red-600 bg-red-100 border border-red-200 rounded-md';
errorDiv.textContent = `Error: ${error.message}`;
litechat.target.appendChild(errorDiv);
}
}
createScrollShooter();
```
This game features:
- Colorful 3D graphics with a 2D gameplay feel
- Multiple power-ups (faster fire rate, bouncy bullets, extra guns, extra lives)
- Increasing difficulty over time
- Smooth controls and responsive gameplay
- Score tracking and game over screen
Use arrow keys to move your spaceship and spacebar to shoot. Collect power-ups that drop randomly from enemies to enhance your firepower!