I need help with collision detection in clone game

Hi, I’m new to the world of game development with Processing and I am struggling to get my code to work. I have a good portion of it working but I cannot figure out collision detection.

Here’s the main loop:

//Create 16 spaceship objects
Spaceships[] ships = new Spaceships[16];

//Create the player object
Player p;

Bullet aBullet;
 //float spacing = 75;
 
 float x = random(50, width);
 float y = 100;
 float spacing = 75;
 int n;
 
 int px = width/2;
 int py = 650;
 boolean hasCollided = false;
 //boolean isShooting = false;
 
 float shipX;
 float shipY;
 

 

void setup(){
  size(680, 680);

  //Initialize ships
  for(int i = 0; i < ships.length; i++){
    ships[i] = new Spaceships(x, y, 50, 1, color(150)); //X coordinate, Y coordinate, size, speed, color
      //Change spacing of ships
      x += spacing;
      //If x is greater than or equal to width, add y spacing to make new line
      if(x >= width - 50 && y >= 100){
        y += spacing;
        x = 50;
      }
  }
  p = new Player(px, py, 2, 25, color(random(0, 255), random(0, 255), random(0, 255))); //X, Y, Speed, Size, Color
  aBullet = new Bullet();
}

void draw(){
  background(50, 100, 100);
  //float factor = constrain(mouseX/10, 0, 5);
  for(int i = 0; i < ships.length; i++){
    ships[i].display();
    ships[i].move();
    ships[i].hitBox();

    //p.keyPressed();
  }
    p.display();
    p.move();
    
   // aBullet.move();
    aBullet.update();
    aBullet.bulletCollision();
    

    //aBullet.bulletCollision();
   //aBullet.crash();

    
    //aBullet.display();
}

void keyPressed(){
  if(key == 'h'){
    aBullet = new Bullet();
    aBullet.update();
  }
}

Here’s the bullet class:

class Bullet{
  
  int x;
  int y;
  int xi;
  int yi;
  boolean isShooting = false;
  
  //float speed = -10;
  //float speed;
    Bullet(){
      this.x = p.x;
      this.y = p.y;
      //y = constrain(yi, 0, 0);
      //this.speed = -10;
      //speed = tempSpeed;
        
  }
  
  void display(){
    rectMode(CENTER);
    stroke(255);
    fill(255);
    rect(p.x, y - 15, 5, 5);
    //y = y - speed;
   // y += -speed;
  }
  
  void move(){
    y = y - 10;
    
  }
  
  void update(){
    move();
    display();
    //crash();
    //bulletCollision();
  }
  
  void bulletCollision(){
   if(x == shipX && y == shipY){
     println("COLLISION");
   }
  }
  
  /*
  boolean crash(){
    color detectedColor;
    for (int i = y;  i <= y; i++)
    {
      detectedColor = get(y, i);
      if (detectedColor == color(0))
      //println("COLLISION HAPPENED");
      {
        println("COLLISION AT " + y);
        return true;
      }
    }
    //println("NO COLLISION DETECTED");
    return false;
}  
*/
  
  /*
  public void simulate(){
    p.x += v.x;
    p.y += v.y;
    
    bulletCollision();
  }
  
  */
  

  
  
} //End Bullet class

Here’s the player class:

class Player{
  //Player variables
  //Go here
  int x;
  int y;
  int xSpeed;
  float pSize;
  color c;
  
  
  float bx;
  float by;
  float bSpeed = 1;
  
  
  Player(int tempX, int tempY, int xSpeed_, float pSize_, color c_){
    x = tempX;
    y = tempY;
    xSpeed = xSpeed_;
    pSize = pSize_;
    c = c_;
    bx = tempX;
    by = tempY - 15;
  }
  
    void move(){
      //x = x + xSpeed;
      
   if(keyPressed){
     if(key == 'd'){
       x = x + xSpeed;
       if(x >= width){x = width;}
      }else if(key == 'a'){
        x = x - xSpeed;
        if(x <= 0){x = 0;}
      }//else if(key == 'h'){
         // shoot(); 
      //}
   }
 }// End move()
  
  void display(){
    rectMode(CENTER);
    noStroke();
    fill(c);
    rect(x, y, pSize, pSize); //draw the player
    rect(x, y - 15, 5, 10); //player's weapon
  }
  
  
  

