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()
+
Binary file fhrl/arrows.png has changed
--- /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()
+
Binary file fhrl/items.png has changed
--- /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 []
+
+
+
Binary file fhrl/mobs2.png has changed
--- /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)
+        ]
+
Binary file fhrl/rocks.png has changed