Jump to content
  • Advertisement
Sign in to follow this  
daviangel

Pygame easy as Py

This topic is 4234 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

OK I'm thinking of starting my own Python/Pygame tutorial in this thread in part to help myself and others who are currently working with Python/Pygame. This came about due to the fact that I finally found a language/graphics API I can make 2D games in a reasonable amount of time and I hope to show that here. Also, it's an attempt to weed out the bugs in my personal pygame engine I dubbed gameEngine and you can see the bug here in this thread. So I'm gonna start all over from scratch without using my custom gameEngine and build up my Pirates clone in python/pgame. That was my main motivation was for learning to program in the first place to make a 2D pirates clone that I could customize to my taste. Also, by posting my progress here I will be able to keep track of how long it takes me since I will be adding little by little as I can find the time to do so. Anyways, lets get started and if anyone wants to add anything feel free to! First you need to have Python and pygame installed for your platform. I'm using Python 2.5.1 and pygame 1.7.1. I don't know if there is a 64bit version of pygame or how hard it would be to compile it from source so all this is on 32bit WinXP but if anyone knows about 64bit pygame support let me know. Now that we have Python and pygame installed the first thing you should do is make sure they are installed and working so do this: 1. Get into Python by using the command line or IDLE to get to the Python interactive shell. 2. Use the following command to import pygame into Python import pygame If pygame is installed correctly nothing will happen. If you get an error message on the other hand you pygame is not installed correctly and you'll need to fix it before you do anything else Pygame helps you easily create game in Python by providing the following: Display- a graphical display Surface- a rectangular area that contains an image Rect- used to determine size of objects and to detect whether 2 objects collide Input modules- lets the user interact with pygame using a mouse,keyboard or joystick Output modules- provides ways to send information back to the user includes audio output for background music and sound effects Utility modules- more modules to help make game programming easier like transformation functions that let you scale and rotate images, manage fonts, working with time I will use the IDEA/ALTER(dibbs to Andy Harris for this) acronoyms as a simple way to remeber all the details that go into getting a game started. Here's what it stands for: I-Import and Initialize D-Display E-Entitites A-Action A-Assign values L-Loop T-Time E-Events R-Refresh screen It's alot to remeber but onece you understand this basic framework you can use it for every game you write. Now I'm gonna break down the above even more so it makes more sense: I-Import and Initialize 1.Be sure pygame is installed on machine 2.Tell Python you gonna use pygame library import pygame 3.Initialize pygame pyame.init() D-Display 1.Create variable to represent the display screen 2.Call pygame.display.set_mode() function 3.Determine the size or resolution of screen 4.Specify any other parameters 5.Set up screen caption with display.set_caption() E-Entitites(things moving about on screen) 1.Create a variable called background to hold the background 2.Use pygame.Surface() to build a Surface object background = pygame.Surface(screen.get_size()) 3.Make the background the same size as the display 4.Convert the background to standard color format using convert() 5.Copy the converted image back to the background background = background.convert() 6.Change the color of the background background.fill((0,0,255)) # note using R,G,B values here A-Action(includes main or game loop) A-Alter Assign values to key variables 1.Create clock variable clock.pygame.time.Clock() 2.Create Boolean to manage game loop keepGoing = True L-Loop 1.Any time you want to end game set keepGoing to False while keepGoing: T-Time 1.Use tick() method to set maximum frame rate 30fps in our case clock.tick(30) E-Events 1.Get list of events that happened during this frame pygame.event.get() 2.Step through each element in the event list for event in pygame.event.get(): 3.Check the event type for now we are just looking for QUIT if event.type == pygame.QUIT: 4.Write some code for the event keepGoing = False R-Refresh screen Finally we get to see our hard work displayed to the screen in this step! To display the screen: 1.Copy the background image to screen using the screen.blit() method screen.blit(background,(0,0)) 2.Copy any foreground images to the screen using screen.blit() This means the first thing you draw will be on the bottom and successive images will appear on top 3.Flip the display - copies screen buffer to display hardware pygame.display.flip() The code for our first pygame program follows:
""" idea.py
    Simplest possible pygame display
    Demonstrates IDEA/ALTER model
    Note: Don't try to run any pygame stuff
    within IDLE will lockup!
    Jaime Moreno
    4/2/07
    """

