comparison skaapsteker/physics.py @ 619:4ffa9d159588

Some coordinate operators, to reduce foo_x, foo_y everywhere.
author Jeremy Thurgood <firxen@gmail.com>
date Fri, 06 May 2011 16:37:43 +0200
parents 62569f486ede
children da331c80ec08
comparison
equal deleted inserted replaced
618:72865593bdc7 619:4ffa9d159588
10 import pygame.sprite 10 import pygame.sprite
11 from pygame.mask import from_surface 11 from pygame.mask import from_surface
12 12
13 from . import options 13 from . import options
14 from .constants import EPSILON 14 from .constants import EPSILON
15 from .utils import cadd, csub, cmul, cdiv, cclamp, cint, cneg, cabs
15 16
16 class Sprite(pygame.sprite.Sprite): 17 class Sprite(pygame.sprite.Sprite):
17 18
18 # physics attributes 19 # physics attributes
19 mobile = True # whether the velocity may be non-zero 20 mobile = True # whether the velocity may be non-zero
57 return self.debug_color 58 return self.debug_color
58 59
59 def draw_debug(self, surface): 60 def draw_debug(self, surface):
60 pygame.draw.rect(surface, self.get_debug_color(), self.collide_rect, 1) 61 pygame.draw.rect(surface, self.get_debug_color(), self.collide_rect, 1)
61 62
62 def deltaf(self, df):
63 dv = df[0] / self.mass, df[1] / self.mass
64 self.deltav(dv)
65 63
66 def deltav(self, dv): 64 def deltav(self, dv):
67 v_x, v_y = self.velocity 65 velocity = cadd(self.velocity, dv)
68 v_x, v_y = v_x + dv[0], v_y + dv[1] 66 self.velocity = cclamp(velocity, self.terminal_velocity)
69 67
70 t_v = self.terminal_velocity
71 v_x = max(min(v_x, t_v[0]), -t_v[0])
72 v_y = max(min(v_y, t_v[1]), -t_v[1])
73
74 self.velocity = (v_x, v_y)
75 68
76 def deltap(self, dt): 69 def deltap(self, dt):
77 old_pos = self.rect.topleft 70 old_pos = self.rect.topleft
78 v_x, v_y = self.velocity 71 self._float_pos = cadd(self._float_pos, cmul(self.velocity, dt))
79 f_x, f_y = self._float_pos 72 self.rect.topleft = cint(self._float_pos)
80 d_x, d_y = v_x * dt, v_y * dt 73 delta_pos = csub(self.rect.topleft, old_pos)
81 f_x, f_y = f_x + d_x, f_y + d_y
82 self._float_pos = f_x, f_y
83 self.rect.topleft = int(f_x), int(f_y)
84 delta_pos = self.rect.left - old_pos[0], self.rect.top - old_pos[1]
85 self.collide_rect.move_ip(delta_pos) 74 self.collide_rect.move_ip(delta_pos)
86 self.floor_rect.move_ip(delta_pos) 75 self.floor_rect.move_ip(delta_pos)
87 76
88 def _check_mask(self): 77 def _check_mask(self):
89 mask = self._mask_cache.get(id(self.image)) 78 mask = self._mask_cache.get(id(self.image))
103 def check_floors(self, floors): 92 def check_floors(self, floors):
104 """Trigger of the current set of floors""" 93 """Trigger of the current set of floors"""
105 pass 94 pass
106 95
107 def apply_friction(self): 96 def apply_friction(self):
108 v_x, v_y = self.velocity 97 self.velocity = cmul(self.velocity, self.friction_coeff)
109 self.velocity = self.friction_coeff[0] * v_x, self.friction_coeff[1] * v_y
110 98
111 def bounce(self, other, normal): 99 def bounce(self, other, normal):
112 """Alter velocity after a collision. 100 """Alter velocity after a collision.
113 101
114 other: sprite collided with 102 other: sprite collided with
115 normal: unit vector (tuple) normal to the collision 103 normal: unit vector (tuple) normal to the collision
116 surface. 104 surface.
117 """ 105 """
118 v_x, v_y = self.velocity 106 bounce_factor = cadd(cmul(self.bounce_factor, other.bounce_factor), 1)
119 b_x = 1.0 + self.bounce_factor[0] * other.bounce_factor[0] 107 deltav = cmul(cneg(normal), cmul(self.velocity, bounce_factor))
120 b_y = 1.0 + self.bounce_factor[1] * other.bounce_factor[1] 108
121 dv_x = - normal[0] * b_x * v_x 109 if normal == (0, 1) and (other.floor or other.block) and self.velocity[1] > 0 and self.collide_rect.top < other.collide_rect.top:
122 dv_y = - normal[1] * b_y * v_y
123
124 if normal == (0, 1) and (other.floor or other.block) and v_y > 0 and self.collide_rect.top < other.collide_rect.top:
125 # Colliding with the ground from above is special 110 # Colliding with the ground from above is special
126 self.on_solid = True 111 self.on_solid = True
127 dv_y = -v_y 112 deltav = (deltav[0], -self.velocity[1])
128 113
129 if other.mobile: 114 if other.mobile:
130 total_mass = self.mass + other.mass 115 total_mass = self.mass + other.mass
131 f_self = self.mass / total_mass 116 f_self = self.mass / total_mass
132 f_other = other.mass / total_mass 117 f_other = other.mass / total_mass
133 118
134 self.deltav((dv_x * f_self, dv_y * f_self)) 119 self.deltav(cmul(deltav, f_self))
135 other.deltav((- dv_x * f_other, - dv_y * f_other)) 120 self.deltav(cmul(cneg(deltav), f_other))
136 else: 121 else:
137 self.deltav((dv_x, dv_y)) # oof 122 self.deltav(deltav) # oof
138 123
139 def update(self): 124 def update(self):
140 pass # only called in wants_update = True 125 pass # only called in wants_update = True
141 126
142 def check_collide_rect(self, new_collide_rect, new_rect, new_image): 127 def check_collide_rect(self, new_collide_rect, new_rect, new_image):
172 self.kill() 157 self.kill()
173 158
174 159
175 class World(object): 160 class World(object):
176 161
177 GRAVITY = 0.0, 9.8 * 80.0 # pixels / s^2 162 GRAVITY = cmul((0.0, 9.8), 80.0) # pixels / s^2
178 163
179 def __init__(self, bounds): 164 def __init__(self, bounds):
180 self._all = pygame.sprite.LayeredUpdates() 165 self._all = pygame.sprite.LayeredUpdates()
181 self._mobiles = pygame.sprite.Group() 166 self._mobiles = pygame.sprite.Group()
182 self._gravitators = pygame.sprite.Group() 167 self._gravitators = pygame.sprite.Group()
219 return 204 return
220 self._collision_groups[layer] = pygame.sprite.Group() 205 self._collision_groups[layer] = pygame.sprite.Group()
221 206
222 def _backout_collisions(self, sprite, others, dt): 207 def _backout_collisions(self, sprite, others, dt):
223 frac, normal, idx = 0.0, None, None 208 frac, normal, idx = 0.0, None, None
224 v_x, v_y = sprite.velocity 209 abs_v_x, abs_v_y = cabs(sprite.velocity)
225 abs_v_x, abs_v_y = abs(v_x), abs(v_y)
226 210
227 # We only backout of "solide" collisions 211 # We only backout of "solide" collisions
228 if sprite.block: 212 if sprite.block:
229 for i, other in enumerate(others): 213 for i, other in enumerate(others):
230 if other.block or other.floor: 214 if other.block or other.floor:
245 sprite.bounce(others[idx], normal) 229 sprite.bounce(others[idx], normal)
246 230
247 for other in others: 231 for other in others:
248 sprite.collided(other) 232 sprite.collided(other)
249 233
250 def update(self): 234
251 if self._last_time is None: 235 def do_gravity(self, dt):
252 self._last_time = time.time() 236 dv = cmul(self.GRAVITY, dt)
253 return
254
255 # find dt
256 now = time.time()
257 self._last_time, dt = now, now - self._last_time
258
259 # gravity
260 dv = self.GRAVITY[0] * dt, self.GRAVITY[1] * dt
261 for sprite in self._gravitators: 237 for sprite in self._gravitators:
262 if sprite.on_solid: 238 if sprite.on_solid:
263 sprite.deltav((dv[0], 0.0)) 239 sprite.deltav((dv[0], 0.0))
264 else: 240 else:
265 sprite.deltav(dv) 241 sprite.deltav(dv)
242
243
244 def update(self):
245 if self._last_time is None:
246 self._last_time = time.time()
247 return
248
249 # find dt
250 now = time.time()
251 self._last_time, dt = now, now - self._last_time
252
253 self.do_gravity(dt)
266 254
267 # friction 255 # friction
268 for sprite in self._mobiles: 256 for sprite in self._mobiles:
269 sprite.apply_friction() 257 sprite.apply_friction()
270 258