def update(self, elapsed_seconds, force=None, extra_drag=0): # Apply force if necessary. if force is not None: self.velocity = vec.add( self.velocity, vec.mul(force, (elapsed_seconds / self.mass)), ) # Apply drag. # Decrease the magnitude of the velocity vector by # the amount of drag. drag = (self.drag_rate + extra_drag) * elapsed_seconds if drag > self.speed: self.velocity = (0, 0) elif drag != 0 and self.velocity != (0, 0): drag_vector = vec.norm(self.velocity, -drag) self.velocity = vec.add( self.velocity, drag_vector, ) # Limit to maximum speed. if self.speed > c.max_speed: self.velocity = vec.norm(self.velocity, c.max_speed) # Update position based on velocity. self.last_pos = self.pos self.pos = vec.add( self.pos, vec.mul(self.velocity, elapsed_seconds), )
def update(s, gs, dt): #print(s.vel) if s.thrusting: force = s.thrustForce * dt facing = vec.fromAngle(s.facing + 180) f = vec.mul(facing, force) s.applyForce(f) offset = vec.fromAngle(s.facing) offset = vec.mul(offset, s.radius) loc = vec.add(s.loc, offset) # v = vec.invert(s.vel) s.driveEmitter.emit(gs, dt, loc, s.facing, vel=s.vel) if not s.engineSoundPlayer.playing: s.engineSoundPlayer.seek(0.0) s.engineSoundPlayer.eos_action = s.engineSoundPlayer.EOS_LOOP s.engineSoundPlayer.play() else: s.engineSoundPlayer.eos_action = s.engineSoundPlayer.EOS_PAUSE # Turning should be either 0, -1 or +1 if s.turning != 0: force = s.turnForce * dt * s.turning s.applyRforce(force) Planet.update(s, gs, dt)
def collide_particles(p1, p2): restitution = p1.restitution * p2.restitution # Don't collide immovable particles. if p1.immovable and p2.immovable: return # Test if p1 and p2 are actually intersecting. if not intersect(p1, p2): return # If one particle is immovable, make it the first one. if not p1.immovable and p2.immovable: p1, p2 = p2, p1 # Vector spanning between the centers, normal to contact surface. v_span = vec.vfrom(p1.pos, p2.pos) # Split into normal and tangential components and calculate # initial velocities. normal = vec.norm(v_span) tangent = vec.perp(normal) v1_tangent = vec.proj(p1.velocity, tangent) v2_tangent = vec.proj(p2.velocity, tangent) p1_initial = vec.dot(p1.velocity, normal) p2_initial = vec.dot(p2.velocity, normal) # Don't collide if particles were actually moving away from each other, so # they don't get stuck inside one another. if p1_initial - p2_initial < 0: return # Handle immovable particles specially. if p1.immovable: p2_final = -p2_initial * restitution p2.velocity = vec.add( v2_tangent, vec.mul(normal, p2_final), ) return # Elastic collision equations along normal component. m1, m2 = p1.mass, p2.mass m1plusm2 = (m1 + m2) / restitution p1_final = (p1_initial * (m1 - m2) / m1plusm2 + p2_initial * (2 * m2) / m1plusm2) p2_final = (p2_initial * (m2 - m1) / m1plusm2 + p1_initial * (2 * m1) / m1plusm2) # Tangential component is unchanged, recombine. p1.velocity = vec.add( v1_tangent, vec.mul(normal, p1_final), ) p2.velocity = vec.add( v2_tangent, vec.mul(normal, p2_final), )
def create_snowball(lobby, pos, angle, force): ball_id = create_snowball_id(lobby) snowball = player.Snowball(ball_id) direction = vec.from_direction(angle, 1) velocity = vec.mul(direction, force * MAX_THROWING_FORCE) snowball.position = vec.add(pos, vec.mul(direction, SNOWBALL_SPAWN_DISTANCE)) snowball.velocity = velocity lobby.snowballs[ball_id] = snowball
def update_physics(self, elapsed_seconds): # Handle turning. if self.turning_time >= c.player_start_turn_time: turn_rate = c.player_turn_rate_radians else: turn_rate = interpolate( c.player_start_turn_rate_radians, c.player_turn_rate_radians, self.turning_time / c.player_start_turn_time, ) self.heading += self.turn_direction * turn_rate * elapsed_seconds self.direction = heading_to_vector(self.heading) # Handle thrust. force = (0, 0) if self.do_thrust: # We vary the thrust depending on how fast the player is # already moving. thrust = curve_value(self.speed, c.player_thrust_curve) force = vec.add( force, vec.mul(self.direction, thrust), ) # Handle braking. extra_drag = 0 if self.do_brake: extra_drag = c.player_braking_drag # Handle boost. if self.boost_time_remaining > 0.0: force = vec.add( force, vec.mul(self.direction, c.player_boost_strength), ) # Get heavy while boosting. if self.boost_heavy_time_remaining > 0.0: self.mass = self.original_mass * c.player_boost_heavy_multiplier self.restitution = ( self.original_restitution * c.player_boost_restitution_multiplier ) else: self.mass = self.original_mass self.restitution = self.original_restitution # Handle rudder. self.rudder_force = (0, 0) if self.velocity != (0, 0): # Only use the rudder if the player is thrusting or turning. if self.do_thrust or self.turn_direction != 0: self.rudder_force = self.calc_rudder_force() force = vec.add(force, self.rudder_force) return force, extra_drag
def canCapture(s, point, distance, targetPlanet): if s.isParent(targetPlanet): #print "Nope, is parent" return False if targetPlanet.parent != None: #print "Nope, has parent" return False if targetPlanet == s: #print "Nope, self" return False if s in targetPlanet.children: #print "Nope, is a child already" return False vecBetweenPlanets = vec.sub(targetPlanet.loc, s.loc) # Adjust distance to measure from surface to surface, not center # to center distance += s.radius + targetPlanet.radius if vec.magSquared(vecBetweenPlanets) > (distance * distance): #print "Nope, out of range" return False # Okay we are close enough to an eligible planet, are we facing it? angleBetweenPlanets = vec.toAngle(vecBetweenPlanets) # Urrrrrg I hate this, -180 to 180 and 0-360 behave differently and both are # awful in different situations so neither one is really correct. point = (point + 360) % 360 angleBetweenPlanets = (angleBetweenPlanets + 360) % 360 #print "Point and angle:", point, angleBetweenPlanets if abs(angleBetweenPlanets - point) < 10: #print "Yep!" return True #print "Nope, angle too great", angleBetweenPlanets, point, abs(angleBetweenPlanets - point) return False vecBetweenPlanets = vec.sub(targetPlanet.loc, s.loc) vecBPU = vec.unit(vecBetweenPlanets) vecToPlanetEdge = vec.mul(vec.perpendicular(vecBPU), targetPlanet.radius) #print("Vec between planets: {0}, vec to planet edge: {1}".format(vecBPU, vec.unit(vecToPlanetEdge))) angularSize = vec.angleBetween( vecBetweenPlanets, vec.add(vecBetweenPlanets, vecToPlanetEdge)) vecToPoint = vec.mul(vec.fromAngle(point), s.radius) angularDistance = vec.angleBetween(vecBetweenPlanets, vecToPoint) #print("Angular size: {0}, angular distance: {1}".format(angularSize, angularDistance)) if angularDistance > abs(angularSize): return False else: # Check distance between planets surfaces distance = distance + (s.radius + targetPlanet.radius) # Can't capture a planet if you're overlapping it # XXX: Doesn't seem to work, but... if distance < 0: return False return vec.within(s.loc, targetPlanet.loc, distance)
def update_physics(self, elapsed_seconds): # Handle turning. if self.turning_time >= c.player_start_turn_time: turn_rate = c.player_turn_rate_radians else: turn_rate = interpolate( c.player_start_turn_rate_radians, c.player_turn_rate_radians, self.turning_time / c.player_start_turn_time, ) self.heading += self.turn_direction * turn_rate * elapsed_seconds self.direction = heading_to_vector(self.heading) # Handle thrust. force = (0, 0) if self.do_thrust: # We vary the thrust depending on how fast the player is # already moving. thrust = curve_value(self.speed, c.player_thrust_curve) force = vec.add( force, vec.mul(self.direction, thrust), ) # Handle braking. extra_drag = 0 if self.do_brake: extra_drag = c.player_braking_drag # Handle boost. if self.boost_time_remaining > 0.0: force = vec.add( force, vec.mul(self.direction, c.player_boost_strength), ) # Get heavy while boosting. if self.boost_heavy_time_remaining > 0.0: self.mass = self.original_mass * c.player_boost_heavy_multiplier self.restitution = (self.original_restitution * c.player_boost_restitution_multiplier) else: self.mass = self.original_mass self.restitution = self.original_restitution # Handle rudder. self.rudder_force = (0, 0) if self.velocity != (0, 0): # Only use the rudder if the player is thrusting or turning. if self.do_thrust or self.turn_direction != 0: self.rudder_force = self.calc_rudder_force() force = vec.add(force, self.rudder_force) return force, extra_drag
def draw_player(self, player): # Show whether or not the player is thrusting. if player.do_thrust: trailing_point = vec.add( player.pos, vec.norm(player.direction, -1.5 * player.radius), ) self.line(THRUST_COLOR, player.pos, trailing_point, .5 * player.radius) if player.boost_heavy_time_remaining > 0.0: trailing_point = vec.add( player.pos, vec.norm(player.direction, -2.0 * player.radius), ) self.line(THRUST_COLOR, player.pos, trailing_point, 1.5 * player.radius) # Show braking and boosting charge up. if player.do_brake: # Redden the brake color as we charge. color = vec.add( BRAKE_COLOR, vec.mul(THRUST_COLOR, player.boost_charge_time / c.player_boost_ready_time)) # Vibrate if we are fully charged. r = 1.2 if player.boost_charge_time == c.player_boost_ready_time: r += 0.1 * math.sin(6 * (2 * math.pi) * pg.time.get_ticks() / 1000) self.circle(color, player.pos, r) # Body. self.circle(PLAYER_COLORS[player.number], player.pos, player.radius) # Show the player pointing towards a direction. leading_point = vec.add( player.pos, vec.norm(player.direction, player.radius), ) self.line(DIRECTION_COLOR, player.pos, leading_point, .2 * player.radius) if SHOW_RUDDER_FORCE: point = vec.add( player.pos, vec.mul(player.rudder_force, .1), ) self.line(THRUST_COLOR, player.pos, point, .1 * player.radius) if SHOW_INTENDED_DIRECTION and hasattr(player, 'intended_direction'): point = vec.add( player.pos, player.intended_direction, ) self.line(THRUST_COLOR, player.pos, point, .1 * player.radius)
def draw_player(self, player): # Show whether or not the player is thrusting. if player.do_thrust: trailing_point = vec.add( player.pos, vec.norm(player.direction, -1.5 * player.radius), ) self.line(THRUST_COLOR, player.pos, trailing_point, .5 * player.radius) if player.boost_heavy_time_remaining > 0.0: trailing_point = vec.add( player.pos, vec.norm(player.direction, -2.0 * player.radius), ) self.line(THRUST_COLOR, player.pos, trailing_point, 1.5 * player.radius) # Show braking and boosting charge up. if player.do_brake: # Redden the brake color as we charge. color = vec.add( BRAKE_COLOR, vec.mul(THRUST_COLOR, player.boost_charge_time / c.player_boost_ready_time) ) # Vibrate if we are fully charged. r = 1.2 if player.boost_charge_time == c.player_boost_ready_time: r += 0.1 * math.sin(6 * (2*math.pi) * pg.time.get_ticks() / 1000) self.circle(color, player.pos, r) # Body. self.circle(PLAYER_COLORS[player.number], player.pos, player.radius) # Show the player pointing towards a direction. leading_point = vec.add( player.pos, vec.norm(player.direction, player.radius), ) self.line(DIRECTION_COLOR, player.pos, leading_point, .2 * player.radius) if SHOW_RUDDER_FORCE: point = vec.add( player.pos, vec.mul(player.rudder_force, .1), ) self.line(THRUST_COLOR, player.pos, point, .1 * player.radius) if SHOW_INTENDED_DIRECTION and hasattr(player, 'intended_direction'): point = vec.add( player.pos, player.intended_direction, ) self.line(THRUST_COLOR, player.pos, point, .1 * player.radius)
def spray(gs, particle, loc, vel, count): for i in range(count): velscale = random.gauss(vel, (vel / 3.0)) direction = random.random() * 360 velvec = vec.mul(vec.fromAngle(direction), velscale) p = particle(loc, velvec) gs.addParticle(p)
def draw(self, screen): self.surface.lock() self.surface.fill(self.clear) pg.draw.line( self.surface, self.green, (14-10, 14), (14+10, 14), 2, ) pg.draw.line( self.surface, self.green, (14, 14-10), (14, 15+10), 2, ) joypos = vec.mul((self.input.x_axis, -self.input.y_axis), 8) pg.draw.circle( self.surface, self.red, vec.add(joypos, (15,15)), 4, ) self.surface.unlock() _width, height = self.display.screen_size x = 10 + 30 * self.number y = height - self.surface.get_height() - 10 screen.blit(self.surface, (x, y))
def intersect_lines(a, b, c, d, segment=False): """ Find the intersection of lines a-b and c-d. If the "segment" argument is true, treat the lines as segments, and check whether the intersection point is off the end of either segment. """ # Reference: # http://geomalgorithms.com/a05-_intersect-1.html u = vec.vfrom(a, b) v = vec.vfrom(c, d) w = vec.vfrom(c, a) u_perp_dot_v = vec.dot(vec.perp(u), v) if float_equal(u_perp_dot_v, 0): return None # We have collinear segments, no single intersection. v_perp_dot_w = vec.dot(vec.perp(v), w) s = v_perp_dot_w / u_perp_dot_v if segment and (s < 0 or s > 1): return None u_perp_dot_w = vec.dot(vec.perp(u), w) t = u_perp_dot_w / u_perp_dot_v if segment and (t < 0 or t > 1): return None return vec.add(a, vec.mul(u, s))
def draw(self, screen): self.surface.lock() self.surface.fill(self.clear) pg.draw.line( self.surface, self.green, (14 - 10, 14), (14 + 10, 14), 2, ) pg.draw.line( self.surface, self.green, (14, 14 - 10), (14, 15 + 10), 2, ) joypos = vec.mul((self.input.x_axis, -self.input.y_axis), 8) pg.draw.circle( self.surface, self.red, vec.add(joypos, (15, 15)), 4, ) self.surface.unlock() _width, height = self.display.screen_size x = 10 + 30 * self.number y = height - self.surface.get_height() - 10 screen.blit(self.surface, (x, y))
def collide_particles(p1, p2): restitution = p1.restitution * p2.restitution # Don't collide immovable particles. if p1.immovable and p2.immovable: return # Test if p1 and p2 are actually intersecting. if not intersect(p1, p2): return # If one particle is immovable, make it the first one. if not p1.immovable and p2.immovable: p1, p2 = p2, p1 # Vector spanning between the centers, normal to contact surface. v_span = vec.vfrom(p1.pos, p2.pos) # Split into normal and tangential components and calculate # initial velocities. normal = vec.norm(v_span) tangent = vec.perp(normal) v1_tangent = vec.proj(p1.velocity, tangent) v2_tangent = vec.proj(p2.velocity, tangent) p1_initial = vec.dot(p1.velocity, normal) p2_initial = vec.dot(p2.velocity, normal) # Don't collide if particles were actually moving away from each other, so # they don't get stuck inside one another. if p1_initial - p2_initial < 0: return # Handle immovable particles specially. if p1.immovable: p2_final = -p2_initial * restitution p2.velocity = vec.add(v2_tangent, vec.mul(normal, p2_final)) return # Elastic collision equations along normal component. m1, m2 = p1.mass, p2.mass m1plusm2 = (m1 + m2) / restitution p1_final = p1_initial * (m1 - m2) / m1plusm2 + p2_initial * (2 * m2) / m1plusm2 p2_final = p2_initial * (m2 - m1) / m1plusm2 + p1_initial * (2 * m1) / m1plusm2 # Tangential component is unchanged, recombine. p1.velocity = vec.add(v1_tangent, vec.mul(normal, p1_final)) p2.velocity = vec.add(v2_tangent, vec.mul(normal, p2_final))
def to_screen(self, pos): """Convert pos to screen coordinates. Takes a tuple a world position, and returns a tuple for the screen position. """ x, y = vec.add( self.screen_origin, vec.mul(pos, self.pixels_per_unit), ) return (int(x), int(y))
def emit(s, gs, dt, loc, facing, vel=vec.ZERO): s.timer += dt while s.timer > s.interval: s.timer -= s.interval for i in range(s.count): variance = + (s.angle * random.random()) - (s.angle / 2.0) angle = facing + variance v = vec.mul(vec.fromAngle(angle), s.speed) v = vec.add(vel, v) part = s.particleType(loc, v) gs.addParticle(part)
def update(self, elapsed_seconds, force=None, extra_drag=0): # Apply force if necessary. if force is not None: self.velocity = vec.add(self.velocity, vec.mul(force, (elapsed_seconds / self.mass))) # Apply drag. # Decrease the magnitude of the velocity vector by # the amount of drag. drag = (self.drag_rate + extra_drag) * elapsed_seconds if drag > self.speed: self.velocity = (0, 0) elif drag != 0 and self.velocity != (0, 0): drag_vector = vec.norm(self.velocity, -drag) self.velocity = vec.add(self.velocity, drag_vector) # Limit to maximum speed. if self.speed > c.max_speed: self.velocity = vec.norm(self.velocity, c.max_speed) # Update position based on velocity. self.last_pos = self.pos self.pos = vec.add(self.pos, vec.mul(self.velocity, elapsed_seconds))
def rebound(self, normal, point=None, restitution=1): # Split into normal and tangential components. tangent = vec.perp(normal) v_tangent = vec.proj(self.velocity, tangent) v_normal = vec.proj(self.velocity, normal) # Invert normal component and recombine, with restitution. v_normal = vec.neg(v_normal) self.velocity = vec.add(v_tangent, vec.mul(v_normal, restitution)) # If the particle is partially inside the wall, move it out. if point is not None: v = vec.vfrom(point, self.pos) if vec.mag2(v) < self.radius ** 2: v = vec.norm(v, self.radius) self.pos = vec.add(point, v)
def draw(s, gs): rot = s.parent.facing + s.loc totalAngle = vec.fromAngle(rot) offsetVec = vec.mul(totalAngle, s.radius) location = vec.add(s.parent.loc, offsetVec) (scx, scy) = gs.screenCoords(location) #print "rot: %s, totalAngle: %s, offsetVec: %s, location: %s, sc: %s" % (rot, totalAngle, offsetVec, location, (scx, scy)) # Add a slight offset to center the image rather than drawing # it from the lower-left corner... # Also add oregano. s.sprite.rotation = s.loc + s.parent.facing #print s.sprite.rotation, s.loc, s.parent.facing s.sprite.position = (scx, scy) s.sprite.draw()
def draw(s, gs): swingSpeed = 190.0 # Degrees per second startingFacing = 90.0 if s.direction > 0: swing = startingFacing + -(s.lifetime * swingSpeed) else: swing = (s.lifetime * swingSpeed) - startingFacing rot = s.parent.facing + s.loc totalAngle = vec.fromAngle(rot) offset = vec.mul(totalAngle, s.radius) location = vec.add(s.parent.loc, offset) s.sprite.position = gs.screenCoords(location) #print location s.sprite.rotation = rot + swing s.sprite.draw()
def rebound(self, normal, point=None, restitution=1): # Split into normal and tangential components. tangent = vec.perp(normal) v_tangent = vec.proj(self.velocity, tangent) v_normal = vec.proj(self.velocity, normal) # Invert normal component and recombine, with restitution. v_normal = vec.neg(v_normal) self.velocity = vec.add( v_tangent, vec.mul(v_normal, restitution), ) # If the particle is partially inside the wall, move it out. if point is not None: v = vec.vfrom(point, self.pos) if vec.mag2(v) < self.radius**2: v = vec.norm(v, self.radius) self.pos = vec.add(point, v)
def updatePhysics(s, dt): s.loc = vec.add(s.loc, vec.mul(s.vel, dt)) s.facing = s.facing + (s.rvel * dt) s.facing = s.facing % 360
] paper_squares = [ [0, 0], [2, -2], [4, -6], [2, 2], [6, 4], [16, 10], [14, -10], [10, 8], [12, -8], ] # 290 mm / 15 sqaures paper_points = [vec.mul(q, 290 / 15) for q in paper_squares] offset = [305, 0] # floor origin is 305 mm in front world_points = [vec.add(p, offset) for p in paper_points] p = Planar(H, offset=offset) # Should be equal print(world_points) print(p.project(image_points)) # Should be equal print(image_points) print(p.project(world_points, reverse=True)) # Make sure H did not get changed
def sprayParticles(s, gs, particle, speed, count): offset = vec.fromAngle(s.loc + s.parent.facing) offset = vec.mul(offset, s.radius) loc = vec.add(s.parent.loc, offset) particles.spray(gs, particle, loc, speed, count)
def update(s, dt): #s.loc = vec.mul(vec.add(s.loc, s.vel), dt) s.loc = vec.add(s.loc, vec.mul(s.vel, dt)) s.life -= dt if s.life < 0: s.alive = False