Mercurial > skaapsteker
view skaapsteker/physics.py @ 85:6e8cfd6fcd63
Avoived?!
author | Adrianna Pińska <adrianna.pinska@gmail.com> |
---|---|
date | Mon, 04 Apr 2011 14:34:04 +0200 |
parents | 6de531d648c3 |
children | a1d95c6152a0 |
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 = (300.0, 300.0) # maximum horizontal and vertial speeds (pixels / s) bounce_factor = (0.98, 1.05) # bounce factor 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 if not self.rect.colliderect(immobile.rect): print " Collision avoided!" return v_x, v_y = self.velocity clip = self.rect.clip(immobile.rect) MAX_DT = 0.1 frac_x = clip.width / abs(v_x) if abs(v_x) > EPSILON else MAX_DT frac_y = clip.height / abs(v_y) if abs(v_y) > EPSILON else MAX_DT if frac_x > frac_y: # collision in y frac = frac_y b_y = -v_y * self.bounce_factor[1] * immobile.bounce_factor[1] b_x = v_x else: # collision in x frac = frac_x b_x = -v_x * self.bounce_factor[0] * immobile.bounce_factor[0] b_y = v_y self.velocity = (-v_x, -v_y) self.deltap(frac * 1.1) self.velocity = (b_x, b_y) class World(object): GRAVITY = 9.8 * 20.0 # pixels / 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) elif (sprite.floor or sprite.block): 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 = (-self.GRAVITY * 0.5 * dt, 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)