#I - Import and initialize
import pygame
pygame.init()

#D - Display configuration
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption("Hello, world!")

#E - Entities (just background for now)
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((100,60,25))

#A - Action (broken into ALTER steps)

  #A - Assign values to key variables
clock = pygame.time.Clock()
keepGoing = True

  #L - Set up main loop
while keepGoing:
    #T - Timer to set frame rate
    clock.tick(30)

    #E - Event handling
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            keepGoing = False

    #R - Refresh display
    screen.blit(background, (0,0))
    pygame.display.flip()

# end main game loop





Copy the above sourcecode into a file and save it. I saved mine as idea.py as you can see in the comments. Now run it by either double-clicking on the file and if everything is setup correctly it will automatically run. If not go to your commandline and I assume Python is in your path and just type: python idea.py You should end up with something like the following image Image Hosted by ImageShack.us You can modify the following line to change the backround color background.fill((0,0,255))-will give you a blue background for example,etc : [Edited by - daviangel on July 19, 2007 8:58:20 PM]

Share this post


Link to post
Share on other sites
Advertisement
Excellent, just so im clear this is a tutorial for 2D game with python right?

Share this post


Link to post
Share on other sites
Quote:
Original post by Epiq
Excellent, just so im clear this is a tutorial for 2D game with python right?

Yup, I'm keeping is as simple as possible so no 3D only 2D.

Share this post


Link to post
Share on other sites
Ok now I'm going to show you how to display a jpg,bmp or any other supported format image file in pygame.
As you can see it's only like one or 2 new lines of code to our original code.
I wrapped the original idea program in a main function too. If you've done any amount of Python programming you should already know that you should put everything in a main function and put
if __name__ == "__main__":
main()
at the end of your code so it doesn't automatically run if it's imported as a module in some other Python code.
Otherwise it's just a matter of using pygame.image.load() function to load your desired image like so:
image = pygame.image.load("openingScreen.bmp") # use whatever image you have and make sure it's in the same directory or program will crash since no error checking done at all to keep code simple.
Also remeber to use convert() right after you load an image or will suffer a perfomance hit. Only time you would not use convert() is if you are making a paint or image processing program which we are not!
Finally, remember to blit the image on top of the background:
screen.blit(image, (0,0))

""" image.py
Illustrates drawing an imported image
Simplest possible pygame display
Demonstrates IDEA/ALTER model
Note: Don't try to run any pygame stuff
within IDLE will lockup!
Jaime Moreno
4/2/07
"""


#I - Import and initialize still in global scope
import pygame
pygame.init()

def main():
#D - Display configuration
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption("Display an image")

#E - Entities (just background for now)
background = pygame.Surface(screen.get_size())
background = background.convert() # don't use for image editors
background.fill((255,255,0))

# note lack of error checking if image not there program will crash!
image = pygame.image.load("openingScreen.bmp")
image = image.convert()

#A - Action (broken into ALTER steps)

#A - Assign values to key variables
clock = pygame.time.Clock()
keepGoing = True

#L - Set up main loop
while keepGoing:
#T - Timer to set frame rate
clock.tick(30)

#E - Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False

#R - Refresh display
screen.blit(background, (0,0))
#screen.blit(image, (250, 150))
screen.blit(image, (0,0))

pygame.display.flip()

# end main game loop
# Run main if this is the primary program
# Note use of 2 underscores
if __name__ == "__main__":
main() # call main function here



You should get your image displayed on the screen if everything goes right like this:


p.s. Once you got this program up and running try using screen.blit(image, (250, 150)) instead of screen.blit(image, (0,0)) and try to figure out what's happening. Hint:I gave the answer in my first post.

Share this post


Link to post
Share on other sites
Ok static images are lots of fun but moving stuff ie animation is even more so today I'm going to show you how to add animation to our simplistic IDEA/ALTER pygame framework.
All you need to do is add a few things like:
1. Build the object that will move usually outside the game loop in the entities otherwise your performance will suffer since you will be creating your object every frame ie 30 times a second!
2. Modify object data. That is create variables to hold your object's x and y values and then change them
3. Check for boundaries
Any time you move something you should see if it moved off the screen and if it do something about it. In this example we will use what they call Wrapping.
4. Refresh the screen.
Inside your game loop draw your object to the new position once it's updated

