LiteChat Race Result
Here is a simple example of a 2D scroll shooter with a 3D effect using Three.js. This example includes live, random bonus drops and enemy difficulty progression.
```runjs
// Clear any previous content
litechat.target.replaceChildren();
async function createShooterGame() {
try {
// Load the modules with proper import map configuration
const modules = await litechat.utils.loadModules([
{
url: 'https://unpkg.com/three@0.170.0/build/three.module.js',
name: 'THREE',
globalKey: 'THREE',
importMap: {
"three": "https://unpkg.com/three@0.170.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.170.0/examples/jsm/"
}
}
]);
const { THREE } = modules;
// Create container
const container = document.createElement('div');
container.className = 'p-4 bg-gray-900 rounded-lg';
// Create canvas
const canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 600;
canvas.className = 'border border-gray-600 rounded';
container.appendChild(canvas);
// Add info text
const info = document.createElement('div');
info.className = 'text-white text-center mt-2';
info.textContent = 'Use arrow keys to move, space to shoot';
container.appendChild(info);
litechat.target.appendChild(container);
// Three.js scene setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x222222);
const camera = new THREE.OrthographicCamera(-canvas.width / 2, canvas.width / 2, canvas.height / 2, -canvas.height / 2, 1, 1000);
camera.position.set(0, 0, 1);
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(canvas.width, canvas.height);
// Add lights
const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
scene.add(ambientLight);
// Player
const playerGeometry = new THREE.BoxGeometry(20, 20, 20);
const playerMaterial = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
const player = new THREE.Mesh(playerGeometry, playerMaterial);
player.position.set(0, 0, 0);
scene.add(player);
// Bullets
const bulletGeometry = new THREE.BoxGeometry(5, 5, 5);
const bulletMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
const bullets = [];
// Enemies
const enemyGeometry = new THREE.BoxGeometry(20, 20, 20);
const enemyMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });
const enemies = [];
// Bonus
const bonusGeometry = new THREE.BoxGeometry(10, 10, 10);
const bonusMaterial = new THREE.MeshLambertMaterial({ color: 0xffff00 });
let bonus = null;
// Game variables
let score = 0;
let lives = 3;
let fireRate = 1;
let bouncyFire = 0;
let guns = 1;
let gunOffset = 0;
// Keyboard input
let keysDown = {};
document.addEventListener('keydown', (event) => {
keysDown[event.key] = true;
});
document.addEventListener('keyup', (event) => {
keysDown[event.key] = false;
});
// Game loop
function animate() {
requestAnimationFrame(animate);
// Move player
if (keysDown['ArrowLeft']) {
player.position.x -= 5;
}
if (keysDown['ArrowRight']) {
player.position.x += 5;
}
if (keysDown['ArrowUp']) {
player.position.y += 5;
}
if (keysDown['ArrowDown']) {
player.position.y -= 5;
}
// Shoot bullets
if (keysDown[' ']) {
for (let i = 0; i < guns; i++) {
const bullet = new THREE.Mesh(bulletGeometry, bulletMaterial);
bullet.position.set(player.position.x + gunOffset * (i - guns / 2 + 0.5), player.position.y, 0);
bullets.push(bullet);
scene.add(bullet);
}
gunOffset = (gunOffset + 5) % 10;
setTimeout(() => {
gunOffset = 0;
}, 100);
}
// Move bullets
for (let i = bullets.length - 1; i >= 0; i--) {
bullets[i].position.y += 10;
if (bullets[i].position.y > canvas.height / 2) {
scene.remove(bullets[i]);
bullets.splice(i, 1);
}
}
// Move enemies
for (let i = enemies.length - 1; i >= 0; i--) {
enemies[i].position.y += 2;
if (enemies[i].position.y > canvas.height / 2) {
scene.remove(enemies[i]);
enemies.splice(i, 1);
lives--;
}
}
// Check collisions
for (let i = bullets.length - 1; i >= 0; i--) {
for (let j = enemies.length - 1; j >= 0; j--) {
if (bullets[i].position.distanceTo(enemies[j].position) < 20) {
scene.remove(bullets[i]);
bullets.splice(i, 1);
scene.remove(enemies[j]);
enemies.splice(j, 1);
score++;
if (bouncyFire > 0) {
const newBullet = new THREE.Mesh(bulletGeometry, bulletMaterial);
newBullet.position.set(enemies[j].position.x, enemies[j].position.y, 0);
bullets.push(newBullet);
scene.add(newBullet);
bouncyFire--;
}
}
}
}
// Add enemies
if (Math.random() < 0.05) {
const enemy = new THREE.Mesh(enemyGeometry, enemyMaterial);
enemy.position.set(Math.random() * canvas.width - canvas.width / 2, -canvas.height / 2, 0);
enemies.push(enemy);
scene.add(enemy);
}
// Add bonus
if (Math.random() < 0.01 && !bonus) {
bonus = new THREE.Mesh(bonusGeometry, bonusMaterial);
bonus.position.set(Math.random() * canvas.width - canvas.width / 2, -canvas.height / 2, 0);
scene.add(bonus);
}
// Check bonus collision
if (bonus && player.position.distanceTo(bonus.position) < 20) {
scene.remove(bonus);
bonus = null;
const bonusType = Math.random();
if (bonusType < 0.25) {
fireRate *= 1.1;
} else if (bonusType < 0.5) {
bouncyFire = 5;
} else if (bonusType < 0.75) {
guns++;
} else {
lives++;
}
}
// Update renderer
renderer.render(scene, camera);
}
animate();
} catch (error) {
litechat.utils.log('error', '❌ FAILED to create scene:', 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);
}
}
createShooterGame();
```