all repos — Legends-RPG @ 51f66118257991c2b8d4f5924f51cf796d98cf8a

A fantasy mini-RPG built with Python and Pygame.

data/components/person.py (view raw)

  1__author__ = 'justinarmstrong'
  2import math, random
  3import pygame as pg
  4from .. import setup
  5
  6
  7class Person(pg.sprite.Sprite):
  8    """Base class for all world characters
  9    controlled by the computer"""
 10
 11    def __init__(self, sheet_key, x, y, direction='right', state='resting'):
 12        super(Person, self).__init__()
 13        self.name = sheet_key
 14        self.get_image = setup.tools.get_image
 15        self.spritesheet_dict = self.create_spritesheet_dict(sheet_key)
 16        self.animation_dict = self.create_animation_dict()
 17        if direction == 'left':
 18            self.index = 1
 19        else:
 20            self.index = 0
 21        self.direction = direction
 22        self.image_list = self.animation_dict[self.direction]
 23        self.image = self.image_list[self.index]
 24        self.rect = self.image.get_rect(left=x, top=y)
 25        self.old_rect = self.rect
 26        self.state_dict = self.create_state_dict()
 27        self.vector_dict = self.create_vector_dict()
 28        self.x_vel = 0
 29        self.y_vel = 0
 30        self.timer = 0.0
 31        self.move_timer = 0.0
 32        self.current_time = 0.0
 33        self.state = state
 34        self.blockers = self.set_blockers()
 35        self.location = self.get_tile_location()
 36        self.dialogue = ['Location: ' + str(self.location)]
 37        self.default_direction = direction
 38
 39
 40    def create_spritesheet_dict(self, sheet_key):
 41        """Implemented by inheriting classes"""
 42        image_list = []
 43        image_dict = {}
 44        sheet = setup.GFX[sheet_key]
 45
 46        image_keys = ['facing up 1', 'facing up 2',
 47                      'facing down 1', 'facing down 2',
 48                      'facing left 1', 'facing left 2',
 49                      'facing right 1', 'facing right 2']
 50
 51        for row in range(2):
 52            for column in range(4):
 53                image_list.append(
 54                    self.get_image(column*32, row*32, 32, 32, sheet))
 55
 56        for key, image in zip(image_keys, image_list):
 57            image_dict[key] = image
 58
 59        return image_dict
 60
 61
 62    def create_animation_dict(self):
 63        """Return a dictionary of image lists for animation"""
 64        image_dict = self.spritesheet_dict
 65
 66        left_list = [image_dict['facing left 1'], image_dict['facing left 2']]
 67        right_list = [image_dict['facing right 1'], image_dict['facing right 2']]
 68        up_list = [image_dict['facing up 1'], image_dict['facing up 2']]
 69        down_list = [image_dict['facing down 1'], image_dict['facing down 2']]
 70
 71        direction_dict = {'left': left_list,
 72                          'right': right_list,
 73                          'up': up_list,
 74                          'down': down_list}
 75
 76        return direction_dict
 77
 78
 79    def create_state_dict(self):
 80        """Return a dictionary of all state methods"""
 81        state_dict = {'resting': self.resting,
 82                      'moving': self.moving,
 83                      'animated resting': self.animated_resting,
 84                      'autoresting': self.auto_resting,
 85                      'automoving': self.auto_moving}
 86
 87        return state_dict
 88
 89
 90    def create_vector_dict(self):
 91        """Return a dictionary of x and y velocities set to
 92        direction keys."""
 93        vector_dict = {'up': (0, -1),
 94                       'down': (0, 1),
 95                       'left': (-1, 0),
 96                       'right': (1, 0)}
 97
 98        return vector_dict
 99