This is the source for today's example:
[source lang ="python"]
""" moveBox.py
Illustrates basic motion using pygame
Uses IDEA/ALTER model
Note: Don't try to run any pygame stuff
within IDLE will lockup!
Jaime Moreno
4/2/07
"""

#I - Import and initialize
import pygame
pygame.init()

#D - Display configuration
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption("move a box!")

#E - Entities (just background for now)
# yellow background
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((255,255,0))

# make a red 25x25 box
box = pygame.Surface((25,25))
box = box.convert()
box.fill((255,0,0)) # red box

# set up some box variables
box_x = 0
box_y = 200


#A - Action (broken into ALTER steps)

#A - Assign values to key variables
clock = pygame.time.Clock()
keepGoing = True

#L - Set up main loop
while keepGoing:
#T - Timer to set frame rate
clock.tick(30)

#E - Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False

#modify box value
box_x += 5
#check boundaries
if box_x > screen.get_width():
box_x = 0

#R - Refresh display
screen.blit(background, (0,0))
screen.blit(box,(box_x,box_y))
pygame.display.flip()

# end main game loop


The code should be self explanatory from the comments. The only thing that might throw you for aloop is that computers don't use the standard Cartesian coordinate system you used in math so y is not postive going up and the origin(0,0) is not the center of your computer screen!
The origin is at the upper left of your screen
x increases as you move from left to right
the largest value for x is screen.get_width()
y increases downward!
the largest value for y is screen.get_height()

You should get something like the following picture except you can't see the box moving of course
Image Hosted by ImageShack.us

Share this post


Link to post
Share on other sites
Ok I was having 2nd thoughts about even posting this code since I really don't plan on using pygames drawing commands much in my game and don't care for them but I'm going to show them just in case someone needs them:

""" drawDemo.py
Illustrates pygame's drawing functions
Simplest possible pygame display
Demonstrates IDEA/ALTER model
Note: Don't try to run any pygame stuff
within IDLE will lockup!
Jaime Moreno
4/2/07
"""


#I - Import and initialize still in global scope
import pygame, math # note we added math to get access for math.pi which we use in drawing arc
pygame.init()

def drawStuff(background):
""" given a surface, draws a bunch of things on it """

# draw a line from (5,100) to (100,100)
pygame.draw.line(background, (255,0,0), (5,100), (100,100))

# draw an unfilled square
pygame.draw.rect(background, (0,255,0), ((200,5), (100,100)),3)

# draw a filled circle
pygame.draw.circle(background, (0,0,255), (400,50), 45)

# draw an arc
pygame.draw.arc(background, (0,0,0), ((5,150), (100,100)),0, math.pi/2, 5)

# draw an ellipse
pygame.draw.ellipse(background, (0xCC, 0xCC, 0x00), ((150,150), (150,100)),0)
# note use of hex color codes in line above if you are into hex instead of RGB values

# draw lines
points = (
(370,160),
(370,237),
(372,193),
(411,194),
(412,237),
(412,160),
(412,237),
(432,227),
(436,196),
(433,230)
)

pygame.draw.lines(background, (0xFF, 0x00, 0x00), False, points, 3)

# draw polygon
points = (
(137,372),
(232,319),
(383,335),
(442,389),
(347,432),
(259,379),
(220,439),
(132,392)
)

pygame.draw.polygon(background, (0x33,0xff,0x33), points)

# compare normal and anti-aliased diagonal lines
pygame.draw.line(background, (0,0,0), (480,425), (550,325),1)

pygame.draw.aaline(background, (0,0,0), (500,425), (570,325), 1)




def main():
#D - Display configuration
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption("Drawing commands")

#E - Entities (just background for now)
background = pygame.Surface(screen.get_size())
background = background.convert() # don't use for image editors
background.fill((255,255,255))

drawStuff(background)
#A - Action (broken into ALTER steps)

#A - Assign values to key variables
clock = pygame.time.Clock()
keepGoing = True

