Mercurial > skaapsteker
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 |