-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcomponent.py
275 lines (227 loc) · 7.63 KB
/
component.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
import entity
import cocos.euclid as eu
import cocos
from inputmanager import inputmanager as in_man
import config
class ComponentNotSetupException(Exception):
pass
class ComponentNotFoundException(Exception):
pass
class Component(object):
_id = 0
sort = 0 # Helps with sorting components.
# subclasses should set a number that reflects the order
# that it should be updated in regard to other components.
def __init__(self):
self.instance_name = entity.get_new_instance_name(self.__class__)
self.is_setup = False
self.parent = None
def early_update(self, dt):
if not self.is_setup:
raise ComponentNotSetupException(self.instance_name)
def late_update(self, dt):
pass
def setup(self):
"""
Called when a component is added to an entity. Gives the component
a chance to get any needed references and possibly add itself
to any required batches.
Any subclass should set self.is_setup to True if it is successfully
set up.
"""
self.is_setup = self.parent is not None
def cleanup(self):
self.is_setup = False
def __str__(self):
return self.instance_name
class SpriteComponent(Component):
"""
A component that gives an entity a visual representation.
A Sprite will be drawn at the center of the entity.
"""
_id = 0
sort = 0 # Should be updated after any components that may affect the
# the position of the entity
def __init__(self, image):
super(SpriteComponent, self).__init__()
self.image = image
def setup(self):
if self.is_setup:
return # quit if we're set-up
if isinstance(self.image, str):
self.sprite = cocos.sprite.Sprite(entity.get_blocky_image(self.image))
else:
self.sprite = cocos.sprite.Sprite(self.image)
self.sprite_name = self.instance_name + '_sprite'
self.parent.add(self.sprite, name=self.sprite_name)
self.is_setup = True
def cleanup(self):
super(SpriteComponent, self).cleanup()
self.parent.remove(self.sprite_name)
self.sprite = None
self.sprite_name = None
self.is_setup = False
class InputComponent(Component):
_id = 0
sort = 5
def setup(self):
self.input_dict = inputmanager.input_manager.get_input_dict(0)
self.is_setup = True
self.vel = 100
def early_update(self, dt):
super(InputComponent, self).early_update(self, dt)
direction = eu.Vector2(self.input_dict['HORIZONTAL_1'],
self.input_dict['VERTICAL_1'])
self.parent.position += direction*self.vel*dt
class Jumper(Component):
sort = 8
def __init__(self, player_index=1):
super(Jumper, self).__init__()
self.player_index = player_index
def setup(self):
self.input_dict = in_man.get_input_dict(self.player_index)
self.is_setup = True
try:
self.physics = self.parent.get_component(PhysicsComponent)
except ComponentNotFoundException:
raise ComponentNotFoundException('Jumper component requires a physics component')
self.jumping = True
self.vel_x = 200
self.vel_y = 339
self.x_acc = 300
# register callback
try:
self.parent.get_component(MapColliderComponent).register_callback(self.collider_callback)
except ComponentNotFoundException:
raise ComponentNotFoundException('Jumper component requires a map collider component')
def early_update(self, dt):
jump = self.input_dict['JUMP']
if jump and not self.jumping:
self.physics.velocity.y = self.vel_y
self.jumping = True
#if not jump and self.jumping:
# self.jumping = False
if abs(self.physics.velocity.y) > 0:
self.jumping = True
hor = self.input_dict['HORIZONTAL_1']
if hor:
self.physics.velocity.x += hor*self.x_acc*dt
else:
self.physics.velocity.x = 0.8*self.physics.velocity.x
if self.physics.velocity.x > self.vel_x:
self.physics.velocity.x = self.vel_x
if self.physics.velocity.x < -self.vel_x:
self.physics.velocity.x = -self.vel_x
def collider_callback(self, collider, change):
if change.x:
self.physics.velocity.x = 0
if change.y:
self.physics.velocity.y = 0
if change.y > 0:
self.jumping = False
#print change
class MapColliderComponent(Component):
"""
A component that contains information used in collisions with other objects.
Works in conjunction with the Sprite components to get
size information.
Maintains a rectangular hit area, with center at the origin of the entity
in layer-space, and with the dimensions of the parent entity's SpriteComponent.
"""
_id = 0
sort = 11
def __init__(self):
super(MapColliderComponent, self).__init__()
self.hit_rect = cocos.rect.Rect(0,0,-1,-1)
self.old_rect = None
self.__added_ = False
self._callbacks = []
self.change = None
def setup(self):
if self.is_setup:
return # quit if we're already set-up
if self.parent.parent:
self.parent.parent.add_map_collider(self)
self.__added_ = True
sprite = self.parent.get_component(SpriteComponent)
if sprite:
sprite_box = sprite.sprite.get_AABB()
self.hit_rect.size = sprite_box.size
self.hit_rect.center = self.parent.position
self.old_rect = self.hit_rect.copy()
if self.__added_ and self.old_rect:
self.is_setup = True
def early_update(self, dt):
super(MapColliderComponent, self).early_update(dt)
self.old_rect.position = self.hit_rect.position # save the old position of the collider
self.hit_rect.center = self.parent.position # update the collider
self.change = None
# The collider is now ready to participate in collisions
def register_callback(self, func):
"""
Registers a function to call when this collider has a collision.
The callback should have the signature:
func(collider, change_vec2d)
"""
self._callbacks.append(func)
def late_update(self, dt):
if self.change:
for cb in self._callbacks:
cb(self, self.change)
self.parent.position = self.hit_rect.center
#print 'pos: {} dt: {}'.format(self.parent.position, dt)
def collision_update(self, change):
# probably want to move the entity according to the new hit_rect position
if not self.change:
self.change = eu.Vector2(*change)
else:
self.change += change
class PhysicsComponent(Component):
"""
A component that moves the entity according basic Newtonian physics
It moves the entity according this component's velocity
Velocity changes according to gravity
"""
_id = 0
sort = 9
def setup(self):
#super(PhysicsComponent, self).setup()
if not self.parent:
return # quit if there isn't a parent yet
if self.is_setup:
return # already setup
self.first_try = True
if self.first_try:
self.gravity = config.GRAVITY
self.velocity = eu.Vector2(0,0)
self.position = eu.Vector2(*self.parent.position)
self.max_fall = None # Determines the maximum speed at which the component
# can move in the vertical direction
self.collider = self.parent.get_component(MapColliderComponent)
if self.collider:
self.is_setup = True
return
if self.first_try is True and self.collider is None:
self.is_setup = False
if not self.first_try:
self.is_setup = True
self.first_try = False
def apply_gravity(self, dt):
"""
Updates the component's velocity according to gravity.
This does not change the component's position
"""
def early_update(self, dt):
self._integrate(dt)
#print 'v: {}, p: {}'.format(self.velocity.y, self.position.y)
#print 'v*60: {} g*60: {}'.format(self.velocity.y*60, self.gravity*60)
def _integrate(self, dt):
self.velocity.y = self.velocity.y - self.gravity * dt
if self.max_fall:
if self.velocity.y < -self.max_fall:
self.velocity.y = -self.max_fall
# Clamp y velocity to max_fall when falling
self.position.x,self.position.y = self.parent.position
print self.position
self.position += self.velocity * dt
self.parent.position = self.position.x, self.position.y