Exemple #1
0
    def __init__(self, parent: NodePath):
        super().__init__()
        self.parent = parent

        self.mouse_np = p3d.camera.attach_new_node(PandaNode('mouse'))
        self.mouse_np.set_y(p3d.lens.get_near())

        picker_node = CollisionNode('mouse_ray')
        picker_np = p3d.camera.attach_new_node(picker_node)
        self._picker_ray = CollisionRay()
        picker_node.add_solid(self._picker_ray)
        self._collision_handler = CollisionHandlerQueue()
        self._traverser = CollisionTraverser('mouse_traverser')
        self._traverser.add_collider(picker_np, self._collision_handler)

        self.actor = Actor(
            resource_filename('tsim', 'data/models/cursor'),
            {'spin': resource_filename('tsim', 'data/models/cursor-spin')})
        self.actor.loop('spin')
        self.actor.reparent_to(parent)
        self.actor.set_pos(0.0, 0.0, 0.0)
        self.actor.set_shader_off()

        self._position = Point(0.0, 0.0)
        self.last_position = self._position
        self.moved = False
        self.pointed_at = None

        self._tool: Optional[Tool] = None
        self._register_events()
Exemple #2
0
    def __init__(self, pos, radius, dest):
        """Setup this portal."""
        #Setup model
        self.model = loader.load_model("./data/models/scenery/portal/portal")
        self.model.set_pos(*pos)  #Y is up in the map data
        self.model.set_scale(radius, radius, radius)

        try:
            texture = loader.load_texture(
                os.path.join("./data/maps", dest, "portal.png"))
            self.model.set_texture(texture, 1)

        except IOError:
            Logger.warning("No portal texture for map '{}'.".format(dest))

        self.model.reparent_to(base.world_mgr.scenery_np)

        #Setup collision detection
        cnode = CollisionNode("portal")
        cnode.add_solid(CollisionSphere(0, 0, 0, 1))
        self.collider = self.model.attach_new_node(cnode)
        self.collider.set_python_tag("object", self)
        base.cTrav.add_collider(self.collider, base.portal_handler)

        #Store desination
        self.dest = dest
Exemple #3
0
 def __init__(self, map, color, node):
     self.map = map
     self.color = color
     self.node = node
     col = CollisionNode(node.name)
     col.add_solid(CollisionSphere((0, 0, 0), 1))
     col.set_collide_mask(base.itemmask)
     self.col_node = self.map.collisions.attach_new_node(col)
     self.col_node.set_pos(node.get_pos())
     self.col_node.set_z(node, 1)
Exemple #4
0
def setup_ray(node, traverser, bitmask, point_a=(0, 0, 1), point_b=(0, 0, 0)):
    ray = CollisionSegment(point_a, point_b)
    col = CollisionNode(node.getName() + "-ray")
    col.add_solid(ray)
    col.set_from_collide_mask(bitmask)
    col.set_into_collide_mask(CollideMask.all_off())
    col_node = node.attach_new_node(col)
    handler = CollisionHandlerQueue()
    traverser.add_collider(col_node, handler)
    return {"collider": col, "ray": ray, "handler": handler, "node": col_node}
Exemple #5
0
 def __initCollisions(self, name):
     self.notify.debug("Initializing collision sphere...")
     ss = CollisionSphere(0, 0, 0, 5)
     ss.setTangible(0)
     snode = CollisionNode(name)
     snode.add_solid(ss)
     snode.set_collide_mask(CIGlobals.WallBitmask)
     self.snp = self.attach_new_node(snode)
     self.snp.setZ(3)
     self.acceptOnce("enter" + self.snp.node().getName(), self.__handleEnterCollisionSphere)
