Mercurial > fhrl
changeset 9:3094d51c1dc7
Update
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Wed, 13 Mar 2013 13:40:50 +0100 |
| parents | 5c4c86502a2f |
| children | 89bcca88e444 |
| files | fhrl/__main__.py fhrl/arrows.png fhrl/display.py fhrl/items.png fhrl/level.py fhrl/mobs.py fhrl/mobs2.png fhrl/resources.py fhrl/rocks.png |
| diffstat | 9 files changed, 376 insertions(+), 284 deletions(-) [+] |
line wrap: on
line diff
--- a/fhrl/__main__.py Tue Mar 12 14:50:30 2013 +0100 +++ b/fhrl/__main__.py Wed Mar 13 13:40:50 2013 +0100 @@ -2,285 +2,11 @@ # -*- coding: utf-8 -*- import pygame -import StringIO -import pkgutil -import random - - -DX = [0, 1, 0, -1] -DY = [-1, 0, 1, 0] -RES = None - - -class Resources(object): - def __init__(self): - self.walls = self.load_atlas('walls.png', 48, 32) - self.floor = self.load_atlas('rocks.png', 48, 32) - self.mobs = self.load_atlas('mobs2.png', 48, 48) - self.items = self.load_atlas('items.png', 48, 32) - - @staticmethod - def load_image(filename): - f = StringIO.StringIO(pkgutil.get_data('fhrl', filename)) - return pygame.image.load(f, filename) - - @classmethod - def load_atlas(cls, filename, width=32, height=None): - image = cls.load_image(filename) - image_width, image_height = image.get_size() - w, h = width, height or width - return [ - image.subsurface((x * w, y * h, w, h)) - for y in xrange(0, image_height // h) - for x in xrange(0, image_width // w) - ] - - -class SortedUpdates(pygame.sprite.RenderUpdates): - def sprites(self): - return sorted(self.spritedict.keys(), key=lambda s: s.rect.bottom) - - -class Level(object): - def __init__(self, (width, height), resources): - self.resources = resources - self.width = width - self.height = height - self.grid = [ - [1] * width for y in xrange(height) - ] - self.generate() - self.populate() - - def generate(self): - for i in xrange(30): - x = random.randrange(1, self.width) - y = random.randrange(1, self.height) - for j in xrange(50): - x = max(1, min(self.width - 1, x + random.randrange(-1, 2))) - y = max(1, min(self.height - 1, y + random.randrange(-1, 2))) - self.grid[y][x] = 0 - for i in xrange(200): - x = random.randrange(1, self.width) - y = random.randrange(1, self.height) - self.grid[y][x] = 1 - for i in xrange(50, 200): - x = random.randrange(2, self.width - 3) - y = random.randrange(2, self.height - 3) - w = random.randrange(3, 10) - h = random.randrange(3, 10) - w = max(1, min(self.width - x - 2, w)) - h = max(1, min(self.height - y - 2, h)) - self.rect(x, y, w, h, 0) - self.rect(x-1, y-1, w+2, h+2, 1) - self.rect(x+1, y+1, w-2, h-2, 1) - if w > 2 and h > 2: - for i in xrange(random.randrange(1, 4)): - if random.choice((0, 1)): - dx = x + random.randrange(w - 2) + 1 - if random.choice((0, 1)): - self.grid[y][dx] = 2 - else: - self.grid[y + h - 1][dx] = 2 - else: - dy = y + random.randrange(h - 2) + 1 - if random.choice((0, 1)): - self.grid[dy][x] = 3 - else: - self.grid[dy][x + w - 1] = 3 - for i in xrange(200): - x = random.randrange(1, self.width) - y = random.randrange(1, self.height) - if self.grid[y][x] == 1: - self.grid[y][x] = 4 - self.rect(0, 0, self.width, self.height, 0) - - - def populate(self): - self.free = [ - (x, y) - for y, row in enumerate(self.grid) - for x, f in enumerate(row) - if f - ] - random.shuffle(self.free) - self.hero = Hero(self.resources.mobs[0], self.free.pop()) - self.monsters = [ - Mob(self.resources.mobs[1], self.free.pop()) - for i in xrange(20) - ] - self.items = [ - Item(self.resources.items[random.randrange(4)], self.free.pop()) - for i in xrange(20) - ] - x, y = self.free.pop() - self.grid[y][x] = 5 - - - def __iter__(self): - return iter(self.grid) - - def rect(self, sx, sy, w, h, v): - sx = max(0, min(self.width, sx)) - sy = max(0, min(self.height, sy)) - w = max(1, min(self.width - sx, w)) - h = max(1, min(self.height - sy, h)) - for y in xrange(sy, sy + h): - self.grid[y][sx] = v - self.grid[y][sx + w - 1] = v - for x in xrange(sx, sx + w): - self.grid[sy][x] = v - self.grid[sy + h - 1][x] = v - return sx, sy, w, h - def render(self, surf): - for y, row in enumerate(self.grid): - for x, f in enumerate(row): - surf.blit(self.resources.floor[f], (x * 48 - 24, y * 32)) - nrows = iter(self.grid) - nrows.next() - for y, (row, nrow) in enumerate(zip(self.grid, nrows)): - for x, ts in enumerate(zip(row, row[1:], nrow, nrow[1:])): - surf.blit( - self.resources.walls[ - sum((not t) * 2**i for i, t in enumerate(ts)) - ], - (x * 48, y * 32) - ) - -class Item(pygame.sprite.DirtySprite): - def __init__(self, image, (x, y)): - super(Item, self).__init__() - self.image = image - self.rect = self.image.get_rect() - self.rect.topleft = x * 48 - 24, y * 32 - 12 - self.x, self.y = x, y - - -class Mob(pygame.sprite.DirtySprite): - def __init__(self, image, (x, y)): - super(Mob, self).__init__() - self.image = image - self.rect = self.image.get_rect() - self.rect.topleft = x * 48 - 24, y * 32 - 33 - self.x, self.y = x, y - - def _walk_anim(self, d): - for frame in xrange(8): - self.rect.move_ip(DX[d] * 6, DY[d] * 4) - yield - - def walk(self, d, level): - x = self.x + DX[d] - y = self.y + DY[d] - if not level.grid[y][x]: - return False - self.x, self.y = x, y - return self._walk_anim(d) - - def act(self, level): - return self.walk(random.randrange(4), level) - - -class Hero(Mob): - def act(self, level): - for event in pygame.event.get(): - if (event.type == pygame.QUIT or - event.type == pygame.KEYDOWN and - event.key == pygame.K_ESCAPE - ): - raise SystemExit() - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_UP: - return self.walk(0, level) - elif event.key == pygame.K_RIGHT: - return self.walk(1, level) - elif event.key == pygame.K_DOWN: - return self.walk(2, level) - elif event.key == pygame.K_LEFT: - return self.walk(3, level) - return False - +from fhrl.display import Display +from fhrl.level import Level +from fhrl.resources import Resources -class Display(object): - def __init__(self): - self.width = 480 - self.height = 480 - self.x, self.y = 0, 0 - self.screen = pygame.display.set_mode((self.width, self.height)) - self.clock = pygame.time.Clock() - self.animations = [] - - def load_level(self, level): - self.background = pygame.Surface( - (level.width * 48 - 48, level.height * 32 - 32) - ) - level.render(self.background) - self.sprites = SortedUpdates() - self.sprites.add(level.hero) - for m in level.monsters: - self.sprites.add(m) - for i in level.items: - self.sprites.add(i) - - def _scroll_anim(self, dx, dy): - frame = 0 - while dx or dy: - ddx = dx and dx // abs(dx) - ddy = dy and dy // abs(dy) - self.x -= ddx - self.y -= ddy - dx -= ddx - dy -= ddy - for s in self.sprites: - s.rect.move_ip(-ddx, -ddy) - frame += 1 - if not frame % 6: - self.update_all() - yield - self.update_all() - - def scroll_by(self, dx, dy, instant=False): - w, h = self.background.get_size() - dx = min(max(self.x, dx), self.x+w-self.width) - dy = min(max(self.y, dy), self.y+h-self.height) - if instant: - self.x -= dx - self.y -= dy - for s in self.sprites: - s.rect.move_ip(-dx, -dy) - else: - self.animations.append(self._scroll_anim(dx, dy)) - - def _sprite_clear(self, screen, rect): - source = rect.move(-self.x, -self.y) - if not self.background.get_rect().contains(source): - screen.fill((0x66, 0x66, 0x66), rect) - screen.blit(self.background, rect, source) - - def update(self): - self.sprites.clear(self.screen, self._sprite_clear) - dirty = self.sprites.draw(self.screen) - pygame.display.update(dirty) - self.clock.tick(24) - - def update_all(self): - self.screen.blit(self.background, (self.x, self.y)) - self.sprites.draw(self.screen) - pygame.display.flip() - - def play_animations(self): - while self.animations: - cont = [] - for anim in self.animations: - try: - anim.next() - except StopIteration: - pass - else: - cont.append(anim) - self.animations = cont - self.update() class Game(object): def __init__(self): @@ -299,15 +25,14 @@ self.display.update_all() while True: while True: - anim = self.level.hero.act(self.level) - if anim: - self.display.animations.append(anim) + anims = self.level.hero.act(self.level, self.display) + if anims: + self.display.animations.extend(anims) break - self.display.update() + else: + self.display.update() for m in self.level.monsters: - anim = m.act(self.level) - if anim: - self.display.animations.append(anim) + self.display.animations.extend(m.act(self.level)) if self.level.hero.rect.right > self.display.width - self.margin: self.display.scroll_by(48, 0) elif self.level.hero.rect.left < self.margin: @@ -320,3 +45,4 @@ pygame.display.init() Game().run() +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fhrl/display.py Wed Mar 13 13:40:50 2013 +0100 @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- + +import pygame + + +class SortedUpdates(pygame.sprite.RenderUpdates): + def sprites(self): + return sorted(self.spritedict.keys(), key=lambda s: s.rect.bottom) + + + +class Display(object): + def __init__(self): + self.width = 480 + self.height = 480 + self.x, self.y = 0, 0 + self.screen = pygame.display.set_mode((self.width, self.height)) + self.clock = pygame.time.Clock() + self.animations = [] + + def load_level(self, level): + self.background = pygame.Surface( + (level.width * 48 - 48, level.height * 32 - 32) + ) + level.render(self.background) + self.sprites = SortedUpdates() + self.sprites.add(level.hero) + for m in level.monsters: + self.sprites.add(m) + for i in level.items: + self.sprites.add(i) + for s in level.stuff: + self.sprites.add(s) + + def _scroll_anim(self, dx, dy): + frame = 0 + while dx or dy: + ddx = dx and dx // abs(dx) + ddy = dy and dy // abs(dy) + self.x -= ddx + self.y -= ddy + dx -= ddx + dy -= ddy + for s in self.sprites: + s.rect.move_ip(-ddx, -ddy) + frame += 1 + if not frame % 6: + self.update_all() + yield + self.update_all() + + def scroll_by(self, dx, dy, instant=False): + w, h = self.background.get_size() + dx = min(max(self.x, dx), self.x+w-self.width) + dy = min(max(self.y, dy), self.y+h-self.height) + if instant: + self.x -= dx + self.y -= dy + for s in self.sprites: + s.rect.move_ip(-dx, -dy) + else: + self.animations.append(self._scroll_anim(dx, dy)) + + def _sprite_clear(self, screen, rect): + source = rect.move(-self.x, -self.y) + if not self.background.get_rect().contains(source): + screen.fill((0x66, 0x66, 0x66), rect) + screen.blit(self.background, rect, source) + + def update(self): + self.sprites.clear(self.screen, self._sprite_clear) + dirty = self.sprites.draw(self.screen) + pygame.display.update(dirty) + self.clock.tick(24) + for event in pygame.event.get(): + if (event.type == pygame.QUIT or + event.type == pygame.KEYDOWN and + event.key == pygame.K_ESCAPE + ): + raise SystemExit() + + def update_all(self): + self.screen.blit(self.background, (self.x, self.y)) + self.sprites.draw(self.screen) + pygame.display.flip() + + def play_animations(self): + while self.animations: + cont = [] + for anim in self.animations: + try: + anim.next() + except StopIteration: + pass + else: + cont.append(anim) + self.animations = cont + if self.animations: + self.update() +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fhrl/level.py Wed Mar 13 13:40:50 2013 +0100 @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- + +import random + +from fhrl.mobs import Hero, Item, Mob, Stuff + + +class Level(object): + def __init__(self, (width, height), resources): + self.resources = resources + self.width = width + self.height = height + self.grid = [ + [1] * width for y in xrange(height) + ] + self.generate() + self.populate() + + def generate(self): + for i in xrange(30): + x = random.randrange(1, self.width) + y = random.randrange(1, self.height) + for j in xrange(50): + x = max(1, min(self.width - 1, x + random.randrange(-1, 2))) + y = max(1, min(self.height - 1, y + random.randrange(-1, 2))) + self.grid[y][x] = 0 + for i in xrange(200): + x = random.randrange(1, self.width) + y = random.randrange(1, self.height) + self.grid[y][x] = 1 + for i in xrange(50, 200): + x = random.randrange(2, self.width - 3) + y = random.randrange(2, self.height - 3) + w = random.randrange(3, 10) + h = random.randrange(3, 10) + w = max(1, min(self.width - x - 2, w)) + h = max(1, min(self.height - y - 2, h)) + self.rect(x, y, w, h, 0) + self.rect(x-1, y-1, w+2, h+2, 1) + self.rect(x+1, y+1, w-2, h-2, 1) + if w > 2 and h > 2: + for i in xrange(random.randrange(1, 4)): + if random.choice((0, 1)): + dx = x + random.randrange(w - 2) + 1 + if random.choice((0, 1)): + self.grid[y][dx] = 2 + else: + self.grid[y + h - 1][dx] = 2 + else: + dy = y + random.randrange(h - 2) + 1 + if random.choice((0, 1)): + self.grid[dy][x] = 3 + else: + self.grid[dy][x + w - 1] = 3 + for i in xrange(200): + x = random.randrange(1, self.width) + y = random.randrange(1, self.height) + if self.grid[y][x] == 1: + self.grid[y][x] = 4 + self.rect(0, 0, self.width, self.height, 0) + + + def populate(self): + self.free = [ + (x, y) + for y, row in enumerate(self.grid) + for x, f in enumerate(row) + if f + ] + random.shuffle(self.free) + self.hero = Hero(self.resources.mobs[0], self.free.pop()) + self.monsters = [ + Mob(self.resources.mobs[random.randrange(1, 3)], self.free.pop()) + for i in xrange(20) + ] + self.items = [ + Item(self.resources.items[random.randrange(6)], self.free.pop()) + for i in xrange(20) + ] + self.stuff = [ + Stuff(self.resources.stuff[random.randrange(4)], self.free.pop()) + for i in xrange(20) + ] + x, y = self.free.pop() + self.grid[y][x] = 5 + + def find_mob(self, (x, y)): + for m in self.monsters: + if (x, y) == (m.x, m.y): + return m + if (x, y) == (self.hero.x, self.hero.y): + return self.hero + + def is_blocked(self, (x, y)): + if self.grid[y][x] == 0: + return True + for s in self.stuff: + if (x, y) == (s.x, s.y): + return True + return False + + def __iter__(self): + return iter(self.grid) + + def rect(self, sx, sy, w, h, v): + sx = max(0, min(self.width, sx)) + sy = max(0, min(self.height, sy)) + w = max(1, min(self.width - sx, w)) + h = max(1, min(self.height - sy, h)) + for y in xrange(sy, sy + h): + self.grid[y][sx] = v + self.grid[y][sx + w - 1] = v + for x in xrange(sx, sx + w): + self.grid[sy][x] = v + self.grid[sy + h - 1][x] = v + return sx, sy, w, h + + def render(self, surf): + for y, row in enumerate(self.grid): + for x, f in enumerate(row): + surf.blit(self.resources.floor[f], (x * 48 - 24, y * 32)) + nrows = iter(self.grid) + nrows.next() + for y, (row, nrow) in enumerate(zip(self.grid, nrows)): + for x, ts in enumerate(zip(row, row[1:], nrow, nrow[1:])): + surf.blit( + self.resources.walls[ + sum((not t) * 2**i for i, t in enumerate(ts)) + ], + (x * 48, y * 32) + ) + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fhrl/mobs.py Wed Mar 13 13:40:50 2013 +0100 @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +import pygame +import random + + +DX = [0, 1, 0, -1, -1, 1, 1, -1] +DY = [-1, 0, 1, 0, -1, -1, 1, 1] +XYD = {(x, y):i for i, (x, y) in enumerate(zip(DX, DY))} + + +class ActException(Exception): + """Base class for all acting-related exceptions.""" + + +class ActBlocked(ActException): + """Raised when you try to move into the wall.""" + +class ActBump(ActException): + """Raised when you try to walk into a monster.""" + + +class Item(pygame.sprite.DirtySprite): + def __init__(self, image, (x, y)): + super(Item, self).__init__() + self.image = image + self.rect = self.image.get_rect() + self.rect.topleft = x * 48 - 24, y * 32 - 12 + self.x, self.y = x, y + + +class Stuff(pygame.sprite.DirtySprite): + def __init__(self, image, (x, y)): + super(Stuff, self).__init__() + self.image = image + self.rect = self.image.get_rect() + self.rect.topleft = x * 48 - 24, y * 32 - 24 + self.x, self.y = x, y + + +class Mob(pygame.sprite.DirtySprite): + def __init__(self, image, (x, y)): + super(Mob, self).__init__() + self.image = image + self.rect = self.image.get_rect() + self.rect.topleft = x * 48 - 24, y * 32 - 33 + self.x, self.y = x, y + + def _walk_anim(self, d): + for frame in xrange(8): + self.rect.move_ip(DX[d] * 6, DY[d] * 4) + yield + + def walk(self, d, level): + x = self.x + DX[d] + y = self.y + DY[d] + if level.is_blocked((x, y)): + raise ActBlocked() + m = level.find_mob((x, y)) + if m: + raise ActBump() + self.x, self.y = x, y + return self._walk_anim(d) + + def act(self, level): + try: + return [self.walk(random.randrange(4), level)] + except ActException: + return [] + + +class Hero(Mob): + def act(self, level, display): + keys = pygame.key.get_pressed() + direction = None + if keys[pygame.K_UP]: + if keys[pygame.K_LEFT]: + direction = 4 + elif keys[pygame.K_RIGHT]: + direction = 5 + else: + direction = 0 + elif keys[pygame.K_DOWN]: + if keys[pygame.K_LEFT]: + direction = 7 + elif keys[pygame.K_RIGHT]: + direction = 6 + else: + direction = 2 + elif keys[pygame.K_LEFT]: + direction = 3 + elif keys[pygame.K_RIGHT]: + direction = 1 + if direction is not None: + try: + return [self.walk(direction, level)] + except ActException: + pass + return [] + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fhrl/resources.py Wed Mar 13 13:40:50 2013 +0100 @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +import StringIO +import pkgutil +import pygame + + +class Resources(object): + def __init__(self): + self.walls = self.load_atlas('walls.png', 48, 32) + self.floor = self.load_atlas('rocks.png', 48, 32) + self.mobs = self.load_atlas('mobs2.png', 48, 48) + self.stuff = self.load_atlas('stuff.png', 48, 48) + self.items = self.load_atlas('items.png', 48, 32) + + @staticmethod + def load_image(filename): + f = StringIO.StringIO(pkgutil.get_data('fhrl', filename)) + return pygame.image.load(f, filename) + + @classmethod + def load_atlas(cls, filename, width=32, height=None): + image = cls.load_image(filename) + image_width, image_height = image.get_size() + w, h = width, height or width + return [ + image.subsurface((x * w, y * h, w, h)) + for y in xrange(0, image_height // h) + for x in xrange(0, image_width // w) + ] +
