Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (576)
games submitted by our members
Games in WIP (497)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Asteroids bouncing off each other when they collide.  (Read 1926 times)
0 Members and 1 Guest are viewing this topic.
Offline Gingerious

Junior Member


Medals: 2



« Posted 2011-09-09 17:40:31 »

This is an exercise out of Beginning Java SE6 Game Programming, Third Edition by Jonathan S Harbour.

So I'm given an exerice in chapter 6 to take the code given to me (which puts one asteroid sprite on the screen, rotates it, and moves it with a velocity represented by a Point object) and make multiple asteroids moving around on screen.  This part was easy.  The second part was that I was to make the asteroids collide and bounce off of each other.

My first run at this produced many problems.  The first was that the asteroids tended to stick to each other instead of bounce.  I found that this was because of rapidly changing velocities due to two asteroids colliding every single frame and the velocity changing so quickly that they didn't get out of each others way.  So instead of checking for collision, I tried to predict a collision.  For the purposes of the exercise, this works just fine.  It also allowed me to bounce the asteroids off of each other.  But it's not completely accurate.  Here's my code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import java.net.*;
import java.lang.Math;

public class MultiSprite extends JFrame implements Runnable, KeyListener {

   int screenWidth = 640;
   int screenHeight = 480;
   
   //double buffer objects
  BufferedImage backbuffer;
   Graphics2D g2d;
   
   int MAX = 5;
   Sprite[] asteroid = new Sprite[MAX];
   
   ImageEntity background;
   Thread gameloop;
   Random rand = new Random();
   
   boolean enterKeyPressed = false;
   
   public static void main(String[] args) {
      new MultiSprite();
   }
   
   public MultiSprite() {
      super("Sprite Test");
      setSize(640, 480);
      setVisible(true);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
      //create the back buffer for smooth graphics
     backbuffer = new BufferedImage(screenWidth, screenHeight, BufferedImage.TYPE_INT_RGB);
      g2d = backbuffer.createGraphics();
     
      //load the background
     background = new ImageEntity(this);
      background.load("bluespace.png");
     
      //load the asteroid sprites
     Point point;
      for (int n = 0; n<MAX; n++){
            asteroid[n] = new Sprite(this, g2d);
         asteroid[n].load("asteroid2.png");
         
         point = new Point(rand.nextInt(600)+20,
            rand.nextInt(440)+20);
         asteroid[n].setPosition(point);
         asteroid[n].setRotationRate(-5 + rand.nextInt(11));
         //asteroid[n].setFaceAngle(rand.nextInt(360));
        //asteroid[n].setMoveAngle(rand.nextInt(360));
        asteroid[n].setAlive(true);
         asteroid[n].setVelocity(new Point(-5 + rand.nextInt(11), -5 + rand.nextInt(11)));
      }
     
      enterKeyPressed = false;
      addKeyListener(this);

        gameloop = new Thread(this);
        gameloop.start();
   }
   
