Mercurial > skaapsteker
view skaapsteker/physics.py @ 66:12ec95a2e8ea
Bouncing.
author | Simon Cross <hodgestar@gmail.com> |
---|---|
date | Sun, 03 Apr 2011 22:56:47 +0200 |
parents | 1be1ca704346 |
children | 60aa6c3eb96f |
line wrap: on
line source
"""Model of gravity, acceleration, velocities and collisions. Works very closely with sprites/base.py. """ import pygame.sprite import pygame.draw import pygame import time from constants import DEBUG, EPSILON class Sprite(pygame.sprite.DirtySprite): mobile = True # whether the velocity may be non-zero gravitates = True # whether gravity applies to the sprite terminal_velocity = (100.0, 100.0) # maximum horizontal and vertial speeds def __init__(self, *args, **kwargs): super(Sprite, self).__init__(*args, **kwargs) self.velocity = (0.0, 0.0) self.rect = pygame.Rect(0, 0, 10, 10) # sub-classes should override self.image = pygame.Surface((10, 10)) self.image.fill((0, 0, 200)) self.visible = 1 self.dirty = 1 self.blendmode = 0 def init_pos(self): self._float_pos = self.rect.topleft def draw_debug(self, surface): pygame.draw.rect(surface, (240, 0, 0), self.rect, 1) def deltav(self, dv): v_x, v_y = self.velocity v_x, v_y = v_x + dv[0], v_y + dv[1] t_v = self.terminal_velocity v_x = max(min(v_x, t_v[0]), -t_v[0]) v_y = max(min(v_y, t_v[1]), -t_v[1]) self.velocity = (v_x, v_y) def deltap(self, dt): v_x, v_y = self.velocity f_x, f_y = self._float_pos d_x, d_y = v_x * dt, v_y * dt f_x, f_y = f_x + d_x, f_y + d_y self._float_pos = f_x, f_y self.rect.topleft = int(f_x), int(f_y) def collide(self, other): print "Collided:", self, other def collide_immobile(self, immobile): print "Collided with immobile:", self, immobile v_x, v_y = self.velocity clip = self.rect.clip(immobile.rect) frac_x = clip.width / abs(v_x) if abs(v_x) > EPSILON else 0.0 frac_y = clip.height / abs(v_y) if abs(v_y) > EPSILON else 0.0 frac = max(frac_x, frac_y) self.velocity = (-v_x, -v_y) self.deltap(frac) class World(object): GRAVITY = 9.8 # m/s^2 def __init__(self): self._all = pygame.sprite.LayeredUpdates() self._mobiles = pygame.sprite.Group() self._immobiles = pygame.sprite.Group() self._gravitators = pygame.sprite.Group() self._last_time = None def add(self, sprite): sprite.init_pos() self._all.add(sprite) if sprite.mobile: self._mobiles.add(sprite) else: self._immobiles.add(sprite) if sprite.gravitates: self._gravitators.add(sprite) def update(self): if self._last_time is None: self._last_time = time.time() return # find dt now = time.time() self._last_time, dt = now, now - self._last_time # gravity dv = (0, self.GRAVITY * dt) for sprite in self._gravitators: sprite.deltav(dv) # position update (do last) for sprite in self._mobiles: sprite.deltap(dt) # check for collisions collisions = [] collide = collisions.append for sprite1 in self._mobiles.sprites(): spritecollide = sprite1.rect.colliderect for sprite2 in self._mobiles.sprites(): if id(sprite1) < id(sprite2) and spritecollide(sprite2): collide((sprite1, sprite2)) for sprite2 in self._immobiles.sprites(): if spritecollide(sprite2): collide((sprite1, sprite2)) self.dispatch_collisions(collisions) def dispatch_collisions(self, collisions): for s1, s2 in collisions: if not s2.mobile: s1.collide_immobile(s2) else: s1.collide(s2) def draw(self, surface): self._all.draw(surface) if DEBUG: for sprite in self._all: sprite.draw_debug(surface)