Skip to content

Commit

Permalink
merge with new lib2d
Browse files Browse the repository at this point in the history
  • Loading branch information
bitcraft committed Oct 30, 2012
1 parent d8e90e5 commit 559d419
Show file tree
Hide file tree
Showing 62 changed files with 8,442 additions and 0 deletions.
405 changes: 405 additions & 0 deletions lib/ui.py

Large diffs are not rendered by default.

Binary file added lib2d/.DS_Store
Binary file not shown.
45 changes: 45 additions & 0 deletions lib2d/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
Lib2d is a game engine that I have been developing to create PyWeek games.


----- this is an experimental version for adventure games -----

What it does:
State (context) management
Animated Sprites with multiple animations and automatic flipping
TMX level importing
Integrated Tiled Editing
Fast, efficient tilemap rendering with parallax support
Basic GUI features
Integrated Chipmunk dynamics (pymunk)
Advanced AI (pygoap)
Integrated animation and input handling (fsa.py)
Simplified save game support
Dialogs


Game Structure Overview:
Map is designed in Tiled with special layer (controlset.tsx)
Game objects are created in world.py and assigned GUID control numbers
The 'world' data structure is pickleable and becomes the save game
When engine is started, the world data structure can be used to play


Control:
Lib2d wraps all pygame events for player input so they can be remapped.
It also make keyboard and joystick controls interchangeable at runtime.
Using fsa.py, instead of coding the behavour of the controls, you can
use a finite state machine to define how the character changes states.

Tilemap:
The tilemap uses a special surface that gets updated in the background
(or by another thread). It performs very well when scrolling. Large TMX
maps can be used since only the visible portions of the map are rendered.


Physics:
The library uses pymunk and cannot work without it. The obvious benefits
are a fast physics system (not more colliding rects!) and it has good
integration with the TMX loader.

You can define your walls in tiles, and they will get loaded into the
Chipmunk engine automatically.
192 changes: 192 additions & 0 deletions lib2d/animation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
from objects import GameObject
from image import Image, ImageTile
from sound import Sound
import res

from collections import namedtuple
import math, itertools


pi2 = math.pi * 2

box = namedtuple('Box', 'width height')


"""
animations may be used by a class that does not need the images, but may need
to know when an animation finishes, where it is at, etc (such as a server).
"""

def calcFrameSize(filename, frames, directions):
"""
load the images for the animation and set the size of each frame
"""

width, height = res.loadImage(filename, 0,0,1).get_size()
return (width / frames, height / directions)


class Animation(GameObject):
"""
Animation is a collection of frames with a few control variables and useful
methods to control it.
Animations can store multiple directions and are picklable.
each set of animation added will count as a seperate direction.
1 animation = no rotations
2 animations = left and right (or up and down)
4 animations = left, right, up, down
6 animations = up, down, nw, ne, sw, se (for hex maps)
and so on.
The animation loader expects the image to be in a specific format.
Loader only supports animations where each frame is the same size.
TODO: implement some sort of timing, rather than relying on frames
"""

def __init__(self,name,image,frames,directions=1,timing=100,sound=None):
GameObject.__init__(self)

assert isinstance(image, Image)

#if sound:
# assert(sound, Sound)


self.name = name
self.image = image
self.images = None
self.directions = directions
self.frames = frames
self.timing = timing

# TODO: some checking to make sure inputs are the correct length
if isinstance(self.frames, int):
self.frames = tuple(range(0, self.frames))
else:
self.frames = tuple(self.frames)

self.real_frames = len(set(self.frames))

if isinstance(self.timing, int):
self.timing = tuple([self.timing] * len(self.frames))
else:
self.timing = tuple(self.timing)


def __iter__(self):
return itertools.izip(self.timing, self.frames)


def returnNew(self):
return self


def load(self, force=False):
"""
load the images for use with pygame
returns a new Animation Object
"""

if (self.images is not None) and (not force):
return

image = self.image.load()

iw, ih = image.get_size()
tw = iw / self.real_frames
th = ih / self.directions
self.images = [None] * (self.directions * self.real_frames)

d = 0
for y in range(0, ih, th):
#if d == ih/th: d = 0
for x in range(0, iw, tw):
try:
frame = image.subsurface((x, y, tw, th))
except ValueError as e:
msg = "Invalid tiles selected for image {}"
raise ValueError, msg.format(self.image.filename)
self.images[(x/tw)+d*self.real_frames] = frame
d += 1


def unload(self):
self.images = []


def getImage(self, number, direction=0):
"""
return the frame by number with the correct image for the direction
direction should be expressed in radians
"""

if self.images == []:
raise Exception, "Avatar hasn't loaded images yet"

if direction < 0:
direction = pi + (pi - abs(direction))
d = int(math.ceil(direction / pi2 * (self.directions - 1)))

try:
return self.images[number+d*self.real_frames]
except IndexError:
msg="{} cannot find image for animation ({}/{})"
raise IndexError, msg.format(self, number+d*self.real_frames,
len(self.images))


def __repr__(self):
return "<Animation %s: \"%s\">" % (id(self), self.name)


class StaticAnimation(Animation):
"""
Animation that only supports one frame
Immutable
"""

def __init__(self, name, image):
GameObject.__init__(self)

try:
assert isinstance(image, Image) or isinstance(image, ImageTile)
except AssertionError:
print name, image
raise

self.image = image
self.name = name
self.frames = [0]
self.timing = [-1]


def load(self):
"""
load the images for use with pygame
"""

self.image = self.image.load()
print "loading, static", self, self.image

def returnNew(self):
return self


def unload(self):
self.image = None


def getImage(self, number, direction=0):
"""
return the frame by number with the correct image for the direction
direction should be expressed in radians
"""

if self.image is None:
raise Exception, "Avatar hasn't loaded images yet"

return self.image

Loading

0 comments on commit 559d419

Please sign in to comment.