  /*
  void keyPressed(){
    if(key == 'd'){
      x += xSpeed;
    }else if (key == 'a'){
      x = -xSpeed;
    }
  } */
}

Here’s the spaceship class:

// Spaceships class

class Spaceships{
  float x;
  float y;
  float xSpeed;
  //float ySpeed;
  float shipSize;
  color c;
  
  
  
  Spaceships(float tempX, float tempY, float tempShipSize, float tempXSpeed, color c_){
    x = tempX;
    y = tempY;
    xSpeed = tempXSpeed;
    //xSpacing = tempXSpacing;
    shipSize = tempShipSize;
    c = c_;

  }
  
  void move(){
    x = x + xSpeed;
    shipX = x;
    shipY = y;
    if(x > width){
      xSpeed = -xSpeed;
      y += 100;
    }else if(x < 0){
      xSpeed = -xSpeed;
      y += 100;
    }else if(y > height - 100){
      y = height - 100;
    }

    
    
    /*
    if(x >= width){
      xSpeed *= -0.95;
      y += 100;
    }else if(x <= 0){
      xSpeed *= -0.95;
      y += 100;
    }
    if(y >= height - 100){
      y = height - 100;
    } */
  }
  
  
  void display(){
    float offset = shipSize / 4;
    ellipseMode(CENTER);
    rectMode(CENTER);
    strokeWeight(2);
    stroke(0);
    fill(c);
    ellipse(x, y - 10, shipSize / 2, shipSize / 2);
    ellipse(x, y, shipSize, shipSize / 2);
    
    stroke(0);
    fill(50, 100, 100);
    ellipse(x, y, offset, offset);
    ellipse(x + offset + 5, y, offset, offset);
    ellipse(x - offset - 5, y, shipSize /4, shipSize / 4);

  }
  
  public void hitBox(){
        //Ship hitboxes
    noStroke();
    fill(0, 0, 0, 0);
    rect(x, y, shipSize, shipSize - 25); //Ship hitboxes
  }
}

I know I’m doing something wrong but I have been hours trying to fix this. Any help is greatly appreciated!

Thank you,
-Mellie

Hello @PaddedMellie ,

Your bullets and ship will never be exactly at the same position!

Use println() statements to see what is going on.
Add a visual queue such as background() to flash when there is a collision.

This code is only comparing along the y-axis when they are within 30 pixels and flashes (code works here):

  void bulletCollision(){
   //println(x, y);
   //println(shipX, shipY);
   println(p.y, this.y);
   println(shipY);
   println();
   
   //if(x == shipX && y == shipY) // May never see this condition!
   {
   if(abs(y - shipY) <30) // If within 30!
     {
     println("COLLISION");
     background(255);
     }
   }
  }

Above is only intended to help get you started with troubleshooting tips.
It can be easily modified for x position.

Note:

I reduced the spaceships to one for testing:
Spaceships[] ships = new Spaceships[1];

It works (detects collision) with one spaceship or first spaceship if you have more than one.

Also look here for guidance:
Guidelines—Asking Questions

Keep at it!

:)

1 Like

Thanks a lot @glv ! I really appreciate the help! :smile: I’m going to keep at it and hopefully get my Space Invaders clone to work.

Consider an Arraylist of spaceships:

ArrayList example:

/**
 * ArrayList of Objects. 
 * 
 * Demonstrates the syntax for creating an ArrayList of custom objects. 
 */

//https://processing.org/reference/ArrayList.html

ArrayList<Particle> particles = new ArrayList<Particle>();
int count = 100;

void setup() 
  {
  size(500, 500);
  noStroke();
    
  for (int i = 0; i < count; i++) 
    {
    int xt = (int) random(width);
    int yt = (int) random(height);
    println(xt, yt);  
    particles.add(new Particle(xt, yt)); // adds particles    
    }
  }

void draw() 
  {
  background(0);
  
  push();
  noFill();
  strokeWeight(2);
  stroke(255, 0, 0);
  circle(mouseX, mouseY, 40);
  pop();
  
  //Loop backward to safely remove last particle
  for (int i = particles.size() - 1; i >= 0; i--) 
  
  //for (int i = 0; i<particles.size(); i++)     // Try this to see what happens!
    {
    Particle p = particles.get(i);
    
    // Remove if mouse is within 20 pixels inside circle
    if (dist(mouseX, mouseY, p.x, p.y) < 20) 
      {
      particles.remove(i);
      continue;  // exits loop once a particle is removed
      }
    
    p.update();
    p.display();
  }
}