Exemple #6
0
    def __init__(self):
        """Setup this camera manager."""
        Logger.info("Initializing camera manager...")
        self.reset()

        #Camera Controls
        #===============
        #F1 - first person view
        #F2 - chase cam view
        #F3 - free cam view
        #W - move forward
        #S - move backward
        #A - move left
        #D - move right
        #R - rise
        #F - fall
        #Up - look up
        #Down - look down
        #Left - turn left
        #Right - turn right
        base.accept("f1", self.change_mode, [CAM_MODE_FIRST_PERSON])
        base.accept("f2", self.change_mode, [CAM_MODE_CHASE])
        base.accept("f3", self.change_mode, [CAM_MODE_FREE])

        base.accept("w", self.set_move_vec_y, [self.speed])
        base.accept("w-up", self.set_move_vec_y, [0])
        base.accept("s", self.set_move_vec_y, [-self.speed])
        base.accept("s-up", self.set_move_vec_y, [0])
        base.accept("a", self.set_move_vec_x, [-self.speed])
        base.accept("a-up", self.set_move_vec_x, [0])
        base.accept("d", self.set_move_vec_x, [self.speed])
        base.accept("d-up", self.set_move_vec_x, [0])
        base.accept("r", self.set_move_vec_z, [self.speed])
        base.accept("r-up", self.set_move_vec_z, [0])
        base.accept("f", self.set_move_vec_z, [-self.speed])
        base.accept("f-up", self.set_move_vec_z, [0])

        base.accept("arrow_up", self.set_rot_vec_p, [self.speed / 10])
        base.accept("arrow_up-up", self.set_rot_vec_p, [0])
        base.accept("arrow_down", self.set_rot_vec_p, [-self.speed / 10])
        base.accept("arrow_down-up", self.set_rot_vec_p, [0])
        base.accept("arrow_left", self.set_rot_vec_h, [self.speed / 10])
        base.accept("arrow_left-up", self.set_rot_vec_h, [0])
        base.accept("arrow_right", self.set_rot_vec_h, [-self.speed / 10])
        base.accept("arrow_right-up", self.set_rot_vec_h, [0])

        #Setup collision detection
        cnode = CollisionNode("camera")
        cnode.add_solid(CollisionSphere(0, 0, 0, 10))
        self.collider = base.camera.attach_new_node(cnode)
        base.cTrav.add_collider(self.collider, base.portal_handler)

        #Start camera manager task
        base.task_mgr.add(self.run_logic)
        Logger.info("Camera manager initialized.")
Exemple #7
0
    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)
Exemple #8
0
    def pieCollisions(self):
        pss = CollisionSphere(0, 0, 0, 1)
        psnode = CollisionNode('projectilePieSensor' + str(id(self)))
        psnode.add_solid(pss)
        self.psnp = self.pie.attach_new_node(psnode)
        self.psnp.set_collide_mask(BitMask32(0))
        self.psnp.node().set_from_collide_mask(CIGlobals.WallBitmask
                                               | CIGlobals.FloorBitmask)

        event = CollisionHandlerEvent()
        event.set_in_pattern("%fn-into")
        event.set_out_pattern("%fn-out")
        base.cTrav.add_collider(self.psnp, event)
Exemple #9
0
 def __initCollisions(self, name):
     self.notify.debug('Initializing collision sphere...')
     numSlots = len(self.circles)
     ss = CollisionSphere(0, 0, 0, self.numPlayers2SphereRadius[numSlots])
     ss.setTangible(0)
     snode = CollisionNode(name)
     snode.add_solid(ss)
     snode.set_collide_mask(CIGlobals.WallBitmask)
     self.snp = self.attach_new_node(snode)
     self.snp.setZ(3)
     self.snp.setY(self.numPlayers2SphereY[numSlots])
     self.snp.setSx(self.numPlayers2SphereSx[numSlots])
     self.snp.setSy(self.numPlayers2SphereSy[numSlots])
     self.acceptOnce('enter' + self.snp.node().getName(), self.__handleEnterCollisionSphere)
 def __initCollisions(self, name):
     self.notify.debug('Initializing collision sphere...')
     numSlots = len(self.circles)
     ss = CollisionSphere(0, 0, 0, self.numPlayers2SphereRadius[numSlots])
     ss.setTangible(0)
     snode = CollisionNode(name)
     snode.add_solid(ss)
     snode.set_collide_mask(CIGlobals.WallBitmask)
     self.snp = self.attach_new_node(snode)
     self.snp.setZ(3)
     self.snp.setY(self.numPlayers2SphereY[numSlots])
     self.snp.setSx(self.numPlayers2SphereSx[numSlots])
     self.snp.setSy(self.numPlayers2SphereSy[numSlots])
     self.acceptOnce('enter' + self.snp.node().getName(), self.__handleEnterCollisionSphere)
