Mercurial > mhrok
changeset 26:7864a945fa1b
Overhaul the animation system to make it more turn-based
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Sat, 10 Mar 2012 09:57:57 +0100 |
| parents | 5aca833e2031 |
| children | d0ca7aad951c |
| files | mhrok.py |
| diffstat | 1 files changed, 133 insertions(+), 89 deletions(-) [+] |
line wrap: on
line diff
--- a/mhrok.py Tue Mar 06 23:03:34 2012 +0100 +++ b/mhrok.py Sat Mar 10 09:57:57 2012 +0100 @@ -13,6 +13,10 @@ from pygame import locals as pg +DX = [-1, 0, 1, 0] +DY = [0, -1, 0, 1] + + class Shadow(pygame.sprite.Sprite): def __init__(self, frames, owner): super(Shadow, self).__init__() @@ -35,6 +39,7 @@ self.images[r] = self.get_image(r) self.radius = radius self.set_radius(radius) + self.rooms = [] def set_radius(self, radius): self.current_radius = radius @@ -42,7 +47,6 @@ self.rect = self.image.get_rect() self.rect.center = self.owner.rect.center - def get_image(self, radius): image = pygame.Surface((radius*5/2, radius*2), pg.SRCALPHA) image.fill((255, 255, 255, 255)) @@ -61,13 +65,10 @@ self.rect.center = self.owner.rect.center -class Mob(pygame.sprite.Sprite): - animations = [[0]] - movements = [(0, 0)] - - def __init__(self, frames, (x, y)): - super(Mob, self).__init__() - self.animation = 0 +class MobSprite(pygame.sprite.Sprite): + def __init__(self, frames, (x, y), animation): + super(MobSprite, self).__init__() + self.animation = animation self.frames = frames self.image = self.frames[0] self.rect = self.image.get_rect() @@ -76,83 +77,129 @@ self.depth = self.rect.bottom def update(self): - self.rect.move_ip(*self.movements[self.animation]) - self.frame = (self.frame + 1) % len(self.animations[self.animation]) - self.image = self.frames[self.animations[self.animation][self.frame]] - self.depth = self.rect.bottom + self.frame = (self.frame + 1) % len(self.animation) + self.image = self.frames[self.animation[self.frame]] + #if self.direction is not None: + # self.rect.move_ip((DX[self.direction]*5, DY[self.direction]*3)) + # self.depth = self.rect.bottom + +class Mob(object): + Sprite = MobSprite + + def __init__(self, (x, y)): + self.pos = x, y + self.direction = None + + def make_sprite(self, tiles): + self.sprite = self.Sprite(tiles, self.pos, self.animation) + shadow = Shadow(tiles, self.sprite) + return self.sprite, shadow, None + + def control(self, level): + self.direction = random.choice([None, 0, 1, 2, 3]) class Bat(Mob): - animations = [ - [25, 26] - ] - movements = [(0, 0), (0, 0)] + animation = [25, 26] class Chest(Mob): - animations = [ - [27], - [28], - ] + animation = [27] class Skeleton(Mob): - animations = [ - [35, 35, 35, 36, 36, 36, 35, 35, 35, 37, 37, 37], - ] + animation = [35, 35, 35, 36, 36, 36, 35, 35, 35, 37, 37, 37] class Teddybear(Mob): - animations = [ - [30, 30, 30, 31, 31, 31, 30, 30, 30, 32, 32, 32], - ] + animation = [30, 30, 30, 31, 31, 31, 30, 30, 30, 32, 32, 32] -class PlayerMob(Mob): - animations = [ - [0, 0, 1, 1, 0, 0, 2, 2], - [5, 5, 6, 6, 5, 5, 7, 7], - [10, 10, 11, 11, 10, 10, 12, 12], - [15, 15, 16, 16, 15, 15, 16, 16], - [0], - [5], - [10], - [15], - ] - movements = [ - (0, 3), - (-5, 0), - (0, -3), - (5, 0), - (0, 0), - (0, 0), - (0, 0), - (0, 0), - ] +class PlayerSprite(pygame.sprite.Sprite): + def __init__(self, frames, (x, y)): + super(PlayerSprite, self).__init__() + self.direction = 0 + self.frames = frames + self.image = self.frames[0] + self.animation = self.stand_animation(self.direction) + self.rect = self.image.get_rect() + self.rect.move_ip(4 + 20 * x, 12 * y) + self.depth = self.rect.bottom + + def update(self): + if self.animation: + try: + self.animation.next() + except StopIteration: + self.animation = None + def walk_animation(self, direction): + frames = [ + [5, 6, 5, 7], + [10, 11, 10, 12], + [15, 16, 15, 16], + [0, 1, 0, 2], + ][direction] + for frame in frames: + yield None + self.rect.move_ip((DX[direction]*5, DY[direction]*3)) + self.image = self.frames[frame] + self.depth = self.rect.bottom + + def stand_animation(self, direction): + yield None + frame = [5, 10, 15, 0][direction] + self.image = self.frames[frame] + + def set_animation(self, animation): + self.animation = animation + try: + self.animation.next() + except StopIteration: + self.animation = None class Player(object): def place(self, (x, y)): self.pos = x, y + self.direction = 3 + self.sprite = None - def make_mob(self, tiles): - self.mob = PlayerMob(tiles, self.pos) - return self.mob + def make_sprite(self, tiles): + self.sprite = PlayerSprite(tiles, self.pos) + shadow = Shadow(tiles, self.sprite) + self.vision = Vision(self.sprite, 64) + return self.sprite, shadow, self.vision + + def walk(self, level, direction): + self.direction = direction + x, y = self.pos + if not level[x + DX[direction], y + DY[direction]]: + return + self.sprite.set_animation(self.sprite.walk_animation(direction)) + self.pos = x + DX[direction], y + DY[direction] def control(self, level): - mx, my = self.mob.rect.topleft - x, y = (mx+1)/20, (my+6)/12 keys = pygame.key.get_pressed() - if keys[pg.K_UP] and level[(mx - 4 + 5) / 20, (my + 6 - 3) / 12]: - self.mob.animation = 2 - elif keys[pg.K_LEFT] and level[(mx - 9 + 5) / 20, (my + 6) / 12]: - self.mob.animation = 1 - elif keys[pg.K_DOWN] and level[(mx - 4 + 5) / 20, (my + 9 + 3) / 12]: - self.mob.animation = 0 - elif keys[pg.K_RIGHT] and level[(mx + 1 + 10) / 20, (my + 6) / 12]: - self.mob.animation = 3 + if keys[pg.K_UP]: + self.walk(level, 1) + elif keys[pg.K_LEFT]: + self.walk(level, 0) + elif keys[pg.K_DOWN]: + self.walk(level, 3) + elif keys[pg.K_RIGHT]: + self.walk(level, 2) else: - self.mob.animation = 4 + self.mob.animation % 4 + self.sprite.set_animation( + self.sprite.stand_animation(self.direction)) + + room = level.find_room(*self.pos) + if room: + self.vision.radius = 64 + if room not in level.lit_rooms: + level.lit_rooms.append(room) + self.vision.rooms.append(room) + else: + self.vision.radius = 40 class SortedUpdates(pygame.sprite.RenderUpdates): @@ -166,7 +213,7 @@ class Level(object): def __init__(self, pc): self.pc = pc - self.mobs = {} + self.mobs = [pc] self.width = 31 self.height = 38 @@ -207,8 +254,8 @@ for i in xrange(r(1, 3)): self[r(x, x+w), r(y, y+h)] = 4 for i in xrange(r(1, 4)): - self.mobs[r(x, x+w), r(y, y+h)] = random.choice( - [Bat, Chest, Teddybear, Skeleton]) + MobClass = random.choice([Bat, Chest, Teddybear, Skeleton]) + self.mobs.append(MobClass((r(x, x + w), r(y, y + h)))) self[r(x, x+w), r(y, y+h)] = 5 (x, y), (w, h) = random.choice(rooms) @@ -291,14 +338,16 @@ def render_sprites(self, tiles): sprites = SortedUpdates() shadows = pygame.sprite.RenderUpdates() - for (x, y), Mob in self.mobs.iteritems(): - mob = Mob(tiles, (x, y)) - sprites.add(mob) - shadows.add(Shadow(tiles, mob)) - mob = self.pc.make_mob(tiles) - sprites.add(mob) - shadows.add(Shadow(tiles, mob)) - return sprites, shadows, mob + visions = pygame.sprite.LayeredDirty() + for mob in self.mobs: + sprite, shadow, vision = mob.make_sprite(tiles) + if sprite: + sprites.add(sprite) + if shadow: + shadows.add(shadow) + if vision: + visions.add(vision) + return sprites, shadows, visions class Display(object): @@ -316,11 +365,9 @@ self.dirty = [] def render_level(self, level): - self.sprites, self.shadows, pcmob = level.render_sprites(self.tiles) + (self.sprites, + self.shadows, self.visions) = level.render_sprites(self.tiles) self.background.blit(level.render_background(self.tiles), (0, 0)) - self.visions = pygame.sprite.LayeredDirty() - self.vision = Vision(pcmob, 64) - self.visions.add(self.vision) def light_room(self, room): (rx, ry), (rw, rh) = room @@ -330,7 +377,7 @@ mh = (rh+1) * 12 + 12 darkroom = self.background.subsurface((mx, my, mw, mh)) darkroom.set_alpha(16) - rect=self.memory.blit(darkroom, (mx, my)) + rect = self.memory.blit(darkroom, (mx, my)) self.fog.blit(self.memory, (mx, my), rect) self.dirty.append(rect) @@ -357,7 +404,11 @@ def update(self): self.sprites.update() self.shadows.update() - self.vision.update() + self.visions.update() + for vision in self.visions: + while vision.rooms: + room = vision.rooms.pop() + self.light_room(room) class Game(object): @@ -372,24 +423,17 @@ def main(self): while not self.game_over: - self.pc.control(self.level) - mx, my = self.pc.mob.rect.topleft - room = self.level.find_room((mx+1)/20, (my+6)/12) - if room: - self.display.vision.radius = 64 - if room not in self.level.lit_rooms: - self.level.lit_rooms.append(room) - self.display.light_room(room) - else: - self.display.vision.radius = 40 - self.display.draw() self.clock.tick(15) self.display.update() + self.display.draw() for event in pygame.event.get(): if event.type == pg.QUIT or ( event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE): self.game_over = True + if self.pc.sprite.animation is None: + for mob in self.level.mobs: + mob.control(self.level) def load_tiles(filename, width, height):
