Really cool game
This commit is contained in:
68
asteroid.js
Normal file
68
asteroid.js
Normal file
@@ -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();
|
||||
}
|
||||
}
|
24
bullet.js
Normal file
24
bullet.js
Normal file
@@ -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);
|
||||
}
|
||||
}
|
30
greenOrb.js
Normal file
30
greenOrb.js
Normal file
@@ -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();
|
||||
}
|
||||
}
|
15
index.html
Normal file
15
index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Asteroids Game</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
|
||||
<script src="ship.js"></script>
|
||||
<script src="asteroid.js"></script>
|
||||
<script src="bullet.js"></script>
|
||||
<script src="shieldOrb.js"></script>
|
||||
<script src="greenOrb.js"></script>
|
||||
<script src="sketch.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
30
shieldOrb.js
Normal file
30
shieldOrb.js
Normal file
@@ -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();
|
||||
}
|
||||
}
|
91
ship.js
Normal file
91
ship.js
Normal file
@@ -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();
|
||||
}
|
||||
}
|
167
sketch.js
Normal file
167
sketch.js
Normal file
@@ -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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user