Collision problem

Hello guys,

I managed to get my rectangles disappear when hit by a bullet but I cant get the ship to detect a collision when they interact with the rectangles.

Please run my code and see if you could spot the problem. Thank you

Press mouse to shoot

http://pastebin.com/P1fjYKvA

Answers

  • edited March 2014 Answer ✓

    In a quick glance I've spotted some inconsistencies:

    • You use translate(), which makes position detection immensely difficult.
    • You've got 2 coordinate systems -> int x, y & PVector pos. Go w/ 1 or the other!
    • If you wanna go w/ the isAlive approach, you've gotta have a way to "awaken" an object
      rather than always instantiating a new 1!
  • What do you mean by your last point? is there another easier way to detect collision?

    Thanks for your reply I really appreciate it.

  • Answer ✓

    Side note: it is time to read To newcomers in this forum: read attentively these instructions.

    You must choose a topic when you create a new message. I moved several of your messages to this category (since you provide code).

  • Thanks for that I didn't know. Do you think you can hep me with my question?

  • edited March 2014

    What do you mean by your last point? is there another easier way to detect collision?

    The last point got nothing to do w/ collision, rather it's about how to "bury" your objects after a collision was detected!

    Collision is about checking coordinates and area of objects.
    As I've mentioned at the 1st point, transformation settings like transform() make collision a daunting task!

  • FluFlu
    edited March 2014

    Hello fellows! I've started making a game very alike with this. I've got two classes. One for the car and one for the bullet. My problem is that it is very hard to detect if they touch. In that case, a GAME OVER message should appear. I've come here to look for a method to detect that colission, but I'm new to programming so a little more detail would be wonderful! By now, all I managed to do is to check if the center point of the bullet intersects with the left top corner of the car, thing witch is almost impossible. With a liitle work, I can also check if it meets all the other corners, making a car out of more rectangles, each one with other rectMode(). One with CENTER and two with CORNERS, but that will be inneficient too. Can you please help me with that? I should also mention that "the bullet" is controled using WASD and there are three cars, each one with random speeds every time the game starts.

  • In this recent thread below, I've posted a neat example of collision among Bullet vs Asteroid objects:
    http://forum.processing.org/two/discussion/3980/check-asteroid-death-help

    You can run it online at the link below:
    http://studio.processingtogether.com/sp/pad/export/ro.9K-kjhuONcJDZ/latest

    However, the collision algorithm used there is for circle shaped objects.
    I can try to modify it for rectangle shaped objects if you want to. O:-)

    As you mentioned already, we gotta choose rectMode(CORNER);, which is the default, or rectMode(CENTER);. 8-X

  • edited January 2015

    Finished expanding the circle-only example to include both CORNER & CENTER rectMode()s as well! (*)

    http://studio.processingtogether.com/sp/pad/export/ro.9K-kjhuONcJDZ/latest


    "Asteroids_Vs__Bullets_Sim.pde":


    /**
     * Asteroids Vs. Bullets Sim (v3.21)
     * by GoToLoop (2014/Mar)
     *
     * forum.processing.org/two/discussion/3980/check-asteroid-death-help
     * forum.processing.org/two/discussion/3890/collision-problem
     *
     * studio.processingtogether.com/sp/pad/export/ro.9K-kjhuONcJDZ/latest
     */
    
    static final int ASTEROIDS = 30, BULLETS = 100, NUM = 10, FPS = 60;
    static final color BG = 0;
    static final boolean ONLINE = 1/2 == 1/2.;
    
    final ArrayList<Asteroid> asteroids;
    final ArrayList<Bullet>   bullets;
    {
      asteroids = ONLINE? new ArrayList() : new ArrayList(ASTEROIDS);
      bullets   = ONLINE? new ArrayList() : new ArrayList(BULLETS);
    }
    
    int score;
    
    void setup() {
      size(900, 750, JAVA2D);
      frameRate(FPS);
      smooth(4);
    
      ellipseMode(CENTER);
      rectMode(Asteroid.RECT_MODE);
    
      strokeWeight(Bullet.DIAM);
      fill(Asteroid.COLOUR);
    
      instantiateSprites();
    }
    
    void draw() {
      background(BG);
    
      displaySprites();
      checkDeath();
      checkVictory();
    }
    
    void mousePressed() {
      loop();
    }
    
    void keyPressed() {
      loop();
    }
    
    void restart() {
      instantiateSprites();
      score = 0;
    }
    
    void instantiateSprites() {
      asteroids.clear();
      //bullets.clear();
    
      for ( int i = 0; i++ != ASTEROIDS; asteroids.add(new Asteroid()) );
    
      for ( int i = 0; i++ != BULLETS; bullets.add(new Bullet(
      random(width), random(height), random(TWO_PI))) );
    }
    
    void displaySprites() {
      noStroke();
      for (int c = asteroids.size(), len = c; c-- != 0;)
        if (asteroids.get(c).script()) {
          final Asteroid a = asteroids.remove(--len);
          if (c != len)  asteroids.set(c, a);
          println("An asteroid has flown too far away!");
        }
    
      stroke(Bullet.COLOUR);
      for (int b = bullets.size(), len = b; b-- != 0;)
        if (bullets.get(b).script()) {
          final Bullet u = bullets.remove(--len);
          if (b != len)  bullets.set(b, u);
          println("A bullet has strayed too far from view!");
        }
    }
    
    void checkDeath() {
      for (int c = asteroids.size(), lenA = c; c-- != 0;) {
        final Asteroid a = asteroids.get(c);
    
        for (int b = bullets.size(), lenB = b; b-- != 0;)
          if (bullets.get(b).checkHit(a)) {
            final Bullet   u = bullets.remove(--lenB);
            final Asteroid r = asteroids.remove(--lenA);
    
            if (b != lenB)  bullets.set(b, u);
            if (c != lenA)  asteroids.set(c, r);
    
            score += NUM;
            println("An asteroid has been pulverized!");
    
            break;
          }
      }
    }
    
    void checkVictory() {
      final int a = asteroids.size(), b = bullets.size();
    
      if (!ONLINE)  frame.setTitle("Score: #" + score
        + "\t\tFPS: #" + round(frameRate));
    
      if (b == 0) {
        println("\nAsteroids left: #" + a + "\tFinal score: #" + score);
        noLoop();
        restart();
      }
    

    }


    "Asteroid.pde":


    class Asteroid {
      static final boolean IS_CIRCLE = false;
      static final int RECT_MODE = CORNER;  // Either CORNER or CENTER.
    
      static final color COLOUR = #00A0F0;
      static final float SPD = 1.5;
    
      static final int DIAM  = 25, RAD = DIAM>>1, RAD_SQ = RAD*RAD;
    
      static final int DIM_X = 20, RAD_X = DIM_X>>1;
      static final int DIM_Y = 30, RAD_Y = DIM_Y>>1;
    
      float x = IS_CIRCLE
        ? random(DIAM, width   - DIAM)
        : random(DIM_X, width  - DIM_X);
    
      float y = IS_CIRCLE
        ? random(DIAM, height  - DIAM)
        : random(DIM_Y, height - DIM_Y);
    
      final float vx, vy;
    
      //Asteroid()  // Fix for JS
      {
        final float dir = random(TWO_PI);
        vx  = cos(dir)*SPD;
        vy  = sin(dir)*SPD;
      }
    
      boolean script() {
        update();
        display();
        return isOuttaBounds();
      }
    
      void update() {
        x += vx;
        y += vy;
      }
    
      void display() {
        if (IS_CIRCLE)  ellipse(x, y, DIAM, DIAM);
        else            rect(x, y, DIM_X, DIM_Y);
      }
    
      boolean isOuttaBounds() {
        return IS_CIRCLE
          ? x < -RAD | x >= width+RAD | y < -RAD | y >= height+RAD
    
          : RECT_MODE == CORNER
          ? x < 0 | x >= width+DIM_X | y < 0 | y >= height+DIM_Y
    
          : x < -RAD_X | x >= width+RAD_X | y < -RAD_Y | y >= height+RAD_Y;
      }
    }
    


    "Bullet.pde":


    class Bullet {
      static final color COLOUR = #C86400;
      static final int DIAM = 4;
      static final float SPD = 4.0;
    
      float x, y;
      final float vx, vy;
    
      Bullet(float xx, float yy, float dir) {
        x = xx;
        y = yy;
    
        vx = cos(dir)*SPD;
        vy = sin(dir)*SPD;
      }
    
      boolean script() {
        update();
        display();
        return isOuttaBounds();
      }
    
      void update() {
        x += vx;
        y += vy;
      }
    
      void display() {
        point(x, y);
      }
    
      boolean isOuttaBounds() {
        return x < -DIAM | x > width+DIAM | y < -DIAM | y > height+DIAM;
      }
    
      boolean checkHit(Asteroid a) {
        return Asteroid.IS_CIRCLE
          ? sq(a.x - x) + sq(a.y - y) < Asteroid.RAD_SQ
    
          : Asteroid.RECT_MODE == CORNER
          ? x >= a.x & x < a.x+Asteroid.DIM_X
          & y >= a.y & y < a.y+Asteroid.DIM_Y
    
          : x >= a.x-Asteroid.RAD_X & x < a.x+Asteroid.RAD_X
          & y >= a.y-Asteroid.RAD_Y & y < a.y+Asteroid.RAD_Y;
      }
    }
    

  • FluFlu
    edited April 2014

    Ok, thank you! I tried to understand what have you done and what every line does, but I told you, I'm pretty new to programming, so, please, could you explain me how does this thing works?

                boolean checkHit(Asteroid a) {
                  return Asteroid.IS_CIRCLE
                      ? sq(a.x - x) + sq(a.y - y) < Asteroid.RAD_SQ
    
                      : Asteroid.RECT_MODE == CORNER
                      ? x >= a.x & x < a.x+Asteroid.DIM_X
                      & y >= a.y & y < a.y+Asteroid.DIM_Y
    
                      : x >= a.x-Asteroid.RAD_X & x < a.x+Asteroid.RAD_X
                      & y >= a.y-Asteroid.RAD_Y & y < a.y+Asteroid.RAD_Y;
                }
    

    I think this is the one responsable for checking if the bullet hit the asteroid, and it's the only part I'm interested in. I would really like to understand and learn from this program something. Thank you so much for all the help! You are really good at what you are doing!

  • edited April 2014

    The original version only dealt w/ round Asteroid objects. So I've converted it to use rectangle shapes as promised! #:-S
    More than that, it can be configured to switch between both! Just set IS_CIRCLE to either true or false. <:-P

    While the round form is confined to ellipseMode(CENTER); only; the rectangles can be either CORNER or CENTER modes!
    Just set constant RECT_MODE to either CORNER or CENTER then. :ar!

    Problem is now, each of those 3 combinations got their own unique algorithm for collision! 8-X
    That's why I'm using a chained ternary operator to determine which 1 to use.
    If the whole of the selected expression is true, it means a Bullet is inside some Asteroid's area.

    If that syntax isn't too clear for you now, take a look at the updated CoffeeScript Mode version I'm gonna post below soon! :>

  • edited June 2015


    "Asteroids_Vs__Bullets_Sim.pde":


        ###
        * Asteroids Vs. Bullets Sim (v3.2)
        * by GoToLoop (2014/Mar)
        *
        * forum.processing.org/two/discussion/3980/check-asteroid-death-help
        * forum.processing.org/two/discussion/3890/collision-problem
        *
        * studio.processingtogether.com/sp/pad/export/ro.9K-kjhuONcJDZ/latest
        ###
        
        ASTEROIDS = 30; BULLETS = 100; NUM = 10; FPS = 60; BG = 0
        asteroids = []; bullets = []
        score = 0; isPaused = no
        
        setup: ->
        
            size 900, 750, JAVA2D; frameRate FPS; smooth 4
            ellipseMode CENTER; rectMode Asteroid::RECT_MODE
            strokeWeight Bullet::DIAM; fill Asteroid::COLOUR
        
            instantiateSprites
        
        
        draw: ->
        
            background BG
            do displaySprites; do checkDeath; do checkVictory
        
        
        mousePressed: -> do keyPressed
        keyPressed:   -> if isPaused ^= on then do noLoop else do doLoop
        
        restart = -> do instantiateSprites; score = 0
        
        instantiateSprites = ->
        
            asteroids.length = bullets.length = 0
        
            asteroids.push new Asteroid  for i in [0...ASTEROIDS] by 1
        
            bullets.push new Bullet(random(width), random(height),
            random(TWO_PI))  for i in [0...BULLETS] by 1
        
            return
        
        
        displaySprites = ->
        
            do noStroke
        
            a = len = asteroids.length; while a--
                if do asteroids[a].script
        
                    asteroids[a] = asteroids[--len]; do asteroids.pop
                    println "An asteroid has flown too far away!"
        
        
            stroke Bullet::COLOUR
        
            b = len = bullets.length; while b--
                if do bullets[b].script
        
                    bullets[b] = bullets[--len]; do bullets.pop
                    println "A bullet has strayed too far from view!"
        
            return
        
        
        checkDeath = ->
        
            b = lenB = bullets.length; while b--
                u = bullets[b]
        
                a = lenA = asteroids.length; while a--
                    if u.checkHit asteroids[a]
                        
                        asteroids[a] = asteroids[--lenA]; do asteroids.pop
                        bullets[b]   = bullets[--lenB];   do bullets.pop
        
                        score += NUM
                        println "An asteroid has been pulverized!"
        
                        break
                        
            return
        
        
        checkVictory = ->
        
            a = asteroids.length; b = bullets.length
        
            #frame.setTitle "Score: ##{score}\t\tFPS: " +
            #    "##{round frameRate}"  unless online
        
            unless b
        
                println "\nAsteroids left: ##{a}\tFinal score: ##{score}"
                isPaused = yes; do noLoop; do restart
    
    


    "Asteroid.pde":


    class Asteroid
    
        IS_CIRCLE: yes
        RECT_MODE: Processing::CENTER  #   Either CORNER or CENTER.
    
        COLOUR: 0xff0000FF; SPD: 1.5; DIAM: 25
        RAD: Asteroid::DIAM>>1; RAD_SQ: Asteroid::RAD * Asteroid::RAD
    
        DIM_X: 20; RAD_X: Asteroid::DIM_X>>1
        DIM_Y: 30; RAD_Y: Asteroid::DIM_Y>>1
    
        constructor: ->
    
            @x = if @IS_CIRCLE then  random @DIAM,  width  - @DIAM
            else                     random @DIM_X, width  - @DIM_X
    
            @y = if @IS_CIRCLE then  random @DIAM,  height - @DIAM
            else                     random @DIM_Y, height - @DIM_Y
    
            dir = random TWO_PI
            @vx = @SPD * cos dir; @vy = @SPD * sin dir
    
    
        script: -> do @update; do @display; do @isOuttaBounds
        update: -> @x += @vx; @y += @vy
    
        display: ->
    
            if @IS_CIRCLE then ellipse @x, @y, @DIAM, @DIAM
            else               rect @x, @y, @DIM_X, @DIM_Y
    
    
        isOuttaBounds: ->
    
            if @IS_CIRCLE
            then @x < -@RAD | @x >= width+@RAD | @y < -@RAD | @y >= height+@RAD
    
            else if @RECT_MODE is CORNER
            then @x < 0 | @x >= width+@DIM_X | @y < 0 | @y >= height+@DIM_Y
    
            else @x < -@RAD_X | @x >= width+@RAD_X |
                 @y < -@RAD_Y | @y >= height+@RAD_Y
    
    


    "Bullet.pde":


    class Bullet
    
        COLOUR: 0xffC86400; DIAM: 4; SPD: 4
    
        constructor: (@x, @y, dir) ->
            @vx = @SPD * cos dir; @vy = @SPD * sin dir
    
        script:  -> do @update; do @display; do @isOuttaBounds
        update:  -> @x += @vx; @y += @vy
        display: -> point @x, @y
    
        isOuttaBounds: ->
            @x < -@DIAM | @x > width+@DIAM | @y < -@DIAM | @y > height+@DIAM
    
        checkHit: (a) ->
    
            if Asteroid::IS_CIRCLE
            then sq(a.x - @x) + sq(a.y - @y) < Asteroid::RAD_SQ
    
            else if Asteroid::RECT_MODE is CORNER
            then @x >= a.x & @x < a.x+Asteroid::DIM_X &
                 @y >= a.y & @y < a.y+Asteroid::DIM_Y
    
            else @x >= a.x-Asteroid::RAD_X & @x < a.x+Asteroid::RAD_X &
                 @y >= a.y-Asteroid::RAD_Y & @y < a.y+Asteroid::RAD_Y
    
    

  • FluFlu
    edited April 2014

    Ok, but I'm still very confused with all the new things I bumped into! In my program, it is used just rectMode(CENTER). All I need is the algorithm to determine if the bullet is inside the asteroid, that's all, thing I can't find in your examples. So I guess what you did there is written in CoffeeScript. It looks very much like processing! Unfortunately, I'm too busy studying at school and studying processing to learn CoffeeScript, but I will do it soon, because it is a very beautiful language! I said I would do it for a few months already. As for detecting the collision, today at the programming hour at school, I asked my teacher about this and she said that I could use the next method: If I know the position and the radius of my circle (thing I do), and the width, height and the position of the upper left corner of the rectangle (thing I also do), I could check if the lenght from the center of the bullet to the upper left corner or any corner it is smaller than the radius. If it is, that means they touched each other, but this method has it's disadvantages. My bullet should have almost the same size as the rectangle, but it isn't a very big issue in my case. Now the problem here is how to get the length of that line from the center at one of the corners. Do you get what I'm saying? I could really make this work with a little help from you, by explaining to me what the algorithm is exactly, and then putting it to code. I told you I'm a newbie, but I learn quickly so I hope it won't take much until I will get what's happening here :). Thanks again for all the help and dedication!

  • edited April 2014

    As mentioned, my example can deal w/ 3 modes:

    1. ellipseMode(CENTER);
    2. rectMode(CORNER);
    3. rectMode(CENTER);

    That's why there are 2 variables in order to to select which 1:

    1. boolean IS_CIRCLE -> true or false
    2. int RECT_MODE -> CORNER or CENTER

    Since each 1 demands a diff. formula in order to detect a collision, method checkHit() gotta which mode is active.

    I've mentioned about the CoffeeScript version b/c it uses a regular if/else if/else chained block.
    Which in turn is obviously more familiar than a chained ternary operator statement used by the Java version example!

    In short, if you're specifically looking for the rectMode(CENTER); algorithm formula, it's the 3rd 1: O:-)

    x >= a.x-Asteroid.RAD_X & x < a.x+Asteroid.RAD_X
          & y >= a.y-Asteroid.RAD_Y & y < a.y+Asteroid.RAD_Y;
    
  • Finally got it! Thank you so much! All is left for me to do is to implement this, avoiding the algorithm for rectMode(CORNER)! I will tell you soon if it worked!

  • edited April 2014

    Good luck! Any further doubts, keep asking! =:)

    So I guess what you did there is written in CoffeeScript. It looks very much like Processing!

    B/c it is Processing! In itself, Processing is a framework API which is atop some programming language.

    Default language is Java, which is called "Java Mode".
    But there are many others available for installation right at the IDE...

    • JavaScript mode.
    • CoffeeScript mode.
    • Android mode.

    There are more Processing based languages besides those 3 modes!

    • Arduino
    • Python
    • Ruby
    • C++
    • etc.

    As you've already noticed, besides Java mode, CS is my 2nd favorite! :D
    CoffeeScript allows us to program in JavaScript while avoiding its most difficult parts like the lack of formal classes!
    And to use all JS' available libraries along w/ Processing and working on any browser! \m/

  • FluFlu
    edited April 2014

    But I really want to program in CoffeeScript too! I know what CoffeeScript is, but I'm a bit confused about what the processing mode for CoffeeScript does. So I install the CoffeeScript Mode and then what? Anyway, isn't it a late hour for americans right now? :)

  • edited April 2014

    Why would you think I'm American? ;;)

    Best place to learn CS is its own site:
    http://CoffeeScript.org

    But for Processing + CS, w/ CoffeeScript Mode active, go to "File -> Examples...". Or just hit CTRL+SHIFT+O.
    There are many examples you can try there! *-:)

  • OK, but my question is what the mode does. So I open it and then I can program there in CoffeeScript but then it saves it as .pde?

  • edited April 2014

    Most modes change the Processing's programming language!
    It still saves as ".pde". But it's not Java anymore!
    Copy & paste my CS example. Save it to compile. Run it and default browser opens it!
    We got full access to Processing's API + JS's API. And we can even import JS libraries as well! :ar!

  • So I can finally program in CoffeeScript? I love processing, it's the best thing that happened to me! But don't worry, I will still ask you a lot of question. ;)

  • OK, I have a problem but it doesn't have anything to do with my little game. If I want to program in Coffee Script, I can't use the mode that processing gives to me, because it is not pure CoffeeScript and I do not like that. So, instead of using the online compiler on their official site, where can I write it and see it in action in the browser? There's gotta be a compiler I can download and an IDE to write in, and then like the processing CoffeeScript mode, to display it in the browser.

  • edited April 2014

    There's gotta be a compiler I can download and an IDE to write in, and then like the processing CoffeeScript mode,
    to display it in the browser.

    In the CoffeeScript site, they advise us to use NodeJS w/ CoffeeScript npm module.

    http://CoffeeScript.org/
    http://NodeJS.org/

    CoffeeScript mode exports itself as a compiled JS script plus an HTML file inside "/web-export-coffee" subfolder.
    Just hit CTRL+K to open it after saving.
    You can check those files to know about how an HTML is made to run JS scripts! O:-)

    I can't use the mode that processing gives to me, because it is not pure CoffeeScript...

    In the same vein that Java mode is not "pure" Java, the other back-end modes goes along!
    Processing is a complete framework library which gives a ready-to-use canvas and lotsa graphics functions!
    If you don't wanna use a Processing mode, you gotta instantiate 1 on your own or use another framework that does that for you!

  • GoToLoop, you use <pre lang="xxx"> to mark up code, which is OK, but the coffeescript brush isn't recognized (yet?) and for Processing, it is lowercase processing, not title case.

  • edited April 2014

    @PhiLho , it's worse if we use something that is recognizable!
    For a CoffeeScript code is fulla @ keywords everywhere! :-S

    I can avoid their usage (a trick I've taught myself) before "class" definition blocks.
    But after that it's impossible (unless we replace @ by this keyword) due to language demands! :-<

    P.S.: The trick is, since we don't expect the "top-class" script to be instantiate more than once,
    there's no need for @ instantiable property "fields", in that top part!

    So we use local variables rather than prototype :: and @ properties! B-)
    And those local variables are even accessible inside the "inner" classes. Just like Java itself! <:-P

    Of course, setup(), draw(), keyPressed() and such are exceptions;
    and must be prototypal properties in order to be called back by Processing.js.
    But fortunately, we rarely have to directly invoke them ourselves! :P

Sign In or Register to comment.