# HG changeset patch # User Jeremy Thurgood # Date 1378155925 -7200 # Node ID 0c49627920eb03073dead6247b67ba6a655346d3 # Parent 829c8b6e142dd4ccd96203374dcc7346edec592c Load game objects from level. diff -r 829c8b6e142d -r 0c49627920eb data/levels/level1 --- a/data/levels/level1 Mon Sep 02 22:40:14 2013 +0200 +++ b/data/levels/level1 Mon Sep 02 23:05:25 2013 +0200 @@ -17,3 +17,30 @@ - [60, 470] - [60, 780] size: [1200, 900] +game_objects: + - classname: Box + args: + - [250, 350] + - classname: FloorSwitch + args: + - [300, 400] + name: switch + - classname: FloorSwitch + args: + - [300, 600] + name: switch2 + - classname: FloorLight + args: + - [300, 500] + - switch + name: light + - classname: FloorLight + args: + - [250, 500] + - both_switches + name: light2 + - classname: StateLogicalAndPuzzler + args: + - switch + - switch2 + name: both_switches diff -r 829c8b6e142d -r 0c49627920eb nagslang/game_object.py --- a/nagslang/game_object.py Mon Sep 02 22:40:14 2013 +0200 +++ b/nagslang/game_object.py Mon Sep 02 23:05:25 2013 +0200 @@ -16,6 +16,8 @@ self._components = {} def add_component(self, name, puzzler): + if not isinstance(puzzler, Puzzler): + puzzler = puzzler.puzzler self._components[name] = puzzler puzzler.set_glue(self) @@ -276,7 +278,7 @@ def make_body(mass, moment, position, damping=None): body = pymunk.Body(mass, moment) - body.position = position + body.position = tuple(position) if damping is not None: body.damping = damping body.velocity_func = damping_velocity_func @@ -321,8 +323,7 @@ class FloorSwitch(GameObject): def __init__(self, space, position): - body = pymunk.Body() - body.position = position + body = make_body(None, None, position) self.shape = pymunk.Circle(body, 30) self.shape.collision_type = COLLISION_TYPE_SWITCH self.shape.sensor = True @@ -335,8 +336,7 @@ class FloorLight(GameObject): def __init__(self, space, position, state_source): - body = pymunk.Body() - body.position = position + body = make_body(None, None, position) self.shape = pymunk.Circle(body, 10) self.shape.collision_type = COLLISION_TYPE_SWITCH self.shape.sensor = True diff -r 829c8b6e142d -r 0c49627920eb nagslang/level.py --- a/nagslang/level.py Mon Sep 02 22:40:14 2013 +0200 +++ b/nagslang/level.py Mon Sep 02 23:05:25 2013 +0200 @@ -1,6 +1,7 @@ import pygame import pygame.locals as pgl +from nagslang import game_object as go from nagslang.resources import resources from nagslang.yamlish import load, dump @@ -26,16 +27,40 @@ self._tile_image = None self._surface = None self._exterior = False + self._glue = go.PuzzleGlue() + self._drawables = [] - def load(self): + def _get_data(self): + # For overriding in tests. with resources.get_file('levels', self.name) as f: - data = load(f) + return load(f) + + def load(self, space): + data = self._get_data() self.x, self.y = data['size'] self.base_tile = data['base_tile'] for i, points in data['polygons'].iteritems(): self.polygons[i] = [] for point in points: self.polygons[i].append(tuple(point)) + for game_object_dict in data.get('game_objects', []): + self._create_game_object(space, **game_object_dict) + + def _create_game_object(self, space, classname, args, name=None): + # We should probably build a registry of game objects or something. + # At least this is better than just calling `eval`, right? + cls = getattr(go, classname) + if issubclass(cls, go.Puzzler): + gobj = cls(*args) + elif issubclass(cls, go.GameObject): + gobj = cls(space, *args) + self._drawables.append(gobj) + else: + raise TypeError( + "Expected a subclass of Puzzler or GameObject, got %s" % ( + classname)) + if name is not None: + self._glue.add_component(name, gobj) def all_closed(self): """Check if all the polygons are closed""" @@ -80,6 +105,9 @@ def get_walls(self): return self.polygons.values() + def get_drawables(self): + return self._drawables + def _draw_walls(self): for index, polygon in self.polygons.items(): color = POLY_COLORS[index] diff -r 829c8b6e142d -r 0c49627920eb nagslang/screens/area.py --- a/nagslang/screens/area.py Mon Sep 02 22:40:14 2013 +0200 +++ b/nagslang/screens/area.py Mon Sep 02 23:05:25 2013 +0200 @@ -68,11 +68,12 @@ def setup(self): self.keys = ControlKeys() self._level = Level(self.name) - self._level.load() + self._level.load(self.space) self._drawables = Drawables() self.add_walls() self.add_protagonist() - self._setup_demo_objects() + self.add_game_objects() + # self._setup_demo_objects() def _setup_demo_objects(self): # TODO: Put this in a level instead @@ -82,10 +83,10 @@ light = FloorLight(self.space, (300, 500), 'switch') light2 = FloorLight(self.space, (250, 500), 'both_switches') light2.zorder = ZORDER_HIGH - glue.add_component('switch', switch.puzzler) - glue.add_component('switch2', switch2.puzzler) - glue.add_component('light', light.puzzler) - glue.add_component('light2', light2.puzzler) + glue.add_component('switch', switch) + glue.add_component('switch2', switch2) + glue.add_component('light', light) + glue.add_component('light2', light2) glue.add_component( 'both_switches', StateLogicalAndPuzzler('switch', 'switch2')) self._drawables.add(switch) @@ -110,6 +111,10 @@ corner = next_corner self.space.add(*self.walls) + def add_game_objects(self): + for drawable in self._level.get_drawables(): + self._drawables.add(drawable) + def add_protagonist(self): self.protagonist = Protagonist(self.space, (350, 300)) self._drawables.add(self.protagonist) diff -r 829c8b6e142d -r 0c49627920eb nagslang/tests/test_game_object.py --- a/nagslang/tests/test_game_object.py Mon Sep 02 22:40:14 2013 +0200 +++ b/nagslang/tests/test_game_object.py Mon Sep 02 23:05:25 2013 +0200 @@ -67,3 +67,16 @@ self.assertEqual('foo', puzzler.get_state()) faker.fake_state = 'bar' self.assertEqual('bar', puzzler.get_state()) + + def test_glue_add_component(self): + glue = game_object.PuzzleGlue() + puzzler = FakePuzzler('foo') + gobj = FakeGameObject(None, None) + gobj.puzzler = FakePuzzler('bar') + + self.assertEqual({}, glue._components) + glue.add_component('foo', puzzler) + self.assertEqual({'foo': puzzler}, glue._components) + glue.add_component('bar', gobj) + self.assertEqual( + {'foo': puzzler, 'bar': gobj.puzzler}, glue._components) diff -r 829c8b6e142d -r 0c49627920eb nagslang/tests/test_level.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nagslang/tests/test_level.py Mon Sep 02 23:05:25 2013 +0200 @@ -0,0 +1,78 @@ +from unittest import TestCase + +from nagslang import game_object as go +from nagslang.level import Level + + +class FakeSpace(object): + def add(self, *objs): + pass + + +class TestLevel(TestCase): + def make_level(self, name, data): + level = Level(name) + level._get_data = lambda: data + return level + + def test_empty_level(self): + level = self.make_level('foo', { + 'size': [5, 10], + 'base_tile': 'tiles/floor.png', + 'polygons': {}, + }) + level.load(FakeSpace()) + self.assertEqual((5, 10), level.get_size()) + self.assertEqual([], level.get_walls()) + self.assertEqual([], level.get_drawables()) + + def test_level_walls(self): + level = self.make_level('foo', { + 'size': [5, 10], + 'base_tile': 'tiles/floor.png', + 'polygons': { + 1: [[1, 1], [2, 1], [1, 2]], + }, + }) + level.load(FakeSpace()) + self.assertEqual((5, 10), level.get_size()) + self.assertEqual([[(1, 1), (2, 1), (1, 2)]], level.get_walls()) + self.assertEqual([], level.get_drawables()) + + def test_level_game_objects(self): + level = self.make_level('foo', { + 'size': [5, 10], + 'base_tile': 'tiles/floor.png', + 'polygons': {}, + 'game_objects': [ + { + 'classname': 'Box', + 'args': [[3, 3]], + }, + { + 'name': 'foo', + 'classname': 'FloorSwitch', + 'args': [[4, 4]], + }, + { + 'name': 'foo_proxy', + 'classname': 'StateProxyPuzzler', + 'args': ['foo'], + }, + ], + }) + level.load(FakeSpace()) + self.assertEqual((5, 10), level.get_size()) + self.assertEqual([], level.get_walls()) + [box, switch] = level.get_drawables() + self.assertTrue(isinstance(box, go.Box)) + self.assertEqual(box.shape.body.position, (3, 3)) + self.assertTrue(isinstance(switch, go.FloorSwitch)) + self.assertEqual(switch.shape.body.position, (4, 4)) + + puzzle_bits = level._glue._components + self.assertEqual(['foo', 'foo_proxy'], sorted(puzzle_bits.keys())) + self.assertTrue( + isinstance(puzzle_bits['foo_proxy'], go.StateProxyPuzzler)) + self.assertEqual('foo', puzzle_bits['foo_proxy']._state_source) + self.assertTrue(isinstance(puzzle_bits['foo'], go.FloorSwitchPuzzler))