Thread: Python Game

    #1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2003
    Posts
    407
    Rep Power
    25

    Python Game


    not really sure if to put this in here or not? :S

    but anyway..

    im making a python game based on the ever popular game, Snake (or the Nokia phone), and im having trouble with the collision detection:

    here is my code

    Code:
    import pygame
    import random
    WIDTH = 640
    HEIGHT = 480
    SIZE = (WIDTH, HEIGHT)
    WHITE = 255, 255, 255  #RGB value for white; RGB for Black is 0,0,0
    RED = 255, 0, 0
    GREEN = 0,255,0
    BLUE = 0,0, 255
    DELAY = 10
    STEP = 5
    MAX_WAIT = 2000
    count = 0 # NAUGHTY GLOBAL VARIABLE; USED TO GENERATE THE RANDOM TURNS OF THE SNAKE
    
    #Begin User Entered Variables:
    CUR_SCORE = "0" # Start Current Score At 0 - This Can be updated
    #                                          Thru-out The Program
    
    BANG = pygame.image.load("bang.gif")
    
    #SNAKE CONSTANTS
    LINE = 5
    LEVEL = [5, 50, 100]  # length of snake in different levels
    SPEED = 30
    
    #WALL CONSTANTS
    THICKNESS = 10
    WALL_1 = pygame.Rect(120,95, 400, 10)
    WALL_2 = pygame.Rect(120, 395, 400, 10)
    WALLS = [WALL_1, WALL_2]
    
    direction = "d" # initial direction of motion
    
    def drawMenu():
        pygame.init()
        screen = pygame.display.set_mode( SIZE)
        background = pygame.Surface(screen.get_size())
        init(background)
        background = background.convert()
        screen.blit(background, (0,0))
        pygame.display.update()
        
        
        #Options Menu
        # Draw options - New Game
        color = (255, 255, 255)
        if self.menuSelect == 0:
                color = (0, 255, 0)
        textMenu = self.fontMenu.render("New Game", 1, color)
        textPosMenu = textMenu.get_rect()
        textPosMenu.bottom = background.get_rect().centery - textPosMenu.height
        textPosMenu.left = background.get_rect().centerx - textPosMenu.width/2
        screen.blit(textMenu, textPosMenu)
        lastBottom = textPosMenu.bottom
    
        # Draw options - High Score
        color = (255, 255, 255)
        if self.menuSelect == 1:
                color = (0, 255, 0)
        textMenu = self.fontMenu.render("High Scores", 1, color)
        textPosMenu = textMenu.get_rect()
        textPosMenu.top = lastBottom+10
        textPosMenu.left = background.get_rect().centerx - textPosMenu.width/2
        screen.blit(textMenu, textPosMenu)
        lastBottom = textPosMenu.bottom
    
        # Draw options - Quit
        color = (255, 255, 255)
        if self.menuSelect == 2:
                color = (0, 255, 0)
        textMenu = self.fontMenu.render("Quit", 1, color)
        textPosMenu = textMenu.get_rect()
        textPosMenu.top = lastBottom+10
        textPosMenu.left = background.get_rect().centerx - textPosMenu.width/2
        screen.blit(textMenu, textPosMenu)
        
    def getName():
        global name,scores, pscores
        print "Please Enter Your Name"
        name = raw_input()
        
    def highScore():
        global name,scores, pscores
        SCORES = [CUR_SCORE]
        NAMES = [name]
        for score in SCORES:
            file = open("scores.txt","a")
            file.write(score)
            for name in NAMES:
                file = open("scores.txt","a")
                file.write(name + "\n")
        file.close()
        #end high score loops
                
        file.close()
    
       
    
    def checkMove(coords):
        global direction, WIDTH, HEIGHT, dancing, count
        move = "go"
        theEvent = pygame.event.poll()
        eventType = theEvent.type
        if eventType == pygame.QUIT :
            move = "q"
        elif eventType == pygame.KEYDOWN:
            if theEvent.key == pygame.K_ESCAPE:
                move = "q"       
            count += 1
    
        #Keyboard Movement
        if eventType == pygame.KEYDOWN:
            if theEvent.key == pygame.K_UP:
                direction = "u"
            elif theEvent.key == pygame.K_RIGHT:
                direction = "r"
            elif theEvent.key == pygame.K_DOWN:
                direction = "d"
            elif theEvent.key == pygame.K_LEFT:
                direction = "l"
                #end What Key?
        #End KeyDown Checking
            
    
        if move != "q":
            move = moveTo(direction, coords)        
        
        return move
    
    # == end checkMove( ) =====
    
    def crashed(x, y, direction):
        # SYNTAX: Rect.collidepoint(x, y) -> bool;
        # collidepoint(x, y) returns True if x, y is inside the rectangle specified by Rect.
        crash = False
        if direction == "l":
            x = x - STEP
            if x < LINE/2:
                crash = True
        if direction == "r":
            x = x + STEP
            if x > SIZE[0] - LINE/2:
                crash = True
        if direction == "u":
            y = y - STEP
            if y < LINE/2:
                crash = True
        if direction == "d":
            y = y + STEP
            if y > SIZE[1] - LINE/2:
                crash = True
        for wall in WALLS:      # could use the same technique to detect if the snake crosses itself.
            if wall.collidepoint(x, y):
                crash = True
             
        return crash
    
    def moveTo(direction, coords):
        crash = "ok"
        if crashed(coords[0], coords[1], direction):
            crash = "boom"
        elif direction =="d":
            coords[1] += STEP
        elif direction == "u":
            coords[1] -= STEP
        elif direction == "l":
            coords[0] -= STEP
        elif direction == "r":
            coords[0] += STEP
        return crash
    
    def drawLine(screen, background, snake, oldX, oldY, usedRect):
        level = len(snake)
        # clear the end of the snake...
        rect = pygame.draw.line(screen, screen.get_at([oldX, oldY]),[oldX, oldY], snake[level -1], LINE)
        # rect represents the rectangle which was the last position of the snake's tail
        screen.blit(background, rect ,rect) # the covers up the tail with the corresponding rectangle from the background.
        for area in usedRect:
            screen.blit(BANG,area) # redraw the explosion in case the snake has crossed it.
        if level > 1:
            screen.fill(BLUE, pygame.draw.line(screen, BLUE, snake[0], snake[1], LINE)) # snake's head
        for i in range(1,level -1):
            screen.fill(GREEN, pygame.draw.line(screen, GREEN, snake[i], snake[i+1], LINE))
        pygame.display.flip()
         
        
    def displayImage(screen, back, centre, usedRect):
        for rect in usedRect:
            screen.blit(back, rect, rect) # cover up the rect from the corresponding bit of the background
            usedRect.remove(rect)
        x = centre[0]
        y = centre[1]
        if x >= WIDTH - (2*STEP):
            x -= 20
        if y >= HEIGHT - (2*STEP):
            y -= 20        
        rect = screen.blit(BANG, [x,y]) # draw the explosion
        usedRect.append(rect)           # remember where the explosion took place.
        pygame.display.flip()
        
    # == end displayImage( ) ====
    
    def update(list, newElement, limit):
        list.insert(0,newElement)
        if len(list) > limit:
            list.pop(limit)
            
    def init(screen):
        screen.fill(WHITE)
        for wall in WALLS:
            screen.fill(RED, wall)
    
    def main( ):
        global WIDTH, HEIGHT,SPEED, direction, snake
        
    # create background ==============
    # background represents the background image for the game. The snake is drawn on top of this background.
        pygame.init()
        screen = pygame.display.set_mode( SIZE)
        background = pygame.Surface(screen.get_size())
        init(background)
        background = background.convert()
        screen.blit(background, (0,0))
        pygame.display.update()
        
    # start the game ==================   
        move = "go"
        snake = []
        usedRect = [] # used to store the position of the last crash.
        x = random.randint(0, WIDTH)
        
        y = random.randint(0, HEIGHT)
       
        centre = [x,y]
        level = LEVEL[1]  # change speed and length of snake for harder levels
        update(snake, [x,y], level)
        move = checkMove(centre)
        update(snake, [centre[0], centre[1]], 0) # sneaky line; some understanding required.
    
        while move != "q":
            drawLine(screen, background, snake, x,y, usedRect)
            if move == "boom":
                displayImage(screen, background, centre, usedRect)
                
    
            pygame.time.delay(SPEED) # wait a bit to slow the snake down
            pygame.event.pump() # sychronise the event queue
            length = len(snake)
            x = snake[length-1][0] # current position of the tail of the snake
            y = snake[length-1][1]
            move = checkMove(centre)
            update(snake, [centre[0], centre[1]], level)
            
        #endwhile
        highScore()
        pygame.display.quit()
        print snake
        
    #end main( )
    
    # ======= call main( ) to start program ==========
    getName()
    drawMenu()
    main( )
    (the completed project wil be for my university assignment - and i do really apreciate the help!)
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2005
    Posts
    78
    Rep Power
    10
    Originally Posted by punkboii
    not really sure if to put this in here or not? :S

    but anyway..

    im making a python game based on the ever popular game, Snake (or the Nokia phone), and im having trouble with the collision detection:
    ...
    (the completed project wil be for my university assignment - and i do really apreciate the help!)
    Ok .. you haven't gotten a response up till now... one of the reasons is that your code is big and somewhat horrible (small and somewhat horrible is easier to cope with ;-)

    Some comments - I may not solve your particular problem, but I can help you make it easier for yourself, or someone who will...

    1/ Unless your professor has mandated javaNamingStyle, use python_naming_style [when in Rome...]. If your professor HAS mandated javaNamingStyle, consider drawing their attention to PEP8...

    2/ using crash="ok"/"boom" is _bad_ style. return True/False or raise an exception.

    3/ Using global variables, especially a lot of global variables, generally indicates poor design. Either you need to pass parameters, or you need an object.

    4/ If your problem is with collision detection, don't post hundreds of lines of menu and scoring code. Post a stripped-down version which just launches the actual game when run...

    5/ The comment "# sneaky line; some understanding required." is rather unhelpful. It's nice that understanding is needed, but would you like to share?

    6/ main() has far too much code in it. A sample main (assuming objects weren't used - which they probably should be) would be:
    Code:
    def main():
        initialise()
        start_menu()
        shutdown()
    7/ drawMenu repeats a lot of code. If you have this kind of repetition it means that you should turn the repetition into either:
    • a function
    • a loop
    • an object

    Which one you pick depends on your preferred coding style.

    8/ consider that what a move really provides is a delta - either (0,1), (0,-1), (1,0) or (-1,0) for (x, y)... so your movement and crash detection code could be simplified to ONE modification for x and y, and ONE check for out of bounds (ie: once you have the delta, you don't need to branch on the direction any more, so you don't need direction="u", etc...)

    --OH.

    Comments on this post

    • wx_uab agrees
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Feb 2004
    Location
    London, England
    Posts
    1,585
    Rep Power
    1373
    Originally Posted by hydroxide
    Ok .. you haven't gotten a response up till now... one of the reasons is that your code is big and somewhat horrible (small and somewhat horrible is easier to cope with ;-)
    the other reason he did not get a reply is that he did not ask a question. Posting up a large blob of code with no indication of what is wrong with it or what he wants us to do with it is a good way to get people to ignore it and move on to the next post. Even asking for people to comment on the code and suggest ways of improving it would have helped.

    BTW, I agree with all of hydroxide's comments. I suggest reading a good book on software design - I recommend 'Refactoring' by Martin Fowler.

    Dave

IMN logo majestic logo threadwatch logo seochat tools logo