Esempio n. 1
0
class NullSystem(System):
    entity_filters = {
        "null": and_filter([NullComponent])
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.entries = []
        self.exits = []
        self.updates = []
    
    def enter_filters(self, filters, entity):
        self.entries.append((filters, entity))
    
    def exit_filters(self, filters, entity):
        self.exits.append((filters, entity))

    def update(self, entities_by_filter):
        self.updates.append(entities_by_filter)
Esempio n. 2
0
class Animate(System):
    entity_filters = {
        'animation': and_filter([
            Animation,
            Model,
        ])
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['animation']:
            animation = entity[Animation]
            actor = entity[Model].node
            if not animation.playing == animation.to_play:
                if len(animation.to_play) > 0:
                    actor.enableBlend()
                else:
                    actor.disableBlend()

                # TODO: Don't stop and swap different animations instantly
                # but ease in (and bounce?) between them.

                #Stop animations not in to_play.
                for name in animation.playing:
                    if not name in animation.to_play:
                        actor.stop(name)
                        actor.setControlEffect(name, 0)

                #Play newly added animations.
                for n, name in enumerate(animation.to_play):
                    if name not in animation.playing:
                        actor.loop(name)
                animation.playing = animation.to_play

            # Set blends each frame
            for b, blend in enumerate(animation.blends):
                if b < len(animation.playing):
                    name = animation.playing[b]
                    actor.setControlEffect(name,
                                           blend / len(animation.playing))

            # Set framerate each frame
            for name in animation.playing:
                actor.setPlayRate(animation.framerate, name)
Esempio n. 3
0
class Cursoring(System):
    entity_filters = {
        'cursor': and_filter([CursorMovement, CharacterController, Model]),
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['cursor']:
            cursor = entity[CursorMovement]
            model = entity[Model]
            char = entity[CharacterController]
            char.translation *= cursor.move_speed
            char.rotation *= cursor.rot_speed
            char.rotation[1] = 0
            if cursor.snapping:
                if char.move.x == 0 and char.move.y == 0 and char.move.z == 0:
                    if char.heading == 0:
                        np = model.node
                        np.set_pos(snap_vector(np.get_pos(), cursor.move_snap))
                        np.set_hpr(snap_vector(np.get_hpr(), cursor.rot_snap))
Esempio n. 4
0
class Frictioning(System):
    '''
    Applies a slow-down to the character.
    '''
    entity_filters = {
        'character':
        and_filter([
            Clock,
            CharacterController,
            FrictionalMovement,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            dt = entity[Clock].game_time
            character = entity[CharacterController]
            friction = entity[FrictionalMovement]

            character.translation *= 0.5**(dt / friction.half_life)
Esempio n. 5
0
class StartBallMotion(System):
    entity_filters = {
        'ball': and_filter([
            Model,
            Scene,
            Position,
            Resting,
            Ball,
        ]),
    }

    def update(self, entities_by_filter):
        # Should resting balls be started?
        start_key = KeyboardButton.space()
        start_balls = base.mouseWatcherNode.is_button_down(start_key)

        if start_balls:
            for entity in set(entities_by_filter['ball']):
                del entity[Resting]
                entity[Movement] = Movement(value=Vec3(-1, 0, 0))
Esempio n. 6
0
class FaceMovement(System):
    entity_filters = {
        'character': and_filter([
            Proxy('geometry_node'),
            Clock,
            CharacterController,
            FacingMovement,
        ]),
    }
    proxies = {'geometry_node': ProxyType(Geometry, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            geometry_proxy = self.proxies['geometry_node']
            geometry = entity[geometry_proxy.component_type]
            geometry_node = geometry_proxy.field(entity)

            controller = entity[CharacterController]
            x, y, z = controller.last_translation_speed
            geometry_node.look_at(x, y, 0)
Esempio n. 7
0
class Jumping(CollisionSystem):
    entity_filters = {
        'character':
        and_filter([
            CharacterController,
            JumpingMovement,
            FallingMovement,
            Scene,
            Clock,
            Model,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            controller = entity[CharacterController]
            falling_movement = entity[FallingMovement]
            jumping_movement = entity[JumpingMovement]
            if controller.jumps and falling_movement.ground_contact:
                falling_movement.inertia += jumping_movement.impulse
Esempio n. 8
0
class Floating(System):
    '''
        Components used :func:`wecs.core.and_filter` 'character'
            | :class:`wecs.panda3d.character.CharacterController`
            | :class:`wecs.panda3d.character.FloatingMovement`
    '''
    entity_filters = {
        'character': and_filter([
            CharacterController,
            FloatingMovement,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            floating = entity[FloatingMovement]

            character.translation *= floating.speed
            character.rotation *= floating.turning_speed
Esempio n. 9
0
class DetermineTimestep(System):
    entity_filters = {
        'clock': and_filter([Clock]),
    }

    def update(self, entities_by_filter):
        clocks_by_parent = defaultdict(set)
        for entity in entities_by_filter['clock']:
            clocks_by_parent[entity[Clock].parent].add(entity)
        updated_parents = set()
        for entity in clocks_by_parent[None]:
            clock = entity[Clock]
            dt = clock.clock()
            # Wall time: The last frame's physical duration
            clock.wall_time = dt
            # Frame time: Wall time, capped to a maximum
            max_timestep = clock.max_timestep
            if dt > max_timestep:
                dt = max_timestep
            clock.frame_time = dt
            # FIXME: Provided for legacy purposes
            clock.timestep = dt
            # Game time: Time-dilated frame time
            clock.game_time = clock.frame_time * clock.scaling_factor
            # ...and to start the loop...
            updated_parents.add(entity._uid)
        while updated_parents:
            next_parents = set()
            for parent in updated_parents:
                if parent in clocks_by_parent:
                    for entity in clocks_by_parent[parent]:
                        child_clock = entity[Clock]
                        parent_clock = entity.world[parent][Clock]
                        child_clock.wall_time = parent_clock.wall_time
                        # FIXME: Rip out timestep
                        child_clock.timestep = parent_clock.frame_time
                        child_clock.frame_time = parent_clock.frame_time
                        child_clock.game_time = parent_clock.game_time * child_clock.scaling_factor
                        next_parents.add(entity._uid)
            updated_parents = next_parents
Esempio n. 10
0
class ExecuteMovement(System):
    '''
    Transcribe the final intended movement to the model, making it an actual movement.

        Components used :func:`wecs.core.and_filter` 'character'
            | :class:`wecs.panda3d.character.CharacterController`
            | :class:`wecs.panda3d.model.Model`
            | :class:`wecs.panda3d.model.Clock`
    '''
    entity_filters = {
        'character':
        and_filter([
            Proxy('character_node'),
            Clock,
            CharacterController,
        ]),
    }
    proxies = {'character_node': ProxyType(Model, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            model_proxy = self.proxies['character_node']
            model = entity[model_proxy.component_type]
            character = entity[CharacterController]
            dt = entity[Clock].game_time

            # Translation: Simple self-relative movement for now.
            model_node = model_proxy.field(entity)
            model_node.set_pos(model_node, character.translation)
            character.last_translation_speed = character.translation / dt

            # Rotation
            if character.clamp_pitch:
                # Adjust intended pitch until it won't move you over a pole.
                preclamp_pitch = model_node.get_p() + character.rotation.y
                clamped_pitch = max(min(preclamp_pitch, 89.9), -89.9)
                character.rotation.y += clamped_pitch - preclamp_pitch

            model_node.set_hpr(model_node, character.rotation)
            character.last_rotation_speed = character.rotation / dt
Esempio n. 11
0
class CastRejuvenationSpell(CanCastRejuvenationMixin, System):
    entity_filters = {
        'cast_spell': and_filter([Mana, CastingRejuvenationSpell, Age, Alive]),
    }
    spell_class = RejuvenationSpell

    def update(self, filtered_entities):
        super().update(filtered_entities)

    def can_cast(self, entity):
        return super().can_cast(entity)

    def cast(self, entity):
        mana = entity.get_component(Mana)
        spell = entity.get_component(self.spell_class)
        age = entity.get_component(Age)

        mana.mana -= spell.mana_cost
        age.age -= spell.time_restored
        if age.age < 0:
            age.age = 0
        print("REJUVENATION SPELL CAST!")
Esempio n. 12
0
class ResizePaddles(System):
    """
    ResizePaddles ensures that the paddle's size stays updated.
    The idea is that other systems may influence the size by changing
    the paddle's Component state. ResizePaddles will make the actual change
    to the Model.
    """
    entity_filters = {
        'paddle': and_filter([
            Model,
            Paddle,
        ]),
    }

    def update(self, entities_by_filter):
        """
        Update the paddle size by setting the scale of the paddle's Model.
        """
        for entity in entities_by_filter['paddle']:
            model = entity[Model]
            paddle = entity[Paddle]
            model.node.set_scale(paddle.size)
Esempio n. 13
0
class PaddleTouchesBoundary(System):
    entity_filters = {
        'paddles': and_filter([
            Proxy('model'),
            Paddle,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in set(entities_by_filter['paddles']):
            model = entity[Model]
            position = entity[Position]
            paddle = entity[Paddle]

            z = position.value.z
            size = paddle.size

            if z + size > 1:
                position.value.z = 1 - size
            elif (z - size) < -1:
                position.value.z = -1 + size
            model.node.set_z(position.value.z)
Esempio n. 14
0
def test_compound_filter_3(world, entity):
    sub_filter_1 = and_filter([ComponentA])
    sub_filter_2 = or_filter([ComponentB, ComponentC])
    f = or_filter([sub_filter_1, sub_filter_2])
    assert not f(entity)

    entity.add_component(ComponentA())
    world.flush_component_updates()
    assert f(entity)

    entity.remove_component(ComponentA)
    entity.add_component(ComponentB())
    world.flush_component_updates()
    assert f(entity)

    entity.remove_component(ComponentB)
    entity.add_component(ComponentC())
    world.flush_component_updates()
    assert f(entity)

    entity.remove_component(ComponentC)
    world.flush_component_updates()
Esempio n. 15
0
class WalkSpeedLimiting(System):
    '''
    Applies a slow-down to the character.
    '''
    entity_filters = {
        'character': and_filter([
            Clock,
            CharacterController,
            WalkingMovement,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            dt = entity[Clock].game_time
            character = entity[CharacterController]
            walking = entity[WalkingMovement]

            v_length = character.translation.length()
            if v_length > walking.speed * dt:
                character.translation.normalize()
                character.translation *= walking.speed * dt
Esempio n. 16
0
class Bumping(CollisionSystem):
    '''
        Stop the character from moving through solid geometry.

        Components used :func:`wecs.core.and_filter` 'character'
            | :class:`wecs.panda3d.model.Scene`
            | :class:`wecs.panda3d.character.CharacterController`
            | :class:`wecs.panda3d.character.BumpingMovement`
            | :class:`wecs.panda3d.model.Clock`
            | :class:`wecs.panda3d.model.Model`
    '''
    entity_filters = {
        'character':
        and_filter([
            Scene,
            CharacterController,
            BumpingMovement,
            Clock,
            Model,
        ]),
    }

    def enter_filter_character(self, entity):
        movement = entity[BumpingMovement]
        self.init_sensors(entity, movement)
        bumper = movement.solids['bumper']
        node = bumper['node']
        movement.queue.add_collider(node, node)

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            scene = entity[Scene]
            character = entity[CharacterController]
            movement = entity[BumpingMovement]
            bumper = movement.solids['bumper']
            node = bumper['node']
            node.set_pos(character.translation)
            movement.traverser.traverse(scene.node)
            character.translation = node.get_pos()
Esempio n. 17
0
class PaddleTouchesBoundary(System):
    entity_filters = {
        'paddles': and_filter([
            Model,
            Scene,
            Position,
            Paddle,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in set(entities_by_filter['paddles']):
            pos = entity.get_component(Position).value
            size = entity.get_component(Paddle).size
            if pos.z + size > 1:
                pos.z = 1 - size
                np = entity.get_component(Model).node
                np.set_z(pos.z)
            if (pos.z - size) < -1:
                pos.z = -1 + size
                np = entity.get_component(Model).node
                np.set_z(pos.z)
Esempio n. 18
0
class DirectlyIndicateDirection(System):
    entity_filters = {
        'character': and_filter([
            Proxy('model'),
            AutomaticTurningMovement,
            TwinStickMovement,
            CharacterController,
            Camera,
            ObjectCentricCameraMode,
        ])
    }
    proxies = {'model': ProxyType(Model, 'node')}
    input_context = 'character_direction'

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            input = entity[Input]
            if self.input_context in input.contexts:
                context = base.device_listener.read_context(self.input_context)
                self.process_input(context, entity)

    def process_input(self, context, entity):
        model_proxy = self.proxies['model']
        model_node = model_proxy.field(entity)
        camera = entity[Camera]
        turning = entity[AutomaticTurningMovement]

        if context['direction'] is not None:
            turning.direction = model_node.get_relative_vector(
                camera.pivot,
                Vec3(
                    context['direction'].x,
                    context['direction'].y,
                    0,
                ),
            )
        else:
            turning.direction = Vec3(0, 1, 0)
Esempio n. 19
0
class BallTouchesBoundary(System):
    entity_filters = {
        'ball': and_filter([
            Model,
            Scene,
            Position,
            Movement,
            Ball,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['ball']:
            np = entity.get_component(Model).node
            z = np.get_z()
            if z > 0.9:
                np.set_z(0.9 - (z - 0.9))
                movement = entity.get_component(Movement).value
                movement.z = -movement.z
            if z < -0.9:
                np.set_z(-0.9 - (z + 0.9))
                movement = entity.get_component(Movement).value
                movement.z = -movement.z
Esempio n. 20
0
class AnimationPlayer(System):
    entity_filters = {
        'character': and_filter([Character]),
    }

    def change_state(self, char, old_state, new_state):
        old_state_def = char.states.get(old_state, {})
        new_state_def = char.states[new_state]

        #char._actor.stop()
        if old_state is not None:
            char._state_paths[old_state].stash()

        transition = char.transitions.get((old_state, new_state))
        if transition:
            char._actor.unstash()

            for part, anim in transition.items():
                Sequence(
                    char._actor.actor_interval(anim, partName=part, playRate=char.play_rates[new_state]),
                    Func(lambda: char._actor.stash()),
                    Func(lambda: char._state_paths[new_state].unstash()),
                ).start()
        else:
            char._actor.stash()
            char._state_paths[new_state].unstash()

    def update(self, entities_by_filter):
        if base.paused:
            return

        for entity in entities_by_filter['character']:
            char = entity[Character]

            if char._state != char.state:
                self.change_state(char, char._state, char.state)
                char._state = char.state
Esempio n. 21
0
class GiveTankMoveCommands(System):
    entity_filters = {
        'tank': and_filter([
            Model,
            Scene,
            Position,
            Movement,
            Tank,
        ]),
    }

    def enter_filter_model(self, entity):
        geometry = entity[Geometry]
        print(geometry)

    def update(self, entities_by_filter):
        for entity in entities_by_filter['tank']:
            tank = entity[Tank]
            movement = entity[Movement]

            # What keys does the player use?
            if tank.player == Players.LEFT:
                up_key = KeyboardButton.ascii_key(b'w')
                down_key = KeyboardButton.ascii_key(b's')
            elif tank.player == Players.RIGHT:
                up_key = KeyboardButton.up()
                down_key = KeyboardButton.down()

            # Read player input
            delta = 0
            if base.mouseWatcherNode.is_button_down(up_key):
                delta += 1
            if base.mouseWatcherNode.is_button_down(down_key):
                delta -= 1

            # Store movement
            movement.value.z = delta
Esempio n. 22
0
class Walking(System):
    entity_filters = {
        'character': and_filter([
            CharacterController,
            WalkingMovement,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            walking = entity[WalkingMovement]

            speed = walking.speed
            if character.sprints and SprintingMovement in entity:
                speed = entity[SprintingMovement].speed
            if character.crouches and CrouchingMovement in entity:
                speed = entity[CrouchingMovement].speed
            if character.move.y < 0:
                speed *= walking.backwards_multiplier

            character.translation *= speed
            character.rotation *= walking.turning_speed
            character.rotation.y = 0  # No pitch adjustment while walking
Esempio n. 23
0
class CollideCamerasWithTerrain(System):
    entity_filters = {
        'camera': and_filter([
            Camera,
            ObjectCentricCameraMode,
            CollisionZoom,
        ])
    }

    def init_entity(self, filter_name, entity):
        camera = entity[Camera]
        center = entity[ObjectCentricCameraMode]
        zoom = entity[CollisionZoom]

        w = zoom.body_width / 2
        segs = ((0, 0, w), (0, 0, -w), (w, 0, 0), (-w, 0, 0))
        for seg in segs:
            segment = CollisionSegment(seg,(0, -center.distance, 0))
            zoom.collision.add_solid(segment)
        zoom.collision.set_into_collide_mask(0)
        cn = camera.camera.parent.attach_new_node(zoom.collision)
        zoom.traverser.add_collider(cn, zoom.queue)

    def update(self, entities_by_filter):
        for entity in entities_by_filter['camera']:
            camera = entity[Camera]
            center = entity[ObjectCentricCameraMode]
            zoom = entity[CollisionZoom]

            zoom.traverser.traverse(render)
            entries = list(zoom.queue.entries)
            if len(entries) > 0:
                hit_pos = entries[0].get_surface_point(camera.camera.parent)
                camera.camera.set_pos(hit_pos)
            else:
                camera.camera.set_pos(0, -center.distance, 0)
Esempio n. 24
0
class TankTouchesBoundary(System):
    entity_filters = {
        'tanks': and_filter([
            Model,
            Scene,
            Position,
            Tank,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in set(entities_by_filter['tanks']):
            model = entity[Model]
            position = entity[Position]
            tank = entity[Tank]

            z = position.value.z
            size = tank.size

            if z + size > 1:
                position.value.z = 1 - size
            elif (z - size) < -1:
                position.value.z = -1 + size
            model.node.set_z(position.value.z)
Esempio n. 25
0
class CastLichdomSpell(CanCastLichdomMixin, System):
    entity_filters = {
        'cast_spell': and_filter([
            Mana,
            CastingLichdomSpell,
            Alive,
        ]),
    }
    spell_class = LichdomSpell

    def update(self, filtered_entities):
        super().update(filtered_entities)

    def cast(self, entity):
        mana = entity.get_component(Mana)
        spell = entity.get_component(self.spell_class)

        if entity.has_component(LichdomSpellEffect):
            mana.mana -= int(spell.mana_cost / 2)
            print("SPELL FIZZLES, already under its effect.")
        else:
            mana.mana -= spell.mana_cost
            entity.add_component(LichdomSpellEffect())
            print("LICHDOM SPELL CAST!")
Esempio n. 26
0
class UpdateStamina(System):
    entity_filters = {
        'character': and_filter([
            CharacterController,
            Stamina,
            Clock,
        ]),
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            stamina = entity[Stamina]
            dt = entity[Clock].timestep
            av = abs(character.move.x) + abs(character.move.y)
            drain = 0
            if character.move.x or character.move.y:
                drain = stamina.move_drain * av
            if character.sprints and SprintingMovement in entity:
                if stamina.current > stamina.sprint_drain * av:
                    drain = stamina.sprint_drain * av
                else:
                    character.sprints = False
            elif character.crouches and CrouchingMovement in entity:
                if stamina.current > stamina.crouch_drain * av:
                    drain = stamina.crouch_drain * av
                else:
                    character.crouches = False
            if character.jumps and JumpingMovement in entity:
                if stamina.current > stamina.jump_drain * av:
                    drain += stamina.jump_drain
                else:
                    character.jumps = False
            stamina.current -= drain * dt
            stamina.current += stamina.recovery * dt
            stamina.current = clamp(stamina.current, 0, stamina.maximum)
Esempio n. 27
0
class Falling(CollisionSystem):
    '''
        Stop the character from falling through solid geometry.

        Components used :func:`wecs.core.and_filter` 'character'
            | :class:`wecs.panda3d.character.CharacterController`
            | :class:`wecs.panda3d.character.FallingMovement`
            | :class:`wecs.panda3d.model.Clock`
            | :class:`wecs.panda3d.model.Model`
    '''
    entity_filters = {
        'character':
        and_filter([
            CharacterController,
            FallingMovement,
            Scene,
            Clock,
            Model,
        ]),
    }

    def enter_filter_character(self, entity):
        self.init_sensors(entity, entity[FallingMovement])

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            # Adjust the falling inertia by gravity, and position the
            # lifter collider.
            self.predict_falling(entity)
            # Find collisions with the ground.
            self.run_sensors(entity, entity[FallingMovement])
            # Adjust the character's intended translation so that his
            # falling is stoppedby the ground.
            self.fall_and_land(entity)

    def predict_falling(self, entity):
        model = entity[Model]
        scene = entity[Scene]
        clock = entity[Clock]
        controller = entity[CharacterController]
        falling_movement = entity[FallingMovement]

        # Adjust inertia by gravity
        falling_movement.local_gravity = model.node.get_relative_vector(
            scene.node,
            falling_movement.gravity,
        )
        frame_gravity = falling_movement.local_gravity * clock.game_time
        falling_movement.inertia += frame_gravity

        # Adjust lifter collider by inertia
        frame_inertia = falling_movement.inertia * clock.game_time
        lifter = falling_movement.solids['lifter']
        node = lifter['node']
        node.set_pos(lifter['center'] + controller.translation + frame_inertia)

    def fall_and_land(self, entity):
        falling_movement = entity[FallingMovement]
        clock = entity[Clock]
        controller = entity[CharacterController]

        falling_movement.ground_contact = False
        frame_falling = falling_movement.inertia * clock.game_time
        if len(falling_movement.contacts) > 0:
            lifter = falling_movement.solids['lifter']['node']
            center = falling_movement.solids['lifter']['center']
            radius = falling_movement.solids['lifter']['radius']
            height_corrections = []
            for contact in falling_movement.contacts:
                if contact.get_surface_normal(lifter).get_z() > 0.0:
                    contact_point = contact.get_surface_point(lifter) - center
                    x = contact_point.get_x()
                    y = contact_point.get_y()
                    # x**2 + y**2 + z**2 = radius**2
                    # z**2 = radius**2 - (x**2 + y**2)
                    expected_z = -sqrt(radius**2 - (x**2 + y**2))
                    actual_z = contact_point.get_z()
                    height_corrections.append(actual_z - expected_z)
            if height_corrections:
                frame_falling += Vec3(0, 0, max(height_corrections))
                falling_movement.inertia = Vec3(0, 0, 0)
                falling_movement.ground_contact = True

        # Now we know how falling / lifting influences the character move
        controller.translation += frame_falling
Esempio n. 28
0
class Inertiing(System):
    '''
        Accelerate character, as opposed to an instantanious velocity.

        Components used :func:`wecs.core.and_filter` 'character'
            | :class:`wecs.panda3d.character.CharacterController`
            | :class:`wecs.panda3d.character.InertialMovement`
            | :class:`wecs.panda3d.model.Model`
            | :class:`wecs.model.clock`
    '''
    entity_filters = {
        'character':
        and_filter([
            CharacterController,
            InertialMovement,
            Model,
            Clock,
        ]),
    }

    def enter_filter_character(self, entity):
        movement = entity[InertialMovement]
        model = entity[Model]
        movement.node.reparent_to(model.node)
        movement.node.set_hpr(0, 0, 0)

    def exit_filter_character(self, entity):
        # detach InertialMovement.node
        import pdb
        pdb.set_trace()

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            dt = entity[Clock].game_time
            model = entity[Model]
            character = entity[CharacterController]
            inertia = entity[InertialMovement]

            # Usually you want to apply inertia only to x and y, and
            # ignore z, so we cache it.
            old_z = character.translation.z

            # We use inertia.node to represent "last frame's" model
            # orientation, scaled for how much inertia you'd like to
            # keep model-relative. Wow, what a sentence...
            # When you run forward and turn around, where should inertia
            # carry you? Physically, towards your new backward
            # direction. The opposite end of the scale of realism is
            # that your inertia vector turns around with you, and keeps
            # carrying you towards your new forward.
            # So if inertia.rotated_inertia = 1.0, inertia.node will
            # be aligned with the model, and thus the inertia vector
            # turns with you. If inertia.rotated_inertia = 0.0,
            # inertia.node will extrapolate the model's past rotation,
            # and the inertia vector will thus be kept still relative to
            # the surroundings.
            inertia.node.set_hpr(
                -character.last_rotation_speed * dt *
                (1 - inertia.rotated_inertia), )
            last_speed_vector = model.node.get_relative_vector(
                inertia.node,
                character.last_translation_speed,
            )

            # Now we calculate the wanted speed difference, and scale it
            # within gameplay limits.
            wanted_speed_vector = character.translation / dt
            delta_v = wanted_speed_vector - last_speed_vector
            max_delta_v = inertia.acceleration * dt
            if delta_v.length() > max_delta_v:
                capped_delta_v = delta_v / delta_v.length() * max_delta_v
                character.translation = (last_speed_vector +
                                         capped_delta_v) * dt

            if inertia.ignore_z:
                character.translation.z = old_z
Esempio n. 29
0
class TurningBackToCamera(System):
    '''
        Turns character away from the camera.

        Components used :func:`wecs.core.and_filter` 'character'
            | :class:`wecs.panda3d.character.TurningBackToCameraMovement`
            | :class:`wecs.panda3d.character.CharacterController`
            | :class:`wecs.panda3d.model.Model`
            | :class:`wecs.panda3d.camera.ThirdPersonCamera`
            | :class:`wecs.panda3d.camera.TurntableCamera`
            | :class:`wecs.panda3d.model.Clock`
    '''
    entity_filters = {
        'character':
        and_filter([
            TurningBackToCameraMovement,
            CharacterController,
            Model,
            Camera,
            ObjectCentricCameraMode,
            Clock,
            or_filter([
                WalkingMovement,
                FloatingMovement,
            ]),
        ])
    }

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            model = entity[Model]
            camera = entity[Camera]
            center = entity[ObjectCentricCameraMode]
            turning = entity[TurningBackToCameraMovement]
            if WalkingMovement in entity:
                movement = entity[WalkingMovement]
            else:
                movement = entity[FloatingMovement]
            dt = entity[Clock].game_time

            if character.move.x**2 + character.move.y**2 > (turning.threshold *
                                                            dt)**2:
                # What's the angle to turn?
                target_angle = camera.pivot.get_h() % 360
                if target_angle > 180.0:
                    target_angle = target_angle - 360.0
                # How far can we turn this frame? Clamp to that.
                max_angle = movement.turning_speed * dt
                if abs(target_angle) > max_angle:
                    target_angle *= max_angle / abs(target_angle)
                # How much of that do we *want* to turn?
                target_angle *= turning.view_axis_alignment

                # So let's turn, and clamp, in case we're already turning.
                old_rotation = character.rotation.x
                character.rotation.x += target_angle
                character.rotation.x = min(character.rotation.x,
                                           movement.turning_speed * dt)
                character.rotation.x = max(character.rotation.x,
                                           -movement.turning_speed * dt)
                # Since the camera rotates with the character, we need
                # to counteract that as well.
                delta_rotation = character.rotation.x - old_rotation
                camera.pivot.set_h(camera.pivot.get_h() - delta_rotation)
Esempio n. 30
0
class UpdateCharacter(System):
    '''
    Convert input to character movement.

        Components used :func:`wecs.core.and_filter` 'character'
            | :class:`wecs.panda3d.character.CharacterController`
            | :class:`wecs.panda3d.model.Clock`
            | :class:`wecs.panda3d.mode.Model`
    '''
    entity_filters = {
        'character': and_filter([
            CharacterController,
            Clock,
            Model,
        ]),
        'input': and_filter([
            CharacterController,
            Input,
        ]),
    }
    input_context = 'character_movement'

    def update(self, entities_by_filter):
        for entity in entities_by_filter['input']:
            input = entity[Input]
            if self.input_context in input.contexts:
                context = base.device_listener.read_context(self.input_context)
                character = entity[CharacterController]

                character.move.x = context['direction'].x
                character.move.y = context['direction'].y
                character.heading = -context['rotation'].x
                character.pitch = context['rotation'].y

                # Special movement modes.
                # By default, you run ("sprint"), unless you press e, in
                # which case you walk. You can crouch by pressing q; this
                # overrides walking and running. Jump by pressing space.
                # This logic is implemented by the Walking system. Here,
                # only intention is signalled.
                character.jumps = context['jump']
                character.sprints = context['sprint']
                character.crouches = context['crouch']

        for entity in entities_by_filter['character']:
            controller = entity[CharacterController]
            model = entity[Model]
            dt = entity[Clock].game_time

            # Rotation
            controller.rotation = Vec3(
                controller.heading * dt,
                controller.pitch * dt,
                0,
            )

            # Translation
            # Controllers gamepad etc.) fill a whole rectangle of input
            # space, but characters are limited to a circle. If you're
            # strafing diagonally, you still don't get sqrt(2) speed.
            xy_dist = sqrt(controller.move.x**2 + controller.move.y**2)
            xy_scaling = 1.0
            if xy_dist > 1:
                xy_scaling = 1.0 / xy_dist
            x = controller.move.x * xy_scaling
            y = controller.move.y * xy_scaling
            z = controller.move.z * xy_scaling
            controller.translation = Vec3(x * dt, y * dt, z * dt)