Mercurial > skaapsteker
comparison skaapsteker/physics.py @ 627:35919d12b792
Path-based collision minimisation and axis-projection backout.
author | Jeremy Thurgood <firxen@gmail.com> |
---|---|
date | Sat, 07 May 2011 20:28:06 +0200 |
parents | 1abb53ae1a6a |
children | 59556235dec7 |
comparison
equal
deleted
inserted
replaced
626:1abb53ae1a6a | 627:35919d12b792 |
---|---|
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 from .utils import (cadd, csub, cmul, cdiv, cclamp, cabsmax, cint, cneg, cabs, |
16 rect_projection) | |
16 | 17 |
17 class Sprite(pygame.sprite.Sprite): | 18 class Sprite(pygame.sprite.Sprite): |
18 | 19 |
19 # physics attributes | 20 # physics attributes |
20 mobile = True # whether the velocity may be non-zero | 21 mobile = True # whether the velocity may be non-zero |
250 now = time.time() | 251 now = time.time() |
251 dt = now - self._last_time | 252 dt = now - self._last_time |
252 self._last_time = now | 253 self._last_time = now |
253 return dt | 254 return dt |
254 | 255 |
256 | |
257 # def collide_sprite(self, dt, sprite): | |
258 # sprite.apply_velocity(dt) | |
259 # sprite_collides = sprite.collide_rect.colliderect | |
260 # collisions = [] | |
261 # for other in self._collision_groups[sprite.collision_layer]: | |
262 # if sprite_collides(other.collide_rect) \ | |
263 # and sprite.check_collides(other): | |
264 # collisions.append(other) | |
265 # if collisions: | |
266 # self._backout_collisions(sprite, collisions, dt) | |
267 # contact_rect = pygame.Rect( | |
268 # (sprite.collide_rect.left, sprite.collide_rect.bottom), | |
269 # (sprite.collide_rect.width, 1)) | |
270 # return contact_rect.colliderect | |
271 | |
272 | |
273 def get_sprite_collisions(self, dt, sprite): | |
274 sprite.apply_velocity(dt) | |
275 sprite_collides = sprite.collide_rect.colliderect | |
276 collisions = [] | |
277 for other in self._collision_groups[sprite.collision_layer]: | |
278 if (sprite_collides(other.collide_rect) | |
279 and sprite.check_collides(other)): | |
280 collisions.append(other) | |
281 return collisions | |
282 | |
283 | |
284 def path_collide(self, dt, sprite): | |
285 dts = [dt/10] * 9 | |
286 dts.append(dt - sum(dts)) | |
287 dtf_acc = 0 | |
288 collisions = [] | |
289 for dtf in dts: | |
290 dtf_acc += dtf | |
291 collisions = self.get_sprite_collisions(dtf, sprite) | |
292 for col in collisions: | |
293 if sprite.block and (col.floor or col.block): | |
294 return collisions, dtf_acc | |
295 return collisions, dt | |
296 | |
297 | |
298 def collide_sprite(self, dt, sprite): | |
299 initial_pos = sprite._float_pos | |
300 collisions = self.get_sprite_collisions(dt, sprite) | |
301 escape_vector = (0, 0) | |
302 if collisions: | |
303 # If we've collided, reset and try again with smaller time increments | |
304 sprite.update_position(initial_pos) | |
305 collisions, dtf = self.path_collide(dt, sprite) | |
306 for col in collisions: | |
307 if sprite.block and (col.floor or col.block): | |
308 escape_vector = cabsmax(escape_vector, rect_projection(sprite.collide_rect, col.collide_rect)) | |
309 sprite.collided(col) | |
310 sprite.update_position(cadd(sprite._float_pos, escape_vector)) | |
311 # if escape_vector[0] != 0: | |
312 # sprite.velocity = (0, sprite.velocity[1]) | |
313 # if escape_vector[1] != 0: | |
314 # sprite.velocity = (sprite.velocity[0], 1) | |
315 # self._backout_collisions(sprite, collisions, dtf) | |
316 contact_rect = pygame.Rect( | |
317 cadd(sprite.collide_rect.bottomleft, (1, 0)), | |
318 (sprite.collide_rect.width, 1)) | |
319 return contact_rect.colliderect | |
320 | |
321 | |
255 def update_sprite_positions(self, dt): | 322 def update_sprite_positions(self, dt): |
256 # position update and collision check (do last) | 323 # position update and collision check (do last) |
257 for sprite in self._mobiles: | 324 for sprite in self._mobiles: |
258 sprite.apply_velocity(dt) | 325 collides = self.collide_sprite(dt, sprite) |
259 sprite_collides = sprite.collide_rect.colliderect | 326 |
260 collisions = [] | 327 # Are we currently in contact with the ground? |
261 for other in self._collision_groups[sprite.collision_layer]: | 328 if not sprite.block: |
262 if sprite_collides(other.collide_rect) \ | 329 continue |
263 and sprite.check_collides(other): | |
264 collisions.append(other) | |
265 if collisions: | |
266 self._backout_collisions(sprite, collisions, dt) | |
267 contact_rect = pygame.Rect( | |
268 (sprite.collide_rect.left, sprite.collide_rect.bottom), | |
269 (sprite.collide_rect.width, 1)) | |
270 collides = contact_rect.colliderect | |
271 floors = [] | 330 floors = [] |
272 | |
273 # Are we currently in contact with the ground? | |
274 sprite.on_solid = False | 331 sprite.on_solid = False |
275 for other in self._collision_groups[sprite.collision_layer]: | 332 for other in self._collision_groups[sprite.collision_layer]: |
276 if (other.floor or other.block) and collides(other.floor_rect): | 333 if (other.floor or other.block) and collides(other.floor_rect): |
277 sprite.on_solid = True | 334 sprite.on_solid = True |
335 if sprite.velocity[1] > 0: | |
336 sprite.velocity = (sprite.velocity[0], 0) | |
278 floors.append(other) | 337 floors.append(other) |
279 sprite.check_floors(floors) | 338 sprite.check_floors(floors) |
280 | 339 |
281 def update(self): | 340 def update(self): |
282 if self._last_time is None: | 341 if self._last_time is None: |