Take the tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

In my game, there is a terrain generator subsequently resulting in many instances. I have implemented this code:

for b in blocklist:
    if b.rect.left>=0:
       if b.rect.right<=640:
          screen.blit(b.sprite, b.rect)

It only renders things within the screen (400-500 blocks), but it still runs as if it were rendering all 2000 or so. What am I doing wrong? Does it have anything to do with

pygame.display.update()

#or

pygame.display.flip()

Is there even a difference?

Here is the entire code:

    #Init stuff
    import pygame,random
    from pygame.locals import *
    from collections import namedtuple
    import time, string
    pygame.mixer.init(frequency=22050, size=-16, channels=2, buffer=500)
    f=open('texdir.txt','r')
    texdir=f.read()
    f.close()
    f=open(texdir+"\\splash.txt",'r')
    splash=f.read()
    splash=splash.replace('(','')
    splash=splash.replace(')','')
    splash=splash.split(',')
    f.close()
    splashlen=len(splash)
    chc=random.randint(0,int(splashlen))
    splash=splash[chc-1]
    f=open(texdir+"//backcolor.txt")
    pygame.init()
    clock=pygame.time.Clock()
    screen=pygame.display.set_mode((640,480))
    pygame.display.set_caption("PiBlocks | By Sam Tubb")
    max_gravity = 100
    blocksel=texdir+"\\dirt.png"
    btype='block'
    backimg = pygame.image.load(texdir+"\\menu.png").convert()
    backimg = pygame.transform.scale(backimg, (640,480))
    clsimg = pygame.image.load("clear.bmp").convert()
    clsimg = pygame.transform.scale(clsimg, (640,480))
    ingame=0
    sbtn=pygame.image.load("startbtn.png").convert()
    qbtn=pygame.image.load("quitbtn.png").convert()
    tbtn=pygame.image.load("texbtn.png").convert()
    sbtnrect=sbtn.get_rect()
    sbtnrect.x=220
    sbtnrect.y=190
    qbtnrect=qbtn.get_rect()
    qbtnrect.x=220
    qbtnrect.y=225
    tbtnrect=tbtn.get_rect()
    tbtnrect.x=220
    tbtnrect.y=260
    go=0
    gotime=35
    select=1
    colliding = False
    Move = namedtuple('Move', ['up', 'left', 'right'])
    player=[]
    blocklist=[]
    font=pygame.font.Font(None,18)

    #set cursor
    curs = pygame.image.load(texdir+"\\cursor.png").convert()
    curs.set_colorkey((0,255,0))

    #set backcolor
    COLOR=f.read()
    f.close()
    COLOR=COLOR.replace('(','')
    COLOR=COLOR.replace(')','')
    COLOR=COLOR.split(',')
    c1=COLOR[0]
    c2=COLOR[1]
    c3=COLOR[2]

    #load sounds
    place=pygame.mixer.Sound('sound\\place.wav')
    place2=pygame.mixer.Sound('sound\\place2.wav')
    place3=pygame.mixer.Sound('sound\\place3.wav')

    #set sprites and animation frames
    psprite = pygame.image.load(texdir+"\\player\\playr.png").convert()
    psprite.set_colorkey((0,255,0))
    psprite2 = pygame.image.load(texdir+"\\player\\playr2.png").convert()
    psprite2.set_colorkey((0,255,0))
    psprite3 = pygame.image.load(texdir+"\\player\\playr3.png").convert()
    psprite3.set_colorkey((0,255,0))
    anim=1
    class Block(object):
            def __init__(self,x,y,sprite,btype):
                    if blocksel==texdir+"\\woodslab.png":
                           self.btype='slab'
                           self.sprite = pygame.image.load(sprite).convert()
                           self.rect = self.sprite.get_rect(top=y+16, left=x)
                    else:
                           self.btype='block'
                           self.sprite = pygame.image.load(sprite).convert_alpha()
                           self.rect = self.sprite.get_rect(top=y, left=x)


    class Player(object):
        sprite=psprite
        def __init__(self, x, y):
            self.rect = self.sprite.get_rect(centery=y, centerx=x)
            # indicates that we are standing on the ground
            # and thus are "allowed" to jump
            self.on_ground = True
            self.xvel = 0
            self.yvel = 0
            self.jump_speed = 7
            self.move_speed = 3

        def update(self, move, blocks):

            # check if we can jump 
            if move.up and self.on_ground:
                self.yvel -= self.jump_speed

            # simple left/right movement
            if move.left:
                    self.xvel = -self.move_speed
            if move.right:
                    self.xvel = self.move_speed

            # if in the air, fall down
            if not self.on_ground:
                self.yvel += 0.3
                # but not too fast
                if self.yvel > max_gravity: self.yvel = max_gravity

            # if no left/right movement, x speed is 0, of course
            if not (move.left or move.right):
                self.xvel = 0

            # move horizontal, and check for horizontal collisions
            self.rect.left += self.xvel
            self.collide(self.xvel, 0, blocks)

            # move vertically, and check for vertical collisions
            self.rect.top += self.yvel
            self.on_ground = False;
            self.collide(0, self.yvel, blocks)

        def collide(self, xvel, yvel, blocks):
            # all blocks that we collide with
            for block in [blocks[i] for i in self.rect.collidelistall(blocks)]:

                # if xvel is > 0, we know our right side bumped 
                # into the left side of a block etc.
                if xvel > 0:
                        self.rect.right = block.rect.left
                if xvel < 0:
                        self.rect.left = block.rect.right

                # if yvel > 0, we are falling, so if a collision happpens 
                # we know we hit the ground (remember, we seperated checking for
                # horizontal and vertical collision, so if yvel != 0, xvel is 0)
                if yvel > 0:
                    self.rect.bottom = block.rect.top
                    self.on_ground = True
                    self.yvel = 0
                # if yvel < 0 and a collision occurs, we bumped our head
                # on a block above us
                if yvel < 0: self.rect.top = block.rect.bottom

    def get_key():
      while 1:
        event = pygame.event.poll()
        if event.type == KEYDOWN:
          return event.key
        else:
          pass

    def display_box(screen, message):
      "Print a message in a box in the middle of the screen"
      fontobject = pygame.font.Font(None,18)
      pygame.draw.rect(screen, (0,0,0),
                       ((screen.get_width() / 2) - 100,
                        (screen.get_height() / 2) - 10,
                        200,20), 0)
      pygame.draw.rect(screen, (255,255,255),
                       ((screen.get_width() / 2) - 102,
                        (screen.get_height() / 2) - 12,
                        204,24), 1)
      if len(message) != 0:
        screen.blit(fontobject.render(message, 1, (255,255,255)),
                    ((screen.get_width() / 2) - 100, (screen.get_height() / 2) - 10))
      pygame.display.flip()

    def ask(screen, question):
      "ask(screen, question) -> answer"
      pygame.font.init()
      current_string = []
      display_box(screen, question + ": " + string.join(current_string,""))
      while 1:
        inkey = get_key()
        if inkey == K_BACKSPACE:
          current_string = current_string[0:-1]
        elif inkey == K_RETURN:
          break
        elif inkey == K_MINUS:
          current_string.append("_")
        elif inkey <= 127:
          current_string.append(chr(inkey))
        display_box(screen, question + ": " + string.join(current_string,""))
      return string.join(current_string,"")
    while True:
            for block in blocklist:
                    if any(block.rect.colliderect(b.rect) for b in blocklist if b is not block):
                            if b.btype=='slab':
                                    blocklist.remove(block)
                            else:
                                    blocklist.remove(b)
            if ingame==1:
                screen.fill((int(c1),int(c2),int(c3)))
                mse = pygame.mouse.get_pos()
                key = pygame.key.get_pressed()
                if key[K_a]:
                        anim+=1
                        if anim==9:
                                anim=1
                if key[K_d]:
                        anim+=1
                        if anim==9:
                                anim=1
                if key[K_1]:
                    blocksel=texdir+"\\dirt.png"
                    btype='block'
                    select=1
                if key[K_2]:
                    blocksel=texdir+"\\stonetile.png"
                    btype='block'
                    select=2
                if key[K_3]:
                    blocksel=texdir+"\\stone.png"
                    btype='block'
                    select=3
                if key[K_4]:
                    blocksel=texdir+"\\sand.png"
                    btype='block'
                    select=4
                if key[K_5]:
                    blocksel=texdir+"\\woodplank.png"
                    btype='block'
                    select=5
                if key[K_6]:
                    blocksel=texdir+"\\woodslab.png"
                    btype='slab'
                    select=6
                if key[K_LEFT]:
                    try:
                            for b in blocklist:
                                b.rect.left+=32
                    except:
                            pass
                    try:
                            player.rect.left+=32
                    except:
                            pass
                if key[K_RIGHT]:
                        try:
                            for b in blocklist:
                                b.rect.left-=32
                        except:
                                pass
                        try:
                            player.rect.left-=32
                        except:
                                pass
                if key[K_UP]:
                        try:
                            for b in blocklist:
                                b.rect.top+=32
                        except:
                                pass
                        try:
                            player.rect.top+=32
                        except:
                                pass
                if key[K_DOWN]:
                        try:
                            for b in blocklist:
                                b.rect.top-=32
                        except:
                                pass
                        try:
                            player.rect.top-=32
                        except:
                                pass
                if key[K_ESCAPE]:
                    execfile('PiBlocks.pyw')
                for event in pygame.event.get():
                    if event.type == QUIT:
                        exit()
                    if event.type == MOUSEBUTTONDOWN:
                            if event.button==4:
                                    if select<9:
                                            select=select+1
                                    else:
                                            select=1
                            elif event.button==5:
                                    if select>1:
                                            select=select-1
                                    else:
                                            select=9
                            if select==1:
                                    blocksel=texdir+"\\dirt.png"
                                    btype='block'
                            if select==2:
                                    blocksel=texdir+"\\stonetile.png"
                                    btype='block'
                            if select==3:
                                    blocksel=texdir+"\\stone.png"
                                    btype='block'
                            if select==4:
                                    blocksel=texdir+"\\sand.png"
                                    btype='block'
                            if select==5:
                                    blocksel=texdir+"\\woodplank.png"
                                    btype='block'
                            if select==6:
                                    blocksel=texdir+"\\woodslab.png"
                                    btype='slab'


                    if key[K_LSHIFT]:
                        if event.type==MOUSEMOTION:
                            if not any(block.rect.collidepoint(mse) for block in blocklist):
                                snd=random.randint(1,3)
                                x=(int(mse[0]) / 32)*32
                                y=(int(mse[1]) / 32)*32
                                if go==1:
                                            if snd==1:
                                                place.play()
                                            elif snd==2:
                                                place2.play()
                                            elif snd==3:
                                                place3.play()
                                            blocklist.append(Block(x,y,blocksel,btype))
                    if key[K_RSHIFT]:
                        if event.type==MOUSEMOTION:
                            to_remove = [b for b in blocklist if b.rect.collidepoint(mse)]
                            for b in to_remove:
                                    if go==1:
                                            blocklist.remove(b)
                    else:
                        if event.type == pygame.MOUSEBUTTONUP:
                            if event.button == 1:
                                to_remove = [b for b in blocklist if b.rect.collidepoint(mse)]
                                for b in to_remove:
                                    if go==1:
                                            blocklist.remove(b)

                                if not to_remove:
                                    snd=random.randint(1,3)
                                    x=(int(mse[0]) / 32)*32
                                    y=(int(mse[1]) / 32)*32
                                    if go==1:
                                            if snd==1:
                                                place.play()
                                            elif snd==2:
                                                place2.play()
                                            elif snd==3:
                                                place3.play()
                                            blocklist.append(Block(x,y,blocksel,btype))

                            elif event.button == 3:
                                x=(int(mse[0]) / 32)*32
                                y=(int(mse[1]) / 32)*32
                                player=Player(x+16,y+16)

                move = Move(key[K_w], key[K_a], key[K_d])

                for b in blocklist:
                        if b.rect.left>=0:
                                if b.rect.right<=640:
                                        screen.blit(b.sprite, b.rect)

                if player:
                    player.update(move, blocklist)
                    if anim==1 or anim==2 or anim==3:
                            screen.blit(psprite, player.rect)
                    elif anim==4 or anim==5 or anim==6:
                            screen.blit(psprite2, player.rect)
                    elif anim==7 or anim==8 or anim==9:
                            screen.blit(psprite3, player.rect)
                x=(int(mse[0]) / 32)*32
                y=(int(mse[1]) / 32)*32
                screen.blit(curs,(x,y))
                clock.tick(60)
                x=blocksel.replace(texdir,'')
                x=x.replace('.png','')
                vers=font.render('PiBlocks Alpha 0.6',True,(255,255,255))
                tex=font.render('Selected Texture Pack: '+texdir,True,(255,255,255))
                words=font.render('Selected Block: '+str(x), True, (255,255,255))
                screen.blit(vers,(1,1))
                screen.blit(tex,(1,12))
                screen.blit(words,(1,25))
                if gotime==0:
                        go=1
                else:
                        gotime-=1
                pygame.display.update()
            elif ingame==0:
                    blocklist=[]
                    mse = pygame.mouse.get_pos()
                    player=[]
                    key = pygame.key.get_pressed()
                    text=font.render(splash, True, (255,255,255))
                    if key[K_RETURN]:
                            ingame=1
                    for event in pygame.event.get():
                            if event.type == QUIT:
                                exit()
                            if event.type == KEYDOWN:
                                    print event.key
                    if sbtnrect.collidepoint(mse):
                            if pygame.mouse.get_pressed()==(1,0,0):
                                    ingame='gen'
                                    top=(random.randint(5,8)*32)
                                    cen=(top+random.randint(4,6)*32)
                                    down=15
                                    across=0
                                    blklvl=0
                                    while across<640:
                                            while down>0:
                                                    screen.fill((0,0,0))
                                                    if blklvl==top:
                                                            blocklist.append(Block(across,blklvl,texdir+"\\grass.png",'block'))
                                                    if blklvl>top:
                                                            if blklvl<cen:
                                                                    blocklist.append(Block(across,blklvl,texdir+"\\dirt.png",'block'))
                                                    if blklvl>cen-1:
                                                            blocklist.append(Block(across,blklvl,texdir+"\\stone.png",'block'))
                                                    down=down-1
                                                    blklvl=blklvl+32

                                            if down==0:
                                                    if across<1920:
                                                            per=(across/(32/5))
                                                            if per>100:
                                                                    per=100
                                                            top=(random.randint(5,8)*32)
                                                            cen=(top+random.randint(4,6)*32)
                                                            down=15 
                                                            blklvl=0
                                                            across=across+32
                                                            down=15
                                                            drawgen=font.render('GENERATION:'+str(per)+'%%', True, (255,255,255))
                                                            screen.blit(drawgen,(1,1))
                                                            pygame.display.flip()
                                            go=0
                                            ingame=1

                    if qbtnrect.collidepoint(mse):
                            if pygame.mouse.get_pressed()==(1,0,0):
                                    exit()
                    if tbtnrect.collidepoint(mse):
                            if pygame.mouse.get_pressed()==(1,0,0):
                                    ingame='texsel'
                    screen.blit(backimg,(0,0))
                    screen.blit(text,(364,76))
                    screen.blit(sbtn,sbtnrect)
                    screen.blit(qbtn,qbtnrect)
                    screen.blit(tbtn,tbtnrect)
                    pygame.display.flip()
            elif ingame=='texsel':
                     screen.blit(clsimg,(0,0))
                     inp = ask(screen, 'Texture Directory')
                     f=open('texdir.txt','w')
                     f.write(str(inp))
                     f.close()
                     pygame.display.flip()
                     execfile('PiBlocks.pyw')

Can someone please give me some tips?

share|improve this question
 
Just changed the code to make it load each sprite one time, but it still runs quite slow! –  Sam Tubb Oct 9 at 1:43
1  
First thoughts: that's a lot of global variables, this should probably be split up into multiple files, and the indentation appears to be inconsistent. –  icktoofay Oct 9 at 3:16
 
Do you mean multiple .py files? –  Sam Tubb Oct 9 at 10:36
1  
Yes. You may be able to split it up into multiple .py files and have them import each-other as modules. –  icktoofay Oct 11 at 18:51
add comment

1 Answer

up vote 3 down vote accepted

First of all, a lot of people who would answer this question will not do so because you can't just copy/paste the code and run it. The code depends on a lot of external files, like images and textfiles, and to run your code, you basically have to trial'n'error your way while creating a bunch of placeholder images...


I'll try to read your code and comment it step by step.

f=open('texdir.txt','r')
texdir=f.read()
f.close()
f=open(texdir+"\\splash.txt",'r')
splash=f.read()
splash=splash.replace('(','')
splash=splash.replace(')','')
splash=splash.split(',')
f.close()
...
f=open(texdir+"//backcolor.txt") 

Here you read some settings/configurations. Better use the ConfigParser module. It will make your code more readable and more easily to follow.


splashlen=len(splash)
chc=random.randint(0,int(splashlen))
splash=splash[chc-1]

To select a random element from as list, you can just use random.choice.


f=open(texdir+"//backcolor.txt")
...
blocksel=texdir+"\\dirt.png"

Sometimes you use // in a path, sometimes \\. Better use os.path.join to create a path so it will work on different operating systems,


COLOR=f.read()
f.close()
COLOR=COLOR.replace('(','')
COLOR=COLOR.replace(')','')
COLOR=COLOR.split(',')
c1=COLOR[0]
c2=COLOR[1]
c3=COLOR[2]

...

if ingame==1:
    screen.fill((int(c1),int(c2),int(c3)))

Well, that's a whole lot of code to read a simple tuple. Let be point to ast.literal_eval, which allows you to savely read a string and convert it into a python structure:

line = f.read()
# assuming 'line' is a string representing a tuple, like (120, 120, 200)
back_color = literal_eval(line) # now, back_color is a tuple

...

if ingame==1:
    screen.fill(back_color)

if key[K_1]:
    blocksel=texdir+"\\dirt.png"
    btype='block'
    select=1
if key[K_2]:
    blocksel=texdir+"\\stonetile.png"
    btype='block'
    select=2

Here, you have three (maybe four if you count the key) values that are connectet to each other, so you should create a type that represents this:

class BlockType(object):
    def __init__(self, name, type, image_path=None, y_offset=0):
        self.name = name
        self.type = type
        if not image_path:
            image_path = name + '.png'
        self.image = pygame.image.load(image_path).convert()
        self.y_offset = y_offset

    def get_rect(self, x, y):
        return self.image.get_rect(top=y+self.y_offset, left=x)


class Block(object):
    def __init__(self, x, y, block_type):
        self.block_type = block_type
        self.image = block_type.image
        self.rect = block_type.get_rect(x, y)

    # don't know if we need the information 'block or slab'         
types = [BlockType('dirt', 'block'), 
         BlockType('stonetile', 'block'), 
         BlockType('stone', 'block'),
         BlockType('grass', 'block'),
         BlockType('sand', 'block'),
         BlockType('woodplank', 'block'),
         BlockType('woodslab', 'slab', y_offset=16)]

block_lookup = {t.name: t for t in types}
key_map = dict(zip([K_1, K_2, K_3, K_4, K_5, K_6], types))

Also, this will allow to remove a lot of code duplication.


if event.button==4:
        if select < 9:
                select=select+1
        else:
                select=1
elif event.button==5:
        if select>1:
                select=select-1
        else:
                select=9

can be simplified to

num_of_types = len(types)

if event.button==4:
    select += 1
elif event.button==5:
    select -= 1
select = max(min(select, num_of_types), 0)

if blklvl==top:
        blocklist.append(Block(across,blklvl,texdir+"\\grass.png",'block'))
if blklvl>top:
        if blklvl<cen:
                blocklist.append(Block(across,blklvl,texdir+"\\dirt.png",'block'))
if blklvl>cen-1:
        blocklist.append(Block(across,blklvl,texdir+"\\stone.png",'block'))

Notice how you repeat the filenames to each different block type all over again? Let's fix that by creating a factory method that uses our new block_lookup dictionary:

# this lookup could also be directly in the Block class
def block_factory(name, x, y):
    return Block(x, y, block_lookup[name])

...

if blklvl == top:
    blocklist.append(block_factory(across, blklvl , 'grass'))
if blklvl > top and blklvl<cen:
    blocklist.append(block_factory(across, blklvl , 'dirt'))
if blklvl > cen-1:
    blocklist.append(block_factory(across, blklvl , 'stone'))

vers=font.render('PiBlocks Alpha 0.6',True,(255,255,255))
tex=font.render('Selected Texture Pack: '+texdir,True,(255,255,255))

You render the text surface once each frame. Text rendering in pygame is quite slow, so you should cache the text surfaces and reuse them.


for block in blocklist:
    if any(block.rect.colliderect(b.rect) for b in blocklist if b is not block):
        if b.btype=='slab':
            blocklist.remove(block)
        else:
            blocklist.remove(b)

No idea what you try to do here. b is declared in the list comprehension above and should not be used outside of it.


There's a lot more what could be improved, but we've already eliminated two performance bottlenecks (reloading images from disk every time a new block is created, text rendering), and I'm running out of space and time, so here's the complete code so far:

#Init stuff
import pygame,random
from pygame.locals import *
from collections import namedtuple
import time, string

import ConfigParser
from ast import literal_eval
from functools import partial
import os

config = ConfigParser.ConfigParser()
config.read("settings.cfg")
options = partial(config.get, 'Options')

pygame.mixer.init(frequency=22050, size=-16, channels=2, buffer=500)
pygame.init()
pygame.display.set_caption(options('Caption'))

size = literal_eval(options('ScreenSize'))
screen = pygame.display.set_mode(size)

clock = pygame.time.Clock()
back_color = literal_eval(options('Backcolor'))
splash = random.choice(literal_eval(options('Splash')))

max_gravity = 100

texdir = options('TextureDir')

backimg = pygame.image.load(texdir+"\\menu.png").convert()
backimg = pygame.transform.scale(backimg, (640,480))
clsimg = pygame.image.load("clear.bmp").convert()
clsimg = pygame.transform.scale(clsimg, (640,480))
ingame=0
sbtn=pygame.image.load("startbtn.png").convert()
qbtn=pygame.image.load("quitbtn.png").convert()
tbtn=pygame.image.load("texbtn.png").convert()
sbtnrect=sbtn.get_rect()
sbtnrect.x=220
sbtnrect.y=190
qbtnrect=qbtn.get_rect()
qbtnrect.x=220
qbtnrect.y=225
tbtnrect=tbtn.get_rect()
tbtnrect.x=220
tbtnrect.y=260
go=0
gotime=35
select=1
colliding = False
Move = namedtuple('Move', ['up', 'left', 'right'])
player=[]
blocklist=[]
font=pygame.font.Font(None,18)

#set cursor
curs = pygame.image.load(texdir+"\\cursor.png").convert()
curs.set_colorkey((0,255,0))

#load sounds
place=pygame.mixer.Sound('sound\\place.wav')
place2=pygame.mixer.Sound('sound\\place2.wav')
place3=pygame.mixer.Sound('sound\\place3.wav')

#set sprites and animation frames
psprite = pygame.image.load(texdir+"\\player\\playr.png").convert()
psprite.set_colorkey((0,255,0))
psprite2 = pygame.image.load(texdir+"\\player\\playr2.png").convert()
psprite2.set_colorkey((0,255,0))
psprite3 = pygame.image.load(texdir+"\\player\\playr3.png").convert()
psprite3.set_colorkey((0,255,0))
anim=1

class BlockType(object):
    def __init__(self, name, type, image_path=None, y_offset=0):
        self.name = name
        self.type = type
        if not image_path:
            image_path = name + '.png'
        self.image = pygame.image.load(image_path).convert()
        self.y_offset = y_offset

    def get_rect(self, x, y):
        return self.image.get_rect(top=y+self.y_offset, left=x)

class Block(object):
    def __init__(self, x, y, block_type):
        self.block_type = block_type
        self.image = block_type.image
        self.rect = block_type.get_rect(x, y)

types = [BlockType('dirt', 'block'), 
         BlockType('stonetile', 'block'), 
         BlockType('stone', 'block'),
         BlockType('grass', 'block'),
         BlockType('sand', 'block'),
         BlockType('woodplank', 'block'),
         BlockType('woodslab', 'slab', y_offset=16)]

block_lookup = {t.name: t for t in types}

def block_factory(name, x, y):
    return Block(x, y, block_lookup[name])

num_of_types = len(types)

key_map = dict(zip([K_1, K_2, K_3, K_4, K_5, K_6], types))

selected_block_type = next(t for t in types if t.name == options('DefaultBlock'))
selected_block_index = types.index(selected_block_type) 

_text_cache = {}
def render_white(text):
    if not text in _text_cache:
        surf = font.render(text ,True,(255,255,255))
        _text_cache[text] = surf
        return surf
    return _text_cache[text]


class Player(object):
    sprite=psprite
    def __init__(self, x, y):
        self.rect = self.sprite.get_rect(centery=y, centerx=x)
        # indicates that we are standing on the ground
        # and thus are "allowed" to jump
        self.on_ground = True
        self.xvel = 0
        self.yvel = 0
        self.jump_speed = 7
        self.move_speed = 3

    def update(self, move, blocks):

        # check if we can jump 
        if move.up and self.on_ground:
            self.yvel -= self.jump_speed

        # simple left/right movement
        if move.left:
                self.xvel = -self.move_speed
        if move.right:
                self.xvel = self.move_speed

        # if in the air, fall down
        if not self.on_ground:
            self.yvel += 0.3
            # but not too fast
            if self.yvel > max_gravity: self.yvel = max_gravity

        # if no left/right movement, x speed is 0, of course
        if not (move.left or move.right):
            self.xvel = 0

        # move horizontal, and check for horizontal collisions
        self.rect.left += self.xvel
        self.collide(self.xvel, 0, blocks)

        # move vertically, and check for vertical collisions
        self.rect.top += self.yvel
        self.on_ground = False;
        self.collide(0, self.yvel, blocks)

    def collide(self, xvel, yvel, blocks):
        # all blocks that we collide with
        for block in [blocks[i] for i in self.rect.collidelistall(blocks)]:

            # if xvel is > 0, we know our right side bumped 
            # into the left side of a block etc.
            if xvel > 0:
                    self.rect.right = block.rect.left
            if xvel < 0:
                    self.rect.left = block.rect.right

            # if yvel > 0, we are falling, so if a collision happpens 
            # we know we hit the ground (remember, we seperated checking for
            # horizontal and vertical collision, so if yvel != 0, xvel is 0)
            if yvel > 0:
                self.rect.bottom = block.rect.top
                self.on_ground = True
                self.yvel = 0
            # if yvel < 0 and a collision occurs, we bumped our head
            # on a block above us
            if yvel < 0: self.rect.top = block.rect.bottom

def get_key():
  while 1:
    event = pygame.event.poll()
    if event.type == KEYDOWN:
      return event.key
    else:
      pass

def display_box(screen, message):
  "Print a message in a box in the middle of the screen"
  fontobject = pygame.font.Font(None,18)
  pygame.draw.rect(screen, (0,0,0),
                   ((screen.get_width() / 2) - 100,
                    (screen.get_height() / 2) - 10,
                    200,20), 0)
  pygame.draw.rect(screen, (255,255,255),
                   ((screen.get_width() / 2) - 102,
                    (screen.get_height() / 2) - 12,
                    204,24), 1)
  if len(message) != 0:
    screen.blit(fontobject.render(message, 1, (255,255,255)),
                ((screen.get_width() / 2) - 100, (screen.get_height() / 2) - 10))
  pygame.display.flip()

def ask(screen, question):
  "ask(screen, question) -> answer"
  pygame.font.init()
  current_string = []
  display_box(screen, question + ": " + string.join(current_string,""))
  while 1:
    inkey = get_key()
    if inkey == K_BACKSPACE:
      current_string = current_string[0:-1]
    elif inkey == K_RETURN:
      break
    elif inkey == K_MINUS:
      current_string.append("_")
    elif inkey <= 127:
      current_string.append(chr(inkey))
    display_box(screen, question + ": " + string.join(current_string,""))
  return string.join(current_string,"")
