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 self.item_list = []
277
278
279 def create_vector_dict(self):
280 """Return a dictionary of x and y velocities set to
281 direction keys."""
282 vector_dict = {'up': (0, -2),
283 'down': (0, 2),
284 'left': (-2, 0),
285 'right': (2, 0)}
286
287 return vector_dict
288
289
290 def update(self, keys, current_time):
291 """Updates player behavior"""
292 self.blockers = self.set_blockers()
293 self.keys = keys
294 self.current_time = current_time
295 self.check_for_input()
296 state_function = self.state_dict[self.state]
297 state_function()
298 self.location = self.get_tile_location()
299
300
301 def check_for_input(self):
302 """Checks for player input"""
303 if self.state == 'resting':
304 if self.keys[pg.K_UP]:
305 self.begin_moving('up')
306 elif self.keys[pg.K_DOWN]:
307 self.begin_moving('down')
308 elif self.keys[pg.K_LEFT]:
309 self.begin_moving('left')
310 elif self.keys[pg.K_RIGHT]:
311 self.begin_moving('right')
312
313
314
315class Soldier(Person):
316 """Soldier for the castle"""
317
318 def __init__(self, x, y, direction='down', state='resting'):
319 super(Soldier, self).__init__('soldier', x, y, direction, state)
320
321
322
323class FemaleVillager(Person):
324 """Female Person for town"""
325
326 def __init__(self, x, y):
327 super(FemaleVillager, self).__init__('femalevillager', x, y)
328 self.index = 1
329
330
331class MaleVillager(Person):
332 """Male Person for town"""
333
334 def __init__(self):
335 super(MaleVillager, self).__init__('male villager', x, y)
336
337
338class King(Person):
339 """King of the town"""
340 def __init__(self, x, y, direction='down', state='resting'):
341 super(King, self).__init__('king', x, y, direction, state)
342
343
344class Well(pg.sprite.Sprite):
345 """Talking well"""
346 def __init__(self, x, y):
347 super(Well, self).__init__()
348 self.image = pg.Surface((32, 32))
349 self.image.set_colorkey((0,0,0))
350 self.rect = self.image.get_rect(left=x, top=y)
351 self.location = self.get_location()
352 self.dialogue = ["I'm a well!"]
353 self.blockers = [self.rect]
354 self.x_vel = self.y_vel = 0
355 self.state = 'resting'
356 self.direction = 'down'
357 self.default_direction = self.direction
358 self.item = None
359
360 def get_location(self):
361 """Get tile location"""
362 x = self.rect.x / 32
363 y = self.rect.y / 32
364
365 return [x, y]
366
367 def begin_auto_resting(self):
368 """Placeholder"""
369 pass
370
371