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]) s = set() assert not f(s) assert not f(entity) s = set([ComponentA]) assert f(s) entity.add_component(ComponentA()) world._flush_component_updates() assert f(entity) s = set([ComponentB]) assert f(s) entity.remove_component(ComponentA) entity.add_component(ComponentB()) world._flush_component_updates() assert f(entity) s = set([ComponentC]) assert f(s) entity.remove_component(ComponentB) entity.add_component(ComponentC()) world._flush_component_updates() assert f(entity)
def test_compound_filter_2(world, entity): sub_filter_1 = or_filter([ComponentA]) f = or_filter([sub_filter_1]) assert not f(entity) entity.add_component(ComponentA()) world.flush_component_updates() assert f(entity)
def test_multiarg_creation(): f = and_filter(ComponentA, or_filter(ComponentB, ComponentC)) s = set() assert not f(s) s = set([ComponentA]) assert not f(s) s = set([ComponentB]) assert not f(s) s = set([ComponentC]) assert not f(s) s = set([ComponentA, ComponentB]) assert f(s) s = set([ComponentA, ComponentC]) assert f(s) s = set([ComponentB, ComponentC]) assert not f(s) s = set([ComponentA, ComponentB, ComponentC]) assert f(s)
class SetupModels(System): entity_filters = { 'model': and_filter([ Model, Position, or_filter([ Scene, PhysicsBody, ]), ]), } def enter_filter_model(self, entity): model = entity[Model] if model.node.name == "": model.node.name = entity._uid.name # Attach to PhysicsBody or Scene; former takes precedence. if CollidableGeometry in entity: entity[Geometry].node.set_collide_mask( entity[CollidableGeometry].collide_mask) if FlattenStrong in entity: model.node.flatten_strong() if PhysicsBody in entity: parent = entity[PhysicsBody].node else: parent = entity[Scene].node model.node.reparent_to(parent) model.node.set_pos(entity[Position].value) # Load hook self.post_load_hook(model.node, entity) def post_load_hook(self, node, entity): pass
class CastRestoreHealthSpell(CanCastRestoreHealthMixin, System): entity_filters = { 'cast_spell': and_filter([ and_filter([Mana, Health, CastingRestoreHealthSpell]), or_filter([Alive, Undead]), ], ), } spell_class = RestoreHealthSpell def update(self, filtered_entities): super().update(filtered_entities) def can_cast(self, entity): return CanCastRestoreHealthMixin.can_cast(self, entity) def cast(self, entity): mana = entity.get_component(Mana) spell = entity.get_component(self.spell_class) age = entity.get_component(Age) health = entity.get_component(Health) mana.mana -= spell.mana_cost health.health += spell.health_restored if health.health > health.max_health: health.health = health.max_health print("RESTORE HEALTH CAST!")
def test_compound_filter_4(world, entity): sub_filter_1 = and_filter([ComponentA]) sub_filter_2 = or_filter([ComponentB, ComponentC]) f = and_filter([sub_filter_1, sub_filter_2]) # A and (B or C) assert not f(entity) entity.add_component(ComponentA()) world.flush_component_updates() # A assert not f(entity) entity.remove_component(ComponentA) world.flush_component_updates() entity.add_component(ComponentB()) world.flush_component_updates() # B assert not f(entity) entity.add_component(ComponentA()) world.flush_component_updates() # A, B assert f(entity) entity.remove_component(ComponentB) entity.add_component(ComponentC()) world.flush_component_updates() # A, C assert f(entity) entity.remove_component(ComponentA) world.flush_component_updates() # C assert not f(entity)
class TurningBackToCamera(System): 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)
def test_compound_filter_4(world, entity): sub_filter_1 = and_filter([ComponentA]) sub_filter_2 = or_filter([ComponentB, ComponentC]) f = and_filter([sub_filter_1, sub_filter_2]) # A and (B or C) # Empty s = set() assert not f(s) assert not f(entity) # A s = set([ComponentA]) assert not f(s) entity.add_component(ComponentA()) world._flush_component_updates() assert not f(entity) entity.remove_component(ComponentA) world._flush_component_updates() # B s = set([ComponentB]) assert not f(s) entity.add_component(ComponentB()) world._flush_component_updates() assert not f(entity) # A, B s = set([ComponentA, ComponentB]) assert f(s) entity.add_component(ComponentA()) world._flush_component_updates() assert f(entity) # A, C s = set([ComponentA, ComponentC]) assert f(s) entity.remove_component(ComponentB) entity.add_component(ComponentC()) world._flush_component_updates() assert f(entity) # C s = set([ComponentC]) assert not f(s) entity.remove_component(ComponentA) world._flush_component_updates() assert not f(entity)
def test_or_filter_with_set(): f = or_filter([ComponentA, ComponentB]) s = set() assert not f(s) s = set([ComponentA]) assert f(s) s = set([ComponentB]) assert f(s) s = set([ComponentA, ComponentB]) assert f(s)
class LoadModels(System): entity_filters = { 'model': and_filter([ Model, Position, or_filter([ Scene, PhysicsBody, ]), ]), } # TODO # Only Model is needed for loading, which then could be done # asynchronously. def init_entity(self, filter_name, entity): # Load model = entity[Model] if model.node is None: if Actor in entity: model.node = direct.actor.Actor.Actor(model.model_name) else: model.node = base.loader.load_model(model.model_name) # Load hook self.post_load_hook(model.node, entity) # Attach to PhysicsBody or Scene; former takes precedence. if CollidableGeometry in entity: model.node.set_collide_mask(entity[CollidableGeometry].collide_mask) if FlattenStrong in entity: model.node.flatten_strong() if PhysicsBody in entity: parent = entity[PhysicsBody].node else: parent = entity[Scene].node model.node.reparent_to(parent) model.node.set_pos(entity[Position].value) # TODO # Destroy node if and only if the Model is removed. def destroy_entity(self, filter_name, entity, component): # Remove from scene if isinstance(component, Model): component.node.destroy_node() else: entity.get_component(Model).node.destroy_node() def post_load_hook(self, node, entity): pass
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
def test_or_filter_with_entity(world, entity): f = or_filter([ComponentA, ComponentB]) assert not f(entity) entity.add_component(ComponentA()) world._flush_component_updates() assert f(entity) entity.add_component(ComponentB()) world._flush_component_updates() assert f(entity) entity.remove_component(ComponentA) world._flush_component_updates() assert f(entity) entity.remove_component(ComponentB) world._flush_component_updates() assert not f(entity)
class ReadySpells(CanCastRejuvenationMixin, CanCastRestoreHealthMixin, CanCastLichdomMixin, System): entity_filters = { 'all_casters': and_filter([Mana]), 'rejuvenation': and_filter([Mana, Age, Alive, RejuvenationSpell]), 'restore_health': and_filter([ and_filter([Mana, Health, RestoreHealthSpell]), or_filter([Alive, Undead]), ]), 'lichdom': and_filter([Mana, Health, Alive, LichdomSpell]), } def update(self, filtered_entities): for entity in filtered_entities['all_casters']: entity.get_component(Mana).spells_ready = [] for spell, mixin in spells.items(): entities = filtered_entities[spell.name] if mixin.can_cast(self, entity, spell_class=spell, readying=True): entity.get_component(Mana).spells_ready.append(spell)
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)
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)