Exemple #11
0
 def setup_shadow_ray(self, shadow_node, mat):
     ray = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
     ray_node = CollisionNode('ray_node')
     ray_node.add_solid(ray)
     self.ray_np = shadow_node.attach_new_node(ray_node)
     self.ray_np.node().set_from_collide_mask(CIGlobals.FloorBitmask)
     self.ray_np.node().set_into_collide_mask(BitMask32.allOff())
     floor_offset = 0.025
     lifter = CollisionHandlerFloor()
     lifter.set_offset(floor_offset)
     lifter.set_reach(4.0)
     lifter.add_collider(self.ray_np, shadow_node)
     if not mat:
         base.cTrav.add_collider(self.ray_np, lifter)
Exemple #12
0
 def ray(self, name, bitmask, point_a=(0, 0, 1), point_b=(0, 0, 0)):
     shape = CollisionSegment(point_a, point_b)
     col = CollisionNode(self.node.getName() + "-ray-" + name)
     col.add_solid(shape)
     col.set_from_collide_mask(bitmask)
     col.set_into_collide_mask(CollideMask.all_off())
     col_node = self.node.attach_new_node(col)
     handler = CollisionHandlerQueue()
     self.traverser.add_collider(col_node, handler)
     return {
         "collider": col,
         "shape": shape,
         "handler": handler,
         "node": col_node
     }
Exemple #13
0
 def sphere(self, name, bitmask, pos=(0, 0, 1), radius=0.2):
     col = CollisionNode(self.node.getName() + "-sphere-" + name)
     shape = CollisionSphere(pos, radius)
     col.add_solid(shape)
     col.set_from_collide_mask(bitmask)
     col.set_into_collide_mask(CollideMask.allOff())
     col_node = self.node.attachNewNode(col)
     handler = CollisionHandlerPusher()
     handler.add_collider(col_node, self.node)
     self.traverser.add_collider(col_node, handler)
     return {
         "collider": col,
         "shape": shape,
         "handler": handler,
         "node": col_node
     }
Exemple #14
0
    def add_border_walls(self):
        '''Attaching invisible walls to map's borders, to avoid falling off map'''
        log.debug("Adding invisible walls to collide with on map's borders")
        wall_coordinates = [
            ((self.map_size[0], 0, 0), (self.map_size[1], 0, 0)),
            ((-self.map_size[0], 0, 0), (-self.map_size[1], 0, 0)),
            ((0, self.map_size[2], 0), (0, self.map_size[3], 0)),
            ((0, -self.map_size[2], 0), (0, -self.map_size[3], 0))
        ]

        for sizes in wall_coordinates:
            wall_node = CollisionNode("wall")
            #it looks like without adding node to pusher (we dont need that there),
            #masks wont work. Thus for now I wont use them, as defaults seem to work
            #wall_node.set_collide_mask(BitMask32(shared.WALLS_COLLISION_MASK))
            wall_node.add_solid(CollisionPlane(Plane(*sizes)))
            wall = render.attach_new_node(wall_node)
Exemple #15
0
 def __init__(self,
              app,
              render,
              camera,
              mouseWatcher,
              pickKeyOn,
              pickKeyOff,
              collideMask,
              pickableTag="pickable"):
     self.render = render
     self.mouseWatcher = mouseWatcher.node()
     self.camera = camera
     self.camLens = camera.node().get_lens()
     self.collideMask = collideMask
     self.pickableTag = pickableTag
     self.taskMgr = app.task_mgr
     # setup event callback for picking body
     self.pickKeyOn = pickKeyOn
     self.pickKeyOff = pickKeyOff
     app.accept(self.pickKeyOn, self._pickBody, [self.pickKeyOn])
     app.accept(self.pickKeyOff, self._pickBody, [self.pickKeyOff])
     # collision data
     self.collideMask = collideMask
     self.cTrav = CollisionTraverser()
     self.collisionHandler = CollisionHandlerQueue()
     self.pickerRay = CollisionRay()
     pickerNode = CollisionNode("Utilities.pickerNode")
     node = NodePath("PhysicsNode")
     node.reparentTo(render)
     anp = node.attachNewNode(pickerNode)
     base.physicsMgr.attachPhysicalNode(pickerNode)
     pickerNode.add_solid(self.pickerRay)
     pickerNode.set_from_collide_mask(self.collideMask)
     pickerNode.set_into_collide_mask(BitMask32.all_off())
     #pickerNode.node().getPhysicsObject().setMass(10)
     self.cTrav.add_collider(self.render.attach_new_node(pickerNode),
                             self.collisionHandler)
     # service data
     self.pickedBody = None
     self.oldPickingDist = 0.0
     self.deltaDist = 0.0
     self.dragging = False
     self.updateTask = None