#L - Set up main loop
while keepGoing:
#T - Timer to set frame rate
clock.tick(30)

#E - Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
elif event.type == pygame.MOUSEBUTTONUP:
print pygame.mouse.get_pos() # useful for debugging

#R - Refresh display
screen.blit(background, (0,0))
pygame.display.flip()

# end main game loop
# Run main if this is the primary program
# Note use of 2 underscores
if __name__ == "__main__":
main() # call main function here


As you can see you probably will need graph paper or some other method to use alot of these commands and even at that I feel it's too much work using 10 or more lines just to specify the points you are going to draw. Actually, if you end up doing any VB/C# system.drawing stuff it's pretty similar and alot more work.
The only thing I really found intersting in the above code is how you can check the mouse position for debugging purposes in the same loop we are checking for a quit command.
If you really want to know more about pygame's available drawing command and how they work just type help("pygame.draw") in a python idle to see what's available.
Oh and here's my screenshot:
Free Image Hosting at www.ImageShack.us

Share this post


Link to post
Share on other sites
Ok since I started getting into getting input from the user in the last post I'm going to post a more thorough example on reading the keyboard and mouse:

""" basicEvents.py
Demonstrates essential mouse
and keyboard events
Only reads one keypress at a time so
key combinations like ctrl+key won't work
Simplest possible pygame display
Demonstrates IDEA/ALTER model
Note: Don't try to run any pygame stuff
within IDLE will lockup!
Jaime Moreno
4/4/07
"""


#I - Import and initialize still in global scope
import pygame
pygame.init()

def main():
#D - Display configuration
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption("Press mouse and keys - look for output in console")

#E - Entities (just background for now)
background = pygame.Surface(screen.get_size())
background = background.convert() # don't use for image editors
background.fill(pygame.color.Color("yellow"))

#A - Action (broken into ALTER steps)

#A - Assign values to key variables
clock = pygame.time.Clock()
keepGoing = True

#L - Set up main loop
while keepGoing:
#T - Timer to set frame rate
clock.tick(30)

#E - Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
elif event.type == pygame.KEYDOWN:
keyName = pygame.key.name(event.key)
print "key pressed:", keyName
if event.key == pygame.K_ESCAPE:
keepGoing = False
elif event.type == pygame.MOUSEBUTTONDOWN:
print "mouse down:",
pygame.mouse.get_pos()
elif event.type == pygame.MOUSEBUTTONUP:
print "mouse up:", pygame.mouse.get_pos()


#R - Refresh display
screen.blit(background, (0,0))
pygame.display.flip()

# end main game loop
# Run main if this is the primary program
# Note use of 2 underscores
if __name__ == "__main__":
main() # call main function here



Use help("pygame") once again and look at the very end where it says DATA and you'll get a list of all the keyboard constants.

Share this post


Link to post
Share on other sites
Ok I wanted to give an example of what use the drawing functions can be even though I'm not planning on using them in my game I think:

""" lines.py
combine event handling and
drawing commands to build
a prototype drawing program """


import pygame
pygame.init()

def main():
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Draw lines with the mouse")

background = pygame.Surface(screen.get_size())
background.fill((255, 255,255))

clock = pygame.time.Clock()
keepGoing = True
preview = False
lineStart = (0, 0)
lineEnd = (0, 0)

while(keepGoing):
clock.tick(30)

for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
elif event.type == pygame.MOUSEBUTTONDOWN:
lineStart = pygame.mouse.get_pos()
preview = True
elif event.type == pygame.MOUSEBUTTONUP:
lineEnd = pygame.mouse.get_pos()
pygame.draw.line(background, (0, 0, 0), lineStart, lineEnd, 3)
preview = False
elif event.type == pygame.MOUSEMOTION:
lineEnd = pygame.mouse.get_pos()


screen.blit(background, (0, 0))
if preview:
pygame.draw.line(screen, (100, 100, 100), lineStart, lineEnd, 1)

pygame.display.flip()

if __name__ == "__main__":
main()



The only new thing is that if you hold the mouse down the line is temporarily drawn to the screen(giving you a cool preview effect) which will disappear as soon as you release the mouse.