class Particle 
  {
  float x, y;
  
  // Constructor
  Particle(int xTemp, int yTemp) 
    {
    x = xTemp;
    y = yTemp;
    }
  
  void update() 
    {
    // Future!  
    }
  
  void display() 
    {
    fill(255, 255, 0);
    circle(x, y, 10);
    }
  }

I shared the above to get you started.
ArrayLists of objects can be a challenge!

Other examples:

There may be more here:

:)

UPDATE:
I rewrote my code and now it works!
It looks a little something like this

Main Loop:

boolean left, right, up;
boolean space;
Player p;
Spaceships [] s;
Projectile [] proj;
int nextProjectile;
Timer firingTimer;
float spacing = 75;
float x = 100;
float y = 100;
float score = 0;
float finalScore;

void setup(){
  size(680, 680);
  
  p = new Player();
  
  s = new Spaceships[10];
  for(int k = 0; k < s.length; k++){
    s[k] = new Spaceships(x);
    x += spacing;
    if(x >= width && y >= 100){
      y += spacing;
      x = 50;
    }
  }
  
  left = false;
  right = false;
  space = false;
  
  proj = new Projectile[5];
  for(int l = 0; l < proj.length; l++){
    proj[l] = new Projectile(150 + l * 50, 550);
  }
  
  nextProjectile = 0;
  
  firingTimer = new Timer(200);
  firingTimer.start();
}

void draw(){
  background(0, 0, 0);
  
  noStroke();
  fill(255);
  text("SCORE: " + score, 50, 50);
  
  if(space){
    if(firingTimer.complete()){
      proj[nextProjectile].fire(p.x + p.w/9, p.y + p.h/2, p.facing);
        nextProjectile = (nextProjectile + 1)%proj.length;
        firingTimer.start();
      
    }
  }
  
  for(int i = 0; i < proj.length; i++){
    proj[i].update();
    for(int j = 0; j < s.length; j++){
      if(intersect(proj[i], s[j]) && !s[j].dead){
        fill(0, 0, 255);
        rect(0, 0, width, height);
        proj[i].reset();
        s[j].destroy();
      }
    }
    proj[i].display();
  }
  p.update();
  p.display();
  
  for(int k = 0; k < s.length; k++){
    if(!s[k].dead){
      s[k].move();
    }
    s[k].update();
    s[k].display();
    if(intersect(p, s[k]) && !s[k].dead){
      fill(255, 0, 0, 50);
      rect(0, 0, width, height);
    }
  }
  
  
  
}

boolean intersect(Player b1, Spaceships b2){
  //Distance on x axis
  float distX = abs((b1.x + b1.w/2) - (b2.x + b2.w/2));
  //distance on y axis
  float distY = abs((b1.y + b1.h/2) - (b2.y + b2.w/2));
  //what is the combined half widths
  float combinedHW = b1.w/2 + b2.w/2;
  //what is the combined half heights
  float combinedHH = b1.h/2 + b2.h/2;
  
  //Check for x axis collision
  if(distX < combinedHW){
    //check on y axis
    if(distY < combinedHH){
      //we collided
      println("YIPPIE");
      return true;
    }
  }
  return false;
}

boolean intersect(Projectile b1, Spaceships b2){
  //Distance on x axis
  float distX = abs((b1.x + b1.w/2) - (b2.x + b2.w/2));
  //distance on y axis
  float distY = abs((b1.y + b1.h/2) - (b2.y + b2.w/2));
  //what is the combined half widths
  float combinedHW = b1.w/2 + b2.w/2;
  //what is the combined half heights
  float combinedHH = b1.h/2 + b2.h/2;
  
  //Check for x axis collision
  if(distX < combinedHW){
    //check on y axis
    if(distY < combinedHH){
      //we collided
      println("YIPPIE");
      return true;
    }
  }
  return false;
}

void keyPressed(){
  switch(keyCode){
    case 37:
    left = true;
    break;
    
    case 38:
    up = true;
    break;

    case 39:
    right = true;
    break;

    case 32:
    space = true;
    break;
  }
}


void keyReleased(){
  switch(keyCode){
    case 37:
    left = false;
    break;
    
    case 38:
    up = false;
    break;
   
    case 39:
    right = false;
    break;

    case 32:
    space = false;
    break;
  } 
}

Player Class:

class Player{
  float x, y, w, h;
  float speedX, maxSpeed;
  String facing;
  
  Player(){
    x = width/2;
    y = 600;
    w = 22;
    h = 44;
    maxSpeed = 5;
    speedX = 0;
    facing = "up";
  }
  
  void update(){
    if(left){
      speedX = -maxSpeed;
    }
    if(right){
      speedX = maxSpeed;
    }
    if((!left && !right) || (left && right)){
      speedX = 0;
    }
    
    checkBounds();
    
    PVector v = new PVector();
    v.x = speedX;
    x += v.x;
  }
  
  void display(){
    fill(0, 0, 255);
    rect(x, y - 10, w / 1.5, h + 5);
    rect(x, y, w * 2, h);
  }
  
  void checkBounds(){
     if(x > width){
      x = -w;
    }
    if(x < -w){
      x = width;
    }

  }
  
}

Projectile Class:

class Projectile{
  float x, y, w, h, vx, vy, startingX, startingY;
  float speed;
  boolean inMotion;
  
  Projectile(float sx, float sy){
    startingX = sx;
    startingY = sy;
    x = sx;
    y = sy;
    w = 10;
    h = 15;
    vx = 0;
    vy = 0;
    speed = 10;
    inMotion = false;
  }
  
  void update(){
    x += vx;
    y += vy;
    checkBounds();
  }
  
  void display(){
    fill(255);
    rect(x, y, w, h);
  }
  
  void fire(float newX, float newY, String facing){
    x = newX;
    y = newY;
    if(!inMotion){
      switch(facing){
        case "up":
        vx = 0;
        vy = -speed;
        w = 10;
        h = 20;
        break;
      }
      inMotion = true;
    }
  }
  
  void reset(){
    x = startingX;
    y = startingY;
    vx = 0;
    vy = 0;
    inMotion = false;
  }
  
  void checkBounds(){
    if(x < -w || x > width || y < -h || y > height){
      reset();
    }
  }
    
}

Spaceships Class:

class Spaceships{
  float x;
  float y;
  float w;
  float h;
  float vx;
  float vy;
  float speed;
  float shipSize;
  color c;
  boolean dead;
  int storedTime = 0;
  
  Spaceships(float tempX){
  x = tempX;
  y = 100;
  w = 50;
  h = 25;
  vx = 0;
  vy = 0;
  speed = random(1, 2);
  dead = false;
  }
  
  void move(){
    x = x + speed;
    if(x > width){
      //x = x - -speed;
      //x -= -speed;
      speed = -speed;
      y += 100;
    }else if(x < 0){
      speed = -speed;
      y += 100;
    }else if(y > height - 100){
      y = height - 100;
    }
  }
  
  void update(){
    x += vx;
    y += vy;
    //checkBounds();
  }
  
  void display(){
    float offset = shipSize / 4;
    ellipseMode(CENTER);
    rectMode(CENTER);
    strokeWeight(2);
    stroke(0);
    fill(170);
    ellipse(x, y - 10, w / 2, h / 2);
    ellipse(x, y, w, h /2 +3);
    
    stroke(0);
    fill(50, 100, 100);
    ellipse(x, y, w/4, h/4);
    ellipse(x + offset + 15, y, w/5, h/5);
    ellipse(x - offset - 15, y, w/4, h / 4);
    
  }
  
  void destroy(){
    vx = 0;
    vy = 0;
    x = -1000;
    dead = true;
    score += 100;
  }
  
  void reset(){
    x = 0;
    y = 100;
    vx = 0;
    vy = 0;
    //inMotion = false;
  }
  
  void checkBounds(){
    if(x < 0 || x > width){
      //reset();
      x = -speed;
    }
  }
  
  
  
}

Timer Class:

class Timer{
  int startTime;
  int interval;
    
    Timer(int timeInterval){
      interval = timeInterval;
    }
    
    void start(){
      startTime = millis();
    }
    
    boolean complete(){
      int elapsedTime = millis() - startTime;
      if(elapsedTime > interval){
        return true;
      }else{
        return false;
      }
    }
}

I found a tutorial on YouTube about making projectiles in Processing and followed along then rewrote my program to utilize what I’d learned and tweak it for what I was using it for.

3 Likes