Exemple #16
0
def make_collision(solid_from, solid_into):
    node_from = CollisionNode("from")
    node_from.add_solid(solid_from)
    node_into = CollisionNode("into")
    node_into.add_solid(solid_into)

    root = NodePath("root")
    trav = CollisionTraverser()
    queue = CollisionHandlerQueue()

    np_from = root.attach_new_node(node_from)
    np_into = root.attach_new_node(node_into)

    trav.add_collider(np_from, queue)
    trav.traverse(root)

    entry = None
    for e in queue.get_entries():
        if e.get_into() == solid_into:
            entry = e

    return (entry, np_from, np_into)
Exemple #17
0
 def __init__(self, map, node):
     self.map = map
     self.node = node
     self.init_heading = self.node.get_h()
     pos = node.get_pos(render)
     node.set_pos(pos)
     if self.node.get_z() < 2:
         self.node.reparent_to(self.map.doors_node_f1)
     else:
         self.node.reparent_to(self.map.doors_node_f2)
     self.node.set_collide_mask(base.mapmask)
     self.open = False
     self.speed = 5
     self.make_key()
     self.timer = 0
     col = CollisionNode(node.name)
     col.add_solid(CollisionSphere((0, 0, 0), 1.5))
     col.set_collide_mask(base.itemmask)
     col_node = self.map.collisions.attach_new_node(col)
     col_node.set_pos(node.get_pos(render))
     col_node.set_y(node, 2)
     self.opening = False
Exemple #18
0
    def add_borders(self):
        """Attach invisible walls to map's borders, to avoid falling off map"""
        log.debug("Adding invisible walls to collide with on map's borders")
        wall_coordinates = [
            ((self.map_size[0], 0, 0), (self.map_size[1], 0, 0)),
            ((-self.map_size[0], 0, 0), (-self.map_size[1], 0, 0)),
            ((0, self.map_size[2], 0), (0, self.map_size[3], 0)),
            ((0, -self.map_size[2], 0), (0, -self.map_size[3], 0)),
        ]

        for sizes in wall_coordinates:
            wall_node = CollisionNode(shared.game_data.border_category)
            # it looks like without adding node to pusher (we dont need that there),
            # masks wont work. Thus for now I wont use them, as defaults seem to work
            # wall_node.set_collide_mask(BitMask32(shared.WALLS_COLLISION_MASK))
            wall_node.add_solid(CollisionPlane(Plane(*sizes)))
            wall = self.scene.attach_new_node(wall_node)

            # adding tag with wall's coordinations, so it will be possible to
            # push entities back if these collide with wall
            # because calling .get_pos() will return LPoint3f(0,0,0)
            wall_node.set_python_tag("position", sizes)
Exemple #19
0
def make_collision(solid_from, solid_into):
    node_from = CollisionNode("from")
    node_from.add_solid(solid_from)
    node_into = CollisionNode("into")
    node_into.add_solid(solid_into)

    root = NodePath("root")
    trav = CollisionTraverser()
    queue = CollisionHandlerQueue()

    np_from = root.attach_new_node(node_from)
    np_into = root.attach_new_node(node_into)

    trav.add_collider(np_from, queue)
    trav.traverse(root)

    entry = None
    for e in queue.get_entries():
        if e.get_into() == solid_into:
            entry = e

    return (entry, np_from, np_into)
Exemple #20
0
    def __init__(self, world):
        self.world = world
        self.root = self.world.root.attach_new_node("player")
        self.root_target = self.world.root.attach_new_node("player_target")
        self.pivot = self.root.attach_new_node("player_pivot")
        base.camera.reparent_to(self.pivot)
        base.camera.set_z(1.7)
        base.cam.node().get_lens().set_fov(90)
        self.traverser = CollisionTraverser()
        self.ray = setup_ray(
            self.pivot,
            self.traverser,
            self.world.mask,
            # ray ends well below feet to register downward slopes
            (0, 0, 1),
            (0, 0, -1))
        self.xyh_inertia = Vec3(0, 0, 0)
        h_acc = ConfigVariableDouble('mouse-accelleration', 0.1).get_value()
        self.xyh_acceleration = Vec3(0.8, 0.8, h_acc)
        self.friction = 0.15
        self.torque = 0.5
        self.last_up = Vec3(0, 0, 1)

        # Collider for portals
        csphere = CollisionSphere(0, 0, 1.25, 1.5)
        cnode = CollisionNode('player')
        cnode.add_solid(csphere)
        cnode.set_from_collide_mask(0x2)
        cnode.set_into_collide_mask(CollideMask.all_off())
        self.collider = self.root.attach_new_node(cnode)
        self.event_handler = CollisionHandlerEvent()
        self.event_handler.add_in_pattern('into-%in')
        self.traverser.add_collider(self.collider, self.event_handler)
        self.collider.show()
        self.teleported = False

        base.input.set_mouse_relativity(True)
