Created
March 20, 2023 12:30
-
-
Save franciscohanna92/3b9cca25569b125f06daf6fbc5f9e67c to your computer and use it in GitHub Desktop.
p5.js tanks game
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let tank; | |
let bullet; | |
let obstacles = []; | |
let tankImg, bulletImg; | |
let aiTanks = []; | |
// Add constants for the play area size | |
const PLAY_AREA_WIDTH = 1000; | |
const PLAY_AREA_HEIGHT = 1000; | |
function preload() { | |
tankImg = loadImage('https://m.media-amazon.com/images/I/11s0jsOXhpL.png'); | |
bulletImg = loadImage('https://i.imgur.com/1mwOzLg.png'); | |
} | |
function setup() { | |
createCanvas(windowWidth, windowHeight); | |
tank = new Tank(); | |
placeObstacles() | |
placeAiTanks() | |
} | |
function draw() { | |
background(220); | |
// Create a camera effect by translating the drawing context based on the tank's position | |
push(); | |
translate(-tank.x + width / 2, -tank.y + height / 2); | |
tank.move(); | |
tank.display(); | |
tank.bullet.display(); | |
tank.bullet.move(); | |
for (let obstacle of obstacles) { | |
obstacle.display(); | |
} | |
// Update and display AI tanks | |
for (let aiTank of aiTanks) { | |
aiTank.move(); | |
aiTank.display(); | |
aiTank.bullet.display(); | |
aiTank.bullet.move(); | |
// Check bullet collisions between tanks | |
tank.checkBulletCollision(aiTank.bullet) | |
aiTank.checkBulletCollision(tank.bullet) | |
// Randomly shoot | |
if (random() < 0.005) { | |
aiTank.shoot(); | |
} | |
} | |
// Draw the play area boundary | |
stroke(0); | |
noFill(); | |
rect(0, 0, PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT); | |
pop(); | |
} | |
function keyPressed() { | |
if (keyCode === 32) { // Spacebar | |
tank.shoot(); | |
} | |
} | |
class Tank { | |
constructor() { | |
this.x = width / 2; | |
this.y = height / 2; | |
this.rotation = 0; | |
this.velocity = createVector(0, 0); | |
this.acceleration = 0; | |
this.damping = 0.92; | |
this.health = 100; | |
this.bullet = new Bullet(); | |
} | |
move() { | |
if (keyIsDown(LEFT_ARROW)) { | |
this.rotation -= 0.05; | |
} | |
if (keyIsDown(RIGHT_ARROW)) { | |
this.rotation += 0.05; | |
} | |
if (keyIsDown(UP_ARROW)) { | |
this.acceleration = 0.2; | |
} else if (keyIsDown(DOWN_ARROW)) { | |
this.acceleration = -0.1; | |
} else { | |
this.acceleration = 0; | |
} | |
let force = createVector(this.acceleration * cos(this.rotation), this.acceleration * sin(this.rotation)); | |
this.velocity.add(force); | |
this.velocity.mult(this.damping); | |
let newX = this.x + this.velocity.x; | |
let newY = this.y + this.velocity.y; | |
// Check for collision with obstacles | |
let collided = false; | |
for (let obstacle of obstacles) { | |
if (obstacle.intersects(newX - 20, newY - 20, 40, 40)) { | |
collided = true; | |
break; | |
} | |
} | |
if (!collided && !this.checkCollisionWithTanks(newX, newY) && newX - 20 > 0 && newX + 20 < PLAY_AREA_WIDTH && newY - 20 > 0 && newY + 20 < PLAY_AREA_HEIGHT) { | |
this.x = newX; | |
this.y = newY; | |
} | |
} | |
intersects(x, y, w, h) { | |
let halfWidth = w / 2; | |
let halfHeight = h / 2; | |
let left = x - halfWidth; | |
let right = x + halfWidth; | |
let top = y - halfHeight; | |
let bottom = y + halfHeight; | |
let tankLeft = this.x - 20; | |
let tankRight = this.x + 20; | |
let tankTop = this.y - 20; | |
let tankBottom = this.y + 20; | |
return !(left > tankRight || right < tankLeft || top > tankBottom || bottom < tankTop); | |
} | |
checkCollisionWithTanks(newX, newY) { | |
// Check collision with the player's tank | |
if (this !== tank && tank.intersects(newX - 20, newY - 20, 40, 40)) { | |
return true; | |
} | |
// Check collision with AI tanks | |
for (let ai_tank of aiTanks) { | |
if (this !== ai_tank && ai_tank.intersects(newX - 20, newY - 20, 40, 40)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
shoot() { | |
if (!this.bullet.active) { | |
this.bullet.shoot(this.x, this.y, this.rotation, this); | |
} | |
} | |
checkBulletCollision(bullet) { | |
if (bullet.active && bullet.owner !== this && this.intersects(bullet.x, bullet.y, 5, 5)) { | |
bullet.active = false; | |
this.health -= 10; | |
if (this.health <= 0) { | |
// Handle tank destruction (e.g., remove the tank from the game, respawn, etc.) | |
} | |
return true; | |
} | |
return false; | |
} | |
display() { | |
if (this.health <= 0) { | |
return; // Don't draw the tank if its health is 0 or less | |
} | |
push() | |
translate(this.x, this.y); | |
rotate(this.rotation); | |
// Set tank color based on health | |
let healthColor = lerpColor(color(255, 0, 0), color(0, 255, 0), this.health / 100); | |
fill(healthColor); | |
// Draw the tank body | |
rectMode(CENTER); | |
rect(0, 0, 40, 40); | |
// Draw the tank turret | |
stroke(0); | |
strokeWeight(3); | |
line(20, 0, 0, 0); | |
pop(); | |
} | |
} | |
class Bullet { | |
constructor() { | |
this.x = 0; | |
this.y = 0; | |
this.rotation = 0; | |
this.speed = 10; | |
this.active = false; | |
this.owner = null | |
} | |
shoot(x, y, rotation, owner) { | |
this.x = x; | |
this.y = y; | |
this.rotation = rotation; | |
this.active = true; | |
this.owner = owner; | |
} | |
move() { | |
this.x += this.speed * cos(this.rotation); | |
this.y += this.speed * sin(this.rotation); | |
if (this.x < 0 || this.x > PLAY_AREA_WIDTH || this.y < 0 || this.y > PLAY_AREA_HEIGHT) { | |
this.active = false; | |
} | |
for (let obstacle of obstacles) { | |
if (obstacle.contains(this.x, this.y)) { | |
this.active = false; | |
} | |
} | |
} | |
display() { | |
if(this.active) { | |
push(); | |
translate(this.x, this.y); | |
rotate(this.rotation); | |
// Set bullet color | |
fill(0); | |
// Draw the bullet | |
ellipse(0, 0, 10, 10); | |
pop(); | |
} | |
} | |
} | |
class Obstacle { | |
constructor(x, y, w, h) { | |
this.x = x; | |
this.y = y; | |
this.w = w; | |
this.h = h; | |
} | |
display() { | |
fill(0); | |
rect(this.x, this.y, this.w, this.h); | |
} | |
contains(x, y) { | |
return x >= this.x && x <= this.x + this.w && y >= this.y && y <= this.y + this.h; | |
} | |
intersects(x, y, w, h) { | |
return !(x > this.x + this.w || x + w < this.x || y > this.y + this.h || y + h < this.y); | |
} | |
} | |
class AITank extends Tank { | |
constructor(x, y) { | |
super(); | |
this.x = x; | |
this.y = y; | |
this.ai_move_timer = 0; | |
this.targetRotation = this.rotation; | |
this.rotationSpeed = 0.05; | |
} | |
move() { | |
this.ai_move_timer--; | |
if (this.ai_move_timer <= 0) { | |
this.ai_move_timer = int(random(50, 200)); | |
this.targetRotation = random(0, TWO_PI); | |
} | |
// Smoothly update the tank's rotation towards the target rotation | |
let deltaRotation = this.targetRotation - this.rotation; | |
if (abs(deltaRotation) > this.rotationSpeed) { | |
let direction = deltaRotation > 0 ? 1 : -1; | |
if (abs(deltaRotation) > PI) { | |
direction *= -1.5; | |
} | |
this.rotation += direction * this.rotationSpeed; | |
} | |
let newX = this.x + 1.5 * cos(this.rotation); | |
let newY = this.y + 1.5 * sin(this.rotation); | |
// Check for collision with obstacles and play area boundaries | |
let collided = false; | |
for (let obstacle of obstacles) { | |
if (obstacle.intersects(newX - 20, newY - 20, 40, 40)) { | |
collided = true; | |
break; | |
} | |
} | |
if (!collided && newX - 20 > 0 && !this.checkCollisionWithTanks(newX, newY) && newX + 20 < PLAY_AREA_WIDTH && newY - 20 > 0 && newY + 20 < PLAY_AREA_HEIGHT) { | |
this.x = newX; | |
this.y = newY; | |
} | |
} | |
} | |
function placeObstacles() { | |
// Clear existing obstacles | |
obstacles = []; | |
// Place new obstacles | |
for (let i = 0; i < 20; i++) { | |
let x = random(PLAY_AREA_WIDTH); | |
let y = random(PLAY_AREA_HEIGHT); | |
obstacles.push(new Obstacle(x, y, 50, 50)); | |
} | |
} | |
function placeAiTanks() { | |
// Clear existing tanks | |
aiTanks = []; | |
// Create new tanks | |
for (let i = 0; i < 10; i++) { | |
aiTanks.push(new AITank(random(PLAY_AREA_WIDTH), random(PLAY_AREA_HEIGHT))); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment