[Tutor] A more Pythonic way to do this

Adam Bark adam.jtm30 at gmail.com
Fri Jul 1 01:35:08 CEST 2005


Here's the problem --> enemyship_sprites.add(Enemy((cols*60)+20, 
(rows*40)+30), level)
1,2 1 2 1 0
you've put a braket after +30 which ends the Enemy call. The numbering is +1 
for opening braket -1 for closing so 0 is the end of the Enemy call if you 
understand this.

On 6/30/05, D. Hartley <denise.hartley at gmail.com> wrote:
> 
> Hey guys!
> 
> I have a 'quest,' and at first glance this email looks long, but the
> problem is probably not as complex as the length implies. Please bear
> with me, if I could get some advice on this particular problem, it
> would go along way toward helping me be a better Python programmer.
> 
> Some of you might remember, a few months ago, I was working on a space
> invaders game for a birthday present. One of the functions I really
> wanted to add to the game was to change the enemy "ships" at each new
> level. Because of my deadline and my newness to Python, I did this in
> an extremely ugly way. To give you an idea:
> 
> the original main loop called:
> enemyship_sprites = createEnemies(screen, enemy_speed)
> 
> createEnemies looks like this:
> 
> def createEnemies(screen, speed):
> enemyship_sprites = EnemySprites(speed)
> for rows in xrange(5):
> for cols in xrange(8):
> enemyship_sprites.add(Enemy((cols*60)+20, (rows*40)+30), level)
> enemyship_sprites.draw(screen)
> return enemyship_sprites
> 
> It creates an instance of EnemySprites (my holder class) which
> contains code for when the ships hit bottom, when to update them, etc.
> It also calls "Enemy()", which looks like this:
> 
> class Enemy(pygame.sprite.Sprite):
> def __init__(self, startx, starty):
> pygame.sprite.Sprite.__init__(self)
> if level == 1:
> self.image, self.rect = load_image('salad_ship.bmp', -1)
> self.rect.centerx = startx
> self.rect.centery = starty
> def update(self, direction, go_down):
> jump = 40 # how much the enemies move to the right/left on
> each jump
> if go_down:
> # if a ship is moving down on this round,
> # it doesn't move on the x-axys
> self.rect.move_ip((0, 5))
> else:
> # move a ship in the x-axys.
> # if direction=1, it moves to the right; -1 to the left
> self.rect.move_ip((jump * direction, 0))
> # maybe it's time for a shot? :)
> # the chances are 1/30
> dice = random.randint(0,30)
> global enemy_shot_sprites
> if dice == 1:
> shot = EnemyShot(self.rect.midtop)
> enemy_shot_sprites.add(shot)
> 
> 
> Now, get ready for one of the uglier things you've probably seen lately 
> (!!):
> 
> Since I can only access the variable "level" from within the main
> loop, for some reason I thought I couldnt use it in my class
> definitions (which of course come before and are outside of the
> mainloop). So within the main loop, I did:
> 
> if level == 1:
> enemyship_sprites = createEnemies1(screen, enemy_speed)
> elif level == 2:
> enemyship_sprites = createEnemies2(screen, enemy_speed)
> elif level == 3:
> enemyship_sprites = createEnemies3(screen, enemy_speed)
> elif level == 4:
> enemyship_sprites = createEnemies4(screen, enemy_speed)
> elif level == 5:
> enemyship_sprites = createEnemies5(screen, enemy_speed)
> elif level == 6:
> enemyship_sprites = createEnemies6(screen, enemy_speed)
> elif level == 7:
> enemyship_sprites = createEnemies7(screen, enemy_speed)
> elif level == 8:
> enemyship_sprites = createEnemies8(screen, enemy_speed)
> else:
> enemyship_sprites = createEnemies9(screen, enemy_speed)
> 
> And yes, I created 9 different createEnemies, all pretty much carbon
> copies of each other except that they called Enemy1, Enemy2, Enemy3,
> etc. And then (you guessed it), I created 9 different Enemy
> functions, too, so that each one could have its own (different)
> bitmap.
> 
> Now... this is just ridiculous.
> 
> To my credit, I did actually know that at the time. But the day before
> the birthday, I figured if I could make it work somehow, I would, and
> I'd make it prettier later. Now just happens to be that later ;)
> 
> So now that I've got a little more Python experience under my belt
> (not much, but a little), it occurred to me that when I call
> createEnemies in the mainloop, I could pass in an argument 'level'.
> 
> mainloop now starting off with:
> enemyship_sprites = createEnemies(screen, enemy_speed, level)
> 
> level is one of my main loop variables, so it'll know what i'm talking
> about and can take that variable and pass it in when it calls
> createEnemies. (Btw, please forgive me if I mix up terms like argument
> and variable or use them in the wrong places, I'm still getting used
> to them!) In any case, then I changed my createEnemies to look like
> this:
> 
> def createEnemies(screen, speed, level):
> enemyship_sprites = EnemySprites(speed)
> for rows in xrange(5):
> for cols in xrange(8):
> enemyship_sprites.add(Enemy((cols*60)+20, (rows*40)+30), level)
> enemyship_sprites.draw(screen)
> return enemyship_sprites
> 
> Since the part that changes each level actually matters when the Enemy
> function gets called (because that's where the bmps are loaded), I
> made Enemy need 'level':
> 
> class Enemy(pygame.sprite.Sprite):
> def __init__(self, startx, starty, level):
> pygame.sprite.Sprite.__init__(self)
> if level == 1:
> self.image, self.rect = load_image('salad_ship.bmp', -1)
> elif level == 2:
> (.................etc)
> self.rect.centerx = startx
> self.rect.centery = starty
> (...............etc)
> 
> 
> Now I know this email is getting hard to read ;)
> 
> At this point I was thinking I'd have one createEnemies, called in the
> mainloop, which would take the level and, when it called Enemy to
> create the ships, use that level argument to determine which bmp to
> use for the ship itself. One createEnemies(), one Enemy(), there you
> go.
> 
> But now it's giving me an error when createEnemies is called, for the
> enemyship_sprites.add(Enemy((cols*60)+20, (rows*40)+30), level) line,
> saying __init__() (and this would be Enemy's init, correct?) takes
> exactly 4 arguments (3 given): and Enemy's init, as you can see,
> takes (self, startx, starty, level). But the first argument is just
> 'self'! I don't have to pass that in.... I never *did*, anyway, in
> all my Enemy1, Enemy2, Enemy3 code...?
> 
> I can send the full code for anybody who thinks that would be
> clearer to look at (ha ha) - I was going to attach it here but it
> would make the message too big for the list. I know that going
> through such a messy
> problem like this is a pain, and questions like this don't always get
> a lot of responses on the list. My code worked, it was just messy,
> and so I suppose I could just leave it alone. But I want to clean it
> up: I want to make it more Pythonic, more organized, more efficient,
> and would really love any advice anyone could offer.
> 
> Heck, for all I know, I could just be needing to add a "self.___"
> somewhere, heaven knows that has tripped me up before!
> 
> Would love to hear from you guys, and thanks again,
> Denise
> _______________________________________________
> Tutor maillist - Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/tutor/attachments/20050701/bf538316/attachment-0001.htm


More information about the Tutor mailing list