def handle_message(self, message): self.polling = False bodies = message.split("#") for body_info in bodies: seperator = body_info.find(":") body_type = body_info[:seperator] body_values = body_info[seperator + 1:].split(",") if body_type == "solar-body": planet = KnownPlanet( body_values[0], body_values[1], int(body_values[2]), Vector(float(body_values[3]), float(body_values[4]), float(body_values[5])), float(body_values[6]), float(body_values[7])) if planet.name in self.planets.keys(): current = self.planets[planet.name] current.update(planet.pos) else: self.planets[planet.name] = planet elif body_type == "general-body": body = KnownBody( body_values[0], int(body_values[1]), Vector(float(body_values[2]), float(body_values[3]), float(body_values[4])), float(body_values[5]), float(body_values[6])) if body.uid in self.general.keys(): current = self.general[body.uid] current.update(body.pos) else: self.general[body.uid] = body else: pass
def load(self, blob): entities.Entity.load(self, blob) self.pos = Vector.from_list(blob['physical.pos']) self.vel = Vector.from_list(blob['physical.vel']) self.rot = Quaternion.from_list(blob['physical.rot']) self.rotvel = Quaternion.from_list(blob['physical.rotvel']) self.radius = blob['physical.radius'] self.mass = blob['physical.mass']
def __init__(self, category_uid, instance_uid, sim): entities.Entity.__init__(self, category_uid, instance_uid, sim) self.pos = Vector(0.0, 0.0, 0.0) self.vel = Vector(0.0, 0.0, 0.0) self.rot = Quaternion.from_angle_and_axis(0.0, Vector(0, 0, 1)) self.rotvel = Quaternion.from_angle_and_axis(0.0, Vector(0.0, 0.0, 1.0)) self.radius = 1.0 self.mass = 1.0
def __init__(self, num_cars, start_pos, walls, checkpoints): self.camera_position = Vector(0, 0) self.walls = walls self.checkpoints = [Vector.from_tuple(x) for x in checkpoints] start_pos_x, start_pos_y = start_pos self.cars = [Car(start_pos_x, start_pos_y) for _ in range(num_cars)] self.reached_checkpoint = [0] * num_cars self.dead = [False] * num_cars self.tracked_car = 0
class PhysicalEntity(entities.Entity): def __init__(self, category_uid, instance_uid, sim): entities.Entity.__init__(self, category_uid, instance_uid, sim) self.pos = Vector(0.0, 0.0, 0.0) self.vel = Vector(0.0, 0.0, 0.0) self.rot = Quaternion.from_angle_and_axis(0.0, Vector(0, 0, 1)) self.rotvel = Quaternion.from_angle_and_axis(0.0, Vector(0.0, 0.0, 1.0)) self.radius = 1.0 self.mass = 1.0 def should_think(self): return True def think(self, dt): self.pos = self.pos + (self.vel * dt) self.rot = self.rot * (self.rotvel ** dt) def accelerate(self, force, dt): acceleration = (force / self.mass) * dt self.vel = self.vel + acceleration def apply_moment(self, angular_acceleration, dt): #print "angular e:", angular_acceleration.as_tuple() q = Quaternion.from_euler_rotation(angular_acceleration) #print "angular q:", q.as_tuple() self.rotvel = self.rotvel * q ** 2 #print "rotvel q:", self.rotvel.as_tuple() #print "rotvel e:", self.rotvel.to_euler_angle().as_tuple() def load(self, blob): entities.Entity.load(self, blob) self.pos = Vector.from_list(blob['physical.pos']) self.vel = Vector.from_list(blob['physical.vel']) self.rot = Quaternion.from_list(blob['physical.rot']) self.rotvel = Quaternion.from_list(blob['physical.rotvel']) self.radius = blob['physical.radius'] self.mass = blob['physical.mass'] def save(self): blob = entities.Entity.save(self) blob['physical.pos'] = self.pos.as_list() blob['physical.vel'] = self.vel.as_list() blob['physical.rot'] = self.rot.as_list() blob['physical.rotvel'] = self.rotvel.as_list() blob['physical.radius'] = self.radius blob['physical.mass'] = self.mass return blob
def ray_segment_intersection(ray, segment): """ Finds the point of intersection between a ray and a segment, or returns None if such a point does not exist. `ray` must be of type `Ray`. A `segment` is a tuple of two `(x, y)` points that define the start and end of the segment accordingly. """ # Based on Wikipedia's `Line–line intersection` x1 = ray.start.x y1 = ray.start.y ray_point = ray.start + ray.direction x2 = ray_point.x y2 = ray_point.y x3, y3 = segment[0] x4, y4 = segment[1] t_num = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) t_den = ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)) u_num = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) u_den = ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)) # The condition is essentially 0 <= u <= 1 and 0 <= t but we check it this way to avoid having # to actually do the division unless we must. if u_den != 0 and (u_num*u_den) >= 0 and abs(u_num) <= abs(u_den) \ and t_den != 0.0 and (t_num*t_den) >= 0: # Intersection! u = u_num / u_den return Vector(x3 + u * (x4 - x3), y3 + u * (y4 - y3)) else: return None
def get_screen_mapping(self, screen): """ Calculates a vector that when added to a point in game-space maps it to screen-space """ screen_rect = screen.get_rect() screen_middle = Vector(screen_rect.width, screen_rect.height) / 2 return screen_middle - self.camera_position
def __init__(self, initial_x, initial_y): """ Constructs a car with the given initial position: `(initial_x, initial_y)` """ self.position = Vector(initial_x, initial_y) self.direction = 0 # In radians self.velocity = 0 self.acceleration = 0
def get_sight_rays(self): """ Returns a list of Ray objects representing the sensors of the car """ rays = [] for ray_angle in (-RAY_ANGLE, 0, RAY_ANGLE): start_pos = self.position direction = Vector.unit_from_angle(self.direction + ray_angle) rays.append(Ray(start_pos, direction)) return rays
def get_bounding_box(self): """ Returns a list represention of the 4 points that define the car's bounding box. This method is expensive, if possible (i.e. the car's position and direction doesn't change) the result should be cached. """ half_width = CAR_BOUNDING_BOX_WIDTH / 2 half_height = CAR_BOUDNING_BOX_HEIGHT / 2 car_rect = [ (Vector(half_width, half_height).rotated(self.direction) + self.position).as_tuple(), (Vector(half_width, -half_height).rotated(self.direction) + self.position).as_tuple(), (Vector(-half_width, -half_height).rotated(self.direction) + self.position).as_tuple(), (Vector(-half_width, half_height).rotated(self.direction) + self.position).as_tuple() ] return car_rect
def draw(self, screen, screen_mapping): """ Draws the car on `screen`, with the position adjusted based on the provided `screen_mapping` """ rotated_sprite = pygame.transform.rotate( Car.get_sprite(), self.direction * 180 / math.pi) sprite_rect = rotated_sprite.get_rect() sprite_middle = Vector(sprite_rect.width, sprite_rect.height) / 2 sprite_position = self.position - sprite_middle screen_position = sprite_position + screen_mapping screen.blit(rotated_sprite, screen_position.as_tuple())
def __init__(self, host_computer): computer.Program.__init__(self, host_computer) global MyProgram self.state = MyProgram.STATE_STOP_THRUSTERS self.timer_end = None self.stat_counter = 0.0 self.rotation = Vector(0, 0, 0) self.rot_period = 1.0 self.set_timer(self.rot_period) self.computer.write('maneuver', 'thrust', ('rot-rcs-ryl', 1E2)) self.computer.write('maneuver', 'thrust', ('rot-rcs-lyl', 1E2))
def physics_update(self, delta_time): """ Updates the car's position and velocity based on its acceleration, given that `delta_time` seconds passed since the last `physics_update` call. """ self.position += delta_time * self.velocity * Vector.unit_from_angle( self.direction) self.velocity += delta_time * self.acceleration # Deal with floating-point instability if abs(self.velocity) < 0.9: self.velocity = 0 if math.fabs(self.velocity) > MAX_VELOCITY: self.velocity *= MAX_VELOCITY / (math.fabs(self.velocity))
def raycast_against_walls(self, ray, max_ray_length=0): # Raycasting against every wall (and therefore against every rect segment) is way too slow # with regards to the amount of ray-casts we want to perform every frame. As such, we must # prune away walls that we know we can't hit anyway, i.e. those that are too far away to # hit. We can only use that optimization if we know the `max_ray_length`. candidate_walls = [] if max_ray_length == 0: candidate_walls = self.walls else: for wall in self.walls: # For each wall, we find the minimum distance to the ray start from the vertices min_sqr_dist_lower_bound = None for vert in wall.verts: sqr_vert_dist = (Vector.from_tuple(vert) - ray.start).sqr_magnitude() sqr_dist_lower_bound = sqr_vert_dist - wall.sqr_half_side if min_sqr_dist_lower_bound is None or sqr_dist_lower_bound < min_sqr_dist_lower_bound: min_sqr_dist_lower_bound = sqr_dist_lower_bound # We then only consider walls that are below the threshold as candidates for hit detection if min_sqr_dist_lower_bound < max_ray_length**2: candidate_walls.append(wall) # We go through each candidate wall, and calculate if an intersection exists between and the # wall and ray, if it does, we update the hit point if it is closer to the ray start closest_point = None shortest_distance = None for wall in candidate_walls: inter_point, ray_dist = ray_rect_intersection(ray, wall.verts) if ray_dist is not None: if shortest_distance is None or ray_dist < shortest_distance: closest_point = inter_point shortest_distance = ray_dist return (closest_point, shortest_distance)
def __init__(self, host, port): asyncore.dispatcher_with_send.__init__(self) self.rx = "" self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((host, port)) self.connected = False self.zoom = 1E-10 self.camera = Vector(0, 0, 0) self.running = True self.polling = False self.network_thread = None self.verbose = False self.bodies = [] self.planets = {} self.general = {} self.transmissions = [] self.colours = { 'Sol': (255, 255, 0), 'Mercury': (100, 50, 50), 'Venus': (200, 200, 50), 'Earth': (100, 100, 255), 'Earth.Moon': (200, 200, 200), 'Mars': (200, 0, 0), 'Jupiter': (150, 0, 50), 'Saturn': (200, 200, 50), 'Uranus': (100, 200, 255), 'Neptune': (50, 100, 255) }
def circle_on_screen(screen, pos, radius): screen_size = screen.get_size() centre = Vector(screen_size[0] / 2, screen_size[1] / 2, 0) distance2 = (pos - centre).magnitude2() return ((distance2 + radius ** 2) < (max(centre.as_tuple()) ** 2))
def main(): state_file = "sim.state" load_state = False save_state = True print "[space-sim] starting" sim = simulation.Simulation() server = Networking(8000, sim) signal_handler = SignalHandler(sim) sim.register_entity_category('spaceship', ship_entity.ShipEntity) sim.register_entity_category('solar-body', solar_entities.SolarBodyEntity) if load_state: print "[space-sim] loading state" sim.load(state_file) else: print "[space-sim] generating state" solar_bodies = [ { 'name': 'Sol', 'pos': Vector(0, 0, 0), 'vel': Vector(0, 0, 0), 'mass': 1.9891E30, 'radius': 695500E3 }, #{ # 'name': 'BlackHole', # 'pos': Vector(-2.4E20, 0, 0), # 'vel': Vector(0, 0, 0), # 'mass': 7.9564E34, # 'radius': 6.7453303E12 #}, { 'name': 'Mercury', 'pos': Vector(5.791000e+10, 0, 0), 'vel': Vector(0, -47.36E3, 0), 'mass': 328.5E21, 'radius': 2440E3 }, { 'name': 'Venus', 'pos': Vector(1.082000e+11, 0, 0), 'vel': Vector(0, -35.02E3, 0), 'mass': 4.867E24, 'radius': 6052E3 }, { 'name': 'Earth', 'pos': Vector(149.59787E9, 0, 0), 'vel': Vector(0, -29.77E3, 0), 'mass': 5.97219E24, 'radius': 6378.1E3 }, { 'name': 'Earth.Moon', 'pos': Vector(149.59787E9 + 385E6, 0, 0), 'vel': Vector(0, -29.77E3 + -1020, 0), 'mass': 7.34767309E22, 'radius': 1737.4E3 }, { 'name': 'Mars', 'pos': Vector(2.279000e+11, 0, 0), 'vel': Vector(0, -24.07E3, 0), 'mass': 6.4174E23, 'radius': 3389.5E3 }, { 'name': 'Jupiter', 'pos': Vector(7.785000e+11, 0, 0), 'vel': Vector(0, -13.06E3, 0), 'mass': 1.898E27, 'radius': 69911E3 }, { 'name': 'Saturn', 'pos': Vector(1.433000e+12, 0, 0), 'vel': Vector(0, -9.68E3, 0), 'mass': 568.3E24, 'radius': 58232E3 }, { 'name': 'Uranus', 'pos': Vector(2.877000e+12, 0, 0), 'vel': Vector(0, -6.8E3, 0), 'mass': 86.81E24, 'radius': 25362E3 }, { 'name': 'Neptune', 'pos': Vector(4.503000e+12, 0, 0), 'vel': Vector(0, -5.43E3, 0), 'mass': 102.4E24, 'radius': 24622E3 } ] for body in solar_bodies: planet = solar_entities.SolarBodyEntity('solar-body', sim.allocate_uid(), sim) planet.name = body['name'] planet.pos = body['pos'] planet.vel = body['vel'] planet.mass = body['mass'] planet.radius = body['radius'] sim.add_entity(planet) ship = ship_entity.ShipEntity('spaceship', sim.allocate_uid(), sim) ship.pos = Vector(149.59787E9 + 6378.1E3 + 370E3, 0, 0) # around the earth ship.vel.y = -29.77E3 + -7.7E3 # Hopefully in orbit ship.radius = 8 # metres ship.mass = 2E3 # kg sim.add_entity(ship) print "[space-sim] hooking SIGINT" signal.signal(signal.SIGINT, signal_handler.handle) print "[space-sim] starting networking" server.start() print "[space-sim] entering simulation loop" while sim.running: sim.update() if save_state: print "[space-sim] saving state" sim.save(state_file) print "[space-sim] shutting down"
def circle_on_screen(screen, pos, radius): screen_size = screen.get_size() centre = Vector(screen_size[0] / 2, screen_size[1] / 2, 0) distance2 = (pos - centre).magnitude2() return ((distance2 + radius**2) < (max(centre.as_tuple())**2))
def main(): pygame.init() width, height = (1024, 768) screen = pygame.display.set_mode((width, height)) running = True observatory = Observatory('localhost', 8000) observatory.start_networking() focus = None focus_name = 'Earth' if focus_name == 'Sol': observatory.zoom = 5E-11 elif focus_name == 'Earth': observatory.zoom = 1E-6 clicked = None poll_rate = 20 next_poll = now_plus(1.0 / poll_rate) zoom_rate = 1.05 large_zoom_rate = zoom_rate * 10 while observatory.running: if now( ) >= next_poll and observatory.connected and not observatory.polling: observatory.poll() next_poll += datetime.timedelta(seconds=1.0 / poll_rate) for event in pygame.event.get(): if event.type == pygame.QUIT: observatory.running = False break elif event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: clicked = event.pos elif event.button == 4: observatory.zoom *= zoom_rate elif event.button == 5: observatory.zoom /= zoom_rate elif event.type == pygame.MOUSEBUTTONUP: if event.button == 1: clicked = None elif event.type == pygame.KEYDOWN: if event.key == pygame.K_e: observatory.zoom *= large_zoom_rate elif event.key == pygame.K_q: observatory.zoom /= large_zoom_rate width_metres = width / observatory.zoom height_metres = height / observatory.zoom if focus_name in observatory.planets.keys(): focus = observatory.planets[focus_name] if focus is not None: px, py, pz = focus.pos.as_tuple() offset_x, offset_y = width_metres / 2, height_metres / 2 if clicked is not None: cx, cy = clicked mx, my = pygame.mouse.get_pos() offset_x -= cx - mx offset_y -= cy - my observatory.camera = Vector(px - offset_x, py - offset_y, 0) observatory.draw(screen) observatory.close() pygame.quit()