    public void run() {
        Thread t = Thread.currentThread();
        while (t == gameloop) {
            try {
                Thread.sleep(30);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
         
         //if game is paused
        if(!enterKeyPressed){
         
            //draw the background
           g2d.drawImage(background.getImage(), 0, 0, screenWidth-1,
               screenHeight-1, this);

            //draw asteroids  
           for(int n = 0; n < MAX; n++){
               if(asteroid[n].alive()) {
                  //asteroid[n].drawBounds(Color.YELLOW);
                 
                  //warp the asteroid at screen edges
                 if (asteroid[n].position().getX() < -50){
                     asteroid[n].setPosition(new Point(getSize().width + 50, (int)asteroid[n].position().getY()));
                  } else if (asteroid[n].position().getX() > getSize().width + 50){
                     asteroid[n].setPosition(new Point(-50, (int)asteroid[n].position().getY()));
                  }
                 
                  //warp the asteroid at screen edges
                 if (asteroid[n].position().getY() < -40){
                     asteroid[n].setPosition(new Point((int)asteroid[n].position().getX(), getSize().height + 40));
                  } else if (asteroid[n].position().getY() > getSize().height + 40){
                     asteroid[n].setPosition(new Point((int)asteroid[n].position().getX(), -40));
                  }
                 
                  CheckCollisions(n);
                 
                  asteroid[n].updatePosition();
                  asteroid[n].updateRotation();
                  asteroid[n].transform();
                  asteroid[n].draw();
               }
            }
            repaint();
         }
        }
    }
   
   public void CheckCollisions(int n){
      for(int x = 0; x < MAX; x++){
         if(x!=n && PredictCollision(asteroid[n], asteroid[x])){
            //we have predicted collision.
           Rectangle intersectRect = asteroid[n].getBounds().intersection(asteroid[x].getBounds());
           
            //collision on x axis: reverse x velocity
           if(intersectRect.getHeight() > intersectRect.getWidth()){
               asteroid[n].setVelocity(new Point(-1 * (int)asteroid[n].velocity().getX(), (int)asteroid[n].velocity().getY()));
               asteroid[x].setVelocity(new Point(-1 * (int)asteroid[x].velocity().getX(), (int)asteroid[x].velocity().getY()));
            }
           
            //collision on both axis equally: reverse x and y velocity
           if(intersectRect.getHeight() == intersectRect.getWidth()){
               asteroid[n].setVelocity(new Point(-1 * (int)asteroid[n].velocity().getX(), -1 * (int)asteroid[n].velocity().getY()));
               asteroid[x].setVelocity(new Point(-1 * (int)asteroid[x].velocity().getX(), -1 * (int)asteroid[x].velocity().getY()));
            }

            //collision on y axis: reverse y velocity
           if(intersectRect.getHeight() < intersectRect.getWidth()){
               asteroid[n].setVelocity(new Point((int)asteroid[n].velocity().getX(), -1 * (int)asteroid[n].velocity().getY()));
               asteroid[x].setVelocity(new Point((int)asteroid[x].velocity().getX(), -1 * (int)asteroid[x].velocity().getY()));
            }
         }
      }
   }
   
   public boolean PredictCollision(Sprite ast1, Sprite ast2){
      if(Math.abs((ast1.position().getX() + ast1.velocity().getX()) - (ast2.position().getX() + ast2.velocity().getX())) < 60 &&
         Math.abs((ast1.position().getY() + ast1.velocity().getY()) - (ast2.position().getY() + ast2.velocity().getY())) < 60){return true;}
      return false;
   }

    public void paint(Graphics g) {
        //draw the back buffer to the screen
       g.drawImage(backbuffer, 0, 0, this);
    }

   //handle keyboard events
   public void keyReleased(KeyEvent k) {}
    public void keyTyped(KeyEvent k) {}
    public void keyPressed(KeyEvent k) {
      switch(k.getKeyCode()){
         case KeyEvent.VK_ENTER:
            enterKeyPressed = !enterKeyPressed;
            break;
      }
   }
     
}


The two main methods to look at here are CheckCollisions and PredictCollision.  Notice how I'm just reversing velocities.  This seems to work ok except in instances where two asteroids are moving in the same direction,  but the one in front is moving slower than the one behind it.  When they collide, they both change course to move in the opposite direction whereas the one in front should get a boost and the one in back should slow down.

Does anyone have a better means of implementing this?  My best guess is that vector math is probably the route to go here.

Edit: I should note that the Sprite class used here contains the velocity valuesas well as a move angle and a face angle.  So I have both a speed and direction.
Offline philfrei
« Reply #1 - Posted 2011-09-09 18:48:26 »

I don't exactly have the best memories of that Harbour book. Perhaps this was because I worked through the 2nd edition, and the 3rd is better. Or perhaps this was because I was a rank beginner and there was a lot I had to learn before the book would make sense. Does he seem like a C-programmer writing Java to you, or is that a faulty memory?

Well, you can always add additional tests re positions and directions before doing calculating the new velocity. But vectors are a good way to go.

Also, simply reversing direction isn't even that accurate in the head-on case. If a fast object hits a slow one head-on, the fast should get the slow's velocity and the slow should get the fast one's velocity (not taking into account mass, off course).

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline Gingerious

Junior Member


Medals: 2



« Reply #2 - Posted 2011-09-09 20:41:04 »

I'd thought about adding more cases, but that seems like it's just trying to brute force it.  I feel there's probably a more elegant solution.

I'm not sure how this book compares to others.  It's my first for game programming.  It does a well-enough job telling someone how to set up their environment, which was a big deal to me because I've never had to before and most books say something along the lines of "just use netbeans".  This one talks about different text editors and IDEs, as well as how to make sure your command line will understand javac or java without having to type out the entire file path.  The book also shows you how things work in practice more than in theory, which i appreciate.

Also, it was free to me through my work. Smiley
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (12 views)
2014-04-15 18:08:23

BurntPizza (11 views)
2014-04-15 03:46:01

UprightPath (24 views)
2014-04-14 17:39:50

UprightPath (10 views)
2014-04-14 17:35:47

Porlus (27 views)
2014-04-14 15:48:38

tom_mai78101 (49 views)
2014-04-10 04:04:31

BurntPizza (108 views)
2014-04-08 23:06:04

tom_mai78101 (208 views)
2014-04-05 13:34:39

trollwarrior1 (176 views)
2014-04-04 12:06:45

CJLetsGame (182 views)
2014-04-01 02:16:10
List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:05:20
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!