class MapPicker():
    __name: Final[str]
    __base: Final[ShowBase]
    __data: Final[NDArray[(Any, Any, Any), np.uint8]]

    # collision data
    __ctrav: Final[CollisionTraverser]
    __cqueue: Final[CollisionHandlerQueue]
    __cn: Final[CollisionNode]
    __cnp: Final[NodePath]

    # picker data
    __pn: Final[CollisionNode]
    __pnp: Final[NodePath]
    __pray: Final[CollisionRay]

    # constants
    COLLIDE_MASK: Final[BitMask32] = BitMask32.bit(1)

    def __init__(self, services: Services, base: ShowBase, map_data: MapData, name: Optional[str] = None):
        self.__services = services
        self.__services.ev_manager.register_listener(self)
        self.__base = base
        self.__name = name if name is not None else (map_data.name + "_picker")
        self.__map = map_data
        self.__data = map_data.data

        # collision traverser & queue
        self.__ctrav = CollisionTraverser(self.name + '_ctrav')
        self.__cqueue = CollisionHandlerQueue()

        # collision boxes
        self.__cn = CollisionNode(self.name + '_cn')
        self.__cn.set_collide_mask(MapPicker.COLLIDE_MASK)
        self.__cnp = self.__map.root.attach_new_node(self.__cn)
        self.__ctrav.add_collider(self.__cnp, self.__cqueue)
        self.__points = []

        z_offset = 1 if self.__map.dim == 3 else self.__map.depth
        for idx in np.ndindex(self.__data.shape):
            if bool(self.__data[idx] & MapData.TRAVERSABLE_MASK):
                p = Point(*idx)
                self.__points.append(p)
                idx = self.__cn.add_solid(CollisionBox(idx, Point3(p.x+1, p.y+1, p.z-z_offset)))
                assert idx == (len(self.__points) - 1)

        # mouse picker
        self.__pn = CollisionNode(self.name + '_pray')
        self.__pnp = self.__base.cam.attach_new_node(self.__pn)
        self.__pn.set_from_collide_mask(MapPicker.COLLIDE_MASK)

        self.__pray = CollisionRay()
        self.__pn.add_solid(self.__pray)
        self.__ctrav.add_collider(self.__pnp, self.__cqueue)

        # debug -> shows collision ray / impact point
        # self.__ctrav.show_collisions(self.__map.root)

    @property
    def name(self) -> str:
        return self.__name

    @property
    def pos(self):
        # check if we have access to the mouse
        if not self.__base.mouseWatcherNode.hasMouse():
            return None

        # get the mouse position
        mpos = self.__base.mouseWatcherNode.get_mouse()

        # set the position of the ray based on the mouse position
        self.__pray.set_from_lens(self.__base.camNode, mpos.getX(), mpos.getY())

        # find collisions
        self.__ctrav.traverse(self.__map.root)

        # if we have hit something sort the hits so that the closest is first
        if self.__cqueue.get_num_entries() == 0:
            return None
        self.__cqueue.sort_entries()

        # compute & return logical cube position
        x, y, z = self.__cqueue.get_entry(0).getSurfacePoint(self.__map.root)
        x, y, z = [max(math.floor(x), 0), max(math.floor(y), 0), max(math.ceil(z), 0)]
        if x == len(self.__data):
            x -= 1
        if y == len(self.__data[x]):
            y -= 1
        if z == len(self.__data[x][y]):
            z -= 1

        return Point(x, y, z)

    def notify(self, event: Event) -> None:
        if isinstance(event, MapUpdateEvent):
            z_offset = 1 if self.__map.dim == 3 else self.__map.depth
            for p in event.updated_cells:
                if p.n_dim == 2:
                    p = Point(*p, 0)

                if bool(self.__data[p.values] & MapData.TRAVERSABLE_MASK):
                    self.__points.append(p)
                    idx = self.__cn.add_solid(CollisionBox(p.values, Point3(p.x+1, p.y+1, p.z-z_offset)))
                    assert idx == (len(self.__points) - 1)
                else:
                    try:
                        i = self.__points.index(p)
                    except ValueError:
                        continue
                    self.__cn.remove_solid(i)
                    self.__points.pop(i)

    def destroy(self) -> None:
        self.__cqueue.clearEntries()
        self.__ctrav.clear_colliders()
        self.__cnp.remove_node()
        self.__pnp.remove_node()