Share this post


Link to post
Share on other sites
Ok I think I've covered enough preliminaries so that anyone that's been programming Python for any amount of time should be able to decipher version 1.0 of my Pirates game!
Here it is:


""" pirates.py
Pirates version 1.0
First complete arcade game
made with Python and Pygame
move ship with mouse
deliver piracy to islands,
avoid thunderstorms.
Each island you plunder adds to your score.
Each cloud you hit is a hurricane and causes you to lose a ship.

Jaime Moreno
4/25/07
"""

#I - Import and initialize still in global scope

import pygame, random
pygame.init()

#D - Display configuration
resolution = (800,600)
screen = pygame.display.set_mode(resolution)

#E - Entities (now contained in their own classes now
# overall IDEA/ALTER game framework still intact though
# we do have 2 alter's due to adding intro screen and game state

class Ship(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("ship.gif")
self.image = self.image.convert()
self.rect = self.image.get_rect()

def update(self):
mousex, mousey = pygame.mouse.get_pos()
self.rect.center = (mousex, 430)

class Island(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("island.gif")
self.image = self.image.convert()
self.rect = self.image.get_rect()
self.reset()

self.dy = 5 # sets islands to move down screen and note speed is same as background scrolling ocean

def update(self):
self.rect.centery += self.dy
if self.rect.top > screen.get_height(): # makes islands wrap around to top
self.reset()

def reset(self):
self.rect.top = 0
self.rect.centerx = random.randrange(0, screen.get_width()) # we don't want islands appearing at same spot all time

class Cloud(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Cloud.gif")
self.image = self.image.convert()
self.rect = self.image.get_rect()
self.reset()

def update(self):
self.rect.centerx += self.dx
self.rect.centery += self.dy
if self.rect.top > screen.get_height():
self.reset()

def reset(self):
self.rect.bottom = 0
self.rect.centerx = random.randrange(0, screen.get_width())
# set clouds to move in random directions at random speeds
self.dy = random.randrange(5, 10)
self.dx = random.randrange(-2, 2)

class Ocean(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("ocean.gif")
self.rect = self.image.get_rect()
self.dy = 5
self.reset()

def update(self):
self.rect.bottom += self.dy
# scrolling trick
# fool the player's eyesight into thinking the ocean background is infinite

if self.rect.bottom >= 1440:
self.reset()

def reset(self):
self.rect.top = -960

class Scoreboard(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.lives = 5
self.score = 0
self.font = pygame.font.SysFont("None", 50)

def update(self):
self.text = "ships: %d, score: %d" % (self.lives, self.score)
yellow = (255, 255, 0)
self.image = self.font.render(self.text, 1, yellow)
self.rect = self.image.get_rect()

def game():
pygame.display.set_caption("Pirates v 1.0 by Jaime!")

background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0, 0))
ship = Ship()

island = Island()
#can add more or less clouds here to make game harder or easier
cloud1 = Cloud()
cloud2 = Cloud()
cloud3 = Cloud()
ocean = Ocean()
scoreboard = Scoreboard()

friendSprites = pygame.sprite.Group(ocean, island, ship)
cloudSprites = pygame.sprite.Group(cloud1, cloud2, cloud3)
scoreSprite = pygame.sprite.Group(scoreboard)

clock = pygame.time.Clock()
#A - Action (broken into ALTER steps)
#A - Assign values to key variables
keepGoing = True
#L - Set up main loop
while keepGoing:
#T - Timer to set frame rate
clock.tick(30)
pygame.mouse.set_visible(False)
#E - Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False


#check collisions

if ship.rect.colliderect(island.rect):

island.reset()
scoreboard.score += 100

hitClouds = pygame.sprite.spritecollide(ship, cloudSprites, False)
if hitClouds:

scoreboard.lives -= 1
if scoreboard.lives <= 0:
keepGoing = False
for theCloud in hitClouds:
theCloud.reset()

friendSprites.update()
cloudSprites.update()
scoreSprite.update()

friendSprites.draw(screen)
cloudSprites.draw(screen)
scoreSprite.draw(screen)
#R - Refresh display
pygame.display.flip()


#return mouse cursor
pygame.mouse.set_visible(True)
return scoreboard.score

def instructions(score):
pygame.display.set_caption("Pirates v 1.0 by Jaime!")

ship = Ship()
ocean = Ocean()

allSprites = pygame.sprite.Group(ocean, ship)
insFont = pygame.font.SysFont(None, 50)
insLabels = []
instructions = (
"Pirates. Last score: %d" % score ,
"Instructions: You are a Pirate,",
"delivering terror to the islands.",
"",
"Sail over an island to plunder it,",
"but be careful not to sail too close",
"to the clouds. Your ship will fall ",
"apart if it is hit by lightning too",
"many times. Steer with the mouse.",
"",
"good luck!",
"",
"click to start, escape to quit..."
)

for line in instructions:
yellow = (255, 255, 0)
tempLabel = insFont.render(line, 1, yellow)
insLabels.append(tempLabel)

#A - Action (broken into ALTER steps)

#A - Assign values to key variables
keepGoing = True
clock = pygame.time.Clock()
pygame.mouse.set_visible(False)
#L - Set up main loop
while keepGoing:
#T - Timer to set frame rate
clock.tick(30)
#E - Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
donePlaying = True
if event.type == pygame.MOUSEBUTTONDOWN:
keepGoing = False
donePlaying = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
keepGoing = False
donePlaying = True

allSprites.update()
allSprites.draw(screen)

for i in range(len(insLabels)):
screen.blit(insLabels, (50, 30*i))
#R - Refresh display
pygame.display.flip()


pygame.mouse.set_visible(True)
return donePlaying

def main():
donePlaying = False
score = 0
while not donePlaying:
donePlaying = instructions(score)
if not donePlaying:
score = game()


if __name__ == "__main__":
main()


And here's the screen shot of the introduction screen
Image Hosted by ImageShack.us

Notice how I added classes for all the main game entities like ship,ocean,island,cloud etc.
Each of them have a constructor, and update and reset method.
The only thing that I didn't really cover is using pygame.font but it's shouldn't be too hard to figure out.
The only tricky stuff really is creating the artwork for the game and to make the illusion of a scrolling background you need to make a background image that is way longer than it is wide(800x1800 for ocean.gif) so the player won't notice you are just recycling the same image over and over. Also make sure to modify the wrap code for the background image appropriately.
I know this was short on explanation but after taking a couple of days off I really wanted to get my Pirate version 1 at least up and running!






Share this post


Link to post
Share on other sites
Looking back at my last post I just realized I totally forgot to talk about one of the most important things you will need to learn to make games no matter what language you use-collision detection!
Unlike alot of other languages where you have to write your own collision detection routines pygames makes it as easy as using the colliderect() method of a Rect object. If two rects are overlapping, the method returns true hence a collision. The following code shows how to use it:

""" spriteSprite.py
demonstrates a simple sprite - sprite
collision using rect's collision method
use mouse to move circle around and test for collisions
"""


import pygame, random
pygame.init()



class Square(pygame.sprite.Sprite):
""" makes a box with a random starting
position and the given color.
To make a red square, use
redSquare = Square((255, 0, 0))

requires screen be predefined and import random """


def __init__(self, color, screen):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.centerx = random.randrange(0, screen.get_width())
self.rect.centery = random.randrange(0, screen.get_height())

class Circle(pygame.sprite.Sprite):
""" makes a blue circle that
follows the mouse. """


def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image.fill((255, 255, 255))
pygame.draw.circle(self.image, (0, 0, 255), (25, 25), 25, 0)
self.rect = self.image.get_rect()

def update(self):
self.rect.center = pygame.mouse.get_pos()

class TransCircle(Circle):
""" extended collisionObjects circle with colorkey
transparency. """

def __init__(self):
Circle.__init__(self)
self.image.set_colorkey((255,255,255))


class Label(pygame.sprite.Sprite):
""" Label Class (simplest version)
Attributes:
font: any pygame font object
text: text to display
center: desired position of label center (x, y)
"""

def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.font = pygame.font.SysFont("None", 30)
self.text = ""
self.center = (320, 240)

def update(self):
self.image = self.font.render(self.text, 1, (0, 0, 0))
self.rect = self.image.get_rect()
self.rect.center = self.center



def main():
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("sprite - to - sprite collision")

background = pygame.Surface(screen.get_size())
background.fill((255, 255, 255))
screen.blit(background, (0, 0))

lblOutput = Label()
lblOutput.center = (100, 50)
lblOutput.text = "Hi"

circle = Circle()
square = Square((0, 255, 0), screen)

allSprites = pygame.sprite.Group(square, circle, lblOutput)

keepGoing = True
clock = pygame.time.Clock()
pygame.mouse.set_visible(False)
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
# Use special colliderect() method of Rect object to test for collision
if circle.rect.colliderect(square.rect):
lblOutput.text = "Collision"
else:
lblOutput.text = "No collision"

allSprites.clear(screen, background)
allSprites.update()
allSprites.draw(screen)

pygame.display.flip()
pygame.mouse.set_visible(True)

if __name__ == "__main__":
main()





Ok now what if you have alot of objects to check for collisions? Using the above example it's still pretty simple but you'll end up with alot of repeated code and gets pretty old and tiring.
In this case pygame comes to the rescue once again with the pygame.sprite.spritecollide() function. It looks for all possible collisions between a sprite and all other sprites in a group so to use it you need to put your game objects into sprite groups as the following program shows:

""" spriteGroup.py
shows how to check for a
collision between a sprite and
a group
Movable circle coming in really handy now
to test for collisions
Also using sprite.spritecollide() instead of rect.colliderect()
This one uses TransCircle instead of Circle for transparent collisions!
Jaime Moreno
4/7/07
"""


import pygame, random
pygame.init()



class Square(pygame.sprite.Sprite):
""" makes a box with a random starting
position and the given color.
To make a red square, use
redSquare = Square((255, 0, 0))

requires screen be predefined and import random """


def __init__(self, color, screen):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.centerx = random.randrange(0, screen.get_width())
self.rect.centery = random.randrange(0, screen.get_height())

class Circle(pygame.sprite.Sprite):
""" makes a blue circle that
follows the mouse. """


def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image.fill((255, 255, 255))
pygame.draw.circle(self.image, (0, 0, 255), (25, 25), 25, 0)
self.rect = self.image.get_rect()

def update(self):
self.rect.center = pygame.mouse.get_pos()

class TransCircle(Circle):
""" extended collisionObjects circle with colorkey
transparency. """

def __init__(self):
Circle.__init__(self)
self.image.set_colorkey((255,255,255))


class Label(pygame.sprite.Sprite):
""" Label Class (simplest version)
Attributes:
font: any pygame font object
text: text to display
center: desired position of label center (x, y)
"""

def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.font = pygame.font.SysFont("None", 30)
self.text = ""
self.center = (320, 240)

def update(self):
self.image = self.font.render(self.text, 1, (0, 0, 0))
self.rect = self.image.get_rect()
self.rect.center = self.center

def main():
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("colliding with a group")

background = pygame.Surface(screen.get_size())
background.fill((255, 255, 255))
screen.blit(background, (0, 0))

lblOutput = Label()
lblOutput.text = "Hi"
lblOutput.center = (100, 50)

circle = Circle()
# make 10 red squares at random locations
squares = []
for i in range(10):
square = Square((255, 0, 0), screen)
squares.append(square) # add square to list

basicSprites = pygame.sprite.Group(circle, lblOutput)
squareGroup = pygame.sprite.Group(squares)

keepGoing = True
clock = pygame.time.Clock()
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False

if pygame.sprite.spritecollide(circle, squareGroup, False): # set to True to have object die
lblOutput.text = "Collision"
else:
lblOutput.text = "No collision"

squareGroup.clear(screen, background)
basicSprites.clear(screen, background)

squareGroup.update()
basicSprites.update()

squareGroup.draw(screen)
basicSprites.draw(screen)

pygame.display.flip()

if __name__ == "__main__":
main()



Finally some things to remember about collisions using pygame:
all sprites are rectangular
pygame uses bounding-box collision detection
what this all means is that sometimes you will register a collision even though you can see on the screen that the objects are not actually touching(but their bounding boxes are!).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!