C: Asteroids shot and asteroid collision detection

I realize my code is C but the section I have questions about is the same as C++ (I think).
I am having problems registering a hit when a shot is at point (1,1) and an asteroid is at point (0,0).
I am using a Makefile that looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CFLAGS = -g 
LDFLAGS += -lm -lglut -lGL

# need these flags on OSX
#CFLAGS += -I/usr/local/include
#LDFLAGS += -L/usr/local/lib -lglut -framework OpenGL

SRC = asteroids.c rgbcolors.c graphui.c

all: roids

asteroids:  $(SRC)
    gcc  $(CFLAGS) $(SRC) -o asteroids $(LDFLAGS)

clean:
    rm -f  asteroids *.o


The screen size is 1 by 1 with the top right being (1,1) and bottom left being (0,0). The ship starts with its center at (0.5, 0.5). I used the 8 ghost ships algorithm (each one screen length and or width away at N,S,E,W and NE, NW, SW, SE positions relative to center ship) for the toroidal effect (basically adding or subtracting 1.0 to the (x,y) coordinates of the center ship depending on position of ghost ship as described). Same thing was done for the asteroids. However, I am having problems with the collision detection between shots and asteroids in that a shot at (1,1) will not hit an asteroid at (0,0).
The conditional statement will return 1 (true) if it is a hit and 0 (false) if it is a miss.
Please take a look below and see why a shot at (1,1) will not hit an asteroid at (0,0).
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
int i=0, j=0;
    //covers 9 cases for 9 worlds but still not passing shot at (1,1) and roid at (0,0)
    for(i=-1; i<=1;i++)
    {
      for(j=-1; j<=1;j++)
      {
      if((shot->x+i) >= (roid->x+i)-(roid->width/2.0) && 
	       (shot->x+i) <= (roid->x+i) + (roid->width/2.0) &&
			(shot->y+j) >= (roid->y+j) - (roid->height/2.0) &&
			(shot->y+j) <= (roid->y+j) + (roid->height/2.0))
	    	{
	    		return 1;
	    	}
	  else
	  	continue;  	
	  }
    }  
	//try the corners
    //if a shot is in any corner and a roid is in any corner, it should register a hit
    if(shot->x==0 && shot->y==0 || shot->x == 0 && shot->y==1 || shot->x==1 && shot->y==0 || shot->x==1 || shot->y==1)//|| shot->x==1 && shot->y==0
    {	
        if(roid->x ==0 && roid->y==0 || roid->x==0 && roid->y==1 || roid->x==1 && roid->y==0 || roid->x==1 && roid->y ==1)
        {
            return 1;
        }
    }
		
    return 0;
Last edited on
I would think you check a shot at each integer location (assuming 1 = 1 pixel?) using the distance formula ... current position of shot (s) vs center of target (t) against radius of target (r).

that is

(sx-tx)*(sx-tx)+(sy-ty)*(sy-ty) <= r*r means it hit.

If the object is too irregular to use a radius, you can use a bounding box(or any geometric shape that suits you) or even a Boolean map representing pixels where true means something was there.

it depends on you whether exact hits are needed or approximates though. Exact hits, the Boolean map might be optimal. One way is if your graphics code has an unused alpha channel (rgba) you can use alpha this way.
The way you are doing it seems overly complicated (?).

as to your actual issue,
print out shot x,y and roid x,y and make sure they are what you think they are.
also try putting () around your logic to be sure ands and ors are correct. It looks like it should return 1 for the conditions you said. Still looking at it..


Last edited on
@jonnin, I don't think it's 1 pixel. The actual height and width is 700*700 but it is abstracted to 1*1. So top right is (1,1) and bottom left is (0,0).

The way it is now, it is checking whether the shot is inside the rectangle that represents an asteroid measuring the width and height from the center (x,y) coordinate of the rectangle.

I'll save your formula for when I change the shape to elliptical or circular I guess.



In lines 7-10, shot and roid are always in the same world. Isn't that negating the purpose of your 9-worlds scenario?
Try just roid->x, instead of roid->x+i etc, but leave shot->x+i as it is. Or do the opposite. However, one of roid and shot should not be moved into a different world ... if both are moved then (1,1) will never catch (0,0).

Your alternative approach of comparing doubles for precise equality (line 22) is also fraught with danger due to inexact representation.
Last edited on
gamers often approximate collisions, often with comical graphical flaws, but when done correctly, its fast and looks fine. We can skip that for now though.

Again:

print out shot x,y and roid x,y and make sure they are what you think they are.
also try putting () around your logic to be sure ands and ors are correct. It looks like it should return 1 for the conditions you said.

@lastchance thanks, it worked when I only modified shot and not roid. I think I get the logic now.

@jonnin, well noted. I should have done that sooner.
Topic archived. No new replies allowed.