Exemple #22
0
    def __init__(
        self,
        name: str,
        category: str,
        collision_settings: CollisionSettings,
        scale: int = None,
        animated_parts: list = None,
        static_parts: list = None,
    ):
        self.name = name
        log.debug(f"Initializing {self.name} object")

        self.category = category

        # creating empty node to attach everything to. This way it will be easier
        # to attach other objects (like floating text and such), coz offset trickery
        # from animation wont affect other items attached to node (since its not
        # a parent anymore, but just another child)
        entity_node = PandaNode(name)
        # for now, self.node will be empty nodepath - we will reparent it to render
        # on spawn, to dont overflood it with reference entity instances
        self.node = NodePath(entity_node)

        # separate visuals node, to which parts from below will be attached
        vn = PandaNode(f"{name}_visuals")
        self.visuals = self.node.attach_new_node(vn)

        # this allows for rotating node around its h without making it invisible
        self.visuals.set_two_sided(True)

        # storage for entity parts (visuals) that will be attached to entity node.
        # static parts is used for stuff that is SpritesheetObject and doesnt have
        # switcher in it. Animated_parts reffers to thing that need to be changed
        # in case some related even occurs
        self.static_parts = static_parts or []
        self.animated_parts = animated_parts or []

        # setting character's collisions
        entity_collider = CollisionNode(self.category)

        # if no collision mask has been received - using defaults
        if collision_settings.mask is not None:
            mask = BitMask32(collision_settings.mask)
            entity_collider.set_from_collide_mask(mask)
            entity_collider.set_into_collide_mask(mask)

        entity_collider.add_solid(
            collision_settings.shape(*collision_settings.size))
        self.collision = self.node.attach_new_node(entity_collider)
        if collision_settings.position:
            self.collision.set_pos(*collision_settings.position)

        self.direction = None

        # initializing visual parts added with self.add_part()
        if self.static_parts or self.animated_parts:
            for sp in self.static_parts:
                sp.instance.wrt_reparent_to(self.visuals)
                if sp.position:
                    sp.instance.set_pos(sp.position)
                if sp.scale:
                    sp.instance.set_scale(sp.scale)

            for ap in self.animated_parts:
                ap.instance.node.wrt_reparent_to(self.visuals)
                if ap.position:
                    ap.instance.node.set_pos(ap.position)
                if ap.scale:
                    ap.instance.node.set_scale(ap.scale)

        # this will rescale whole node with all parts attached to it
        # in case some part as already been rescaled above - it will be rescaled
        # again, which may cause issues
        if scale:
            self.node.set_scale(scale)

        self.change_direction("right")

        # death status, that may be usefull during cleanup
        self.dead = False

        # attaching python tags to node, so these will be accessible during
        # collision events and similar stuff
        self.node.set_python_tag("name", self.name)
        self.node.set_python_tag("category", self.category)

        # I thought to put ctrav there, but for whatever reason it glitched proj
        # to fly into left wall. So I moved it to Creature subclass

        # debug function to show collisions all time
        if shared.settings.show_collisions:
            self.collision.show()
