commit 694cc903c8c2b221faf8fcf77e7c89f44d61436e Author: Eric Ratliff Date: Wed Jun 25 22:14:38 2025 -0500 Really cool game diff --git a/asteroid.js b/asteroid.js new file mode 100644 index 0000000..33d06de --- /dev/null +++ b/asteroid.js @@ -0,0 +1,68 @@ +class Asteroid { + constructor(pos, r, isGolden = random() < 0.1) { + if (pos) { + this.pos = pos.copy(); + this.r = r ? r / 2 : random(30, 50); + } else { + this.pos = createVector(random(width), random(height)); + this.r = random(30, 50); + while (dist(this.pos.x, this.pos.y, ship.pos.x, ship.pos.y) < 100) { + this.pos = createVector(random(width), random(height)); + } + } + this.vel = p5.Vector.random2D(); + this.vel.mult(random(1, 3)); + this.total = floor(random(5, 15)); + this.offset = []; + for (let i = 0; i < this.total; i++) { + this.offset[i] = random(-this.r * 0.5, this.r * 0.5); + } + this.isGolden = isGolden; + this.hitsLeft = isGolden ? 3 : 1; + } + + update() { + this.pos.add(this.vel); + } + + edges() { + if (this.pos.x > width + this.r) this.pos.x = -this.r; + else if (this.pos.x < -this.r) this.pos.x = width + this.r; + if (this.pos.y > height + this.r) this.pos.y = -this.r; + else if (this.pos.y < -this.r) this.pos.y = height + this.r; + } + + hits(bullet) { + let d = dist(this.pos.x, this.pos.y, bullet.pos.x, bullet.pos.y); + return d < this.r; + } + + breakup() { + let newA = []; + this.hitsLeft--; + if (this.hitsLeft > 0) { + newA.push(this); + } else if (this.r > 20) { + newA.push(new Asteroid(this.pos, this.r, this.isGolden)); + newA.push(new Asteroid(this.pos, this.r, this.isGolden)); + } + return newA; + } + + show() { + push(); + translate(this.pos.x, this.pos.y); + noFill(); + stroke(this.isGolden ? color(255, 215, 0) : 255); // Golden or white + beginShape(); + for (let i = 0; i < this.total; i++) { + let angle = map(i, 0, this.total, 0, TWO_PI); + let r = this.r + this.offset[i]; + let x = r * cos(angle); + let y = r * sin(angle); + vertex(x, y); + } + endShape(CLOSE); + pop(); + } +} \ No newline at end of file diff --git a/bullet.js b/bullet.js new file mode 100644 index 0000000..bb0cad3 --- /dev/null +++ b/bullet.js @@ -0,0 +1,24 @@ +class Bullet { + constructor(pos, angle) { + this.pos = pos.copy(); + this.vel = p5.Vector.fromAngle(angle); + this.vel.mult(10); + this.r = 4; + } + + update() { + this.pos.add(this.vel); + } + + show() { + push(); + fill(255); + noStroke(); + ellipse(this.pos.x, this.pos.y, this.r * 2); + pop(); + } + + offscreen() { + return (this.pos.x < 0 || this.pos.x > width || this.pos.y < 0 || this.pos.y > height); + } +} \ No newline at end of file diff --git a/greenOrb.js b/greenOrb.js new file mode 100644 index 0000000..bbf41ef --- /dev/null +++ b/greenOrb.js @@ -0,0 +1,30 @@ +class GreenOrb { + constructor() { + this.pos = createVector(random(width), random(height)); + this.r = 10; + this.vel = p5.Vector.random2D(); + this.vel.mult(random(1, 2)); + while (dist(this.pos.x, this.pos.y, ship.pos.x, ship.pos.y) < 100) { + this.pos = createVector(random(width), random(height)); + } + } + + update() { + this.pos.add(this.vel); + } + + edges() { + if (this.pos.x > width + this.r) this.pos.x = -this.r; + else if (this.pos.x < -this.r) this.pos.x = width + this.r; + if (this.pos.y > height + this.r) this.pos.y = -this.r; + else if (this.pos.y < -this.r) this.pos.y = height + this.r; + } + + show() { + push(); + fill(0, 255, 0); // Green + noStroke(); + ellipse(this.pos.x, this.pos.y, this.r * 2); + pop(); + } +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..e367bcf --- /dev/null +++ b/index.html @@ -0,0 +1,15 @@ + + + + Asteroids Game + + + + + + + + + + + \ No newline at end of file diff --git a/shieldOrb.js b/shieldOrb.js new file mode 100644 index 0000000..24bf97e --- /dev/null +++ b/shieldOrb.js @@ -0,0 +1,30 @@ +class ShieldOrb { + constructor() { + this.pos = createVector(random(width), random(height)); + this.r = 10; + this.vel = p5.Vector.random2D(); + this.vel.mult(random(1, 2)); + while (dist(this.pos.x, this.pos.y, ship.pos.x, ship.pos.y) < 100) { + this.pos = createVector(random(width), random(height)); + } + } + + update() { + this.pos.add(this.vel); + } + + edges() { + if (this.pos.x > width + this.r) this.pos.x = -this.r; + else if (this.pos.x < -this.r) this.pos.x = width + this.r; + if (this.pos.y > height + this.r) this.pos.y = -this.r; + else if (this.pos.y < -this.r) this.pos.y = height + this.r; + } + + show() { + push(); + fill(0, 255, 255); // Cyan + noStroke(); + ellipse(this.pos.x, this.pos.y, this.r * 2); + pop(); + } +} \ No newline at end of file diff --git a/ship.js b/ship.js new file mode 100644 index 0000000..45b115d --- /dev/null +++ b/ship.js @@ -0,0 +1,91 @@ +class Ship { + constructor() { + this.pos = createVector(width / 2, height / 2); + this.r = 20; + this.heading = 0; + this.rotation = 0; + this.vel = createVector(0, 0); + this.isBoosting = false; + this.shieldActive = false; + this.shieldEndTime = 0; + this.quadShotActive = false; + this.quadShotEndTime = 0; + } + + update() { + if (this.isBoosting) { + this.boost(); + } + this.pos.add(this.vel); + this.vel.mult(0.99); // Friction + this.heading += this.rotation; + if (this.shieldActive && millis() > this.shieldEndTime) { + this.shieldActive = false; + } + if (this.quadShotActive && millis() > this.quadShotEndTime) { + this.quadShotActive = false; + } + } + + boost() { + let force = p5.Vector.fromAngle(this.heading); + force.mult(0.1); + this.vel.add(force); + } + + hits(obj) { + let d = dist(this.pos.x, this.pos.y, obj.pos.x, obj.pos.y); + return d < this.r + obj.r; + } + + edges() { + if (this.pos.x > width + this.r) this.pos.x = -this.r; + else if (this.pos.x < -this.r) this.pos.x = width + this.r; + if (this.pos.y > height + this.r) this.pos.y = -this.r; + else if (this.pos.y < -this.r) this.pos.y = height + this.r; + } + + setRotation(a) { + this.rotation = a; + } + + boosting(b) { + this.isBoosting = b; + } + + activateShield() { + this.shieldActive = true; + this.shieldEndTime = millis() + 10000; // 10 seconds + } + + activateQuadShot() { + this.quadShotActive = true; + this.quadShotEndTime = millis() + 10000; // 10 seconds + } + + show() { + push(); + translate(this.pos.x, this.pos.y); + rotate(this.heading + PI / 2); + if (this.shieldActive) { + // Pulsing shield effect in last 2 seconds + let timeLeft = (this.shieldEndTime - millis()) / 1000; + let scaleFactor = this.shieldActive && timeLeft < 2 ? 1 + 0.1 * sin(millis() / 100) : 1; + scale(scaleFactor); + noFill(); + stroke(0, 255, 255); // Cyan shield + ellipse(0, 0, this.r * 2.5); + } + // Ship fill: green if quad-shot active, else black + if (this.quadShotActive) { + let timeLeft = (this.quadShotEndTime - millis()) / 1000; + let alpha = this.quadShotActive && timeLeft < 2 ? map(sin(millis() / 100), -1, 1, 100, 255) : 255; + fill(0, 255, 0, alpha); + } else { + fill(0); + } + stroke(255); + triangle(-this.r, this.r, this.r, this.r, 0, -this.r); + pop(); + } +} \ No newline at end of file diff --git a/sketch.js b/sketch.js new file mode 100644 index 0000000..8128389 --- /dev/null +++ b/sketch.js @@ -0,0 +1,167 @@ +let ship; +let asteroids = []; +let bullets = []; +let shieldOrb = null; +let greenOrb = null; +let lives = 3; +let score = 0; +let gameOver = false; +let lastShieldSpawn = 0; +let lastGreenSpawn = 0; + +function setup() { + createCanvas(800, 600); + ship = new Ship(); + for (let i = 0; i < 5; i++) { + asteroids.push(new Asteroid()); + } +} + +function draw() { + background(0); + + if (gameOver) { + textSize(32); + fill(255); + textAlign(CENTER); + text("Game Over! Score: " + score, width / 2, height / 2); + text("Press R to Restart", width / 2, height / 2 + 40); + return; + } + + // Display lives and score + textSize(20); + fill(255); + text("Lives: " + lives, 50, 30); + text("Score: " + score, 50, 60); + + // Handle continuous key input (WASD) + if (keyIsDown(65)) { // A key + ship.setRotation(-0.1); + } + if (keyIsDown(68)) { // D key + ship.setRotation(0.1); + } + if (keyIsDown(87)) { // W key + ship.boosting(true); + } else { + ship.boosting(false); + } + + // Update and show ship + ship.update(); + ship.show(); + ship.edges(); + + // Spawn shield orb periodically + if (millis() - lastShieldSpawn > 15000 && !shieldOrb) { + shieldOrb = new ShieldOrb(); + lastShieldSpawn = millis(); + } + + // Spawn green orb periodically + if (millis() - lastGreenSpawn > 20000 && !greenOrb) { + greenOrb = new GreenOrb(); + lastGreenSpawn = millis(); + } + + // Update and show shield orb + if (shieldOrb) { + shieldOrb.update(); + shieldOrb.show(); + shieldOrb.edges(); + if (ship.hits(shieldOrb)) { + ship.activateShield(); + shieldOrb = null; + } + } + + // Update and show green orb + if (greenOrb) { + greenOrb.update(); + greenOrb.show(); + greenOrb.edges(); + if (ship.hits(greenOrb)) { + ship.activateQuadShot(); + greenOrb = null; + } + } + + // Update and show bullets + for (let i = bullets.length - 1; i >= 0; i--) { + bullets[i].update(); + bullets[i].show(); + if (bullets[i].offscreen()) { + bullets.splice(i, 1); + } + } + + // Update and show asteroids + for (let i = asteroids.length - 1; i >= 0; i--) { + if (!asteroids[i]) continue; // Skip if asteroid is undefined + asteroids[i].update(); + asteroids[i].show(); + asteroids[i].edges(); + + // Check collision with ship + if (ship.hits(asteroids[i]) && !ship.shieldActive) { + lives--; + if (lives <= 0) { + gameOver = true; + } else { + ship = new Ship(); // Reset ship position + } + } + + // Check collision with bullets + for (let j = bullets.length - 1; j >= 0; j--) { + if (asteroids[i] && asteroids[i].hits(bullets[j])) { + let isGolden = asteroids[i].isGolden; // Store before removal + let newAsteroids = asteroids[i].breakup(); + asteroids.splice(i, 1); + bullets.splice(j, 1); + asteroids.push(...newAsteroids); + score += isGolden ? 20 : 10; // Use stored isGolden value + break; // Exit bullet loop after collision + } + } + } +} + +function keyPressed() { + if (keyCode === 32) { // Spacebar to shoot + if (ship.quadShotActive) { + // Fire in four directions: forward, backward, left, right + bullets.push(new Bullet(ship.pos, ship.heading)); + bullets.push(new Bullet(ship.pos, ship.heading + PI)); + bullets.push(new Bullet(ship.pos, ship.heading - PI / 2)); + bullets.push(new Bullet(ship.pos, ship.heading + PI / 2)); + } else { + bullets.push(new Bullet(ship.pos, ship.heading)); + } + } + if (keyCode === 82 && gameOver) { // R to restart + lives = 3; + score = 0; + asteroids = []; + bullets = []; + shieldOrb = null; + greenOrb = null; + ship = new Ship(); + lastShieldSpawn = millis(); + lastGreenSpawn = millis(); + for (let i = 0; i < 5; i++) { + asteroids.push(new Asteroid()); + } + gameOver = false; + } +} + +function keyReleased() { + if (keyCode === 65 || keyCode === 68) { // A or D key + ship.setRotation(0); + } + if (keyCode === 87) { // W key + ship.boosting(false); + } +} \ No newline at end of file