Skip to content

Instantly share code, notes, and snippets.

@shricodev
Created August 3, 2025 08:48
Show Gist options
  • Select an option

  • Save shricodev/493fe9e8fe2b725e5c43ff88a9cd62d0 to your computer and use it in GitHub Desktop.

Select an option

Save shricodev/493fe9e8fe2b725e5c43ff88a9cd62d0 to your computer and use it in GitHub Desktop.
Geometry Dash (Developed by Kimi K2 AI Model) - Blog Demo
// Audio System for Rhythm-Based Gameplay
class AudioManager {
constructor() {
this.audioContext = null;
this.masterGain = null;
this.musicGain = null;
this.sfxGain = null;
this.isInitialized = false;
this.beatInterval = 500; // 120 BPM
this.lastBeatTime = 0;
this.beatCount = 0;
// Sound effects using Web Audio API
this.sounds = {
jump: null,
death: null,
collect: null,
complete: null
};
// Background music pattern
this.musicPattern = [
{ freq: 440, duration: 0.25, type: 'sine' }, // A4
{ freq: 554, duration: 0.25, type: 'sine' }, // C#5
{ freq: 659, duration: 0.25, type: 'sine' }, // E5
{ freq: 440, duration: 0.25, type: 'sine' }, // A4
{ freq: 523, duration: 0.5, type: 'sine' }, // C5
{ freq: 659, duration: 0.5, type: 'sine' }, // E5
{ freq: 784, duration: 0.25, type: 'sine' }, // G5
{ freq: 659, duration: 0.25, type: 'sine' }, // E5
{ freq: 523, duration: 0.5, type: 'sine' } // C5
];
}
async initialize() {
try {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
// Create gain nodes
this.masterGain = this.audioContext.createGain();
this.musicGain = this.audioContext.createGain();
this.sfxGain = this.audioContext.createGain();
// Connect gain nodes
this.musicGain.connect(this.masterGain);
this.sfxGain.connect(this.masterGain);
this.masterGain.connect(this.audioContext.destination);
// Set initial volumes
this.masterGain.gain.value = 0.3;
this.musicGain.gain.value = 0.2;
this.sfxGain.gain.value = 0.4;
this.isInitialized = true;
console.log('Audio system initialized');
} catch (error) {
console.warn('Audio initialization failed:', error);
}
}
playSound(type, frequency = 440, duration = 0.1, waveType = 'sine') {
if (!this.isInitialized) return;
try {
const oscillator = this.audioContext.createOscillator();
const gainNode = this.audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(this.sfxGain);
oscillator.type = waveType;
oscillator.frequency.setValueAtTime(frequency, this.audioContext.currentTime);
// ADSR envelope
gainNode.gain.setValueAtTime(0, this.audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(0.3, this.audioContext.currentTime + 0.01);
gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + duration);
oscillator.start(this.audioContext.currentTime);
oscillator.stop(this.audioContext.currentTime + duration);
} catch (error) {
console.warn('Sound playback failed:', error);
}
}
playJumpSound() {
this.playSound('jump', 523.25, 0.15, 'sine'); // C5
}
playDeathSound() {
this.playSound('death', 220, 0.3, 'sawtooth'); // A3
}
playCollectSound() {
this.playSound('collect', 659.25, 0.2, 'triangle'); // E5
}
playCompleteSound() {
// Victory fanfare
const melody = [523.25, 659.25, 783.99, 1046.50]; // C5, E5, G5, C6
melody.forEach((freq, index) => {
setTimeout(() => {
this.playSound('complete', freq, 0.3, 'sine');
}, index * 150);
});
}
playBackgroundMusic() {
if (!this.isInitialized) return;
// Create a simple looping pattern
const playPattern = () => {
this.musicPattern.forEach((note, index) => {
setTimeout(() => {
this.playSound('music', note.freq, note.duration, note.type);
}, index * note.duration * 1000);
});
// Loop the pattern
setTimeout(playPattern, this.musicPattern.reduce((sum, note) => sum + note.duration, 0) * 1000);
};
playPattern();
}
getBeatTiming() {
const now = this.audioContext ? this.audioContext.currentTime : Date.now() / 1000;
const beat = Math.floor(now / (this.beatInterval / 1000));
const nextBeat = (beat + 1) * (this.beatInterval / 1000);
const timeToNextBeat = nextBeat - now;
return {
beat: beat,
timeToNextBeat: timeToNextBeat,
isOnBeat: timeToNextBeat < 0.1
};
}
resume() {
if (this.audioContext && this.audioContext.state === 'suspended') {
this.audioContext.resume();
}
}
}
// Global audio manager
const audioManager = new AudioManager();
// Initialize audio on first user interaction
document.addEventListener('click', () => {
audioManager.resume();
if (!audioManager.isInitialized) {
audioManager.initialize();
}
}, { once: true });
document.addEventListener('keydown', () => {
audioManager.resume();
if (!audioManager.isInitialized) {
audioManager.initialize();
}
}, { once: true });
// Fixed Geometry Dash Game - No Audio, Functional
// This version fixes the screen positioning and interaction issues
// Game configuration
const CONFIG = {
GRAVITY: 0.8,
JUMP_FORCE: -15,
PLAYER_SIZE: 30,
GROUND_Y: 500,
GAME_SPEED: 6,
LEVEL_LENGTH: 8000,
CAMERA_OFFSET: 100,
SCREEN_SHAKE: 20
};
// Simple level design
const LEVEL = {
obstacles: [
{ x: 300, type: 'spike', height: 40 },
{ x: 500, type: 'spike', height: 50 },
{ x: 700, type: 'gap', width: 80 },
{ x: 1000, type: 'spike', height: 60 },
{ x: 1200, type: 'spike', height: 70 },
{ x: 1400, type: 'spike', height: 80 },
{ x: 1600, type: 'gap', width: 100 },
{ x: 2000, type: 'spike', height: 90 },
{ x: 2200, type: 'spike', height: 60 },
{ x: 2400, type: 'spike', height: 100 },
{ x: 2600, type: 'gap', width: 120 },
{ x: 3200, type: 'spike', height: 110 },
{ x: 3400, type: 'spike', height: 70 },
{ x: 3600, type: 'spike', height: 90 },
{ x: 3800, type: 'gap', width: 150 },
{ x: 4200, type: 'spike', height: 120 },
{ x: 4400, type: 'spike', height: 80 },
{ x: 4600, type: 'spike', height: 100 },
{ x: 4800, type: 'spike', height: 90 },
{ x: 5000, type: 'gap', width: 180 },
{ x: 5400, type: 'spike', height: 130 },
{ x: 5600, type: 'spike', height: 100 },
{ x: 5800, type: 'spike', height: 110 },
{ x: 6000, type: 'spike', height: 120 },
{ x: 6200, type: 'gap', width: 200 },
{ x: 6800, type: 'spike', height: 100 },
{ x: 7000, type: 'spike', height: 90 },
{ x: 7200, type: 'spike', height: 110 },
{ x: 7400, type: 'spike', height: 100 },
{ x: 7600, type: 'spike', height: 120 }
]
};
// Player class
class Player {
constructor() {
this.x = 100;
this.y = CONFIG.GROUND_Y - CONFIG.PLAYER_SIZE;
this.velocityY = 0;
this.isGrounded = true;
this.rotation = 0;
}
update() {
this.velocityY += CONFIG.GRAVITY;
this.y += this.velocityY;
if (this.y >= CONFIG.GROUND_Y - CONFIG.PLAYER_SIZE) {
this.y = CONFIG.GROUND_Y - CONFIG.PLAYER_SIZE;
this.velocityY = 0;
this.isGrounded = true;
this.rotation = 0;
} else {
this.isGrounded = false;
this.rotation += 0.3;
}
}
jump() {
if (this.isGrounded) {
this.velocityY = CONFIG.JUMP_FORCE;
this.isGrounded = false;
}
}
display() {
push();
translate(this.x + CONFIG.PLAYER_SIZE/2, this.y + CONFIG.PLAYER_SIZE/2);
rotate(this.rotation);
// Player body
fill(255, 100, 150);
stroke(255, 255, 255);
strokeWeight(2);
rect(-CONFIG.PLAYER_SIZE/2, -CONFIG.PLAYER_SIZE/2, CONFIG.PLAYER_SIZE, CONFIG.PLAYER_SIZE, 8);
// Eyes
fill(0);
ellipse(-8, -8, 4, 4);
ellipse(8, -8, 4, 4);
pop();
}
checkCollision(obstacle) {
if (obstacle.type === 'spike') {
return (this.x < obstacle.x + obstacle.width &&
this.x + CONFIG.PLAYER_SIZE > obstacle.x &&
this.y < obstacle.y + obstacle.height &&
this.y + CONFIG.PLAYER_SIZE > obstacle.y);
} else if (obstacle.type === 'gap') {
return (this.x < obstacle.x + obstacle.width &&
this.x + CONFIG.PLAYER_SIZE > obstacle.x &&
this.y + CONFIG.PLAYER_SIZE > CONFIG.GROUND_Y);
}
return false;
}
}
// Obstacle class
class Obstacle {
constructor(x, type, height = 40, width = 40) {
this.x = x;
this.type = type;
this.height = height;
this.width = width;
this.y = type === 'spike' ? CONFIG.GROUND_Y - height : CONFIG.GROUND_Y;
}
display() {
push();
if (this.type === 'spike') {
fill(255, 80, 80);
stroke(255, 255, 255);
strokeWeight(2);
triangle(this.x, CONFIG.GROUND_Y,
this.x + this.width/2, this.y,
this.x + this.width, CONFIG.GROUND_Y);
} else if (this.type === 'gap') {
fill(255, 80, 80);
rect(this.x, CONFIG.GROUND_Y, this.width, 10);
}
pop();
}
}
// Game state management
let gameState = 'start';
let player, obstacles, cameraX = 0;
let attempts = 0;
let startTime = 0;
let currentTime = 0;
let progress = 0;
function setup() {
let canvas = createCanvas(1200, 600);
canvas.parent('gameContainer');
// Initialize game objects
player = new Player();
// Create obstacles
obstacles = [];
for (let obs of LEVEL.obstacles) {
obstacles.push(new Obstacle(obs.x, obs.type, obs.height, obs.width));
}
textAlign(CENTER, CENTER);
frameRate(60);
}
function draw() {
// Clear background
background(100, 150, 200);
switch (gameState) {
case 'start':
drawStartScreen();
break;
case 'playing':
updateGame();
displayGame();
break;
case 'dead':
drawDeathScreen();
break;
case 'completed':
drawCompletionScreen();
break;
}
// Update UI
updateUI();
}
function updateGame() {
// Move player forward automatically
player.x += CONFIG.GAME_SPEED;
// Update camera to follow player
cameraX = player.x - CONFIG.CAMERA_OFFSET;
// Update player physics
player.update();
// Check collisions
for (let obstacle of obstacles) {
if (player.checkCollision(obstacle)) {
gameOver();
return;
}
}
// Check level completion
if (player.x >= CONFIG.LEVEL_LENGTH) {
gameCompleted();
return;
}
}
function displayGame() {
push();
translate(-cameraX, 0);
// Draw ground
fill(100, 200, 100);
rect(0, CONFIG.GROUND_Y, CONFIG.LEVEL_LENGTH + width, height - CONFIG.GROUND_Y);
// Draw obstacles
for (let obstacle of obstacles) {
obstacle.display();
}
// Draw player
player.display();
// Draw finish line
fill(255, 255, 0);
rect(CONFIG.LEVEL_LENGTH, 0, 10, CONFIG.GROUND_Y);
pop();
}
function drawStartScreen() {
push();
fill(255);
textSize(48);
text("GEOMETRY DASH", width/2, height/2 - 50);
fill(200);
textSize(24);
text("Press SPACE or CLICK to start", width/2, height/2);
text("Avoid the obstacles and reach the end!", width/2, height/2 + 30);
pop();
}
function drawDeathScreen() {
push();
fill(0, 0, 0, 150);
rect(0, 0, width, height);
fill(255, 80, 80);
textSize(64);
text("GAME OVER", width/2, height/2 - 50);
fill(255);
textSize(24);
text(`Time: ${currentTime.toFixed(1)}s`, width/2, height/2);
text(`Progress: ${progress}%`, width/2, height/2 + 30);
text("Press SPACE or CLICK to restart", width/2, height/2 + 60);
pop();
}
function drawCompletionScreen() {
push();
fill(0, 100, 0, 100);
rect(0, 0, width, height);
fill(100, 255, 100);
textSize(48);
text("LEVEL COMPLETE!", width/2, height/2 - 30);
fill(255);
textSize(24);
text(`Final Time: ${currentTime.toFixed(1)}s`, width/2, height/2);
text("Press SPACE or CLICK to play again", width/2, height/2 + 30);
pop();
}
function updateUI() {
if (gameState === 'playing') {
currentTime = (millis() - startTime) / 1000;
progress = floor((player.x / CONFIG.LEVEL_LENGTH) * 100);
// Update DOM elements
document.getElementById('attempts').textContent = attempts;
document.getElementById('time').textContent = currentTime.toFixed(1);
document.getElementById('progress').textContent = progress;
}
}
function gameOver() {
gameState = 'dead';
}
function gameCompleted() {
gameState = 'completed';
}
function startGame() {
gameState = 'playing';
attempts++;
startTime = millis();
cameraX = 0;
// Reset player position
player.x = 100;
player.y = CONFIG.GROUND_Y - CONFIG.PLAYER_SIZE;
player.velocityY = 0;
player.isGrounded = true;
player.rotation = 0;
}
function keyPressed() {
if (key === ' ') {
if (gameState === 'playing') {
player.jump();
} else {
startGame();
}
return false; // Prevent default space behavior
}
}
function mousePressed() {
if (gameState === 'playing') {
player.jump();
} else {
startGame();
}
return false; // Prevent default mouse behavior
}
// Geometry Dash Ultra - Enhanced Version
let player;
let obstacles = [];
let particles = [];
let backgroundParticles = [];
let gameState = 'start'; // 'start', 'playing', 'dead', 'completed'
let attempts = 0;
let startTime = 0;
let currentTime = 0;
let cameraX = 0;
let levelProgress = 0;
let screenShake = 0;
let bgHue = 0;
// Game settings
const GRAVITY = 0.8;
const JUMP_FORCE = -15;
const PLAYER_SIZE = 30;
const GROUND_Y = 500;
const GAME_SPEED = 6;
// Level design - obstacles placed at specific positions
const LEVEL_LENGTH = 8000;
const OBSTACLE_PATTERN = [
{ x: 400, type: 'spike', height: 40 },
{ x: 600, type: 'spike', height: 60 },
{ x: 800, type: 'gap', width: 100 },
{ x: 1100, type: 'spike', height: 50 },
{ x: 1300, type: 'spike', height: 70 },
{ x: 1500, type: 'spike', height: 40 },
{ x: 1700, type: 'gap', width: 120 },
{ x: 2000, type: 'spike', height: 80 },
{ x: 2200, type: 'spike', height: 60 },
{ x: 2400, type: 'spike', height: 50 },
{ x: 2600, type: 'spike', height: 70 },
{ x: 2800, type: 'gap', width: 150 },
{ x: 3200, type: 'spike', height: 90 },
{ x: 3400, type: 'spike', height: 60 },
{ x: 3600, type: 'spike', height: 80 },
{ x: 3800, type: 'gap', width: 180 },
{ x: 4200, type: 'spike', height: 100 },
{ x: 4400, type: 'spike', height: 70 },
{ x: 4600, type: 'spike', height: 90 },
{ x: 4800, type: 'spike', height: 60 },
{ x: 5000, type: 'gap', width: 200 },
{ x: 5400, type: 'spike', height: 110 },
{ x: 5600, type: 'spike', height: 80 },
{ x: 5800, type: 'spike', height: 100 },
{ x: 6000, type: 'spike', height: 70 },
{ x: 6200, type: 'gap', width: 220 },
{ x: 6600, type: 'spike', height: 120 },
{ x: 6800, type: 'spike', height: 90 },
{ x: 7000, type: 'spike', height: 110 },
{ x: 7200, type: 'spike', height: 80 },
{ x: 7400, type: 'spike', height: 100 },
{ x: 7600, type: 'spike', height: 90 },
{ x: 7800, type: 'spike', height: 120 }
];
class Player {
constructor() {
this.x = 100;
this.y = GROUND_Y - PLAYER_SIZE;
this.velocityY = 0;
this.isGrounded = true;
this.trail = [];
this.glow = 0;
}
update() {
this.velocityY += GRAVITY;
this.y += this.velocityY;
if (this.y >= GROUND_Y - PLAYER_SIZE) {
this.y = GROUND_Y - PLAYER_SIZE;
this.velocityY = 0;
this.isGrounded = true;
} else {
this.isGrounded = false;
}
// Add trail effect
this.trail.push({ x: this.x, y: this.y, alpha: 255 });
if (this.trail.length > 10) {
this.trail.shift();
}
// Update trail alpha
for (let i = 0; i < this.trail.length; i++) {
this.trail[i].alpha -= 25;
}
this.glow += 0.1;
}
jump() {
if (this.isGrounded) {
this.velocityY = JUMP_FORCE;
this.isGrounded = false;
// Jump particles
for (let i = 0; i < 8; i++) {
particles.push(new Particle(this.x, this.y + PLAYER_SIZE,
random(-3, 3), random(-8, -2), color(255, 200, 100)));
}
}
}
display() {
push();
// Draw trail
for (let i = 0; i < this.trail.length; i++) {
let t = this.trail[i];
let alpha = t.alpha;
fill(255, 100, 150, alpha);
noStroke();
ellipse(t.x, t.y + PLAYER_SIZE/2, PLAYER_SIZE * 0.8, PLAYER_SIZE * 0.8);
}
// Draw glow
for (let i = 3; i > 0; i--) {
fill(255, 100, 150, 30);
noStroke();
ellipse(this.x + PLAYER_SIZE/2, this.y + PLAYER_SIZE/2,
PLAYER_SIZE + i * 10, PLAYER_SIZE + i * 10);
}
// Draw player
fill(255, 100, 150);
stroke(255, 255, 255);
strokeWeight(2);
rect(this.x, this.y, PLAYER_SIZE, PLAYER_SIZE, 8);
// Inner detail
fill(255, 255, 255, 100);
noStroke();
rect(this.x + 5, this.y + 5, PLAYER_SIZE - 10, PLAYER_SIZE - 10, 4);
pop();
}
checkCollision(obstacle) {
if (obstacle.type === 'spike') {
return (this.x < obstacle.x + obstacle.width &&
this.x + PLAYER_SIZE > obstacle.x &&
this.y + PLAYER_SIZE > obstacle.y);
} else if (obstacle.type === 'gap') {
return (this.x < obstacle.x + obstacle.width &&
this.x + PLAYER_SIZE > obstacle.x &&
this.y + PLAYER_SIZE > GROUND_Y);
}
return false;
}
}
class Obstacle {
constructor(x, type, height = 40, width = 40) {
this.x = x;
this.type = type;
this.height = height;
this.width = width;
this.y = type === 'spike' ? GROUND_Y - height : GROUND_Y;
this.pulse = 0;
}
update() {
this.pulse += 0.1;
}
display() {
push();
if (this.type === 'spike') {
// Draw spike with gradient
let spikeColor = color(255, 80, 80);
let spikeHighlight = color(255, 150, 150);
// Glow effect
for (let i = 3; i > 0; i--) {
fill(255, 80, 80, 20);
noStroke();
triangle(this.x - 5, GROUND_Y,
this.x + this.width/2, this.y - 10 - sin(this.pulse) * 3,
this.x + this.width + 5, GROUND_Y);
}
// Main spike
fill(spikeColor);
stroke(255, 255, 255);
strokeWeight(2);
triangle(this.x, GROUND_Y,
this.x + this.width/2, this.y - sin(this.pulse) * 3,
this.x + this.width, GROUND_Y);
// Highlight
fill(spikeHighlight);
noStroke();
triangle(this.x + 5, GROUND_Y - 5,
this.x + this.width/2, this.y - sin(this.pulse) * 3 + 5,
this.x + this.width - 5, GROUND_Y - 5);
} else if (this.type === 'gap') {
// Draw gap indicator
stroke(255, 80, 80);
strokeWeight(3);
line(this.x, GROUND_Y, this.x, GROUND_Y + 20);
line(this.x + this.width, GROUND_Y, this.x + this.width, GROUND_Y + 20);
// Warning stripes
for (let i = 0; i < this.width; i += 20) {
fill(255, 80, 80, 100);
noStroke();
rect(this.x + i, GROUND_Y, 10, 5);
}
}
pop();
}
}
class Particle {
constructor(x, y, vx, vy, col) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.col = col;
this.life = 255;
this.size = random(3, 8);
}
update() {
this.x += this.vx;
this.y += this.vy;
this.vy += 0.2;
this.life -= 5;
this.size *= 0.98;
}
display() {
push();
fill(red(this.col), green(this.col), blue(this.col), this.life);
noStroke();
ellipse(this.x, this.y, this.size);
pop();
}
isDead() {
return this.life <= 0 || this.size <= 0.5;
}
}
class BackgroundParticle {
constructor() {
this.x = random(width);
this.y = random(height);
this.size = random(1, 3);
this.speed = random(0.5, 2);
this.opacity = random(50, 150);
}
update() {
this.x -= this.speed;
if (this.x < -10) {
this.x = width + 10;
this.y = random(height);
}
}
display() {
push();
fill(255, 255, 255, this.opacity);
noStroke();
ellipse(this.x, this.y, this.size);
pop();
}
}
function setup() {
let canvas = createCanvas(1200, 600);
canvas.parent('gameContainer');
player = new Player();
// Create obstacles
obstacles = [];
for (let obs of OBSTACLE_PATTERN) {
obstacles.push(new Obstacle(obs.x, obs.type, obs.height, obs.width));
}
// Create background particles
for (let i = 0; i < 50; i++) {
backgroundParticles.push(new BackgroundParticle());
}
textAlign(CENTER, CENTER);
frameRate(60);
}
function draw() {
// Dynamic background
bgHue = (bgHue + 0.2) % 360;
colorMode(HSB);
background(bgHue, 30, 95);
colorMode(RGB);
// Apply screen shake
if (screenShake > 0) {
translate(random(-screenShake, screenShake), random(-screenShake, screenShake));
screenShake *= 0.9;
}
// Update and display background particles
for (let particle of backgroundParticles) {
particle.update();
particle.display();
}
if (gameState === 'start') {
drawStartScreen();
return;
}
if (gameState === 'dead') {
drawDeathScreen();
return;
}
if (gameState === 'completed') {
drawCompletionScreen();
return;
}
if (gameState === 'playing') {
updateGame();
displayGame();
}
}
function updateGame() {
// Move player forward
player.x += GAME_SPEED;
// Update camera
cameraX = player.x - 100;
// Update player
player.update();
// Update obstacles
for (let obstacle of obstacles) {
obstacle.update();
}
// Update particles
for (let i = particles.length - 1; i >= 0; i--) {
particles[i].update();
if (particles[i].isDead()) {
particles.splice(i, 1);
}
}
// Check collisions
for (let obstacle of obstacles) {
if (player.checkCollision(obstacle)) {
gameOver();
return;
}
}
// Check level completion
if (player.x >= LEVEL_LENGTH) {
gameCompleted();
return;
}
// Update time and progress
currentTime = (millis() - startTime) / 1000;
levelProgress = floor((player.x / LEVEL_LENGTH) * 100);
// Update UI
document.getElementById('attempts').textContent = attempts;
document.getElementById('time').textContent = currentTime.toFixed(1);
document.getElementById('progress').textContent = levelProgress;
}
function displayGame() {
push();
translate(-cameraX, 0);
// Draw ground with gradient
for (let i = 0; i < LEVEL_LENGTH + width; i += 20) {
let groundColor = lerpColor(color(150, 200, 255), color(200, 150, 255),
sin(i * 0.01 + frameCount * 0.02) * 0.5 + 0.5);
fill(groundColor);
noStroke();
rect(i, GROUND_Y, 20, height - GROUND_Y);
}
// Draw grid pattern on ground
stroke(255, 255, 255, 50);
strokeWeight(1);
for (let i = 0; i < LEVEL_LENGTH + width; i += 40) {
line(i, GROUND_Y, i, height);
}
// Draw obstacles
for (let obstacle of obstacles) {
obstacle.display();
}
// Draw player
player.display();
// Draw particles
for (let particle of particles) {
particle.display();
}
// Draw finish line
fill(100, 255, 100);
stroke(255, 255, 255);
strokeWeight(3);
rect(LEVEL_LENGTH, 0, 10, GROUND_Y);
// Finish flag
fill(255, 255, 100);
triangle(LEVEL_LENGTH + 20, 50, LEVEL_LENGTH + 20, 100, LEVEL_LENGTH + 60, 75);
pop();
}
function drawStartScreen() {
push();
fill(255, 255, 255, 200);
textSize(48);
textAlign(CENTER, CENTER);
text("GEOMETRY DASH ULTRA", width/2, height/2 - 50);
textSize(24);
fill(255, 255, 255, 150);
text("Press SPACE or CLICK to start", width/2, height/2 + 20);
text("Avoid the spikes and gaps!", width/2, height/2 + 50);
pop();
}
function drawDeathScreen() {
push();
fill(255, 80, 80, 200);
textSize(64);
textAlign(CENTER, CENTER);
text("GAME OVER", width/2, height/2 - 50);
textSize(24);
fill(255, 255, 255, 150);
text(`Time survived: ${currentTime.toFixed(1)}s`, width/2, height/2);
text(`Progress: ${levelProgress}%`, width/2, height/2 + 30);
text("Press SPACE or CLICK to restart", width/2, height/2 + 60);
pop();
}
function drawCompletionScreen() {
push();
fill(100, 255, 100, 200);
textSize(64);
textAlign(CENTER, CENTER);
text("LEVEL COMPLETE!", width/2, height/2 - 50);
textSize(24);
fill(255, 255, 255, 150);
text(`Final time: ${currentTime.toFixed(1)}s`, width/2, height/2);
text(`Attempts: ${attempts}`, width/2, height/2 + 30);
text("Press SPACE or CLICK to play again", width/2, height/2 + 60);
pop();
// Celebration particles
if (frameCount % 5 === 0) {
for (let i = 0; i < 5; i++) {
particles.push(new Particle(random(width), random(height),
random(-5, 5), random(-10, -5),
color(random(100, 255), random(100, 255), random(100, 255))));
}
}
}
function gameOver() {
gameState = 'dead';
screenShake = 20;
// Death particles
for (let i = 0; i < 20; i++) {
particles.push(new Particle(player.x - cameraX, player.y,
random(-8, 8), random(-8, 8), color(255, 80, 80)));
}
}
function gameCompleted() {
gameState = 'completed';
}
function startGame() {
gameState = 'playing';
attempts++;
startTime = millis();
currentTime = 0;
cameraX = 0;
levelProgress = 0;
// Reset player
player = new Player();
// Reset obstacles
obstacles = [];
for (let obs of OBSTACLE_PATTERN) {
obstacles.push(new Obstacle(obs.x, obs.type, obs.height, obs.width));
}
// Clear particles
particles = [];
}
function keyPressed() {
if (key === ' ') {
if (gameState === 'playing') {
player.jump();
} else {
startGame();
}
}
}
function mousePressed() {
if (gameState === 'playing') {
player.jump();
} else {
startGame();
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Geometry Dash Ultra</title>
<style>
body {
margin: 0;
padding: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: 'Arial', sans-serif;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
#gameContainer {
position: relative;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
overflow: hidden;
}
#ui {
position: absolute;
top: 20px;
left: 20px;
color: white;
font-size: 18px;
font-weight: bold;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
z-index: 100;
}
#instructions {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
color: white;
font-size: 14px;
text-align: center;
opacity: 0.8;
}
.particle {
position: absolute;
pointer-events: none;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="gameContainer">
<div id="ui">
<div>Attempts: <span id="attempts">0</span></div>
<div>Time: <span id="time">0.0</span>s</div>
<div>Progress: <span id="progress">0</span>%</div>
</div>
<div id="instructions">
Press SPACE or CLICK to jump • Avoid obstacles • Reach the end!
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
<script src="particles.js"></script>
<script src="audio.js"></script>
<script src="enhanced-game.js"></script>
</body>
</html>
// Particle System for Epic Visual Effects
class ParticleSystem {
constructor() {
this.particles = [];
this.trails = [];
}
addParticle(x, y, type = 'jump') {
const colors = {
jump: ['#FF6B9D', '#C44569', '#F8B500'],
death: ['#FF4757', '#FF3838', '#FF9500'],
collect: ['#00D9FF', '#0099CC', '#48CAE4'],
trail: ['#A8E6CF', '#7FCDCD', '#5DADE2']
};
const color = colors[type][Math.floor(Math.random() * colors[type].length)];
for (let i = 0; i < (type === 'death' ? 15 : 5); i++) {
this.particles.push({
x: x + random(-10, 10),
y: y + random(-10, 10),
vx: random(-8, 8),
vy: random(-12, -2),
size: random(3, 8),
color: color,
life: 1.0,
decay: random(0.02, 0.05),
type: type
});
}
}
addTrail(x, y) {
this.trails.push({
x: x,
y: y,
size: random(8, 12),
alpha: 0.6,
decay: 0.08
});
}
update() {
// Update particles
for (let i = this.particles.length - 1; i >= 0; i--) {
const p = this.particles[i];
p.x += p.vx;
p.y += p.vy;
p.vy += 0.3; // gravity
p.life -= p.decay;
p.size *= 0.98;
if (p.life <= 0 || p.size < 0.5) {
this.particles.splice(i, 1);
}
}
// Update trails
for (let i = this.trails.length - 1; i >= 0; i--) {
const t = this.trails[i];
t.alpha -= t.decay;
t.size *= 0.95;
if (t.alpha <= 0) {
this.trails.splice(i, 1);
}
}
}
render() {
// Render trails
for (const trail of this.trails) {
push();
noStroke();
fill(168, 230, 207, trail.alpha * 255);
ellipse(trail.x, trail.y, trail.size);
pop();
}
// Render particles
for (const p of this.particles) {
push();
noStroke();
const c = color(p.color);
c.setAlpha(p.life * 255);
fill(c);
if (p.type === 'death') {
star(p.x, p.y, p.size, p.size * 0.5, 5);
} else {
ellipse(p.x, p.y, p.size);
}
pop();
}
}
}
function star(x, y, radius1, radius2, npoints) {
let angle = TWO_PI / npoints;
let halfAngle = angle / 2.0;
beginShape();
for (let a = 0; a < TWO_PI; a += angle) {
let sx = x + cos(a) * radius2;
let sy = y + sin(a) * radius2;
vertex(sx, sy);
sx = x + cos(a + halfAngle) * radius1;
sy = y + sin(a + halfAngle) * radius1;
vertex(sx, sy);
}
endShape(CLOSE);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.game-container {
position: relative;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
canvas {
display: block;
border-radius: 20px;
}
.ui-overlay {
position: absolute;
top: 20px;
left: 20px;
right: 20px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
pointer-events: none;
}
.attempts-counter, .time-counter {
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
padding: 10px 20px;
border-radius: 25px;
color: white;
font-weight: bold;
font-size: 16px;
border: 1px solid rgba(255, 255, 255, 0.3);
}
.start-screen, .death-screen, .completion-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(10px);
color: white;
z-index: 20;
}
.start-screen h1, .death-screen h1, .completion-screen h1 {
font-size: 48px;
margin-bottom: 20px;
text-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
}
.start-screen p, .death-screen p, .completion-screen p {
font-size: 20px;
margin-bottom: 30px;
opacity: 0.8;
}
.start-button, .restart-button, .continue-button {
background: linear-gradient(135deg, #667eea, #764ba2);
border: none;
padding: 15px 40px;
font-size: 18px;
color: white;
border-radius: 30px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.start-button:hover, .restart-button:hover, .continue-button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
}
.hidden {
display: none !important;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
.shake {
animation: shake 0.3s ease-in-out;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment