Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
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,
                })