[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [pygame] Background and collision detection in Lunar Lander game



At 05:28 PM 7/14/02 -0500, you wrote:
>I have written a simple Lunar lander type game in pygame.
>
>I now want to add a lunar surface with a designated landing area.
>
>I can do the surface as a BMP of course.  But I want an easy way to handle 
>collision detection.
>
>Is there any cookbook method for this?
>
>I thought about writing a program to convert the BMP into a set of 
>rectangles that could be used for collision detection.  I coul then put 
>those rectangles in a file, load the file at run time, and build a list.
>
>Two problems with that:  I do not know the format of a BMP.  And I think I 
>would get a LARGE number of rectangles on a 30x300 BMP file.

Here's how I would do it. I don't know much about your program's structure, 
so these are sort of educated guesses.

I'm going to make four assumptions:

1) your 'ground' is a surface generated randomly for each level.
2) the 'ground' is either all one colour (or the 'topmost' part of the 
ground is all one colour).
3) the surface of the ground has one sky/ground interface per column - ie, 
no tunnels or overhangs.
4) The lander is squarish in shape - most lander programs accomplish this 
by giving the lander legs that touch the bottom left and bottom right of 
its rect - so no pixel perfect collision detection is needed.

When I generate my ground surface at the beginning of each level, I'm going 
to create a list. This list will have one value for each x position - if my 
surface is 300 wide, it will have 300 values. The value is the 'height' of 
the ground in that column of pixels. The code might look something like this:

ground_surface = generate_random_ground_surface(difficulty_level)
ground_color = (128, 128, 128)  # medium grey
collision_points = []

for column in range(ground_surface.get_width()):
     for row in range(ground_surface.get_height()):
         if ground_surface.get_at((column, row)) == ground_color:
             collision_points.append(row)
             break

Ok. Now we have a list, 300 values long. Each value is the highest height 
of the ground in that column of pixels.

Each frame, I just have to check whether or not my spacecraft is _below_ 
the height of the ground.  I can optimize a little, since I only have to 
check against those parts of the ground that the spacecraft is _over_. It 
might look a little like this:

def is_colliding(lander_rect, collision_points):
     possible_collision_points = 
collision_points[lander_rect.left:lander_rect.right]
     for column_height in possible_collision_points:
         if lander_rect.bottom >= column_height:
             return 1
     return 0

Then I call it each frame:

if is_colliding(lander_rect, collision_points):
     lander_explode()

You can do the same as the whole thing above for the landing area too, just 
by making the landing area pixels a different colour from the rest of the 
ground - which is probably a good idea anyway; otherwise the player won't 
know where to land ;)

This code can be optimized of course, but I've tried to make it as clear as 
I can. Hope this helps.

David Clark
www.pygame.org/pcr

____________________________________
pygame mailing list
pygame-users@seul.org
http://pygame.seul.org