all repos — Legends-RPG @ d8373003d109394bfb66273042e2a2fb96a2b738

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