while True:
        for block in blocklist:
            if any(block.rect.colliderect(b.rect) for b in blocklist if b is not block):
                blocklist.remove(block)

        if ingame==1:
            screen.fill(back_color)
            mse = pygame.mouse.get_pos()
            key = pygame.key.get_pressed()
            if key[K_a]:
                    anim+=1
                    if anim==9:
                            anim=1
            if key[K_d]:
                    anim+=1
                    if anim==9:
                            anim=1

            if key[K_LEFT]:
                try:
                        for b in blocklist:
                            b.rect.left+=32
                except:
                        pass
                try:
                        player.rect.left+=32
                except:
                        pass
            if key[K_RIGHT]:
                    try:
                        for b in blocklist:
                            b.rect.left-=32
                    except:
                            pass
                    try:
                        player.rect.left-=32
                    except:
                            pass
            if key[K_UP]:
                    try:
                        for b in blocklist:
                            b.rect.top+=32
                    except:
                            pass
                    try:
                        player.rect.top+=32
                    except:
                            pass
            if key[K_DOWN]:
                    try:
                        for b in blocklist:
                            b.rect.top-=32
                    except:
                            pass
                    try:
                        player.rect.top-=32
                    except:
                            pass
            if key[K_ESCAPE]:
                execfile('PiBlocks.pyw')
            for event in pygame.event.get():
                if event.type == QUIT:
                    exit()
                if event.type == MOUSEBUTTONDOWN:
                    if event.button == 4:
                        selected_block_index += 1
                    elif event.button == 5:
                        selected_block_index -= 1
                    selected_block_index = max(min(selected_block_index, num_of_types-1), 0)
                    selected_block_type = types[selected_block_index]
                elif event.type == KEYDOWN:
                    if event.key in key_map:
                        selected_block_type = key_map[event.key]
                        selected_block_index = types.index(selected_block_type)
                elif event.type==MOUSEMOTION:
                    if key[K_LSHIFT]:
                        if not any(block.rect.collidepoint(mse) for block in blocklist):
                            snd=random.randint(1,3)
                            x=(int(mse[0]) / 32)*32
                            y=(int(mse[1]) / 32)*32
                            if go==1:
                                if snd==1:
                                    place.play()
                                elif snd==2:
                                    place2.play()
                                elif snd==3:
                                    place3.play()
                                blocklist.append(Block(x,y,selected_block_type))
                    elif key[K_RSHIFT]:
                        to_remove = [b for b in blocklist if b.rect.collidepoint(mse)]
                        for b in to_remove:
                                if go==1:
                                        blocklist.remove(b)
                elif event.type == pygame.MOUSEBUTTONUP:
                    if event.button == 1:
                        to_remove = [b for b in blocklist if b.rect.collidepoint(mse)]
                        for b in to_remove:
                            if go==1:
                                    blocklist.remove(b)

                        if not to_remove:
                            snd=random.randint(1,3)
                            x=(int(mse[0]) / 32)*32
                            y=(int(mse[1]) / 32)*32
                            if go==1:
                                    if snd==1:
                                        place.play()
                                    elif snd==2:
                                        place2.play()
                                    elif snd==3:
                                        place3.play()
                                    blocklist.append(Block(x,y,selected_block_type))

                    elif event.button == 3:
                        x=(int(mse[0]) / 32)*32
                        y=(int(mse[1]) / 32)*32
                        player=Player(x+16,y+16)

            move = Move(key[K_w], key[K_a], key[K_d])

            for b in blocklist:
                    if b.rect.left>=0:
                            if b.rect.right<=640:
                                    screen.blit(b.image, b.rect)

            if player:
                player.update(move, blocklist)
                if anim==1 or anim==2 or anim==3:
                        screen.blit(psprite, player.rect)
                elif anim==4 or anim==5 or anim==6:
                        screen.blit(psprite2, player.rect)
                elif anim==7 or anim==8 or anim==9:
                        screen.blit(psprite3, player.rect)
            x=(int(mse[0]) / 32)*32
            y=(int(mse[1]) / 32)*32
            screen.blit(curs,(x,y))
            clock.tick(60)
            screen.blit(render_white('PiBlocks Alpha 0.6'), (1,1))
            screen.blit(render_white('Selected Texture Pack: ' + texdir), (1,12))
            screen.blit(render_white('Selected Block: '+ selected_block_type.name), (1,25))
            if gotime==0:
                go=1
            else:
                gotime-=1
            pygame.display.update()
        elif ingame==0:
                blocklist=[]
                mse = pygame.mouse.get_pos()
                player=[]
                key = pygame.key.get_pressed()
                text=font.render(splash, True, (255,255,255))
                if key[K_RETURN]:
                        ingame=1
                for event in pygame.event.get():
                        if event.type == QUIT:
                            exit()
                        if event.type == KEYDOWN:
                                print event.key
                if sbtnrect.collidepoint(mse):
                        if pygame.mouse.get_pressed()==(1,0,0):
                                ingame='gen'
                                top=(random.randint(5,8)*32)
                                cen=(top+random.randint(4,6)*32)
                                down=15
                                across=0
                                blklvl=0
                                while across<640:
                                        while down>0:
                                                screen.fill((0,0,0))
                                                if blklvl==top:
                                                    blocklist.append(block_factory('grass', across, blklvl))
                                                if blklvl>top and blklvl<cen:
                                                        blocklist.append(block_factory('dirt', across, blklvl))
                                                if blklvl>cen-1:
                                                    blocklist.append(block_factory('stone', across, blklvl))
                                                down=down-1
                                                blklvl=blklvl+32

                                        if down==0:
                                                if across<1920:
                                                        per=(across/(32/5))
                                                        if per>100:
                                                                per=100
                                                        top=(random.randint(5,8)*32)
                                                        cen=(top+random.randint(4,6)*32)
                                                        down=15 
                                                        blklvl=0
                                                        across=across+32
                                                        down=15
                                                        drawgen=font.render('GENERATION:'+str(per)+'%%', True, (255,255,255))
                                                        screen.blit(drawgen,(1,1))
                                                        pygame.display.flip()
                                        go=0
                                        ingame=1

                if qbtnrect.collidepoint(mse):
                        if pygame.mouse.get_pressed()==(1,0,0):
                                exit()
                if tbtnrect.collidepoint(mse):
                        if pygame.mouse.get_pressed()==(1,0,0):
                                ingame='texsel'
                screen.blit(backimg,(0,0))
                screen.blit(text,(364,76))
                screen.blit(sbtn,sbtnrect)
                screen.blit(qbtn,qbtnrect)
                screen.blit(tbtn,tbtnrect)
                pygame.display.flip()
        elif ingame=='texsel':
                 screen.blit(clsimg,(0,0))
                 inp = ask(screen, 'Texture Directory')
                 f=open('texdir.txt','w')
                 f.write(str(inp))
                 f.close()
                 pygame.display.flip()
                 execfile('PiBlocks.pyw')

and the config file (settings.cfg):

[Options]
Backcolor: (100, 100, 100)
TextureDir: .
DefaultBlock: dirt
ScreenSize: (640, 480)
Caption: PiBlocks | By Sam Tubb
Splash: ('Some splash!', 'Play This!', 'Whhooooaaaa!!')

Further steps are fixing indentation, clean up the deep nesting of if blocks, maybe introduce classes that represent the different game states, and removing the evil empty try/except blocks. Also, some code of blocks could also extrated to functions to improve readability.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.