Exemplo n.º 1
0
class Jumping(CollisionSystem):
    '''
        Make the character jump.

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

    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
Exemplo n.º 2
0
class CollisionSystem(System):
    proxies = {
        'character_node': ProxyType(Model, 'node'),
        'scene_node': ProxyType(Model, 'parent'),
    }

    def init_sensors(self, entity, movement):
        solids = movement.solids
        for tag, solid in solids.items():
            solid['tag'] = tag
            if solid['shape'] is CollisionSphere:
                shape = CollisionSphere(solid['center'], solid['radius'])
                self.add_shape(entity, movement, solid, shape)
            elif solid['shape'] is CollisionCapsule:
                shape = CollisionCapsule(
                    solid['end_a'],
                    solid['end_b'],
                    solid['radius'],
                )
                self.add_shape(entity, movement, solid, shape)
        if movement.debug:
            scene_proxy = self.proxies['scene_node']
            scene = entity[scene_proxy.component_type]
            scene_node = scene_proxy.field(entity)

            movement.traverser.show_collisions(scene_node)

    def add_shape(self, entity, movement, solid, shape):
        model_proxy = self.proxies['character_node']
        model = entity[model_proxy.component_type]
        model_node = model_proxy.field(entity)

        node = NodePath(
            CollisionNode('{}-{}'.format(
                movement.tag_name,
                solid['tag'],
            )))
        solid['node'] = node
        node.node().add_solid(shape)
        node.node().set_from_collide_mask(movement.from_collide_mask)
        node.node().set_into_collide_mask(movement.into_collide_mask)
        node.reparent_to(model_node)
        movement.traverser.add_collider(node, movement.queue)
        node.set_python_tag(movement.tag_name, movement)
        if 'debug' in solid and solid['debug']:
            node.show()

    def run_sensors(self, entity, movement):
        scene_proxy = self.proxies['scene_node']
        scene = entity[scene_proxy.component_type]
        scene_node = scene_proxy.field(entity)

        movement.traverser.traverse(scene_node)
        movement.queue.sort_entries()
        movement.contacts = movement.queue.entries
Exemplo n.º 3
0
class Take(System):
    entity_filters = {
        'cursor': [Input, MouseOveringCamera, UserInterface, Inventory],
    }
    proxies = {
        'model': ProxyType(wecs.panda3d.prototype.Model, 'node'),
    }
    input_context = 'interface'
    
    def update(self, entities_by_filter):
        for entity in entities_by_filter['cursor']:
            input = entity[Input]
            # Can the player currently take?
            if self.input_context in input.contexts:
                context = base.device_listener.read_context(self.input_context)
                # Does he take?
                if context.get('take', False):
                    ui = entity[UserInterface]
                    target = ui.targeted_entity
                    # Does he point at a targetable entity?
                    if target is not None:
                        target_entity = self.world.get_entity(target)
                        # Can it be taken?
                        if Takeable in target_entity:
                            # Then take it.
                            self.take(entity, target_entity)

    def take(self, entity, target_entity):
        item_node = self.proxies['model'].field(target_entity)
        item_node.detach_node()  # TODO: Reattach to inventory
        del entity[Takeable]
        entity[Inventory].items.append(target_entity._uid)
        entity[Inventory].dirty = True
        print(entity[Inventory].items)
Exemplo n.º 4
0
class ErectCharacter(System):
    entity_filters = {
        'character': [
            Proxy('model_node'),
            CharacterController,
        ],
    }
    proxies = {'model_node': ProxyType(Model, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            model_node = self.proxies['model_node'].field(entity)
            up = character.gravity * -1

            roll = math.atan(character.gravity.x /
                             character.gravity.z) / (2.0 * math.pi) * 360.0
            model_node.set_r(model_node, roll)

            # FIXME: We now shoud recalculate gravity by also rolling the vector.

            pitch = math.atan(character.gravity.y /
                              character.gravity.z) / (2.0 * math.pi) * 360.0
            model_node.set_p(model_node, -pitch)

            character.gravity = Vec3(0, 0, -character.gravity.length())
Exemplo n.º 5
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([
            Proxy('scene_node'),
            Proxy('character_node'),
            Clock,
            CharacterController,
            BumpingMovement,
        ]),
    }
    proxies = {
        'character_node': ProxyType(Model, 'node'),
        'scene_node': ProxyType(Model, 'parent'),
    }

    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_proxy = self.proxies['scene_node']
            scene = entity[scene_proxy.component_type]
            scene_node = scene_proxy.field(entity)
            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()
Exemplo n.º 6
0
class AnimateCharacter(System):
    entity_filters = {
        'animated_character':
        and_filter([Proxy('actor'), Animation, CharacterController])
    }
    proxies = {'actor': ProxyType(Actor, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['animated_character']:
            controller = entity[CharacterController]
            animation = entity[Animation]
            actor_proxy = self.proxies['actor']
            actor = actor_proxy.field(entity)

            if FallingMovement in entity:
                grounded = entity[FallingMovement].ground_contact
            else:
                grounded = False

            initial = "idle"
            if not grounded:
                if controller.translation.z > 0.1:
                    initial = "jump"
                elif controller.translation.z < -0.1:
                    initial = "fall"
            elif controller.crouches:
                initial = "crouch"
            animation.to_play = [initial, "walk_forward", "run_forward"]
            # TODO: bad constant, 1.4? Should be fixed in animation
            # when the right value is found in lab.
            forward_speed = abs(controller.translation.y * 1.4)
            idle = max(0, (1 - forward_speed))
            walk = 1 - abs(forward_speed - 0.5) * 2
            run = max(0, forward_speed * 2 - 1)
            blends = [idle, walk, run]
            # sideways movement
            # TODO: same here, another constant. Fix in animation after lab.
            strafe_speed = (controller.translation.x * 1.4)
            if not strafe_speed == 0:
                blends.append(abs(strafe_speed))
                if strafe_speed > 0:
                    animation.to_play.append("walk_right")
                elif strafe_speed < 0:
                    animation.to_play.append("walk_left")

            animation.framerate = (0.5 + (forward_speed + abs(strafe_speed)))
            # If walking backwards simply play the animation in reverse
            # TODO: Only do this when there's no animations for walking backwards.
            if controller.translation.y < 0:
                animation.framerate = -animation.framerate
            if controller.translation.z < -0.2:
                animation.framerate *= 0.2

            animation.blends = blends
Exemplo n.º 7
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([
            Proxy('character_node'),
            Clock,
            AutomaticTurningMovement,
            TurningBackToCameraMovement,
            CharacterController,
            or_filter([
                WalkingMovement,
                FloatingMovement,
            ]),
            Camera,
            ObjectCentricCameraMode,
        ])
    }
    proxies = {'character_node': ProxyType(Model, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            camera = entity[Camera]
            center = entity[ObjectCentricCameraMode]
            turning = entity[TurningBackToCameraMovement]
            autoturning = entity[AutomaticTurningMovement]
            model_node = self.proxies['character_node'].field(entity)

            dt = entity[Clock].game_time

            autoturning.direction = model_node.get_relative_vector(
                camera.pivot,
                Vec3(0, 1, 0),
            )
            if character.move.xy.length() >= turning.threshold * dt:
                autoturning.alignment = turning.view_axis_alignment
            else:
                autoturning.alignment = 0.0
Exemplo n.º 8
0
class Animate(System):
    entity_filters = {
        'animation': and_filter([
            Proxy('actor'),
            Animation,
        ])
    }
    proxies = {'actor': ProxyType(Actor, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['animation']:
            animation = entity[Animation]
            actor_proxy = self.proxies['actor']
            actor = actor_proxy.field(entity)

            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 name not 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)
Exemplo n.º 9
0
    class BareTypeProxy(System):
        entity_filters = {
            'test': Proxy('proxy'),
        }
        proxies = {
            'proxy': ProxyType(TestComponent, 'foo'),
        }

        def update(self, entity_by_filters):
            for entity in entity_by_filters['test']:
                proxy = self.proxies['proxy']
                # test = entity[proxy.component_type]

                token = proxy.field(entity)

                global token_out
                token_out = token
Exemplo n.º 10
0
class ReorientInputBasedOnCamera(System):
    """
    By default, player input is relative to the character. If it is
    viewed from a third person perspective, it is usually preferable to
    rotate them so that they align with the camera instead.
    """
    entity_filters = {
        'reorient': and_filter([
            Camera,
            ObjectCentricCameraMode,
            CameraReorientedInput,
            Proxy('model'),
            CharacterController,
        ]),
    }
    proxies = {
        'model': ProxyType(Model, 'node'),
    }

    def enter_filter_reorient(self, entity):
        camera = entity[Camera]
        reorienter = entity[CameraReorientedInput]

        reorienter.node.reparent_to(camera.camera)

    def exit_filter_reorient(self, entity):
        reorienter = entity[CameraReorientedInput]

        reorienter.node.detach_node()

    def update(self, entities_by_filter):
        for entity in entities_by_filter['reorient']:
            model_proxy = self.proxies['model']
            model = entity[model_proxy.component_type]
            model_node = model_proxy.field(entity)
            character = entity[CharacterController]
            camera = entity[Camera]
            reorienter = entity[CameraReorientedInput]

            reorienter.node.set_p(model_node, 0)
            character.translation = model_node.get_relative_vector(
                reorienter.node,
                character.translation,
            )
Exemplo n.º 11
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)
Exemplo n.º 12
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
Exemplo n.º 13
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)
Exemplo n.º 14
0
class AdjustGravity(System):
    entity_filters = {
        'character': [
            Proxy('model_node'),
            CharacterController,
        ],
    }
    proxies = {'model_node': ProxyType(Model, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            model_node = self.proxies['model_node'].field(entity)

            gravity_node = base.render
            attractor = model_node.get_pos(gravity_node)
            attractor.y = 0.0
            attractor.normalize()
            attractor *= 9.81
            local_gravity = model_node.get_relative_vector(
                gravity_node,
                attractor,
            )
            character.gravity = local_gravity
Exemplo n.º 15
0
from panda3d.core import Point3
from panda3d.core import Vec3
from panda3d.core import CollisionSphere

# from wecs import cefconsole
import wecs
from wecs.core import ProxyType
from wecs.aspects import Aspect
from wecs.aspects import factory
# from wecs.panda3d import debug

from wecs.panda3d.constants import FALLING_MASK
from wecs.panda3d.constants import BUMPING_MASK

m_proxy = {
    'model': ProxyType(wecs.panda3d.prototype.Model, 'node'),
}
cn_proxy = {
    'character_node': ProxyType(wecs.panda3d.prototype.Model, 'node'),
    'scene_node': ProxyType(wecs.panda3d.prototype.Model, 'parent'),
}

# Each frame, run these systems. This defines the game itself.
system_types = [
    wecs.panda3d.prototype.ManageModels,
    wecs.panda3d.camera.PrepareCameras(proxies=m_proxy),
    wecs.mechanics.clock.DetermineTimestep,
    wecs.panda3d.character.UpdateCharacter(proxies=cn_proxy),
    wecs.panda3d.character.Walking,
    wecs.panda3d.character.Bumping(proxies=cn_proxy),
    wecs.panda3d.character.Falling(proxies=cn_proxy),
Exemplo n.º 16
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([
            Proxy('scene_node'),
            Proxy('character_node'),
            Clock,
            CharacterController,
            FallingMovement,
        ]),
    }
    proxies = {
        'character_node': ProxyType(Model, 'node'),
        'scene_node': ProxyType(Model, 'parent'),
    }

    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):
        character = entity[CharacterController]
        model_proxy = self.proxies['character_node']
        model = entity[model_proxy.component_type]
        model_node = model_proxy.field(entity)
        scene_proxy = self.proxies['scene_node']
        scene = entity[scene_proxy.component_type]
        scene_node = scene_proxy.field(entity)

        clock = entity[Clock]
        controller = entity[CharacterController]
        falling_movement = entity[FallingMovement]

        # Adjust inertia by gravity
        frame_gravity = character.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(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:
                # FIXME: We're assuming a sphere here.
                # We only use the lower half of the sphere, no equator.
                if contact.get_surface_normal(lifter).get_z() > 0.0:
                    contact_point = contact.get_surface_point(lifter)
                    contact_point -= center  # In solid's space
                    xy = contact_point.xy
                    expected_z = -sqrt(radius ** 2 - xy.length() ** 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 movement
        controller.translation += frame_falling
Exemplo n.º 17
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([
            Proxy('character_node'),
            Clock,
            CharacterController,
            InertialMovement,
        ]),
    }
    proxies = {'character_node': ProxyType(Model, 'node')}

    def enter_filter_character(self, entity):
        movement = entity[InertialMovement]
        model_proxy = self.proxies['character_node']
        model = entity[model_proxy.component_type]
        model_node = model_proxy.field(entity)

        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_proxy = self.proxies['character_node']
            model = entity[model_proxy.component_type]
            model_node = model_proxy.field(entity)
            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. And if it is between those, it will
            # interpolate accordingly.
            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
            if inertia.delta_inputs:
                delta_v = wanted_speed_vector
            else:
                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
            else:
                capped_delta_v = delta_v

            character.translation = (last_speed_vector + capped_delta_v) * dt

            if inertia.ignore_z:
                character.translation.z = old_z
Exemplo n.º 18
0
class AutomaticallyTurnTowardsDirection(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([
            Proxy('character_node'),
            Clock,
            AutomaticTurningMovement,
            CharacterController,
            or_filter([
                WalkingMovement,
                FloatingMovement,
            ]),
        ])
    }
    proxies = {'character_node': ProxyType(Model, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            turning = entity[AutomaticTurningMovement]
            model_node = self.proxies['character_node'].field(entity)
            if WalkingMovement in entity:
                movement = entity[WalkingMovement]
            else:
                movement = entity[FloatingMovement]
            dt = entity[Clock].game_time

            if turning.direction.xy.length() > 0.0:
                # How much would he have to adjust heading to face
                # towards the given vector?
                direc = Vec2(turning.direction.xy)
                angle = Vec2(0, 1).signed_angle_deg(direc)
                
                # How far can we turn this frame? Clamp to that.
                max_angle = movement.turning_speed
                if abs(angle) > max_angle:
                    angle = copysign(max_angle, angle)
                # How much of that do we *want* to turn?
                angle *= turning.alignment

                # So let's turn, and clamp, in case we're already turning.
                old_rotation = character.rotation.x
                character.rotation.x += angle
                character.rotation.x = min(
                    character.rotation.x,
                    max_angle,
                )
                character.rotation.x = max(
                    character.rotation.x,
                    -max_angle,
                )
                # Since the camera rotates with the character, we need
                # to counteract that as well.
                delta_rotation = character.rotation.x - old_rotation
                turning.angle = delta_rotation

                # FIXME: This needs to be its own system
                camera = entity[Camera]
                camera.pivot.set_h(camera.pivot.get_h() - delta_rotation)
Exemplo n.º 19
0
class AvatarUI(System):
    """
    Command rules:
    if not embodied and not targeting_selection:
        selection(goto target)
    if not embodied and targeting_selection:
        selection(idle)
    if embodied and selecting and not targeting_selection:
        selection(goto target)
    if embodied and selecting and targeting_selection:
        selection(idle)
    if embodied and not selecting and targeting_selection:
        self(idle)
    if embodied and not selecting and not targeting_selection:
        self(goto target)
    """
    entity_filters = {
        'cursor': [Input, MouseOveringCamera, UserInterface],
    }
    proxies = {
        'parent': ProxyType(wecs.panda3d.prototype.Model, 'parent'),
    }
    input_context = 'select_entity'

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

    def process_input(self, entity, context):
        ui = entity[UserInterface]
        mouseover = entity[MouseOveringCamera]

        mouseovered_entity = None
        if mouseover.entity is not None:
            mouseovered_entity = self.world.get_entity(mouseover.entity)
        targeting_self = mouseover.entity == entity._uid

        selected_entity = None
        if ui.selected_entity is not None:
            selected_entity = self.world.get_entity(ui.selected_entity)
        target_entity = None
        if ui.targeted_entity is not None:
            target_entity = self.world.get_entity(ui.targeted_entity)
        point_coordinates = ui.point_coordinates
        targeting_selection = False
        if selected_entity is not None and ui.selected_entity == ui.targeted_entity:
            targeting_selection = True

        embodied = Embodiable in entity
        targeting_embodiable = None
        if mouseovered_entity is not None:
            targeting_embodiable = Embodiable in mouseovered_entity

        # Now we can evaluate the player's input. First, he clicked to
        # select.
        if context.get('select', False):
            if target_entity is None or Selectable not in target_entity:
                # Selecting while not pointing at a valid target
                # unselects.
                ui.selected_entity = None
                ui.select_indicator.detach_node()
            else:
                # But selecting a selectable entity... selects it.
                if not embodied or mouseover.entity != entity._uid:
                    ui.selected_entity = target_entity._uid
        # The player instead clicked to give a command, and there is a
        # valid target, ...
        elif context.get('command', False):
            # 3rd person mode, giving command with to selected entity
            if not embodied and selected_entity and target_entity and not targeting_selection:
                action = ['walk_to_entity', mouseover.entity]
                if point_coordinates:
                    action.append(point_coordinates)
                self.command(selected_entity, *action)
            if not embodied and targeting_selection:
                self.command(selected_entity, 'idle')
            if embodied and selected_entity and target_entity and not targeting_selection:
                action = ['walk_to_entity', mouseover.entity]
                if point_coordinates:
                    action.append(point_coordinates)
                self.command(selected_entity, *action)
            if embodied and ui.selected_entity and target_entity and not targeting_selection:
                self.command(entity, 'idle')
            if embodied and targeting_selection:
                self.command(selected_entity, 'idle')
            if embodied and not ui.selected_entity and targeting_selection:
                self.command(entity, 'idle')
            if embodied and not ui.selected_entity and target_entity and not targeting_self:
                action = ['walk_to_entity', mouseover.entity]
                if point_coordinates:
                    action.append(point_coordinates)
                self.command(entity, *action)
            if embodied and targeting_self and not ui.selected_entity:
                self.command(entity, 'idle')
        # Now the player clicked to dis-/embody...
        elif context.get('embody', False):
            if not embodied and not targeting_embodiable and selected_entity:
                self.embody(entity, selected_entity)
            if not embodied and targeting_embodiable:
                self.embody(entity, target_entity)
            if embodied and targeting_embodiable and not targeting_self:
                self.jump_body(entity, target_entity)
            if embodied and not targeting_embodiable:
                self.disembody(entity)

    def command(self, entity, *action):
        ai = entity[BehaviorAI]
        ai.behavior = action

    def embody(self, entity, target):
        pc_mind.add(target)
        third_person.add(target)
        self.world.destroy_entity(entity)

    def jump_body(self, entity, target):
        pc_mind.remove(entity)
        third_person.remove(entity)
        pc_mind.add(target)
        third_person.add(target)

    def disembody(self, entity):
        scene = self.proxies['parent'].field(entity)
        pos = entity[Camera].camera.get_pos(scene)
        hpr = entity[Camera].camera.get_hpr(scene)
        pos.z += 0.5
        hpr.y = 0
        hpr.z = 0
        pc_mind.remove(entity)
        if first_person.in_entity(entity):
            first_person.remove(entity)
        if third_person.in_entity(entity):
            third_person.remove(entity)
        spawn_point = {
            wecs.panda3d.prototype.Model:
            dict(
                parent=scene,
                post_attach=lambda: wecs.panda3d.prototype.transform(
                    pos=pos,
                    hpr=hpr,
                ),
            ),
        }
        observer.add(
            self.world.create_entity(name="Observer"),
            overrides={
                **spawn_point,
            },
        )
Exemplo n.º 20
0
class CollisionSystem(System):
    proxies = {
        'character_node': ProxyType(Model, 'node'),
        'scene_node': ProxyType(Model, 'parent'),
    }

    def init_sensors(self, entity, movement):
        solids = movement.solids
        for tag, solid in solids.items():
            if 'shape' in solid:  # Create solids from specification
                solid['tag'] = tag
                if solid['shape'] is CollisionSphere:
                    shape = CollisionSphere(solid['center'], solid['radius'])
                elif solid['shape'] is CollisionCapsule:
                    shape = CollisionCapsule(
                        solid['end_a'],
                        solid['end_b'],
                        solid['radius'],
                    )
                else:
                    raise Exception("Shape unsupported.")
                self.add_shape(entity, movement, solid, shape)
            else:  # Fetch solids from model
                model_node = self.proxies['character_node'].field(entity)
                solid_nodes = model_node.find_all_matches(
                    f'**/{movement.node_name}',
                )
                # FIXME: This is a temporary prevention of sing multiple
                # solids in one movement system. This whole .py needs to
                # be refactored to account for multiple ones.
                assert len(solids) == 1
                solid_node = solid_nodes[0]

                solid_node.reparent_to(model_node)

                solid['node'] = solid_node
                solid_objects = solid_node.node().get_solids()
                # FIXME: As above, please refactor this .py to account
                # for multiple solids.
                assert len(solids) == 1
                solid_object = solid_objects[0]
                solid['shape'] = solid_object.type
                if solid['shape'] == CollisionSphere:
                    solid['center'] = solid_object.center
                    solid['radius'] = solid_object.radius

                # FIXME: This is mostly copypasta from add_solid, which
                # should be broken up.
                node = solid_node.node()
                node.set_from_collide_mask(movement.from_collide_mask)
                node.set_into_collide_mask(movement.into_collide_mask)
                movement.traverser.add_collider(
                    solid_node,
                    movement.queue,
                )
                node.set_python_tag(movement.tag_name, movement)
                if movement.debug:
                    solid_node.show()

        if movement.debug:
            scene_proxy = self.proxies['scene_node']
            scene = entity[scene_proxy.component_type]
            scene_node = scene_proxy.field(entity)

            movement.traverser.show_collisions(scene_node)

    def add_shape(self, entity, movement, solid, shape):
        model_proxy = self.proxies['character_node']
        model = entity[model_proxy.component_type]
        model_node = model_proxy.field(entity)

        node = NodePath(
            CollisionNode(
                f'{movement.tag_name}-{solid["tag"]}',
            ),
        )
        solid['node'] = node
        node.node().add_solid(shape)
        node.node().set_from_collide_mask(movement.from_collide_mask)
        node.node().set_into_collide_mask(movement.into_collide_mask)
        node.reparent_to(model_node)
        movement.traverser.add_collider(node, movement.queue)
        node.set_python_tag(movement.tag_name, movement)
        if 'debug' in solid and solid['debug']:
            node.show()

    def run_sensors(self, entity, movement):
        scene_proxy = self.proxies['scene_node']
        scene = entity[scene_proxy.component_type]
        scene_node = scene_proxy.field(entity)

        movement.traverser.traverse(scene_node)
        movement.queue.sort_entries()
        movement.contacts = movement.queue.entries
Exemplo n.º 21
0
# These modules contain the actual game mechanics, which we are tying
# together into an application in this file:

import movement
import paddles
import ball

logging.getLogger().setLevel(logging.DEBUG)

if __name__ == '__main__':
    ECSShowBase()  # ShowBase + base.ecs_world + base.add_system()
    base.disable_mouse()
    base.accept('escape', sys.exit)

    model_proxies = {
        'model': ProxyType(wecs.panda3d.prototype.Model, 'node'),
    }
    systems = [
        # Attach the entity's Model. This gives an entity a node as
        # presence in the scene graph.
        # Attach Geometry to the Model's node.
        wecs.panda3d.prototype.ManageModels(),
        # If the Paddle's size has changed, apply it to the Model.
        paddles.ResizePaddles(proxies=model_proxies),
        # Read player input and store it on Movement
        paddles.GivePaddlesMoveCommands(proxies=model_proxies),
        # Apply the Movement
        movement.MoveObject(proxies=model_proxies),
        # Did the paddle move too far? Back to the boundary with it!
        paddles.PaddleTouchesBoundary(),
        # If the Ball has hit the edge, it reflects off it.
Exemplo n.º 22
0
class MouseOverOnEntity(System):
    entity_filters = {
        'mouseoverable': [Proxy('model'), MouseOverable],
        'mouseoverable_geometry': [Proxy('geometry'), MouseOverableGeometry],
        'camera': [Camera, Input, MouseOveringCamera],
    }
    proxies = {
        'model': ProxyType(Model, 'node'),
        'geometry': ProxyType(Geometry, 'node'),
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.traverser = CollisionTraverser()
        self.queue = CollisionHandlerQueue()

        self.picker_ray = CollisionRay()
        self.picker_node = CollisionNode('mouse ray')
        self.picker_node.add_solid(self.picker_ray)
        self.picker_node.set_from_collide_mask(MOUSEOVER_MASK)
        self.picker_node.set_into_collide_mask(0x0)
        self.picker_node_path = NodePath(self.picker_node)

        self.traverser.add_collider(self.picker_node_path, self.queue)

    def enter_filter_mouseoverable(self, entity):
        model_proxy = self.proxies['model']
        model_node = model_proxy.field(entity)
        mouseoverable = entity[MouseOverable]

        into_node = CollisionNode('wecs_mouseoverable')
        into_node.add_solid(mouseoverable.solid)
        into_node.set_from_collide_mask(0x0)
        into_node.set_into_collide_mask(mouseoverable.mask)
        into_node_path = model_node.attach_new_node(into_node)
        into_node_path.set_python_tag('wecs_mouseoverable', entity._uid)

    def exit_filter_mouseoverable(self, entity):
        # FIXME: Undo all the other stuff that accumulated!
        entity[MouseOverable].solid.detach_node()

    def enter_filter_mouseoverable_geometry(self, entity):
        into_node = self.proxies['geometry'].field(entity)

        old_mask = into_node.get_collide_mask()
        new_mask = old_mask | entity[MouseOverableGeometry].mask
        into_node.set_collide_mask(new_mask)
        into_node.find('**/+GeomNode').set_python_tag('wecs_mouseoverable',
                                                      entity._uid)

    def update(self, entities_by_filter):
        for entity in entities_by_filter['camera']:
            mouse_overing = entity[MouseOveringCamera]
            camera = entity[Camera]
            input = entity[Input]

            # Reset overed entity to None
            mouse_overing.entity = None
            mouse_overing.collision_entry = None

            requested = 'mouse_over' in input.contexts
            has_mouse = base.mouseWatcherNode.has_mouse()
            if requested and has_mouse:
                # Attach and align testing ray, and run collisions
                self.picker_node_path.reparent_to(camera.camera)
                mpos = base.mouseWatcherNode.get_mouse()
                self.picker_ray.set_from_lens(
                    base.camNode,
                    mpos.getX(),
                    mpos.getY(),
                )
                self.traverser.traverse(camera.camera.get_top())

                # Remember reference to mouseovered entity, if any
                if self.queue.get_num_entries() > 0:
                    self.queue.sort_entries()
                    entry = self.queue.get_entry(0)
                    picked_node = entry.get_into_node_path()
                    picked_uid = picked_node.get_python_tag(
                        'wecs_mouseoverable')
                    mouse_overing.entity = picked_uid
                    mouse_overing.collision_entry = entry
Exemplo n.º 23
0
class UpdateMouseOverUI(System):
    entity_filters = {
        'cursor': [Input, MouseOveringCamera, UserInterface],
    }
    input_context = 'select_entity'
    proxies = {
        'model': ProxyType(Model, 'node'),
    }

    def exit_filter_cursor(self, entity):
        ui = entity[UserInterface]
        ui.select_indicator.detach_node()
        ui.target_indicator.detach_node()
        ui.point_indicator.detach_node()

    def update(self, entities_by_filter):
        for entity in entities_by_filter['cursor']:
            ui = entity[UserInterface]
            mouseover = entity[MouseOveringCamera]
            mouseovered_entity_uid = mouseover.entity
            mouseovered_entity = None
            selected_entity = None
            target_entity = None
            point_coordinates = None

            # Does the currently selected entity still exist, and which
            # is it?
            if ui.selected_entity is not None:
                try:
                    selected_entity = self.world.get_entity(ui.selected_entity)
                except NoSuchUID:
                    ui.selected_entity = None
            # Update the selection indicator
            if selected_entity is not None:
                selected_node = self.proxies['model'].field(selected_entity)
                ui.select_indicator.reparent_to(selected_node)
            else:
                ui.select_indicator.detach_node()

            # Update target and point indicators.
            if mouseovered_entity_uid is not None:
                # If we are pointing at an entity, then target, point,
                # or do neither, depending on the entity.
                mouseovered_entity = self.world.get_entity(
                    mouseovered_entity_uid)
                mouseovered_entity_node = self.proxies['model'].field(
                    mouseovered_entity)
                if Targetable in mouseovered_entity:
                    target_entity = mouseovered_entity
                    ui.target_indicator.reparent_to(mouseovered_entity_node)
                    ui.point_indicator.detach_node()
                elif Pointable in mouseovered_entity:
                    target_entity = mouseovered_entity
                    ui.target_indicator.detach_node()
                    ui.point_indicator.reparent_to(mouseovered_entity_node)
                    # FIXME: Adjust position
                    point_coordinates = mouseover.collision_entry.get_surface_point(
                        mouseovered_entity_node)
                    ui.point_indicator.set_pos(point_coordinates)
                else:
                    ui.target_indicator.detach_node()
                    ui.point_indicator.detach_node()
            else:
                # If we're not pointing at an entity, don't indicate a
                # target.
                ui.target_indicator.detach_node()
                ui.point_indicator.detach_node()

            # Write results into the component for consumption by other
            # systems.
            if selected_entity is None:
                ui.selected_entity = None
            else:
                ui.selected_entity = selected_entity._uid
            if target_entity is None:
                ui.targeted_entity = None
            else:
                ui.targeted_entity = target_entity._uid
            ui.point_coordinates = point_coordinates
Exemplo n.º 24
0
 class NonBareTypeProxy(ProxyingNullSystem):
     proxies = {
         'null_proxy': ProxyType(NullComponent),
     }
Exemplo n.º 25
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([
            Proxy('character_node'),  # Not used, but required for a complete character
            Clock,
            CharacterController,
        ]),
        'input': and_filter([
            CharacterController,
            Input,
        ]),
    }
    proxies = {'character_node': ProxyType(Model, 'node')}
    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]

                if context['direction'] is not None:
                    character.move.x = context['direction'].x
                    character.move.y = context['direction'].y
                else:
                    character.move = Vec2(0, 0)
                if context['rotation'] is not None:
                    character.heading = -context['rotation'].x
                    character.pitch = context['rotation'].y
                else:
                    character.heading = 0
                    character.pitch = 0

                # 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 = False
                character.sprints = False
                character.crouches = False

                if 'jump' in context:
                    character.jumps = context['jump']
                if 'sprint' in context:
                    character.sprints = context['sprint']
                if 'crouch' in context:
                    character.crouches = context['crouch']

        for entity in entities_by_filter['character']:
            controller = entity[CharacterController]
            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)
Exemplo n.º 26
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([
            Proxy('character_node'),
            Clock,
            TurningBackToCameraMovement,
            CharacterController,
            or_filter([
                WalkingMovement,
                FloatingMovement,
            ]),
            Camera,
            ObjectCentricCameraMode,
        ])
    }
    proxies = {'character_node': ProxyType(Model, 'node')}

    def update(self, entities_by_filter):
        for entity in entities_by_filter['character']:
            character = entity[CharacterController]
            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)
Exemplo n.º 27
0
class AvatarUI(System):
    """
    Command rules:
    if not embodied and not targeting_selection:
        selection(goto target)
    if not embodied and targeting_selection:
        selection(idle)
    if embodied and selecting and not targeting_selection:
        selection(goto target)
    if embodied and selecting and targeting_selection:
        selection(idle)
    if embodied and not selecting and targeting_selection:
        self(idle)
    if embodied and not selecting and not targeting_selection:
        self(goto target)
    """
    entity_filters = {
        'cursor': [Input, MouseOveringCamera, UserInterface],
    }
    proxies = {
        'parent': ProxyType(Model, 'parent'),
    }
    input_context = 'select_entity'
    
    def update(self, entities_by_filter):
        for entity in entities_by_filter['cursor']:
            input = entity[Input]
            if self.input_context in input.contexts:
                context = base.device_listener.read_context(self.input_context)
                self.process_input(entity, context)

    def process_input(self, entity, context):
        ui = entity[UserInterface]
        mouseover = entity[MouseOveringCamera]

        mouseovered_entity = None
        if mouseover.entity is not None:
            mouseovered_entity = self.world.get_entity(mouseover.entity)
        targeting_self = mouseover.entity == entity._uid

        selected_entity = None
        if ui.selected_entity is not None:
            selected_entity = self.world.get_entity(ui.selected_entity)
        target_entity = None
        if ui.targeted_entity is not None:
            target_entity = self.world.get_entity(ui.targeted_entity)
        point_coordinates = ui.point_coordinates
        targeting_selection = False
        if selected_entity is not None and ui.selected_entity == ui.targeted_entity:
            targeting_selection = True
        
        embodied = Embodiable in entity
        targeting_embodiable = None
        if mouseovered_entity is not None:
            targeting_embodiable = Embodiable in mouseovered_entity
        
        # Now we can evaluate the player's input. First, he clicked to
        # select.
        if context.get('select', False):
            if target_entity is None or Selectable not in target_entity:
                # Selecting while not pointing at a valid target
                # unselects.
                ui.selected_entity = None
                ui.select_indicator.detach_node()
            else:
                # But selecting a selectable entity... selects it.
                if not embodied or mouseover.entity != entity._uid:
                    ui.selected_entity = target_entity._uid
        # The player instead clicked to give a command, and there is a
        # valid target, ...
        elif context.get('command', False):
            # 3rd person mode, giving command with to selected entity
            if not embodied and selected_entity and target_entity and not targeting_selection:
                action = ['walk_to_entity', mouseover.entity]
                if point_coordinates:
                    action.append(point_coordinates)
                self.command(selected_entity, *action)
            if not embodied and targeting_selection:
                self.command(selected_entity, 'idle')
            if embodied and selected_entity and target_entity and not targeting_selection:
                action = ['walk_to_entity', mouseover.entity]
                if point_coordinates:
                    action.append(point_coordinates)
                self.command(selected_entity, *action)
            if embodied and ui.selected_entity and target_entity and not targeting_selection:
                self.command(entity, 'idle')
            if embodied and targeting_selection:
                self.command(selected_entity, 'idle')
            if embodied and not ui.selected_entity and targeting_selection:
                self.command(entity, 'idle')
            if embodied and not ui.selected_entity and target_entity and not targeting_self:
                action = ['walk_to_entity', mouseover.entity]
                if point_coordinates:
                    action.append(point_coordinates)
                self.command(entity, *action)
            if embodied and targeting_self and not ui.selected_entity:
                self.command(entity, 'idle')
        # Now the player clicked to dis-/embody...
        elif context.get('embody', False):
            if not embodied and not targeting_embodiable and selected_entity:
                self.embody(entity, selected_entity)
            if not embodied and targeting_embodiable:
                self.embody(entity, target_entity)
            if embodied and targeting_embodiable and not targeting_self:
                self.jump_body(entity, target_entity)
            if embodied and not targeting_embodiable:
                self.disembody(entity)

    def command(self, entity, *action):
        ai = entity[BehaviorAI]
        ai.behavior = action

    def embody(self, entity, target):
        raise NotImplementedError

    def jump_body(self, entity, target):
        raise NotImplementedError

    def disembody(self, entity):
        raise NotImplementedError
Exemplo n.º 28
0
class PrepareCameras(System):
    """
    Add a `Camera` to an entity with the `'model`' proxy to attach a 
    camera to its node.

    Add `MountedCameraMode` or `ObjectCentricCameraMode` to specify how
    the camera should place itself. 
    """
    entity_filters = {
        'camera': and_filter([
            Camera,
            Proxy('model'),
        ]),
        'mount': and_filter([
            Camera,
            MountedCameraMode,
        ]),
        'mount_actor': and_filter([
            Camera,
            MountedCameraMode,
            Actor,
        ]),
        'center': and_filter([
            Camera,
            ObjectCentricCameraMode,
        ]),
    }
    proxies = {
        'model': ProxyType(Model, 'node'),
    }

    def enter_filter_camera(self, entity):
        model_proxy = self.proxies['model']
        model = entity[model_proxy.component_type]
        camera = entity[Camera]

        camera.camera.reparent_to(camera.pivot)
        camera.pivot.reparent_to(model_proxy.field(entity))
        camera.camera.node().get_lens().set_fov(camera.fov)

    def exit_filter_camera(self, entity):
        camera = entity[Camera]

        camera.pivot.detach_node()
        camera.camera.detach_node()

    def enter_filter_mount(self, entity):
        camera = entity[Camera]
        camera.pivot.set_pos(0, 0, 0)
        camera.pivot.set_hpr(0, 0, 0)
        camera.camera.set_pos(0, 0, 0)
        camera.camera.set_hpr(0, 0, 0)

    def enter_filter_mount_actor(self, entity):
        camera = entity[Camera]
        node = entity[Actor].node
        joint = node.expose_joint(None, 'modelRoot', 'camera')
        if joint:
            camera.pivot.set_pos((0, 0, 0))
            camera.pivot.reparent_to(joint)

    def exit_filter_mount(self, entity):
        model_proxy = self.proxies['model']
        model = entity[model_proxy.component_type]
        camera = entity[Camera]

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

            center.heading = 0
            center.pitch = 0
            center.zoom = 0