100
101    def update(self, current_time, *args):
102        """Implemented by inheriting classes"""
103        self.blockers = self.set_blockers()
104        self.current_time = current_time
105        self.image_list = self.animation_dict[self.direction]
106        state_function = self.state_dict[self.state]
107        state_function()
108        self.location = self.get_tile_location()
109
110
111
112    def set_blockers(self):
113        """Sets blockers to prevent collision with other sprites"""
114        blockers = []
115
116        if self.state == 'resting' or self.state == 'autoresting':
117            blockers.append(pg.Rect(self.rect.x, self.rect.y, 32, 32))
118
119        elif self.state == 'moving' or self.state == 'automoving':
120            if self.rect.x % 32 == 0:
121                tile_float = self.rect.y / float(32)
122                tile1 = (self.rect.x, math.ceil(tile_float)*32)
123                tile2 = (self.rect.x, math.floor(tile_float)*32)
124                tile_rect1 = pg.Rect(tile1[0], tile1[1], 32, 32)
125                tile_rect2 = pg.Rect(tile2[0], tile2[1], 32, 32)
126                blockers.extend([tile_rect1, tile_rect2])
127
128            elif self.rect.y % 32 == 0:
129                tile_float = self.rect.x / float(32)
130                tile1 = (math.ceil(tile_float)*32, self.rect.y)
131                tile2 = (math.floor(tile_float)*32, self.rect.y)
132                tile_rect1 = pg.Rect(tile1[0], tile1[1], 32, 32)
133                tile_rect2 = pg.Rect(tile2[0], tile2[1], 32, 32)
134                blockers.extend([tile_rect1, tile_rect2])
135
136        return blockers
137
138
139
140    def get_tile_location(self):
141        """Converts pygame coordinates into tile coordinates"""
142        if self.rect.x == 0:
143            tile_x = 0
144        elif self.rect.x % 32 == 0:
145            tile_x = (self.rect.x / 32)
146        else:
147            tile_x = 0
148
149
150        if self.rect.y == 0:
151            tile_y = 0
152        elif self.rect.y % 32 == 0:
153            tile_y = (self.rect.y / 32)
154
155        else:
156            tile_y = 0
157
158        return [tile_x, tile_y]
159
160
161    def resting(self):
162        """
163        When the Person is not moving between tiles.
164        Checks if the player is centered on a tile.
165        """
166        self.image = self.image_list[self.index]
167
168        assert(self.rect.y % 32 == 0), ('Player not centered on tile: '
169                                        + str(self.rect.y))
170        assert(self.rect.x % 32 == 0), ('Player not centered on tile'
171                                        + str(self.rect.x))
172
173
174    def moving(self):
175        """Increment index and set self.image for animation."""
176        self.animation()
177
178        assert(self.rect.x % 32 == 0 or self.rect.y % 32 == 0), \
179            'Not centered on tile'
180
181
182    def animated_resting(self):
183        self.animation(500)
184
185
186    def animation(self, freq=100):
187        """Adjust sprite image frame based on timer"""
188        if (self.current_time - self.timer) > freq:
189            if self.index < (len(self.image_list) - 1):
190                self.index += 1
191            else:
192                self.index = 0
193            self.timer = self.current_time
194
195        self.image = self.image_list[self.index]
196
197
198
199    def begin_moving(self, direction):
200        """Transition the player into the 'moving' state."""
201        self.direction = direction
202        self.image_list = self.animation_dict[direction]
203        self.timer = self.current_time
204        self.move_timer = self.current_time
205        self.state = 'moving'
206
207        if self.rect.x % 32 == 0:
208            self.y_vel = self.vector_dict[self.direction][1]
209        if self.rect.y % 32 == 0:
210            self.x_vel = self.vector_dict[self.direction][0]
211
212
213    def begin_resting(self):
214        """Transition the player into the 'resting' state."""
215        self.state = 'resting'
216        self.index = 1
217        self.x_vel = self.y_vel = 0
218
219
220    def begin_auto_moving(self, direction):
221        """Transition sprite to a automatic moving state"""
222        self.direction = direction
223        self.image_list = self.animation_dict[direction]
224        self.state = 'automoving'
225        self.x_vel = self.vector_dict[direction][0]
226        self.y_vel = self.vector_dict[direction][1]
227        self.move_timer = self.current_time
228
229
230    def begin_auto_resting(self):
231        """Transition sprite to an automatic resting state"""
232        self.state = 'autoresting'
233        self.index = 1
234        self.x_vel = self.y_vel = 0
235        self.move_timer = self.current_time
236
237
238    def auto_resting(self):
239        """
240        Determine when to move a sprite from resting to moving in a random
241        direction.
242        """
243        #self.image = self.image_list[self.index]
244        self.image_list = self.animation_dict[self.direction]
245        self.image = self.image_list[self.index]
246
247        assert(self.rect.y % 32 == 0), ('Player not centered on tile: '
248                                        + str(self.rect.y))
249        assert(self.rect.x % 32 == 0), ('Player not centered on tile'
250                                        + str(self.rect.x))
251
252        if (self.current_time - self.move_timer) > 2000:
253            direction_list = ['up', 'down', 'left', 'right']
254            random.shuffle(direction_list)
255            direction = direction_list[0]
256            self.begin_auto_moving(direction)
257            self.move_timer = self.current_time
258
259
260
261    def auto_moving(self):
262        """Animate sprite and check to stop"""
263        self.animation()
264
265        assert(self.rect.x % 32 == 0 or self.rect.y % 32 == 0), \
266            'Not centered on tile'
267
268
269
270class Player(Person):
271    """User controlled character"""
272
273    def __init__(self, direction):
274        super(Player, self).__init__('player', 0, 0, direction)
275
276
277    def create_vector_dict(self):
278        """Return a dictionary of x and y velocities set to
279        direction keys."""
280        vector_dict = {'up': (0, -2),
281                       'down': (0, 2),
282                       'left': (-2, 0),
283                       'right': (2, 0)}
284
285        return vector_dict
286
287
288    def update(self, keys, current_time):
289        """Updates player behavior"""
290        self.blockers = self.set_blockers()
291        self.keys = keys
292        self.current_time = current_time
293        self.check_for_input()
294        state_function = self.state_dict[self.state]
295        state_function()
296        self.location = self.get_tile_location()
297
298
299    def check_for_input(self):
300        """Checks for player input"""
301        if self.state == 'resting':
302            if self.keys[pg.K_UP]:
303                self.begin_moving('up')
304            elif self.keys[pg.K_DOWN]:
305                self.begin_moving('down')
306            elif self.keys[pg.K_LEFT]:
307                self.begin_moving('left')
308            elif self.keys[pg.K_RIGHT]:
309                self.begin_moving('right')
310
311
312
313class Soldier(Person):
314    """Soldier for the castle"""
315
316    def __init__(self, x, y, direction='down', state='resting'):
317        super(Soldier, self).__init__('soldier', x, y, direction, state)
318
319
320
321class FemaleVillager(Person):
322    """Female Person for town"""
323
324    def __init__(self, x, y):
325        super(FemaleVillager, self).__init__('femalevillager', x, y)
326        self.index = 1
327
328
329class MaleVillager(Person):
330    """Male Person for town"""
331
332    def __init__(self):
333        super(MaleVillager, self).__init__('male villager', x, y)
334
335
336class King(Person):
337    """King of the town"""
338    def __init__(self, x, y, direction='down', state='resting'):
339        super(King, self).__init__('king', x, y, direction, state)
340