changeset 1:c8a7aa8fadbb

Initial import
author Radomir Dopieralski <moindev@sheep.art.pl>
date Sat, 15 Dec 2007 23:16:54 +0100
parents 8076aec96236
children 36b63652966f
files abi2.png avatar.py box.png brain.png cache.py corridor.png floor.png game.py jello.png joe.png level.py main.py map.txt monster.py readme.txt skeleton.png stairs.png util.py
diffstat 18 files changed, 351 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
Binary file abi2.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/avatar.py	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,42 @@
+import pygame
+from pygame.locals import *
+
+from util import *
+
+class Avatar(pygame.sprite.Sprite):
+
+    def __init__(self, x=0, y=0, image_file="abi2.png"):
+        '''Create the avatar. Each one is likely to have different graphics.'''
+
+        pygame.sprite.Sprite.__init__(self)
+        # The starting values
+        self.x = x
+        self.y = y
+        self.z = y*16-12
+        self.rect = Rect(self.x*24, self.z, 24, 24)
+        self.frame = 0
+        self.facing = 0
+        self.frames = read_frames(image_file, 24)
+        self.image = self.frames[0][2]
+   
+    def update(self):
+        '''Actually animate the avatar'''
+
+        if self.facing:
+            self.image = self.frames[self.frame/2][self.facing-1]
+            self.z = self.y*16-12+self.frame*delta_y[self.facing]*2-delta_y[self.facing]*16
+            x = self.x*24+self.frame*delta_x[self.facing]*3-delta_x[self.facing]*24
+            self.rect = Rect(x, self.z, 24, 24)
+            self.frame += 1
+            if self.frame>=len(self.frames)*2:
+                self.frame = 0
+                self.facing = 0
+        else:
+            self.image = self.frames[0][2]
+            self.z = self.y*16-12
+            self.rect = Rect(self.x*24, self.z, 24, 24)
+
+    def walk(self, direction):
+        self.facing = direction
+        self.x += delta_x[self.facing]
+        self.y += delta_y[self.facing]
Binary file box.png has changed
Binary file brain.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cache.py	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,21 @@
+import pygame
+from pygame.locals import *
+
+class Cache:
+    def __init__(self):
+        self.images = {}
+
+    def get_image(self, filename=None):
+        '''Return an image from specified file.'''
+
+        if not filename in self.images:
+            try:
+                self.images[filename] = pygame.image.load(filename).convert()
+            except:
+                return None
+        return self.images[filename]
+
+    def get_object(self, url):
+        '''Return an object identified by specified url'''
+        
+        return None
Binary file corridor.png has changed
Binary file floor.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/game.py	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,48 @@
+import pygame
+from pygame.locals import *
+
+from level import Level
+from avatar import Avatar
+
+class Game:
+    def __init__(self):
+        # Init
+        pygame.init()
+        self.screen = pygame.display.set_mode((480, 320))
+        self.clock = pygame.time.Clock()
+
+        # Prapare the map 
+        self.level = Level(self.screen, 'map.txt')
+
+    def main_loop(self):
+        self.level.refresh(self.screen)
+        av = self.level.player
+        key_pressed = None
+        while 1:
+            # Update the screen
+            self.level.update(self.screen)
+            self.clock.tick(15)
+            # Process input
+            for event in pygame.event.get():
+                if event.type==QUIT:
+                    return
+                elif event.type==KEYDOWN:
+                    key_pressed = event.key
+            if av.frame==0:
+                keys = pygame.key.get_pressed()
+                if ((keys[K_UP] or key_pressed==K_UP) and 
+                    not self.level.is_blocked(av.x, av.y-1)):
+                    av.walk(1)
+                elif ((keys[K_DOWN] or key_pressed==K_DOWN) and
+                    not self.level.is_blocked(av.x, av.y+1)):
+                    av.walk(3)
+                elif ((keys[K_LEFT] or key_pressed==K_LEFT) and
+                    not self.level.is_blocked(av.x-1, av.y)):
+                    av.walk(4)
+                elif ((keys[K_RIGHT] or key_pressed==K_RIGHT) and
+                    not self.level.is_blocked(av.x+1, av.y)):
+                    av.walk(2)
+                elif key_pressed == K_ESCAPE:
+                    return
+                key_pressed = None
+
Binary file jello.png has changed
Binary file joe.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level.py	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,90 @@
+import re
+
+import pygame
+from pygame.locals import *
+
+from monster import Monster
+from avatar import Avatar
+from cache import Cache
+from util import *
+
+class MapFileError:
+    pass
+
+class Level:
+    def __init__(self, screen, filename):
+        self.animations = SortedUpdates()
+        self.avatar = Avatar(0, 0)
+        self.background = pygame.Surface(screen.get_size())
+        self.read_map(filename)
+        self.cache = Cache()
+        self.create_map()
+    
+    def create_map(self):
+        '''Create background and animations.'''
+
+        self.background.fill( (0, 0, 0) )
+        x =0
+        y =0
+        for line in self.map:
+            for tile in line:
+                urls = self.map_key[tile]
+                if urls:
+                    image = self.cache.get_image(urls[0])
+                    if image:
+                        self.background.blit(image , (x*24, y*16))
+                    for url in urls[1:]:
+                        if url=='joe.png':
+                            self.player = Avatar(x, y)
+                            self.animations.add(self.player)
+                        else:
+                            self.animations.add(Monster(x, y, url))
+                x += 1
+            x = 0
+            y += 1
+
+    def read_map(self, filename):
+        '''Read the map from a file.'''
+
+        self.map = []
+        self.blocking = []
+        self.map_key = {}
+        for line in file(filename).readlines():
+            m = re.match('^(?P<key>.)\s+<(?P<urls>.*)>\s*$', line)
+            if m:
+                urls = re.split('>\s*<', m.group('urls'))
+                self.map_key[m.group('key')] = urls
+            elif re.match('^\s*$', line):
+                pass # Ignore empty lines
+            else:
+                map_line = []
+                block_line = []
+                for char in line:
+                    if char in self.map_key:
+                        map_line.append(char)
+                        if char=='X':
+                            block_line.append(True)
+                        else:
+                            block_line.append(False)
+                self.map.append(map_line)
+                self.blocking.append(block_line)
+
+    def is_blocked(self, x, y):
+        try:
+            return self.blocking[y][x]
+        except:
+            return True
+
+    def refresh(self, screen):
+        '''Redraw the whole level'''
+
+        screen.blit(self.background, (0, 0) )
+        pygame.display.update()
+
+    def update(self, screen):
+        '''Redraw and update all the animated parts'''
+
+        self.animations.clear(screen, self.background)
+        self.animations.update()
+        dirty = self.animations.draw(screen)
+        pygame.display.update(dirty)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.py	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+'''
+Summary:
+--------
+    This is a mockup test for some animated sprites.
+    The map is read from the file "map.txt", the graphics
+    is taken from attached image files. The rest is
+    hardcoded in the program.
+
+    This is a python program, it requires the python
+    interpreter (available at http://python.org) and
+    the PyGame python library (available at
+    http://pygame.org).
+
+    -- Radomir 'The Sheep' Dopieralski <dw@sheep.art.pl>
+
+Keys:
+-----
+    arrows   -- walk around
+    esc      -- quit
+
+
+Change Log:
+-----------
+
+0.0.5
+    - Fixed bug with wrong rectange sizes
+    - Made the animation frames into subsurfaces
+    - Now using true transparency in the images
+    - Pressing a key kind of skips the animation 
+      (character jumps immediately to new position)
+    - All the tiles are now 32x32 in size, 
+      but spaced like 24x24 tiles and overlapping
+    - Flattened class structure
+    - Moved the map to a separate class Level
+    - Moved the classes to separate files
+    - Moved the tile-reading code into separate file
+    - Moved the map tiles to one image
+    - Added monsters to map format
+    - Added different monster graphics
+
+0.0.4
+    - The map is read from a file
+    ...
+'''
+
+import game
+game.Game().main_loop()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/map.txt	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,30 @@
+X <>
+: <floor.png>
+. <corridor.png>
+> <stairs.png>
+M <floor.png> <jello.png>
+S <floor.png> <skeleton.png>
+B <floor.png> <brain.png>
+& <floor.png> <box.png>
+@ <floor.png> <joe.png>
+
+::::::XXXXXXXXXXXXXX
+::::::..::::XX::::::
+::M:::XX::::..::&:::
+::::::XXX.XXXX::::::
+XXX.XXXXX.XXXXXX.XXX
+XXX.XXX::::::XXX.XXX
+XXX.XXX::::::XXX.XXX
+XXX....::::::XXX.XXX
+XXX.XXX::::::X:::::X
+XXX.XXX@:::::X:::::X
+XXX.XXXXXX.XXX::M::X
+XXX.XXXXXX.XXX:::::X
+X::::::XX:::XXXX.XXX
+X::>:::XX:S:.....XXX
+XX.XXXXXX:::XXXX.XXX
+XX.XXXXXX.XXXXXX.XXX
+X::::::::::::::::::X
+.::::B:::::::::::::.
+X::::::::::::::::::X
+XXXXXXXXXXXXXXXXXXXX
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/monster.py	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,32 @@
+import pygame
+from pygame.locals import *
+
+from util import *
+
+class Monster(pygame.sprite.Sprite):
+    '''Monsters only have two frames of animation.'''
+
+    def __init__(self, x=0, y=0, image_file="monster.png"):
+        pygame.sprite.Sprite.__init__(self)
+        self.frame = 0
+        self.delay = 0
+        self.x = x
+        self.y = y
+        self.z = y*16-12
+        self.rect = Rect(self.x*24, self.y*16-12, 24, 24)
+        self.frames = read_frames(image_file)
+        self.image = self.frames[0][0]
+
+    def update(self):
+        '''Change the frame of animation'''
+
+        self.image = self.frames[0][self.frame]
+        # Ok, this ain't nice :)
+        if self.delay>=3:
+            self.frame += 1
+            if self.frame>=len(self.frames[0]):
+                self.frame = 0
+            self.delay = 0
+        else:
+            self.delay += 1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.txt	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,7 @@
+This is a simple test of sprite animation.
+
+You need Python (http://python.org) to run it, as well
+as Pygame (http://pygame.org), a Python library.
+
+Either double-click the main.py file, or run:
+python main.py
Binary file skeleton.png has changed
Binary file stairs.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util.py	Sat Dec 15 23:16:54 2007 +0100
@@ -0,0 +1,32 @@
+import pygame
+from pygame.locals import *
+
+delta_x = (0, 0, 1, 0, -1)
+delta_y = (0, -1, 0, 1, 0)
+facings = {
+    'stand':    0,
+    'north':    1,
+    'east':     2,
+    'south':    3,
+    'west':     4,
+}
+
+def read_frames(filename, size=24):
+    '''Read an image and split it into tiles.'''
+
+    image = pygame.image.load(filename).convert()
+    w, h = image.get_size()
+    frames = []
+    for y in range(0, h/size):
+        frames.append([])
+        for x in range(0, w/size):
+            frames[y].append(image.subsurface((x*size, y*size, size, size)))
+    return frames
+
+
+class SortedUpdates(pygame.sprite.RenderUpdates):
+    def z_compare(self, a, b): return a.z-b.z
+    def sprites(self):
+        l = self.spritedict.keys()
+        l.sort(self.z_compare)
+        return l