def test_add(self): node = QuadTreeNode(0, 0, 5, 5, max_count=2) node.add_entity(self.create_entity(0, 0, 1, 1)) node.add_entity(self.create_entity(1, 0, 1, 1)) self.assertEquals(len(node.children), 0) self.assertEquals(len(node.entities), 2)
def test_remove(self): node = QuadTreeNode(0, 0, 5, 5, max_count=2) node.add_entity(self.create_entity(0, 0, 1, 1)) node.add_entity(self.create_entity(1, 0, 1, 1)) sub_child_entity = self.create_entity(1, 0, 3, 3) node.add_entity(sub_child_entity) self.assertEquals(len(node.children[3].entities), 1) node.remove_entity(sub_child_entity) self.assertEquals(len(node.children[3].entities), 0)
def update(self, delta): self.handle_messages() self.collisions = [] if settings.USE_SPATIAL_PARTITIONING: quad_tree = QuadTreeNode(0, 0, settings.SCREEN_WIDTH, settings.SCREEN_HEIGHT) for entity in self.entities: quad_tree.add_entity(entity) self.system_manager.send_message({ 'message_type': MESSAGE_TYPE.QUAD_TREE, 'quad_tree': quad_tree, }) for entity in self.entities: if entity.get(ImmovableComponent): continue physics_component = entity[PhysicsComponent] physics_component.update_forces(delta) if 'Friction' in physics_component.forces: friction_force = physics_component.forces['Friction'] velocity_delta_due_to_friction = delta * friction_force.vector / physics_component.mass non_friction_forces = physics_component.get_net_force(exclude_forces=['Friction']) non_friction_accel = non_friction_forces / physics_component.mass velocity_without_friction = delta * non_friction_accel + physics_component.velocity velocity_with_friction = velocity_without_friction + velocity_delta_due_to_friction # friction was overly aggressive, time to undo some friction if ((velocity_without_friction[0] < 0 and velocity_with_friction[0] >= 0) or (velocity_without_friction[0] > 0 and velocity_with_friction[0] <= 0)): physics_component.velocity = velocity_with_friction physics_component.velocity = Vec2d(0, physics_component.velocity[1]) physics_component.forces.pop('Friction') else: physics_component.velocity = velocity_with_friction else: net_force = physics_component.get_net_force() physics_component.acceleration = net_force / physics_component.mass physics_component.velocity += delta * physics_component.acceleration entity.position += delta * physics_component.get_total_velocity() for entity_a in self.entities: overlapping_entities = [] if entity_a.get(ImmovableComponent): continue collision_candidates = quad_tree.get_intersections(entity_a) if settings.USE_SPATIAL_PARTITIONING else self.entities for entity_b in collision_candidates: if entity_a == entity_b: continue if entity_a.get(CharacterComponent) and entity_b.get(CharacterComponent): continue shape_a = entity_a.get(ShapeComponent) shape_b = entity_b.get(ShapeComponent) if shape_a is None or shape_b is None: continue separating_vectors, overlap = calculate_separating_vectors(shape_a.get_points(), shape_b.get_points()) entity_a_total_velocity = entity_a[PhysicsComponent].get_total_velocity() if overlap and entity_a.collision_mask & entity_b.collision_type: overlapping_entities.append(entity_b) self.system_manager.send_message({ 'message_type': MESSAGE_TYPE.COLLISION, 'collider': entity_a, 'collidee': entity_b }) if entity_a.get(SkipCollisionResolutionComponent) or entity_b.get(SkipCollisionResolutionComponent): continue resolution_vector = self.find_resolution_vector(separating_vectors) resolution_vector_normalized = resolution_vector.normalized() if resolution_vector_normalized == Vec2d(0, -1): entity_a.send_message({ 'message_type': MESSAGE_TYPE.LANDED, }) entity_a[PhysicsComponent].velocity = Vec2d(entity_a[PhysicsComponent].velocity[0], 0) if entity_a[PhysicsComponent].velocity[0] > 0: direction_multiplier = -1 elif entity_a[PhysicsComponent].velocity[0] < 0: direction_multiplier = 1 else: direction_multiplier = 0 if direction_multiplier != 0: entity_a[PhysicsComponent].forces['Friction'] = Force( self.coefficient_of_friction * entity_a[PhysicsComponent].mass * Vec2d(direction_multiplier * entity_a[PhysicsComponent].get_net_force()[1], 0), source=entity_b ) elif 'Friction' in entity_a[PhysicsComponent].forces: entity_a[PhysicsComponent].forces.pop('Friction') elif resolution_vector_normalized == Vec2d(0, 1): entity_a[PhysicsComponent].velocity = Vec2d(entity_a[PhysicsComponent].velocity[0], 0) entity_a.position += resolution_vector if 'Friction' in entity_a[PhysicsComponent].forces: friction_force = entity_a[PhysicsComponent].forces['Friction'] if friction_force.source not in overlapping_entities: entity_a[PhysicsComponent].forces.pop('Friction') if len(overlapping_entities) == 0: entity_a.send_message({ 'message_type': MESSAGE_TYPE.AIRBORNE, })