Exemple #23
0
    def __init__(self,
                 name,
                 spritesheet=None,
                 sprite_size=None,
                 hitbox_size=None,
                 collision_mask=None,
                 position=None,
                 animations_speed=None):
        log.debug(f"Initializing {name} object")

        if not animations_speed:
            animations_speed = DEFAULT_ANIMATIONS_SPEED
        self.animations_timer = animations_speed
        self.animations_speed = animations_speed

        if not sprite_size:
            sprite_size = DEFAULT_SPRITE_SIZE

        if not spritesheet:
            #I cant link assets above, coz their default value is None
            texture = base.assets.sprite[name]
        else:
            texture = base.assets.sprite[spritesheet]

        size_x, size_y = sprite_size
        log.debug(f"{name}'s size has been set to {size_x}x{size_y}")

        #the magic that allows textures to be mirrored. With that thing being
        #there, its possible to use values in range 1-2 to get versions of sprites
        #that will face the opposite direction, removing the requirement to draw
        #them with hands. Without thing thing being there, 0 and 1 will be threated
        #as same coordinates, coz "out of box" texture wrap mode is "repeat"
        texture.set_wrap_u(Texture.WM_mirror)
        texture.set_wrap_v(Texture.WM_mirror)
        sprite_data = spritesheet_cutter.cut_spritesheet(texture, sprite_size)

        horizontal_scale, vertical_scale = sprite_data['offset_steps']
        offsets = sprite_data['offsets']

        entity_frame = CardMaker(name)
        #setting frame's size. Say, for 32x32 sprite all of these need to be 16
        entity_frame.set_frame(-(size_x / 2), (size_x / 2), -(size_y / 2),
                               (size_y / 2))

        entity_object = render.attach_new_node(entity_frame.generate())
        entity_object.set_texture(texture)

        #okay, this does the magic
        #basically, to show the very first sprite of 2 in row, we set tex scale
        #to half (coz half is our normal char's size). If we will need to use it
        #with sprites other than first - then we also should adjust offset accordingly
        #entity_object.set_tex_offset(TextureStage.getDefault(), 0.5, 0)
        #entity_object.set_tex_scale(TextureStage.getDefault(), 0.5, 1)
        entity_object.set_tex_scale(TextureStage.getDefault(),
                                    horizontal_scale, vertical_scale)

        #now, to use the stuff from cut_spritesheet function.
        #lets say, we need to use second sprite from sheet. Just do:
        #entity_object.set_tex_offset(TextureStage.getDefault(), *offsets[1])
        #but, by default, offset should be always set to 0. In case our object
        #has just one sprite. Or something like that
        default_sprite = 0
        entity_object.set_tex_offset(TextureStage.getDefault(),
                                     *offsets[default_sprite])

        #enable support for alpha channel. This is a float, e.g making it non-100%
        #will require values between 0 and 1
        entity_object.set_transparency(1)

        #if no position has been received - wont set it up
        if position:
            entity_object.set_pos(*position)

        #setting character's collisions
        entity_collider = CollisionNode(name)

        #if no collision mask has been received - using defaults
        if collision_mask:
            entity_collider.set_from_collide_mask(BitMask32(collision_mask))
            entity_collider.set_into_collide_mask(BitMask32(collision_mask))

        #TODO: move this to be under character's legs
        #right now its centered on character's center
        if hitbox_size:
            self.hitbox_size = hitbox_size
        else:
            #coz its sphere and not oval - it doesnt matter if we use x or y
            #but, for sake of convenience - we are going for size_y
            self.hitbox_size = (size_y / 2)

        entity_collider.add_solid(CollisionSphere(0, 0, 0, self.hitbox_size))
        entity_collision = entity_object.attach_new_node(entity_collider)

        #this will explode if its not, but I dont have a default right now
        if name in ANIMS:
            entity_anims = ANIMS[name]

        self.name = name
        self.object = entity_object
        self.collision = entity_collision
        self.sprites = offsets
        #setting this to None may cause crashes on few rare cases, but going
        #for "idle_right" wont work for projectiles... So I technically add it
        #there for anims updater, but its meant to be overwritten at 100% cases
        self.current_animation = None
        #this will always be 0, so regardless of consistency I will live it be
        self.current_frame = default_sprite
        self.animations = entity_anims
        #death status, that may be usefull during cleanup
        self.dead = False

        #attaching python tags to object node, so these will be accessible during
        #collision events and similar stuff
        self.object.set_python_tag("name", self.name)

        #I thought to put ctrav there, but for whatever reason it glitched projectile
        #to fly into left wall. So I moved it to Creature subclass

        #debug function to show collisions all time
        #self.collision.show()

        #do_method_later wont work there, coz its indeed based on frames
        base.task_mgr.add(self.update_anims, "update entity's animations")
Exemple #24
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