- commit
- 0252f075b2837d8e775ff335e3dee82dc5657682
- parent
- 94d705f49a24f735a1365131043ab08d83e133be
- Author
- Tobias Bengfort <tobias.bengfort@gmx.net>
- Date
- 2014-10-31 14:03
add some map/sprites abstraction
Diffstat
| M | docs/source/index.rst | 1 | + |
| A | laneya/map.py | 112 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | laneya/server.py | 44 | +++++++++----------------------------------- |
3 files changed, 122 insertions, 35 deletions
diff --git a/docs/source/index.rst b/docs/source/index.rst
@@ -10,6 +10,7 @@ Contents 10 10 quickstart 11 11 protocol 12 12 actions -1 13 map 13 14 deferred 14 15 15 16 Indices and tables
diff --git a/laneya/map.py b/laneya/map.py
@@ -0,0 +1,112 @@
-1 1 import protocol
-1 2
-1 3
-1 4 class Map(object):
-1 5 """A singel map containing sprites.
-1 6
-1 7 The map object takes care of managing all sprites within one map. As only
-1 8 very few actions involve multiple maps (e.g. moving from one map to
-1 9 another) this covers a lot of the game logic.
-1 10
-1 11 The passed server is used to send updates to the clients.
-1 12
-1 13 Map objects expose an API for the server (e.g. :py:meth:`step`) and another
-1 14 one for sprites (e.g. :py:meth:`move_sprite`).
-1 15
-1 16 """
-1 17 def __init__(self, server):
-1 18 self.server = server
-1 19 self.sprites = {}
-1 20 self.movable_layer = [[None for i in xrange(100)] for i in xrange(100)]
-1 21
-1 22 def step(self):
-1 23 """Update this map and all of its sprites.
-1 24
-1 25 If this map is currently active (contains at least on user), the server
-1 26 should call this method once per mainloop cycle.
-1 27
-1 28 """
-1 29 for sprite in self.sprites.itervalues():
-1 30 sprite.step()
-1 31
-1 32 def is_collision_free(self, x, y):
-1 33 """Check whether a sprite can move to field (x, y)."""
-1 34 return self.movable_layer[x][y] is None
-1 35
-1 36 def move_sprite(self, sprite, dx, dy):
-1 37 """Move a sprite."""
-1 38 if self.is_collision_free(sprite.x + dx, sprite.y + dy):
-1 39 sprite.x += dx
-1 40 sprite.y += dy
-1 41 self.server.broadcastUpdate(
-1 42 'position',
-1 43 x=sprite.x,
-1 44 y=sprite.y,
-1 45 entity=sprite.id)
-1 46 else:
-1 47 raise protocol.IllegalError
-1 48
-1 49
-1 50 class Sprite(object):
-1 51 """Simple base class for visible game objects."""
-1 52
-1 53 def __init__(self, name, _map, x, y):
-1 54 self.id = "%s:%s" % (self.__class__.__name__, name)
-1 55 self.map = _map
-1 56 self.x = x
-1 57 self.y = y
-1 58
-1 59 self.map.sprites[self.id] = self
-1 60
-1 61 def kill(self):
-1 62 """Remove this sprite from the map."""
-1 63 del self.map.sprites[self.id]
-1 64
-1 65 def step(self):
-1 66 """Update this sprite.
-1 67
-1 68 This function is executed once per mainloop cycle. Subclasses should
-1 69 overwrite this in order to define custom behavior.
-1 70
-1 71 """
-1 72 pass
-1 73
-1 74 def interact(self, other):
-1 75 """Interact with this sprite.
-1 76
-1 77 Subclasses should overwrite this in order to define custom
-1 78 interactions.
-1 79
-1 80 """
-1 81 pass
-1 82
-1 83
-1 84 class MovingSprite(Sprite):
-1 85 """A sprite that can move.
-1 86
-1 87 You can set :py:attr:`direction` to one of 'north', 'east', 'south', 'west'
-1 88 or 'stop'. This sprite will then automatically move one filed in the
-1 89 specified direction in every mainloop cycle.
-1 90
-1 91 """
-1 92
-1 93 def __init__(self, *args, **kwargs):
-1 94 super(MovingSprite, self).__init__(*args, **kwargs)
-1 95 self.direction = 'stop'
-1 96
-1 97 def step(self):
-1 98 if self.direction == 'north':
-1 99 self.map.move_sprite(self, 0, -1)
-1 100 elif self.direction == 'east':
-1 101 self.map.move_sprite(self, 1, 0)
-1 102 elif self.direction == 'south':
-1 103 self.map.move_sprite(self, 0, 1)
-1 104 elif self.direction == 'west':
-1 105 self.map.move_sprite(self, -1, 0)
-1 106
-1 107
-1 108 class User(MovingSprite):
-1 109 """Sprite representing a user."""
-1 110
-1 111
-1 112 __all__ = ['Map', 'Sprite', 'MovingSprite', 'User']
diff --git a/laneya/server.py b/laneya/server.py
@@ -6,62 +6,36 @@ from twisted.internet import reactor 6 6 from twisted.internet import task 7 7 8 8 import protocol9 -110 -111 -1 class User(object):12 -1 def __init__(self, position_x=0, position_y=0, direction='stop'):13 -1 self.position_x = position_x14 -1 self.position_y = position_y15 -1 self.direction = direction-1 9 from map import Map, User 16 10 17 11 18 12 class Server(protocol.ServerProtocolFactory): 19 13 def __init__(self): 20 14 protocol.ServerProtocolFactory.__init__(self) 21 15 self.users = {}22 -1 self.movable_layer = [[None for i in xrange(100)] for i in xrange(100)]-1 16 self.map = Map(self) # TODO: more than one map 23 17 24 18 def requestReceived(self, user, action, **kwargs): # TODO 25 19 if user not in self.users:26 -1 self.users[user] = User()-1 20 self.users[user] = User(user, self.map, 10, 10) 27 21 print("login %s" % user) 28 22 29 23 if action == 'move': 30 24 self.users[user].direction = kwargs['direction'] 31 25 elif action == 'logout': -1 26 self.users[user].kill() 32 27 del self.users[user] 33 28 print("logout %s" % user) 34 29 else: 35 30 raise protocol.InvalidError 36 31 37 32 def mainloop(self):38 -1 for key, user in self.users.iteritems():39 -1 if user.direction == 'north':40 -1 self.move_user(user, 0, -1)41 -1 elif user.direction == 'east':42 -1 self.move_user(user, 1, 0)43 -1 elif user.direction == 'south':44 -1 self.move_user(user, 0, 1)45 -1 elif user.direction == 'west':46 -1 self.move_user(user, -1, 0)47 -1 if user.direction != 'stop':48 -1 self.broadcastUpdate(49 -1 'position',50 -1 x=user.position_x,51 -1 y=user.position_y,52 -1 entity=key)-1 33 # only the maps with users in them get updated -1 34 for _map in self.get_active_maps(): -1 35 _map.step() 53 3654 -1 def collision_check(self, new_x, new_y):55 -1 return self.movable_layer[new_x][new_y] is None56 -157 -1 def move_user(self, user, dx, dy):58 -1 if self.collision_check(user.position_x, user.position_y - 1):59 -1 self.movable_layer[user.position_x][user.position_y] = None60 -1 user.position_x += dx61 -1 user.position_y += dy62 -1 self.movable_layer[user.position_x][user.position_y] = user63 -1 else:64 -1 raise protocol.IllegalError-1 37 def get_active_maps(self): -1 38 return set([user.map for user in self.users.itervalues()]) 65 39 66 40 67 41 def main():