python game

Discussion in 'Python' started by jacksonkemp1234@gmail.com, Jun 19, 2013.

  1. Guest

    I made this game where you move a player over bears, but the bears keep loading over the plaeyer making it hard to see it, also when i move down the player goes down to the right

    here is my code:

    import pygame, sys, random
    from pygame.locals import *
    from threading import Timer

    #set up pygame
    pygame.init()
    mainClock = pygame.time.Clock()

    #set up the window
    WINDOW_WIDTH = 400
    WINDOW_HEIGHT = 400
    windowSurface = pygame.display.set_mode((WINDOW_WIDTH,
    WINDOW_HEIGHT),0)
    pygame.display.set_caption('Get the Bears')

    #set up color constants
    BLACK = (0,0,0)
    BLUE = (0, 0, 255)
    #set winning text
    textFont = pygame.font.SysFont("impact", 60)
    text = textFont.render("YOU WIN!", True, (193, 0, 0))

    #set up the player and bear data structures
    bearCounter = 0
    NEW_BEAR = 40
    BEAR_SIZE = 64
    playerImage = pygame.image.load('hunter.png')
    bearImage = pygame.image.load('bear.png')

    player = pygame.Rect(300, 100, 40, 40)
    bears = []
    for i in range(20):
    bears.append(pygame.Rect(random.randint(0, WINDOW_WIDTH - BEAR_SIZE),
    random.randint(0, WINDOW_HEIGHT - BEAR_SIZE),
    BEAR_SIZE, BEAR_SIZE))
    #movement variables
    moveLeft = False
    moveRight = False
    moveDown = False
    moveUp = False

    MOVE_SPEED = 15

    #run the game loop
    startGame = True
    while startGame == True:
    #check for quit
    for event in pygame.event.get():
    if event.type == QUIT:
    pygame.quit()
    sys.exit()
    if event.type == KEYDOWN:
    #keyboard variables
    if event.key == K_LEFT:
    moveRight = False
    moveLeft = True
    if event.key == K_RIGHT:
    moveRight = True
    moveLeft = False
    if event.key == K_UP:
    moveUp = True
    moveDown = False
    if event.key == K_DOWN:
    moveUp = False
    moveDown = True
    if event.type == KEYUP:
    if event.key == K_ESCAPE:
    pygame.quit()
    sys.exit()
    if event.key == K_LEFT:
    moveLeft = False;
    if event.key == K_RIGHT:
    moveRight = False;
    if event.key == K_UP:
    moveUp = False;
    if event.key == K_DOWN:
    moveDown = False;

    bearCounter += 1
    if bearCounter >= NEW_BEAR:
    #clear bear array and add new bears
    bearCounter = 0
    bears.append(pygame.Rect(random.randint(0, WINDOW_WIDTH - BEAR_SIZE),
    random.randint(0, WINDOW_HEIGHT - BEAR_SIZE),
    BEAR_SIZE, BEAR_SIZE))
    #draw black background
    windowSurface.fill(BLACK)

    #move player
    if moveDown and player.bottom < WINDOW_HEIGHT:
    player.top += MOVE_SPEED
    if moveUp and player.top > 0:
    player.top -= MOVE_SPEED
    if moveLeft and player.left > 0:
    player.left -= MOVE_SPEED
    if moveDown and player.right < WINDOW_WIDTH:
    player.right += MOVE_SPEED

    windowSurface.blit(playerImage, player)
    for bear in bears:
    windowSurface.blit(bearImage, bear)

    #check if player has intersected with bear
    for bear in bears[:]:


    def explosion():
    for bear in bears:
    if player.colliderect(bear) and (moveLeft == False and
    moveRight == False and moveUp == False and
    moveDown == False):
    bears.remove(bear)
    if player.colliderect(bear) and (moveLeft == False and
    moveRight == False and moveUp == False and
    moveDown == False):
    t = Timer(1, explosion)
    t.start()
    if len(bears) == 0:
    bearCounter = 0
    windowSurface.blit(text, (90, 104))
    startGame = False

    #draw the window
    pygame.display.update()
    mainClock.tick(40)

    while startGame == False:
    for event in pygame.event.get():
    if event.type == QUIT:
    pygame.quit()
    sys.exit()
     
    , Jun 19, 2013
    #1
    1. Advertising

  2. On Wed, 19 Jun 2013 13:18:49 -0700, jacksonkemp1234 wrote:

    > windowSurface.blit(playerImage, player)
    > for bear in bears:
    > windowSurface.blit(bearImage, bear)


    Try changing this to draw the bears first, then the player.

    --
    Denis McMahon,
     
    Denis McMahon, Jun 19, 2013
    #2
    1. Advertising

  3. On Wed, 19 Jun 2013 13:18:49 -0700, jacksonkemp1234 wrote:

    > if moveDown and player.right < WINDOW_WIDTH:
    > player.right += MOVE_SPEED


    Should this be moveRight instead of moveDown?

    --
    Denis McMahon,
     
    Denis McMahon, Jun 19, 2013
    #3
  4. This is prob'ly the freakiest thing I've ever run...

    Anyhoo, I recommend that when you post slabs of code to a mailing list
    you at least make it runnable for us. We don't have the images. I
    "fixed" it by doing:
    | playerImage = pygame.Surface((40, 40))
    | bearImage = pygame.Surface((64, 64))
    |
    | playerImage.fill(pygame.Color("red"))
    | bearImage.fill(pygame.Color("blue"))

    I'll not just give you answers, here, but try and make you understand
    what you need to do to make your code shiny. I'll answer your
    questions on the way, though.

    On 19 June 2013 21:18, <> wrote:
    > I made this game where you move a player over bears, but the bears keep loading over the plaeyer making it hard to see it, also when i move down theplayer goes down to the right
    >
    > here is my code:
    >
    > import pygame, sys, random
    > from pygame.locals import *
    > from threading import Timer


    You probably want to split up these lines; all the cool kids do:
    | import sys
    | import random
    | import pygame
    |
    | from pygame.locals import *
    | from threading import Timer

    This is just style; you might wonder why people do this but it's
    something I've found makes sense in the long run for some reason, and
    it's recommended as such.


    > #set up pygame
    > pygame.init()
    > mainClock = pygame.time.Clock()
    >
    > #set up the window
    > WINDOW_WIDTH = 400
    > WINDOW_HEIGHT = 400
    > windowSurface = pygame.display.set_mode((WINDOW_WIDTH,
    > WINDOW_HEIGHT),0)
    > pygame.display.set_caption('Get the Bears')
    >
    > #set up color constants
    > BLACK = (0,0,0)
    > BLUE = (0, 0, 255)


    Ah! Pygame has a color module.

    For example, instead of:
    | windowsurface.fill(BLACK)

    it's better to do:
    | windowsurface.fill(pygame.Color("black"))


    > #set winning text
    > textFont = pygame.font.SysFont("impact", 60)
    > text = textFont.render("YOU WIN!", True, (193, 0, 0))


    Just a niggle here; it'd be better to call this "win_text" or some
    other more descriptive name.
    It's also better to use under_score_names; they're more readable. It
    took me about a year to realise this, but it's true. It's also
    recommended.

    > #set up the player and bear data structures
    > bearCounter = 0
    > NEW_BEAR = 40
    > BEAR_SIZE = 64


    I'll come back to this later.

    > playerImage = pygame.image.load('hunter.png')
    > bearImage = pygame.image.load('bear.png')


    I replaced this with:
    | player_image = pygame.Surface((40, 40))
    | bear_image = pygame.Surface((64, 64))
    |
    | player_image.fill(pygame.Color("red"))
    | bear_image.fill(pygame.Color("blue"))

    Note that I'm changing things like the naming scheme as I go.

    > player = pygame.Rect(300, 100, 40, 40)


    Although it's OK to use pygame.Rect as a "player" now, it's not a
    "player" and you really shouldn't let this be a habit. It'd be better
    to call this player_rect, or some more useful name.

    > bears = []
    > for i in range(20):
    > bears.append(pygame.Rect(random.randint(0, WINDOW_WIDTH - BEAR_SIZE),
    > random.randint(0, WINDOW_HEIGHT - BEAR_SIZE),
    > BEAR_SIZE, BEAR_SIZE))


    Split this up, damnit!
    | for i in range(10):
    | x = random.randint(0, WINDOW_WIDTH - BEAR_SIZE)
    | y = random.randint(0, WINDOW_HEIGHT - BEAR_SIZE)
    |
    | bears.append((x, y), (BEAR_SIZE, BEAR_SIZE))

    See how this way it's more obvious what it all means, there's no silly
    line-wrapping *and* it's easier to read.

    > #movement variables
    > moveLeft = False
    > moveRight = False
    > moveDown = False
    > moveUp = False
    >
    > MOVE_SPEED = 15


    ER MER GERD

    Think about what you're doing here. If I ask you what direction an
    object on the screen is going in, do you say:
    1) Left, about 15 pixels a frame
    2) West at 5 klicks per hour
    3) Left=True, Right=False, Up=False, Down=False, Speed=15
    ?

    Well, it's not (3). So let us think about this.

    A good "classical" newbie method, which works for non-newbie stuff too, is just

    | directions = {"left", "right", "up", "down"}
    | movement_direction = "left"

    However, it's not the best. In "programming terms" you'd want variable
    speed in *both* directions. My preferred method is:

    | velocity = [the_value_of_x, the_value_of_y]

    so you'd write above:

    | velocity = [0, 0]

    See how nice that is? We'll come back to this later.

    > #run the game loop
    > startGame = True
    > while startGame == True:


    Noooo! Not you too!

    <START PERSONAL OPINION, NOT SHARED BY EVERYONE>
    You have here a (really weird - I'll come to that later) "infinite" loop.
    This is best described like so:

    | while True:
    | stuff()
    | if finished():
    | break

    That's what "break" is for, after all.

    Even better (I think) you can do:

    | while "game is running":
    | stuff()
    | if finished():
    | break

    which explains what you're doing concisely without changing the
    meaning of the code.

    A second advantage of this method
    <END>

    Plus, if you *insist* on "while FLAG", choose a good name. "startGame"
    is wrong, because it's not only running during the start of the game.

    You mean:
    | while game_running:

    > #check for quit

    This is a misplaced comment.

    > for event in pygame.event.get():
    > if event.type == QUIT:
    > pygame.quit()
    > sys.exit()


    You don't need pygame.quit(), by the way. That only needs to be done
    if you want to close pygame *before* the script is over. It also means
    that you can't "catch" an exit nicely like this, so this should just
    be removed.

    > if event.type == KEYDOWN:
    > #keyboard variables
    > if event.key == K_LEFT:
    > moveRight = False
    > moveLeft = True
    > if event.key == K_RIGHT:
    > moveRight = True
    > moveLeft = False
    > if event.key == K_UP:
    > moveUp = True
    > moveDown = False
    > if event.key == K_DOWN:
    > moveUp = False
    > moveDown = True
    > if event.type == KEYUP:
    > if event.key == K_ESCAPE:
    > pygame.quit()
    > sys.exit()
    > if event.key == K_LEFT:
    > moveLeft = False;
    > if event.key == K_RIGHT:
    > moveRight = False;
    > if event.key == K_UP:
    > moveUp = False;
    > if event.key == K_DOWN:
    > moveDown = False;


    OH MOTHER OF GOD!

    When you write something like that, the #1 reason is that you've done
    something a bad way.
    Please note that it's wrong; you shouldn't deal with keeping track of
    whether keys are up - pygame does that *much better* for you.

    Let's rewrite this using our new velocity stuff!:
    | for event in pygame.event.get():
    | if event.type == QUIT:
    | sys.exit()
    |
    | pressed = pygame.key.get_pressed()
    |
    | velocity[0] = pressed[K_RIGHT] - pressed[K_LEFT]
    | velocity[1] = pressed[K_DOWN] - pressed[K_UP]

    That's it. Really!

    Since we have a simple definition of velocity, velocity[0] is just the
    amount you move right minus the amount you move left, and similar for
    velocity[1].

    Oh, and suddenly it all works (after changes to the rest of the code)!
    Bugs just disappear!

    > bearCounter += 1
    > if bearCounter >= NEW_BEAR:
    > #clear bear array and add new bears
    > bearCounter = 0
    > bears.append(pygame.Rect(random.randint(0, WINDOW_WIDTH - BEAR_SIZE),
    > random.randint(0, WINDOW_HEIGHT - BEAR_SIZE),
    > BEAR_SIZE, BEAR_SIZE))


    Again, split this up:
    | bear_counter += 1
    | if bear_counter >= NEW_BEAR:
    | #clear bear array and add new bears
    | bear_counter = 0
    |
    | x = random.randint(0, WINDOW_WIDTH - BEAR_SIZE)
    | y = random.randint(0, WINDOW_HEIGHT - BEAR_SIZE)
    |
    | bears.append(pygame.Rect((x, y), (BEAR_SIZE, BEAR_SIZE)))

    But what does "clear bear array" mean? You don't clear any lists,
    especially not arrays! You only set "bearCounter" to 0. Why? That
    makes it a timeout, not a counter of bears!

    Thus you should do something more like this:
    | bear_countdown = 40
    ....
    | bear_countdown -= 1
    | if bear_countdown <= 0:
    | bear_countdown = 40
    | more_bears()

    You have a spontaneous indent from here on! That's not good!
    It means that your "while startGame == False" runs *inside* "while
    startGame == True", which is quite paradoxical. It means you don't
    move as much as you do. I've fixed that for me. To be fair though, I
    have no idea what your indents are meant to be like. It seems you
    haven't thought about it as much as you should have. I'll get back to
    that at the end.

    > #draw black background
    > windowSurface.fill(BLACK)


    Remember;
    | window_surface.fill(pygame.Color("black"))

    > #move player
    > if moveDown and player.bottom < WINDOW_HEIGHT:
    > player.top += MOVE_SPEED
    > if moveUp and player.top > 0:
    > player.top -= MOVE_SPEED
    > if moveLeft and player.left > 0:
    > player.left -= MOVE_SPEED
    > if moveDown and player.right < WINDOW_WIDTH:
    > player.right += MOVE_SPEED


    Oh noes! This again!

    You may be able to guess that we can do something nice again!
    Please note that "player.right += 1" *is the same as* "player.top +=1"
    and "player.middle += 1" and so on.
    This is obvious with a bit of thought.

    Hence:
    | player.x += velocity[0]
    | player.y += velocity[1]

    and we can stop you going off the ends with:
    | player.clamp_ip(((0, 0), (WINDOW_WIDTH, WINDOW_HEIGHT)))

    Note that you'll move slower like this; you can just multiply by a factor:
    | player.x += velocity[0] * SPEED_FACTOR
    | player.y += velocity[1] * SPEED_FACTOR

    > windowSurface.blit(playerImage, player)
    > for bear in bears:
    > windowSurface.blit(bearImage, bear)


    You wanted the player on top. This won't happen as you've written it
    as you draw the player and *then* the bear, so the bear is above.

    You want to flip this:

    | for bear in bears:
    | window_surface.blit(bear_image, bear)
    | window_surface.blit(player_image, player)

    If you want to be really cool you can do this (requires modern pygame [>=1.8])
    | for bear in bears:
    | window_surface.blit(bear_image, bear)
    | window_surface.blit(player_image, player, special_flags=BLEND_MAX)

    > #check if player has intersected with bear
    > for bear in bears[:]:
    > def explosion():
    > for bear in bears:
    > if player.colliderect(bear) and (moveLeft == False and
    > moveRight == False and moveUp == False and
    > moveDown == False):
    > bears.remove(bear)
    > if player.colliderect(bear) and (moveLeft == False and
    > moveRight == False and moveUp == False and
    > moveDown == False):
    > t = Timer(1, explosion)
    > t.start()
    > if len(bears) == 0:
    > bearCounter = 0
    > windowSurface.blit(text, (90, 104))
    > startGame = False


    This here is a bit of freaky-clever shenanigans.
    Some's OK, some's not.

    Really, You have a loop in a function in a loop in a loop. That's too much.
    Take the function out of the loop. Then realise it's pointless to have
    a loop in there - it's probably not what you want. You probably want:
    | def explosion(bear):
    | def callback():
    | if player.colliderect(bear) and velocity == [0, 0]:
    | bears.remove(bear)
    | return callback
    ....
    | t = Timer(0.8, explosion(bear))

    What?! This is actually a common thing in a lot of languages.
    Basically, you take one argument and make a new function inside it
    which does what you want. This is what you did in the loop, but out of
    the loop. It also plays slightly differently, as it kills each bear
    separately.

    Before we get carried away, though...
    Why are you mixing frame-based and time-based code?! WHY?!

    Never do that. I realise it seems like the easy solution - it probably
    is - but it's not the right one.

    > #draw the window
    > pygame.display.update()
    > mainClock.tick(40)
    >
    > while startGame == False:
    > for event in pygame.event.get():
    > if event.type == QUIT:
    > pygame.quit()
    > sys.exit()


    This is inside your "while startGame == True", which is rehduculush.

    Moving it out doesn't seem to work with "while True:"..."break", as
    you've have imbedded loops. The "proper" solution, á mon avis, is an
    exception. This is a bit advanced but you don't need to know much
    about it.

    Up at the top do:

    | class GameWon(Exception): pass

    That makes an "exception class" you can use.

    Instead of:
    | if len(bears) == 0:
    | bear_countdown = 0
    | window_surface.blit(winning_text, (90, 104))
    | break

    write:

    | pygame.display.flip() # We need this extra one as we're
    bypassing some extra stuff doing it this way
    | raise GameWon

    This will break out of things until it meets something that can
    "handle" it. To do that you need to wrap your whole main "while
    startGame == True" loop in a "try:"..."except:"

    Like so:
    | try:
    | while "game is running":
    ....
    | except GameWon:
    | while "showing the winning screen":
    | for event in pygame.event.get():
    | if event.type == QUIT:
    | sys.exit()

    Note that I don't need pygame.quit(), as before.


    I made a couple more changes, but nothing significant.

    NOTE THAT ALTHOUGH I'LL POST THE CODE WITH ALL THE CHANGES I MADE, THE
    POINT ISN'T TO GIVE YOU REFACTORED CODE.
    It's to explain to you what's there to improve, and know what to do
    next time, etc.

    # CODE FOLLOWING

    import sys
    import random
    import pygame

    from pygame.locals import *
    from threading import Timer

    #set up pygame
    pygame.init()
    main_clock = pygame.time.Clock()

    #set up the window
    WINDOW_WIDTH = 400
    WINDOW_HEIGHT = 400
    window_surface = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), 0)
    pygame.display.set_caption('Get the Bears')

    window_filler = window_surface.copy()
    window_filler.fill(pygame.Color("black"))
    window_filler.set_alpha(50)

    #set winning text
    text_font = pygame.font.SysFont("impact", 60)
    winning_text = text_font.render("YOU WIN!", True, (193, 0, 0))

    #set up the player and bear data structures
    bear_countdown = 40
    BEAR_SIZE = 64

    player_image = pygame.Surface((40, 40))
    bear_image = pygame.Surface((64, 64))

    player_image.fill(pygame.Color("dark red"))
    bear_image.fill(pygame.Color("dark blue"))

    player = pygame.Rect(300, 100, 40, 40)
    bears = []

    for i in range(10):
    x = random.randint(0, WINDOW_WIDTH - BEAR_SIZE)
    y = random.randint(0, WINDOW_HEIGHT - BEAR_SIZE)

    bears.append(pygame.Rect((x, y), (BEAR_SIZE, BEAR_SIZE)))

    #movement variables
    velocity = [0, 0]
    SPEED_FACTOR = 15

    class GameWon(Exception): pass

    def explosion(bear):
    def callback():
    if player.colliderect(bear) and velocity == [0, 0]:
    bears.remove(bear)
    return callback

    try:
    while "game is running":
    for event in pygame.event.get():
    if event.type == QUIT:
    sys.exit()

    pressed = pygame.key.get_pressed()

    velocity[0] = pressed[K_RIGHT] - pressed[K_LEFT]
    velocity[1] = pressed[K_DOWN] - pressed[K_UP]

    if len(bears) == 0:
    raise GameWon

    bear_countdown -= 1
    if bear_countdown <= 0:
    #clear bear array and add new bears
    bear_countdown = 40

    x = random.randint(0, WINDOW_WIDTH - BEAR_SIZE)
    y = random.randint(0, WINDOW_HEIGHT - BEAR_SIZE)

    bears.append(pygame.Rect((x, y), (BEAR_SIZE, BEAR_SIZE)))

    window_surface.blit(window_filler, (0, 0))

    #move player
    player.x += velocity[0] * SPEED_FACTOR
    player.y += velocity[1] * SPEED_FACTOR

    player.clamp_ip(((0, 0), (WINDOW_WIDTH, WINDOW_HEIGHT)))

    for bear in bears:
    window_surface.blit(bear_image, bear, special_flags=BLEND_ADD)
    window_surface.blit(player_image, player, special_flags=BLEND_ADD)

    #check if player has intersected with bear
    for bear in bears[:]:
    if player.colliderect(bear) and velocity == [0, 0]:
    Timer(0.6, explosion(bear)).start()

    #draw the window
    pygame.display.update()
    main_clock.tick(40)

    except GameWon:
    window_surface.blit(winning_text, (90, 104))
    pygame.display.flip()

    while "showing the winning screen":
    pygame.display.flip()
    for event in pygame.event.get():
    if event.type == QUIT:
    sys.exit()

    # END CODE

    Apologies for the massive post, and not checking it for errors. It's
    too long to care about that.
     
    Joshua Landau, Jun 20, 2013
    #4
  5. Jackson Kemp Guest

    Thankyou this was very helpful
     
    Jackson Kemp, Jun 20, 2013
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. BlackHawke
    Replies:
    12
    Views:
    1,580
    Andrew Thompson
    Jan 26, 2004
  2. judith
    Replies:
    0
    Views:
    1,662
    judith
    Nov 1, 2006
  3. Max Kubierschky
    Replies:
    10
    Views:
    1,854
    pabloreda
    Mar 31, 2007
  4. Advertiser for `2D Games Development Central`

    {Game Development} 2D Game Development Central

    Advertiser for `2D Games Development Central`, May 7, 2008, in forum: Java
    Replies:
    2
    Views:
    416
    RedGrittyBrick
    May 8, 2008
  5. Advertiser for `2D Games Development Central`

    {Game Development} 2D Game Development Central

    Advertiser for `2D Games Development Central`, May 7, 2008, in forum: C++
    Replies:
    0
    Views:
    399
    Advertiser for `2D Games Development Central`
    May 7, 2008
Loading...

Share This Page