-
Notifications
You must be signed in to change notification settings - Fork 1
/
gamebox.py
691 lines (593 loc) · 26.6 KB
/
gamebox.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
# A library file for simplifying pygame interaction. You MUST place this file in the same directory as your game py files.
'''This code is the original work of Luther Tychonievich, who releases it
into the public domain
As a courtesy, Luther would appreciate it if you acknowledged him in any work
that benefited from this code.'''
from __future__ import division
import pygame, sys
import urllib, os.path
if 'urlretrieve' not in dir(urllib):
from urllib.request import urlretrieve as _urlretrieve
else:
_urlretrieve = urllib.urlretrieve
pygame.init()
# a cache to avoid loading images many time
_known_images = {}
_known_sounds = {}
def _image(key, flip=False, w=0, h=0, angle=0):
'''A method for loading images, caching them, and flipping them'''
if '__hash__' not in dir(key):
key = id(key)
angle, w, h = int(angle), int(w), int(h)
ans = None
if (key, flip, w, h, angle) in _known_images:
ans = _known_images[(key, flip, w, h, angle)]
elif angle != 0:
base = _image(key, flip, w, h)
img = pygame.transform.rotozoom(base, angle, 1)
_known_images[(key, flip, w, h, angle)] = img
ans = img
elif w != 0 or h != 0:
base = _image(key, flip)
img = pygame.transform.smoothscale(base, (w, h))
_known_images[(key, flip, w, h, angle)] = img
ans = img
elif flip:
base = _image(key)
img = pygame.transform.flip(base, True, False)
_known_images[(key, flip, w, h, angle)] = img
ans = img
else:
img, _ = _get_image(key)
_known_images[(key, flip, w, h, angle)] = img
ans = img
if w == 0 and h == 0:
if angle != 0:
tmp = _image(key, flip, w, h)
else:
tmp = ans
_known_images[(key, flip, tmp.get_width(), tmp.get_height(), angle)] = ans
return ans
def _image_from_url(url):
'''a method for loading images from urls by first saving them locally'''
filename = os.path.basename(url)
if not os.path.exists(filename):
if '://' not in url: url = 'http://' + url
_urlretrieve(url, filename)
image, filename = _image_from_file(filename)
return image, filename
def _image_from_file(filename):
'''a method for loading images from files'''
image = pygame.image.load(filename).convert_alpha()
_known_images[filename] = image
_known_images[(image.get_width(), image.get_height(), filename)] = image
return image, filename
def _get_image(thing):
'''a method for loading images from cache, then file, then url'''
if thing in _known_images: return _known_images[thing], thing
sid = '__id__' + str(id(thing))
if sid in _known_images: return _known_images[sid], sid
if type(thing) is str:
if os.path.exists(thing): return _image_from_file(thing)
return _image_from_url(thing)
_known_images[sid] = thing
_known_images[(thing.get_width(), thing.get_height(), sid)] = thing
return thing, sid
def load_sprite_sheet(url_or_filename, rows, columns):
'''Loads a sprite sheet. Assumes the sheet has rows-by-columns evenly-spaced images and returns a list of those images.'''
sheet, key = _get_image(url_or_filename)
height = sheet.get_height() / rows
width = sheet.get_width() / columns
frames = []
for row in range(rows):
for col in range(columns):
clip = pygame.Rect(col * width, row * height, width, height)
frame = sheet.subsurface(clip)
frames.append(frame)
return frames
__all__ = ['load_sprite_sheet']
def from_image(x, y, filename_or_url):
'''Creates a SpriteBox object at the given location from the provided filename or url'''
image, key = _get_image(filename_or_url)
return SpriteBox(x, y, image, None)
__all__.append('from_image')
def from_color(x, y, color, width, height):
'''Creates a SpriteBox object at the given location with the given color, width, and height'''
return SpriteBox(x, y, None, color, width, height)
__all__.append('from_color')
def from_text(x, y, text, fontname, fontsize, color, bold=False, italic=False):
'''Creates a SpriteBox object at the given location with the given text as its content'''
font = pygame.font.match_font(fontname.replace(" ", "").lower())
if font is None:
sys.stderr.write("ERROR: no font named " + fontname + "; using default font instead")
font = pygame.font.Font(font, fontsize)
font.set_bold(bold)
font.set_italic(italic)
if type(color) is str: color = pygame.Color(color)
return from_image(x, y, font.render(text, True, color))
__all__.append('from_text')
def load_sound(url_or_filename):
'''Reads a sound file from a given filename or url'''
if url_or_filename in _known_images: return _known_sounds[url_or_filename]
if not os.path.exists(url_or_filename):
filename = os.path.basename(url_or_filename)
if not os.path.exists(filename):
_urlretrieve(url_or_filename, filename)
url_or_filename = filename
sound = pygame.mixer.Sound(url_or_filename)
_known_sounds[url_or_filename] = sound
return sound
__all__.append('load_sound')
class Camera(object):
'''A camera defines what is visible. It has a width, height, full screen status,
and can be moved. Moving a camera changes what is visible.
'''
is_initialized = False
# __slots__ = ["_surface", "x", "y", "speedx", "speedy"]
def __init__(self, width, height, full_screen=False):
'''Camera(pixelsWide, pixelsTall, False) makes a window; using True instead makes a full-screen display.'''
if Camera.is_initialized: raise Exception("You can only have one Camera at a time")
# if height > 768: raise Exception("The Game Expo screens will only be 768 pixels tall")
# if width > 1366: raise Exception("The Game Expo screens will only be 1366 pixels wide")
if full_screen:
self.__dict__['_surface'] = pygame.display.set_mode([width, height], pygame.FULLSCREEN)
else:
self.__dict__['_surface'] = pygame.display.set_mode([width, height])
self.__dict__['_x'] = 0
self.__dict__['_y'] = 0
Camera.is_initialized = True
def move(self, x, y=None):
'''camera.move(3, -7) moves the screen's center to be 3 more pixels to the right and 7 more up'''
if y is None: x, y = x
self.x += x
self.y += y
def draw(self, thing, *args):
'''camera.draw(box) draws the provided SpriteBox object
camera.draw(image, x, y) draws the provided image centered at the provided coordinates
camera.draw("Hi", "Arial", 12, "red", x, y) draws the text Hi in a red 12-point Arial font at x,y'''
if isinstance(thing, SpriteBox):
thing.draw(self)
elif isinstance(thing, pygame.Surface):
try:
if len(args) == 1:
x, y = args[0]
else:
x, y = args[:2]
self._surface.blit(thing, [x - thing.get_width() / 2, y - thing.get_height() / 2])
except e:
raise Exception("Wrong arguments; try .draw(surface, [x,y])")
elif type(thing) is str:
try:
font = pygame.font.match_font(args[0].replace(" ", "").lower())
if font is None:
sys.stderr.write("ERROR: no font named " + fontname + "; using default font instead")
size = args[1]
color = args[2]
if type(color) is str: color = pygame.Color(color)
self.draw(pygame.font.Font(font, size).render(thing, True, color), *args[3:])
except e:
raise Exception("Wrong arguments; try .draw(text, fontName, fontSize, color, [x,y])")
else:
raise Exception("I don't know how to draw a ", type(thing))
def display(self):
'''Causes what has been drawn recently by calls to draw(...) to be displayed on the screen'''
pygame.display.flip()
def clear(self, color):
'''Erases the screen by filling it with the given color'''
if type(color) is str: color = pygame.Color(color)
self._surface.fill(color)
def __getattr__(self, name):
if name in self.__dict__: return self.__dict__[name]
x, y, w, h = self._x, self._y, self._surface.get_width(), self._surface.get_height()
if name == 'left': return x
if name == 'right': return x + w
if name == 'top': return y
if name == 'bottom': return y + h
if name == 'x': return x + w / 2
if name == 'y': return y + h / 2
if name == 'center': return x + w / 2, y + h / 2
if name == 'topleft': return x, y
if name == 'topright': return x + w, y
if name == 'bottomleft': return x, y + h
if name == 'bottomright': return x + w, y + h
if name == 'width': return w
if name == 'height': return h
if name == 'size': return w, h
if name == 'mousex': return pygame.mouse.get_pos()[0] + self._x
if name == 'mousey': return pygame.mouse.get_pos()[1] + self._y
if name == 'mouse': return pygame.mouse.get_pos()[0] + self._x, pygame.mouse.get_pos()[1] + self._y
if name == 'mouseclick': return any(pygame.mouse.get_pressed())
raise Exception("There is no '" + name + "' in a Camera object")
def __setattr__(self, name, value):
if name in self.__dict__:
self.__dict__[name] = value
return
w, h = self._surface.get_width(), self._surface.get_height()
if name == 'left':
self._x = value
elif name == 'right':
self._x = value - w
elif name == 'top':
self._y = value
elif name == 'bottom':
self._y = value - h
elif name == 'x':
self._x = value - w / 2
elif name == 'y':
self._y = value - h / 2
elif name == 'center':
self._x, self._y = value[0] - w / 2, value[1] - h / 2
elif name == 'topleft':
self._x, self._y = value[0], value[1]
elif name == 'topright':
self._x, self._y = value[0] - w, value[1]
elif name == 'bottomleft':
self._x, self._y = value[0], value[1] - h
elif name == 'bottomright':
self._x, self._y = value[0] - w, value[1] - h
elif name in ['width', 'height', 'size', 'mouse', 'mousex', 'mousey', 'mouseclick']:
raise Exception("You cannot change the '" + name + "' of a Camera object")
else:
sys.stderr.write("creating field named " + name)
self.__dict__[name] = value
def __repr__(self):
return str(self)
def __str__(self):
return '%dx%d Camera centered at %d,%d' % (self.width, self.height, self.x, self.y)
__all__.append('Camera')
class SpriteBox(object):
'''Intended to represent a sprite (i.e., an image that can be drawn as part of a larger view) and the box that contains it. Has various collision and movement methods built in.'''
# __slots__ = ["x","y","speedx","speedy","_w","_h","_key","_image","_color"]
def __init__(self, x, y, image, color, w=None, h=None):
'''You should probably use the from_image, from_text, or from_color method instead of this one'''
self.__dict__['x'] = x
self.__dict__['y'] = y
self.__dict__['speedx'] = 0
self.__dict__['speedy'] = 0
if image is not None:
self._set_key(image, False, 0, 0, 0)
if w is not None:
if h is not None:
self.size = w, h
else:
self.width = w
elif h is not None:
self.height = h
elif color is not None:
if w is None or h is None: raise Exception("must supply size of color box")
self.__dict__['_key'] = None
self.__dict__['_image'] = None
self.__dict__['_w'] = w
self.__dict__['_h'] = h
self.color = color
pass
def _set_key(self, name, flip, width, height, angle):
width = int(width + 0.5)
height = int(height + 0.5)
angle = ((int(angle) % 360) + 360) % 360
unrot = _image(name, flip, width, height)
if width == 0 and height == 0:
width = unrot.get_width()
height = unrot.get_height()
self.__dict__['_key'] = (name, flip, width, height, angle)
self.__dict__['_image'] = _image(*self.__dict__['_key'])
self.__dict__['_color'] = None
self.__dict__['_w'] = self.__dict__['_image'].get_width()
self.__dict__['_h'] = self.__dict__['_image'].get_height()
def __getattr__(self, name):
x, y, w, h = self.x, self.y, self._w, self._h
if name == 'xspeed': name = 'speedx'
if name == 'yspeed': name = 'speedy'
if name == 'left': return x - w / 2
if name == 'right': return x + w / 2
if name == 'top': return y - h / 2
if name == 'bottom': return y + h / 2
if name == 'center': return x, y
if name == 'topleft': return x - w / 2, y - h / 2
if name == 'topright': return x + w / 2, y - h / 2
if name == 'bottomleft': return x - w / 2, y + h / 2
if name == 'bottomright': return x + w / 2, y + h / 2
if name == 'width': return w
if name == 'height': return h
if name == 'width': return w
if name == 'height': return h
if name == 'size': return w, h
if name == 'speed': return self.speedx, self.speedy
if name == 'rect': return pygame.Rect(self.topleft, self.size)
if name == 'image': return self.__dict__['_image']
if name in self.__dict__:
return self.__dict__[name]
raise Exception("There is no '" + name + "' in a SpriteBox object")
def __setattr__(self, name, value):
w, h = self._w, self._h
if name == 'xspeed': name = 'speedx'
if name == 'yspeed': name = 'speedy'
if name in self.__dict__:
self.__dict__[name] = value
elif name == 'left':
self.x = value + w / 2
elif name == 'right':
self.x = value - w / 2
elif name == 'top':
self.y = value + h / 2
elif name == 'bottom':
self.y = value - h / 2
elif name == 'center':
self.x, self.y = value[0], value[1]
elif name == 'topleft':
self.x, self.y = value[0] + w / 2, value[1] + h / 2
elif name == 'topright':
self.x, self.y = value[0] - w / 2, value[1] + h / 2
elif name == 'bottomleft':
self.x, self.y = value[0] + w / 2, value[1] - h / 2
elif name == 'bottomright':
self.x, self.y = value[0] - w / 2, value[1] - h / 2
elif name == 'width':
self.scale_by(value / w)
elif name == 'height':
self.scale_by(value / h)
elif name == 'size':
if self.__dict__['_image'] is not None:
key = self.__dict__['_key']
self._set_key(key[0], key[1], value[0], value[1], key[4])
else:
self.__dict__['_w'] = value[0]
self.__dict__['_h'] = value[1]
elif name == 'speed':
self.speedx, self.speedy = value[0], value[1]
elif name == 'color':
self.__dict__['_image'] = None
self.__dict__['_key'] = None
if type(value) is str: value = pygame.Color(value)
self.__dict__['_color'] = value
elif name == 'image':
self.__dict__['_color'] = None
if self.__dict__['_key'] is None:
self._set_key(value, False, w, h, 0)
else:
key = self.__dict__['_key']
self._set_key(value, *key[1:])
else:
sys.stderr.write("creating filed named " + name)
self.__dict__[name] = value
def overlap(self, other, padding=0, padding2=None):
'''b1.overlap(b1) returns a list of 2 values such that self.move(result) will cause them to not overlap
Returns [0,0] if there is no overlap (i.e., if b1.touches(b2) returns False
b1.overlap(b2, 5) adds a 5-pixel padding to b1 before computing the overlap
b1.overlap(b2, 5, 10) adds a 5-pixel padding in x and a 10-pixel padding in y before computing the overlap'''
if padding2 is None: padding2 = padding
l = other.left - self.right - padding
r = self.left - other.right - padding
t = other.top - self.bottom - padding2
b = self.top - other.bottom - padding2
m = max(l, r, t, b)
if m >= 0:
return [0, 0]
elif m == l:
return [l, 0]
elif m == r:
return [-r, 0]
elif m == t:
return [0, t]
else:
return [0, -b]
def touches(self, other, padding=0, padding2=None):
'''b1.touches(b1) returns True if the two SpriteBoxes overlap, False if they do not
b1.touches(b2, 5) adds a 5-pixel padding to b1 before computing the touch
b1.touches(b2, 5, 10) adds a 5-pixel padding in x and a 10-pixel padding in y before computing the touch'''
if padding2 is None: padding2 = padding
l = other.left - self.right - padding
r = self.left - other.right - padding
t = other.top - self.bottom - padding2
b = self.top - other.bottom - padding2
return max(l, r, t, b) <= 0
def bottom_touches(self, other, padding=0, padding2=None):
'''b1.bottom_touches(b2) returns True if both b1.touches(b2) and b1's bottom edge is the one causing the overlap.'''
if padding2 is None: padding2 = padding
return self.overlap(other, padding + 1, padding2 + 1)[1] < 0
def top_touches(self, other, padding=0, padding2=None):
'''b1.top_touches(b2) returns True if both b1.touches(b2) and b1's top edge is the one causing the overlap.'''
if padding2 is None: padding2 = padding
return self.overlap(other, padding + 1, padding2 + 1)[1] > 0
def left_touches(self, other, padding=0, padding2=None):
'''b1.left_touches(b2) returns True if both b1.touches(b2) and b1's left edge is the one causing the overlap.'''
if padding2 is None: padding2 = padding
return self.overlap(other, padding + 1, padding2 + 1)[0] > 0
def right_touches(self, other, padding=0, padding2=None):
'''b1.right_touches(b2) returns True if both b1.touches(b2) and b1's right edge is the one causing the overlap.'''
if padding2 is None: padding2 = padding
return self.overlap(other, padding + 1, padding2 + 1)[0] < 0
def contains(self, x, y=None):
'''checks if the given point is inside this SpriteBox's bounds or not'''
if y is None: x, y = x
return abs(x - self.x) * 2 < self._w and abs(y - self.y) * 2 < self._h
def move_to_stop_overlapping(self, other, padding=0, padding2=None):
'''b1.move_to_stop_overlapping(b2) makes the minimal change to b1's position necessary so that they no longer overlap'''
o = self.overlap(other, padding, padding2)
if o != [0, 0]:
self.move(o)
if o[0] * self.speedx < 0: self.speedx = 0
if o[1] * self.speedy < 0: self.speedy = 0
def move_both_to_stop_overlapping(self, other, padding=0, padding2=None):
'''b1.move_both_to_stop_overlapping(b2) changes both b1 and b2's positions so that they no longer overlap'''
o = self.overlap(other, padding, padding2)
if o != [0, 0]:
self.move(o[0] / 2, o[1] / 2)
other.move(-o[0] / 2, -o[1] / 2)
if o[0] != 0:
self.speedx = (self.speedx + other.speedx) / 2
other.speedx = self.speedx
if o[1] != 0:
self.speedy = (self.speedy + other.speedy) / 2
other.speedy = self.speedy
def move(self, x, y=None):
'''change position by the given amount in x and y. If only x given, assumed to be a point [x,y]'''
if y is None: x, y = x
self.x += x
self.y += y
def move_speed(self):
'''change position by the current speed field of the SpriteBox object'''
self.move(self.speedx, self.speedy)
def full_size(self):
'''change size of this SpriteBox to be the original size of the source image'''
if self.__dict__['_key'] is None: return
key = self.__dict__['_key']
self._set_key(key[0], key[1], 0, 0, key[4])
def __repr__(self):
return str(self)
def __str__(self):
return '%dx%d SpriteBox centered at %d,%d' % (self._w, self._h, self.x, self.y)
def copy_at(self, newx, newy):
'''Make a new SpriteBox just like this one but at the given location instead of here'''
return SpriteBox(newx, newy, self._image, self._color, self._w, self._h)
def copy(self):
'''Make a new SpriteBox just like this one and in the same location'''
return self.copy_at(self.x, self.y)
def scale_by(self, multiplier):
'''Change the size of this SpriteBox by the given factor
b1.scale_by(1) does nothing; b1.scale_by(0.4) makes b1 40% of its original width and height.'''
if self.__dict__['_key'] is None:
self._w *= multiplier
self._h *= multiplier
else:
key = self.__dict__['_key']
self._set_key(key[0], key[1], key[2] * multiplier, key[3] * multiplier, key[4])
def draw(self, surface):
'''b1.draw(camera) is the same as saying camera.draw(b1)
b1.draw(image) draws a copy of b1 on the image proivided'''
if isinstance(surface, Camera):
if self.__dict__['_color'] is not None:
region = self.rect.move(-surface._x, -surface._y)
region = region.clip(surface._surface.get_rect())
surface._surface.fill(self._color, region)
elif self.__dict__['_image'] is not None:
surface._surface.blit(self._image, [self.left - surface._x, self.top - surface._y])
else:
if self.__dict__['_color'] is not None:
surface.fill(self._color, self.rect)
elif self.__dict__['_image'] is not None:
surface.blit(self._image, self.topleft)
def flip(self):
'''mirrors the SpriteBox left-to-right.
Mirroring top-to-bottom can be accomplished by
b1.rotate(180)
b1.flip()'''
if self.__dict__['_key'] is None: return
key = self.__dict__['_key']
self._set_key(key[0], not key[1], *key[2:])
def rotate(self, angle):
'''Rotates the SpriteBox by the given angle (in degrees).'''
if self.__dict__['_key'] is None: return
key = self.__dict__['_key']
self._set_key(key[0], key[1], key[2], key[3], key[4] + angle)
_timeron = False
_timerfps = 0
def timer_loop(fps, callback):
'''Requests that pygame call the provided function fps times a second
fps: a number between 1 and 60
callback: a function that accepts a set of keys pressed since the last tick
----
seconds = 0
def tick(keys):
seconds += 1/30
if pygame.K_DOWN in keys:
print 'down arrow pressed'
if not keys:
print 'no keys were pressed since the last tick'
camera.draw(box)
camera.display()
gamebox.timer_loop(30, tick)
----'''
global _timeron, _timerfps
keys = set([])
if fps > 1000: fps = 1000
_timerfps = fps
_timeron = True
pygame.time.set_timer(pygame.USEREVENT, int(1000 / fps))
while True:
event = pygame.event.wait()
if event.type == pygame.QUIT: break
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: break
if event.type == pygame.KEYDOWN:
keys.add(event.key)
if event.type == pygame.KEYUP and event.key in keys:
keys.remove(event.key)
if event.type == pygame.USEREVENT:
pygame.event.clear(pygame.USEREVENT)
callback(keys)
pygame.time.set_timer(pygame.USEREVENT, 0)
_timeron = False
def pause():
'''Pauses the timer; an error if there is no timer to pause'''
if not _timeron: raise Exception("Cannot pause a timer before calling timer_loop(fps, callback)")
pygame.time.set_timer(pygame.USEREVENT, 0)
def unpause():
'''Unpauses the timer; an error if there is no timer to unpause'''
if not _timeron: raise Exception("Cannot pause a timer before calling timer_loop(fps, callback)")
pygame.time.set_timer(pygame.USEREVENT, int(1000 / _timerfps))
def stop_loop():
'''Completely quits one timer_loop or keys_loop, usually ending the program'''
pygame.event.post(pygame.event.Event(pygame.QUIT))
def keys_loop(callback):
'''Requests that pygame call the provided function each time a key is pressed
callback: a function that accepts the key pressed
----
def onPress(key):
if pygame.K_DOWN == key:
print 'down arrow pressed'
if pygame.K_a in keys:
print 'A key pressed'
camera.draw(box)
camera.display()
gamebox.keys_loop(onPress)
----'''
while True:
event = pygame.event.wait()
if event.type == pygame.QUIT: break
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: break
if event.type == pygame.KEYDOWN:
callback(event.key)
if __name__ == "__main__":
camera = Camera(400, 400)
camera.x = 10
b = from_text(40, 50, "Blue", "Arial", 40, "red", italic=True, bold=True)
b.speedx = 3
b.left += 2
b.y = 100
b.move_speed()
camera.draw(b)
camera.display()
smurfs = load_sprite_sheet("http://www.flashpulse.com/moho/smurf_sprite.PNG", 4, 4)
def tick(keys):
if keys:
if pygame.K_0 in keys:
b.image = smurfs[0]
elif pygame.K_1 in keys:
b.image = smurfs[1]
elif pygame.K_2 in keys:
b.image = smurfs[2]
elif pygame.K_3 in keys:
b.image = smurfs[3]
elif pygame.K_4 in keys:
b.image = smurfs[4]
elif pygame.K_5 in keys:
b.image = smurfs[5]
elif pygame.K_6 in keys:
b.image = smurfs[6]
elif pygame.K_7 in keys:
b.image = smurfs[7]
elif pygame.K_8 in keys:
b.image = smurfs[8]
elif pygame.K_9 in keys:
b.image = smurfs[9]
elif pygame.K_a in keys:
stop_loop()
elif keys:
b.image = "http://www.pygame.org/docs/_static/pygame_tiny.png"
b.full_size()
b.rotate(-5)
b.center = camera.mouse
b.bottom = camera.bottom
camera.draw(b)
camera.display()
timer_loop(30, tick)