-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathactor.py
executable file
·93 lines (80 loc) · 3.15 KB
/
actor.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
#!/usr/bin/env python3
'''
@author Michele Tomaiuolo - http://www.ce.unipr.it/people/tomamic
@license This software is free - http://www.gnu.org/licenses/gpl.html
'''
class Actor():
'''Interface to be implemented by each game character
'''
def move(self):
'''Called by Arena, at the actor's turn
'''
raise NotImplementedError('Abstract method')
def collide(self, other: 'Actor'):
'''Called by Arena, whenever the `self` actor collides with some
`other` actor
'''
raise NotImplementedError('Abstract method')
def position(self) -> (int, int, int, int):
'''Return the rectangle containing the actor, as a 4-tuple of ints:
(left, top, width, height)
'''
raise NotImplementedError('Abstract method')
def symbol(self) -> (int, int, int, int):
'''Return the position (x, y, w, h) of current sprite, if it is contained in
a larger image, with other sprites. Otherwise, simply return (0, 0, 0, 0)
'''
raise NotImplementedError('Abstract method')
def priority(self) -> int:
'''Return the priority of the actor'''
raise NotImplementedError('Abstract method')
class Arena():
'''A generic 2D game, with a given size in pixels and a list of actors
'''
def __init__(self, size: (int, int)):
'''Create an arena, with given dimensions in pixels
'''
self._w, self._h = size
self._actors = []
def add(self, a: Actor):
'''Register an actor into this arena.
Actors are blitted in their order of registration
'''
if a not in self._actors:
self._actors.append(a)
def remove(self, a: Actor):
'''Cancel an actor from this arena
'''
if a in self._actors:
self._actors.remove(a)
def move_all(self):
'''Move all actors (through their own move method).
After each single move, collisions are checked and eventually
the `collide` methods of both colliding actors are called
'''
actors = list(reversed(self._actors))
for a in actors:
a.move()
for other in actors:
# reversed order, so actors drawn on top of others
# (towards the end of the cycle) are checked first
if other is not a and self.check_collision(a, other):
a.collide(other)
other.collide(a)
def check_collision(self, a1: Actor, a2: Actor) -> bool:
'''Check the two actors (args) for mutual collision (bounding-box
collision detection). Return True if colliding, False otherwise
'''
x1, y1, w1, h1 = a1.position()
x2, y2, w2, h2 = a2.position()
return (y2 < y1 + h1 and y1 < y2 + h2
and x2 < x1 + w1 and x1 < x2 + w2
and a1 in self._actors and a2 in self._actors)
def actors(self) -> list:
'''Return a copy of the list of actors
'''
return list(self._actors)
def size(self) -> (int, int):
'''Return the size of the arena as a couple: (width, height)
'''
return (self._w, self._h)