class ShipCollision:
    def __init__(self, ship):

        self.ship = ship

        self.setup_collision()
        self.queue = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('Collision Traverser')
        self.traverser.showCollisions(render)
        self.traverser.add_collider(self.target_nodepath, self.queue)
        base.taskMgr.add(self.collide, "Collision Task")

    def setup_collision(self):

        self.target = CollisionSphere(0, 0, 0, 0.5)
        self.target_node = CollisionNode('collision_ship')
        self.target_node.setFromCollideMask(ENEMIES)
        self.target_node.setIntoCollideMask(ALLIES)
        self.target_nodepath = self.ship.model.attach_new_node(self.target_node)
        self.target_nodepath.node().addSolid(self.target)
        #self.target_nodepath.show()

    def collide(self, task):

        self.traverser.traverse(render)

        for entry in self.queue.get_entries():
            #print("Ship:")
            #print(entry)
            self.ship.model.cleanup()
            self.ship.model.removeNode()

        return task.cont
class RayThatCollidesWithScene:
    def __init__(self):
        self.hitters = [self.setup_collision_ray(offset, bitmask)
                        for offset, bitmask in [
                            (-3, BM_LEFT),
                            (3, BM_RIGHT),
                       ]]
        self.queue = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('Collision Traverser')
        self.traverser.showCollisions(base.render)
        for ray in self.hitters:
            self.traverser.add_collider(ray, self.queue)
        base.taskMgr.add(self.collide, "Collision Task")

    def setup_collision_ray(self, offset, bitmask):
        # Hitter. Do note that not every combination of object works,
        # there is a table for that in the manual.
        hitter = CollisionRay(0, 0, 0, 0, 1, 0)
        hitter_node = CollisionNode('collision_hitter')
        hitter_node.setFromCollideMask(bitmask)
        hitter_nodepath = base.render.attach_new_node(hitter_node)
        hitter_nodepath.node().addSolid(hitter)
        hitter_nodepath.set_pos(offset, -2, 0)
        hitter_nodepath.show()
        return hitter_nodepath

    def collide(self, task):
        self.traverser.traverse(render)
        for entry in self.queue.get_entries():
            print(entry)
        return task.cont
class EntityCollision:
    def __init__(self, entity):

        self.entity = entity

        self.setup_collision()
        self.queue = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('Collision Traverser')
        self.traverser.showCollisions(render)
        self.traverser.add_collider(self.target_nodepath, self.queue)
        base.taskMgr.add(self.collide, "Collision Task")

    def setup_collision(self):
        self.target = CollisionSphere(0, 0, 0, 1)
        self.target_node = CollisionNode('collision_entity')
        self.target_node.setFromCollideMask(ALLIES)  # unused
        self.target_node.setIntoCollideMask(ENEMIES)
        self.target_nodepath = self.entity.model.attach_new_node(self.target_node)
        self.target_nodepath.node().addSolid(self.target)
        self.target_nodepath.show()

    def collide(self, task):

        self.traverser.traverse(render)

        for entry in self.queue.get_entries():
            # print("Entity:")
            pos = entry.getSurfacePoint(self.entity.model)
            pos_x = pos[0]
            pos_z = pos[2]
            self.entity.spawn_particles(pos_x, pos_z)
            self.entity.life -= 1

        return task.cont
Beispiel #4
0
class ShipCollision:
    def __init__(self, game):
        self.game = game
        self.setup_collision()
        self.queue = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('Collision Traverser')
        self.traverser.showCollisions(render)
        self.traverser.add_collider(self.target_nodepath, self.queue)
        base.taskMgr.add(self.collide, "Collision Task")

    def setup_collision(self):
        self.target = CollisionSphere(0, 0, 0, 0.5)
        self.target_node = CollisionNode('collision_ship')
        self.target_node.setFromCollideMask(ENEMIES)
        self.target_node.setIntoCollideMask(ALLIES)
        self.target_nodepath = self.game.ship.model.attach_new_node(
            self.target_node)
        self.target_nodepath.node().addSolid(self.target)
        self.target_nodepath.show()

    def collide(self, task):
        self.traverser.traverse(render)
        for entry in self.queue.get_entries():
            print("Ship:")
            print(entry)
        return task.cont
Beispiel #5
0
def test_collision_traverser_pickle():
    from direct.stdpy.pickle import dumps, loads

    handler = CollisionHandlerQueue()

    collider1 = NodePath(CollisionNode("collider1"))
    collider2 = NodePath(CollisionNode("collider2"))

    trav = CollisionTraverser("test123")
    trav.respect_prev_transform = True
    trav.add_collider(collider1, handler)
    trav.add_collider(collider2, handler)

    trav = loads(dumps(trav, -1))
    assert trav.respect_prev_transform is True

    assert trav.name == "test123"
    assert trav.get_num_colliders() == 2
    collider1 = trav.get_collider(0)
    collider2 = trav.get_collider(1)
    assert collider1.name == "collider1"
    assert collider2.name == "collider2"

    # Two colliders must still be the same object; this only works with our own
    # version of the pickle module, in direct.stdpy.pickle.
    assert trav.get_handler(collider1) == trav.get_handler(collider2)
Beispiel #6
0
class RayThatCollidesWithScene:
    def __init__(self):
        self.hitters = [
            self.setup_collision_ray(offset, bitmask) for offset, bitmask in [
                (-3, BM_LEFT),
                (3, BM_RIGHT),
            ]
        ]
        self.queue = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('Collision Traverser')
        self.traverser.showCollisions(base.render)
        for ray in self.hitters:
            self.traverser.add_collider(ray, self.queue)
        base.taskMgr.add(self.collide, "Collision Task")

    def setup_collision_ray(self, offset, bitmask):
        # Hitter. Do note that not every combination of object works,
        # there is a table for that in the manual.
        hitter = CollisionRay(0, 0, 0, 0, 1, 0)
        hitter_node = CollisionNode('collision_hitter')
        hitter_node.setFromCollideMask(bitmask)
        hitter_nodepath = base.render.attach_new_node(hitter_node)
        hitter_nodepath.node().addSolid(hitter)
        hitter_nodepath.set_pos(offset, -2, 0)
        hitter_nodepath.show()
        return hitter_nodepath

    def collide(self, task):
        self.traverser.traverse(render)
        for entry in self.queue.get_entries():
            print(entry)
        return task.cont
Beispiel #7
0
class BulletCollision:
    def __init__(self, bullet):

        self.bullet = bullet

        self.setup_collision()
        self.queue = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('Collision Traverser')
        self.traverser.showCollisions(render)
        self.traverser.add_collider(self.target_nodepath, self.queue)
        base.taskMgr.add(self.collide, "Collision Task")

    def setup_collision(self):

        self.target = CollisionSphere(0, 0, 0, 0.1)
        self.target_node = CollisionNode('collision_bullet')
        self.target_node.setFromCollideMask(ENEMIES)
        self.target_node.setIntoCollideMask(ALLIES)

        self.target_nodepath = self.bullet.model.attach_new_node(
            self.target_node)
        self.target_nodepath.node().addSolid(self.target)
        self.target_nodepath.show()

    def collide(self, task):

        self.traverser.traverse(render)

        for entry in self.queue.get_entries():

            #print("Bullet:")
            #print(entry)
            self.bullet.model.removeNode()

        return task.cont
Beispiel #8
0
class EntityCollision:
    def __init__(self, entity):

        self.entity = entity

        self.setup_collision()
        self.queue = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('Collision Traverser')
        self.traverser.showCollisions(render)
        self.traverser.add_collider(self.target_nodepath, self.queue)
        base.taskMgr.add(self.collide, "Collision Task")

    def setup_collision(self):
        self.target = CollisionSphere(0, 0, 0, 1)
        self.target_node = CollisionNode('collision_entity')
        self.target_node.setFromCollideMask(ALLIES)  # unused
        self.target_node.setIntoCollideMask(ENEMIES)
        self.target_nodepath = self.entity.model.attach_new_node(
            self.target_node)
        self.target_nodepath.node().addSolid(self.target)
        self.target_nodepath.show()

    def collide(self, task):

        self.traverser.traverse(render)

        for entry in self.queue.get_entries():
            # print("Entity:")
            pos = entry.getSurfacePoint(self.entity.model)
            pos_x = pos[0]
            pos_z = pos[2]
            self.entity.spawn_particles(pos_x, pos_z)
            self.entity.life -= 1

        return task.cont
Beispiel #9
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)
Beispiel #10
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)
Beispiel #11
0
class Cursor(DirectObject):
    """Cursor object for the UI."""

    parent: NodePath
    mouse_np: NodePath
    actor: Actor
    last_position: Point
    moved: bool
    pointed_at: Optional[NodePath]

    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()

    @property
    def position(self) -> Point:
        """Get the cursor position."""
        return self._position

    @position.setter
    def position(self, value: Union[Point, Iterable]):
        if not isinstance(value, Point):
            value = Point(*islice(value, 2))
        self.actor.set_x(value.x)
        self.actor.set_y(value.y)
        self._position = value

    @property
    def tool(self) -> Optional[Tool]:
        """Get current tool."""
        return self._tool

    @tool.setter
    def tool(self, value: Tool):
        if self._tool is not None:
            self._tool.cleanup()
        self.ignore_all()
        self._register_events()
        self._tool = value
        if value is not None:
            for key in INPUT.keys_for('tool_1'):
                self.accept(key, self._tool.on_button1_press)
                self.accept(f'{key}-up', self._tool.on_button1_release)
            for key in INPUT.keys_for('tool_2'):
                self.accept(key, self._tool.on_button2_press)
                self.accept(f'{key}-up', self._tool.on_button2_release)
            for key in INPUT.keys_for('tool_3'):
                self.accept(key, self._tool.on_button3_press)
                self.accept(f'{key}-up', self._tool.on_button3_release)
            self.accept('cursor_move', self._tool.on_cursor_move)

    def update(self):
        """Update callback."""
        self.actor.set_scale(p3d.camera.get_z()**0.6 / 10)
        self.moved = False

        if p3d.mouse_watcher.has_mouse():
            mouse_x, mouse_y = p3d.mouse_watcher.get_mouse()
            self._picker_ray.set_from_lens(p3d.cam_node, mouse_x, mouse_y)
            self._traverser.traverse(p3d.render)

            if self._collision_handler.get_num_entries():
                self._collision_handler.sort_entries()
                node_path = (
                    self._collision_handler.get_entry(0).get_into_node_path())
                self.position = node_path.get_pos(p3d.render)
                self.actor.set_z(2.0)
                self.pointed_at = node_path
            else:
                self.pointed_at = None
                film = p3d.lens.get_film_size() * 0.5
                self.mouse_np.set_x(mouse_x * film.x)
                self.mouse_np.set_y(p3d.lens.get_focal_length())
                self.mouse_np.set_z(mouse_y * film.y)
                self.last_position = self._position
                mouse_pos = self.mouse_np.get_pos(self.parent)
                cam_pos = p3d.camera.get_pos(self.parent)
                mouse_vec = mouse_pos - cam_pos
                if mouse_vec.z < 0.0:
                    scale = -mouse_pos.z / mouse_vec.z
                    self.actor.set_pos(mouse_pos + mouse_vec * scale)
                    self.position = self.actor.get_pos()
                    if self._position != self.last_position:
                        self.moved = True
                        p3d.messenger.send('cursor_move')

        if self._tool is not None:
            self._tool.on_update()

    def _on_simulation_step(self, dt: Duration):
        if self._tool is not None:
            self._tool.on_simulation_step(dt)

    def _register_events(self):
        def set_tool(tool: Type[Tool]):
            self.tool = tool(self)
            log.info('[%s] Changing tool to %s', __name__, tool.__name__)

        for tool in TOOLS:
            try:
                self.accept(tool.KEY, partial(set_tool, tool))
            except AttributeError:
                log.warning('[%s] No KEY set for tool %s', __name__,
                            tool.__name__)
        self.accept('simulation_step', self._on_simulation_step)
Beispiel #12
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
Beispiel #13
0
class Player():
    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)

    def handle_input(self):
        dt = globalClock.get_dt()
        directional_keys = (["strafe_right",
                             "strafe_left"], ["forward", "backward"])
        for k, keys in enumerate(directional_keys):
            if base.input.buttons[keys[0]]:
                self.xyh_inertia[k] += self.xyh_acceleration[k] * dt
            elif base.input.buttons[keys[1]]:
                self.xyh_inertia[k] -= self.xyh_acceleration[k] * dt
            self.xyh_inertia[k] /= 1 + self.friction

        if base.mouseWatcherNode.hasMouse():
            h = base.input.mouse_movement.x * self.xyh_acceleration[2] * dt
            self.pivot.set_h(self.pivot, h)
            p = base.input.mouse_movement.y * self.xyh_acceleration[2] * dt
            base.cam.set_p(base.cam, p)
            base.cam.set_p(max(-70, min(base.cam.get_p(), 70)))
            #base.cam.set_r(0)

    def ray_to_destination(self, xonly=0):
        if xonly:
            self.ray["node"].set_x(self.pivot, self.xyh_inertia[1] * xonly)
            self.ray["node"].set_y(self.pivot, 0)
        else:
            self.ray["node"].set_x(self.pivot, self.xyh_inertia[0])
            self.ray["node"].set_y(self.pivot, self.xyh_inertia[1])

    def move_to_ray(self):
        self.ray["handler"].sort_entries()
        #closest_entry = list(self.ray["handler"].entries)[0]
        closest_entry = None
        delta = float('inf')
        dot = -1.0
        for c in list(self.ray["handler"].entries):
            if closest_entry is None:
                closest_entry = c
                delta = c.get_surface_point(self.root).length()
                dot = self.last_up.dot(c.get_surface_normal(render))
                continue
            if c.get_surface_point(self.root).length() < delta:
                if self.last_up.dot(c.get_surface_normal(render)) > dot:
                    closest_entry = c
                    dot = self.last_up.dot(c.get_surface_normal(render))
                    delta = c.get_surface_point(self.root).length()

        collision_point = closest_entry.get_surface_point(render)
        collision_normal = closest_entry.get_surface_normal(render)
        self.last_up = collision_normal
        # take heed of the ray ending well below feet
        #collision_point.set_z(max(0,collision_point.z))
        self.root.set_pos(render, collision_point)
        self.root_target.set_pos(render, collision_point)
        self.root_target.heads_up(render, collision_point, collision_normal)

    def update(self):
        if self.teleported:
            self.xyh_inertia = Vec3(0, self.xyh_acceleration[1], 0)
            self.teleported = False
        dt = globalClock.get_dt()
        self.handle_input()
        if self.xyh_inertia.length() > 0:
            self.ray_to_destination()
            self.traverser.traverse(render)
            if self.ray["handler"].get_num_entries() > 0:
                self.move_to_ray()
            else:
                self.ray_to_destination(-1)
                self.traverser.traverse(render)
                if self.ray["handler"].get_num_entries() > 0:
                    self.move_to_ray()
                else:
                    self.ray_to_destination(1)
                    self.traverser.traverse(render)
                    if self.ray["handler"].get_num_entries() > 0:
                        self.move_to_ray()
            self.ray["node"].set_y(self.pivot, 0)
        current_quat = self.root.get_quat()
        target_quat = self.root_target.get_quat()
        current_quat.normalize()
        target_quat.normalize()
        if current_quat.is_same_direction(target_quat):
            self.root.set_quat(target_quat)
            return
        self.root.set_quat(current_quat + (target_quat - current_quat) *
                           (ROTATION_SPEED * dt))
Beispiel #14
0
class Labrintth(ShowBase):

    def __init__(self):

          #from panda3d bump mapping demo
        # Configure the parallax mapping settings (these are just the defaults)
        loadPrcFileData("", "parallax-mapping-samples 3\n"
                            "parallax-mapping-scale 0.1")

        # Initialize the ShowBase class from which we inherit, which will
        # create a window and set up everything we need for rendering into it.
        ShowBase.__init__(self)


        #titles from panda3d bumb mapping demo
        # Check video card capabilities.
        if not self.win.getGsg().getSupportsBasicShaders():
            addTitle("Bump Mapping: "
                "Video driver reports that Cg shaders are not supported.")
            return

        self.playerHealth = 10
        self.loseHealth = True


        brickTexture = loader.loadTexture("models/brick-c.jpg")

        self.lstWalls = makeMaze()
        self.ptGrid = makePointGrid()

        #self.camera.setPos(self.ptGrid[len(self.ptGrid)-1][0])                                           
        self.focus = LVector3(0,1000,30)
     
        for row in range(len(self.ptGrid)):
            for col in range(len(self.ptGrid[row])):
                for n in range(2):
                    
                    #wall model made by 'TheCreator', https://free3d.com/3d-model/brick-wall-51172.html
                    self.wall = loader.loadModel("models/walls")
                    self.wall.setTexture(brickTexture)
                    self.wall.setScale(25.3)
                    self.wall.setPos(self.ptGrid[row][col])
                    self.wallC = self.wall.find("**/collideWall")
                    self.wallC.node().setIntoCollideMask(BitMask32.bit(0))
                    self.wallC.show()

                    #right of cell
                    if n == 0:
                        if self.lstWalls[row][col][n] == 1: 
                            self.wall.setX(self.wall, 1.05)
                            self.wall.setZ(5)
                            self.wall.reparentTo(render)

                    #down of cell
                    else: 
                        if self.lstWalls[row][col][n] == 1:
                            self.wall.setHpr(90,0,0)
                            self.wall.setX(self.wall, -3)    
                            self.wall.setZ(5)      
                            self.wall.reparentTo(render)

                    
        self.spacing = self.ptGrid[0][1][0] - self.ptGrid[0][0][0]

        self.exit = loader.loadModel('models/walls')
        self.exit.setScale(25.3)
        self.exit.setColorScale(0.6,0.6,1,1)

        self.exitCoord, wall = generateDoor(self.ptGrid, self.lstWalls)
        self.exitPos = self.ptGrid[self.exitCoord[0]][self.exitCoord[1]]
        self.exit.setPos(self.exitPos)

        for n in range(2):
            if n == 0:
                if wall[n] == 2: 
                    self.exit.setX(self.exit, 1.15)
                    self.exit.setZ(5)

            #down of cell
            else: 
                if wall[n] == 2:
                    self.exit.setHpr(90,0,0)
                    self.exit.setX(self.exit, -3.2)
                    self.exit.setZ(5)         

        self.exit.reparentTo(render)
        self.exit.detachNode()

        numPpl = 15 #make first pos minotaur
        pplLst = []
        pplLst = generatePosLst(pplLst, numPpl, self.ptGrid, self.spacing)


        targetPos = pplLst[random.randint(1, len(pplLst)-1)]
        print('target:',targetPos)

        #ball model from panda3D ball in maze demo
        num = 0
        for pos in range(1, len(pplLst)):
            num += 1

            #if the person in the list is the minotaur's target, set it's 
            #name to self.target
            if pplLst[pos] == targetPos:
                self.target = loader.loadModel("models/alfred")
                self.target.setPos(pplLst[pos])
                self.target.setScale(5)
                self.target.reparentTo(render)

                self.targetK = self.target.attachNewNode(CollisionNode('targetDie'))
                self.targetK.node().addSolid(CollisionSphere(0, 0, 5, 6))
                self.targetK.node().setIntoCollideMask(BitMask32.bit(2))
                #self.targetK.show()

                self.targetS = self.target.attachNewNode(CollisionNode('targetSave'))
                self.targetS.node().addSolid(CollisionSphere(0, 0, 5, 6))
                self.targetS.node().setIntoCollideMask(BitMask32.bit(1))
                #self.targetS.show()

            #otherwise, keep it as a self.ppl
            else: 
                self.ppl = loader.loadModel("models/alfred")
                self.ppl.setPos(pplLst[pos])
                self.ppl.setScale(5)

                #put a tag on each person so we can tell them apart
                self.ppl.setTag('personNum', str(num))
                self.ppl.reparentTo(render)
  
                #make it so that the people can be collision detected
                self.pplC = self.ppl.attachNewNode(CollisionNode('pplCollision'))
                self.pplC.node().addSolid(CollisionSphere(0, 0, 5, 7))
                self.pplC.node().setIntoCollideMask(BitMask32.bit(1))
                self.pplC.setTag('personCNum', str(num))
                #self.pplC.show()
        
        #first index in pplLst = minotar
        minotaurPos = pplLst[0]

        #Minotaur 3d model by 'Clint Bellanger' https://opengameart.org/content/minotaur
        self.minotaur = Actor("models/TheMinotaur")
        self.minotaur.setPos(minotaurPos)
        self.minotaur.setScale(25)
        self.minotaur.reparentTo(render)


        minotaurTexture = loader.loadTexture("models/catfur.jpg")
        self.minotaur.setTexture(minotaurTexture)

        self.minC = self.minotaur.attachNewNode(CollisionNode('minCollision'))
        self.minC.node().addSolid(CollisionSphere(0 , 0, 1, 0.5))
        self.minC.node().setFromCollideMask(BitMask32.bit(2))
        #self.minC.node().setIntoCollideMask(BitMask32.bit(1))
        #self.minC.show()

        self.minBat = self.minotaur.attachNewNode(CollisionNode('battle'))
        self.minBat.node().addSolid(CollisionSphere(0, 0, 1, 4.3))
        self.minBat.node().setIntoCollideMask(BitMask32.bit(1))
        self.minBat.show()

        self.minHit = self.minotaur.attachNewNode(CollisionNode('hit'))
        self.minHit.node().addSolid(CollisionSphere(0, 0, 1.5, 0.4))
        self.minHit.node().setIntoCollideMask(BitMask32.bit(3))

        self.minAtk = self.minotaur.attachNewNode(CollisionNode('attack'))
        self.minAtk.node().addSolid(CollisionSphere(0, 0, 1.85, 0.4))
        self.minAtk.node().setIntoCollideMask(BitMask32.bit(4))
        self.minAtk.show()

        self.cTrav = CollisionTraverser()
        self.cHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.minC, self.cHandler)
        self.cTrav.addCollider(self.minAtk, self.cHandler)

        self.minotaurObj = Minotaur(self.minotaur.getPos())

        #find the path the minotaur takes to kill the person
        self.killPath = self.minotaurObj.findPerson(minotaurPos, targetPos, self.ptGrid, self.lstWalls, self.spacing)
        self.minSpeed = 1
        self.sleepDelay = 13
        self.killFlag = True
        self.killDone = False
        self.killPause = False
        self.killPaused = False

        self.hit = False
        self.hurtTime = 0
        self.minDied = False
        self.minTimeDied = 0
        self.attackTrig = False
        self.warningTrig = True

        taskMgr.add(self.minotaurKilling, "minotaurKilling")
        taskMgr.add(self.minotaurDie, 'minotaurDied')
        taskMgr.add(self.pauseKill, 'pauseKill')

        self.saved = 0
        self.addSaved = False
        self.saveTrig = False

        taskMgr.add(self.displaySaved, "saved")
        
        #collisions
        #create a ball for collisions 
        self.camBall = loader.loadModel("models/ball")
        self.camBall.setPos(self.spacing/2, self.spacing/2, -1)
        self.camBall.setScale(10)
        #self.camBall.setColorScale(0, 1, 0.7, 1)
        self.camBall.reparentTo(render)

        self.playerPos = (0,0,0)
        
        self.camBallC = self.camBall.find("**/ball")
        #self.camBallC = self.camBall.attachNewNode(CollisionNode('camCollision'))
        #self.camBallC.node().addSolid(CollisionSphere(0, 0, 0, 1.2))
        self.camBallC.node().setFromCollideMask(BitMask32.bit(0))

        self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(self.camBallC, self.camBall)

        self.cTrav.addCollider(self.camBallC, self.pusher)
        self.camBallC.setPos(0,0.0002,0)

        self.camC = self.camera.attachNewNode(CollisionNode('cameraCollision'))
        self.camC.node().addSolid(CollisionSphere(0, 0, 0, 0.01))
        self.camC.node().setFromCollideMask(BitMask32.bit(1))
        self.camC.node().setIntoCollideMask(BitMask32.bit(4))
        self.camC.show()

        self.cTrav.addCollider(self.camC, self.cHandler)

        taskMgr.add(self.disappear, "disappear")

        #sting-sword model created by  KangaroOz 3D, from: https://www.turbosquid.com/FullPreview/Index.cfm/ID/1125944
        self.sword = loader.loadModel('models/sting-sword')
        self.sword.wrtReparentTo(self.camBall)
        self.sword.detachNode()
        
        self.sword.setY(1)
        self.sword.setX(0.5)
        self.sword.setZ(0.2)
        self.sword.setScale(0.07)


        self.swordC = self.sword.attachNewNode(CollisionNode('stab'))
        self.swordC.node().addSolid(CollisionSphere(0, 25, 0, 2))
        self.swordC.node().setFromCollideMask(BitMask32.bit(3))
        #self.swordC.show()

        self.attacked = False
        self.stabbing = False

        self.cTrav.add_collider(self.swordC, self.cHandler)


        swordTexture = loader.loadTexture("models/Sting_Emissive.png")
        self.sword.setTexture(swordTexture)

        self.stabDelay = 0

        self.redBarL = loader.loadModel('models/walls')
        self.redBarL.setScale(3)
        self.redBarL.setColorScale(250,0,0,1)
        self.redBarL.setPos(38.5, 60,5)
        self.redBarL.wrtReparentTo(self.camBall)
        self.redBarL.detachNode()

        self.redBarR = loader.loadModel('models/walls')
        self.redBarR.setScale(3)
        self.redBarR.setColorScale(250,0,0,1)
        self.redBarR.setPos(55.7,60,5)
        self.redBarR.wrtReparentTo(self.camBall)
        self.redBarR.detachNode()
        
        self.hurtTimeP = 0

        #make list of controls 
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "backward": 0, "cam-left": 0,\
             "cam-right": 0, "stab":0, "map": 0, "instrMode":0, "gameMode":0}

        # Make the mouse invisible, turn off normal mouse controls
        self.disableMouse()
        props = WindowProperties()
        props.setCursorHidden(True)
       

        # Set the current viewing target
        self.heading = 0
        self.pitch = 0
        self.last = 0

        self.startMode = True
        self.startTrig = True
        self.startDestroy = True
        self.instrMode = False
        self.instrTrig = True
        self.instrShown = False
        self.instrDestroy = True
        self.gameMode = False

        self.bkGround = loader.loadModel('models/walls')
        self.bkGround.reparentTo(self.camBall)
        self.bkGround.setColorScale(0,0.5,0.55,1)
        self.bkGround.setPos(-1,3,0)

        taskMgr.add(self.showStart, "start-screen")


        taskMgr.add(self.controlCamera, "camera-task")
        self.accept("escape", sys.exit, [0])

        self.accept("o", self.setKey, ["instrMode", True])
        self.accept("p", self.setKey, ["gameMode", True])

        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["backward", True])
        self.accept("w", self.setKey, ["stab", True])
        self.accept("s", self.setKey, ["down", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["backward", False])
        self.accept("w-up", self.setKey, ["stab", False])
        self.accept("s-up", self.setKey, ["down", False])


        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("d", self.setKey, ["cam-right", True])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("d-up", self.setKey, ["cam-right", False])

        self.accept("space", self.setKey, ["map", True])
        self.accept("space-up", self.setKey, ["map", False])


        
    def setKey(self, key, value):
        self.keyMap[key] = value

    def startKill(self): 
        try:
            self.target.setColorScale(250,0,0,1)
        except: 
            pass
        intervalL = self.intervalLst()

        self.kill = Sequence(intervalL[0], name = 'kill person')
        for i in range(1, len(intervalL)):
            self.kill.append(intervalL[i])
        self.kill.start()

    def pauseKill(self, task):
        print(self.killPaused, self.killPause)
        if self.gameMode == True:

            if self.killDone == True:
                self.kill.finish()
               
            if self.killPaused == False and self.killPause == True:
                print('hmmmmmmmmmmmm')
                self.kill.pause()
                self.killPaused = True

            if self.killPaused == True and self.killPause == False:
                self.kill.resume()
                self.killPaused = False

        return Task.cont

    def intervalLst(self):
        intervals = []
        for i in range(len(self.killPath)):
            intervals += [self.minotaur.posInterval(self.minSpeed, Point3(self.killPath[i]))]
        return intervals

    def stab(self, task):
        timer = globalClock.getFrameTime()
        
        speed = 0.2
        stabIn = LerpPosInterval(self.sword, speed, Point3(0,4,0.2))
        stabOut = LerpPosInterval(self.sword, speed, Point3(0.5,1,0.2))
        stab = Sequence(stabIn, stabOut, name = 'stab')
        stab.start()

        self.stabbing = True 

        if self.hit == True: 
            self.minotaurObj.hit()

            self.hurtTime = globalClock.getFrameTime()
            self.hurtShow(task)
            
            self.hit = False
            self.stabbing = False


    def hurtShow(self,  task):
        if self.hit == True:
            timer = globalClock.getFrameTime()
            if timer - self.hurtTime < 2:
                self.minotaur.setColorScale(180,0,0,1)
        return Task.cont

    def attack(self, task):
        if self.attackTrig == True:
            speed = 1
            turnSpeed = 0.5
            attackPos, distance, direction = self.minotaurObj.attack(self.camera.getPos(), self.minotaur.getPos(), \
                self.ptGrid, self.spacing, self.lstWalls)
            origPt = self.minotaur.getPos()
            if attackPos != None:
                attack = LerpPosInterval(self.minotaur, speed, Point3(attackPos))
                turnToPlayer = LerpHprInterval(self.minotaur, turnSpeed, self.minotaurObj.facePlayer(direction))
                if distance == 'short':
                    retract = LerpPosInterval(self.minotaur, speed, origPt)
                    attackSeq = Sequence(turnToPlayer, attack, retract, name = 'attack')
                    attackSeq.start()
                else: 
                    attackSeq = Sequence(turnToPlayer, attack, name = 'attack')
                    attackSeq.start()

            self.attackTrig = False

            
    def attackShow(self, task):
        if self.attacked == True:
            timer = globalClock.getFrameTime()
            if timer - self.hurtTimeP < 2:
                self.redBarL.reparentTo(self.camBall)
                self.redBarR.reparentTo(self.camBall)
            if self.loseHealth == True:
                self.playerHealth -= 10
                print(self.playerHealth)
                self.loseHealth = False

        return Task.cont


    def displaySaved(self, task):
        if self.gameMode == True:
            if self.saved == 0 and self.saveTrig == False:
                msg = 'Saved: ' + str(self.saved)
                self.displSaved = OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=.05,
                                shadow=(0, 0, 0, 1),parent=base.a2dTopLeft, align=TextNode.ALeft,
                                 pos=(0.05, -1.9))
                self.saveTrig = True
            
            if self.addSaved == True and self.saveTrig == True and self.saved > 0:
                print('here')
                self.displSaved.destroy()
                msg = 'Saved: ' + str(self.saved)
                self.displSaved = OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=.05,
                                shadow=(0, 0, 0, 1),parent=base.a2dTopLeft, align=TextNode.ALeft,
                                 pos=(0.05, -1.9))
                self.addSaved = False

        return Task.cont
        
    def minotaurKilling(self, task):
        if self.gameMode == True:
            #timer for minotaur sleeping
            timer = globalClock.getFrameTime()
            timeLeft = self.sleepDelay - int(timer)

            #put up the instructions before the minotaur wakes up
            if timeLeft >= 0:

                if self.warningTrig == True:
                    if timeLeft == 1:
                        msg = "You have 1 second to find the Minotaur before he wakes up!"
                    elif timeLeft == 0:
                        msg = "He's awake!"
                    else: 
                        msg = "You have " + str(timeLeft) + " seconds to find the Minotaur before he wakes up!"
                    
                    self.warning = OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                shadow=(0, 0, 0, 1),parent=base.a2dTopLeft, align=TextNode.ALeft,
                                 pos=(0.05, -0.08))
                    self.displayWarning = timer
                    self.warningTrig = False

                if timer - self.displayWarning > 0.92: 
                    self.warning.destroy()
                    self.warningTrig = True

            if timeLeft < 0:
                self.warning.destroy()

            #wake the minotaur up after time ends
            if timeLeft < 0 and self.killFlag == True:
                self.startKill()
                self.killFlag = False

            #make sure minotaur is always the right color
            if timer - self.hurtTime > 2:
                self.minotaur.setColorScaleOff()

            if timer - self.hurtTimeP > 2:
                self.redBarL.detachNode()
                self.redBarR.detachNode()

            if self.minDied == True:
                if timer - self.minTimeDied > 20:
                    self.minotaur.detachNode()
                    self.exit.reparentTo(render)
                    self.showRopes()

            if timer - self.hurtTimeP > 2:
                    self.loseHealth = True

        return Task.cont

    def minotaurDie(self, task):

        if self.minotaurObj.health <= 0 and self.minDied == False:
            dieSpeed = 3
            die = LerpHprInterval(self.minotaur, dieSpeed, (self.camera.getX(), 90, 5))
            die.start()
            self.minDied = True
            self.minTimeDied = globalClock.getDt()

        return Task.cont

    def showropes(self):
        ropeHeight = 30
        lastRope = findExitPos(self.exitPos, self.ptGrid, self.spacing)

        playerPos = findPlayerPos(self.camera.getPos(), self.spacing)
        playerPos = (playerPos[0], playerPos[1], ropeHeight)

        ropePath, ropeDir = findExit(playerPos, lastRope, self.ptGrid, self.lstWalls, self.spacing)
        lastDir = findDir(self.exitCoord, self.ptGrid)

        if ropeDir != None:
            ropeDir += [lastDir]

        #gold texture found at https://www.google.com/url?sa=i&source=images&cd=&cad=r\
        #ja&uact=8&ved=2ahUKEwjw76Lbv4rfAhVpvFkKHY3JDPYQjRx6BAgBEAU&url=http%3A%2F\
        #%2Fmetal.graphics%2Fgraphic%2Fbrushed%2Fgold-texture%2F&psig=AOvVaw1q3Yu\
        #xuuGvetU4fhA1cIqh&ust=1544161415078294
        
        goldTexture = loader.loadTexture("models/gold.jpg")
        if ropePath != None:

            #rope model by Robert J. Smith, https://www.cgtrader.com/free-3d-models/industrial/tool/knot-rope
            for pos in range(len(ropePath)):
                rope = loader.loadModel("models/rope1")
                rope.setPos(ropePath[pos])
                rope.setScale(3.6)
                rope.setZ(-5)

                if pos < len(ropeDir):
                    if ropeDir[pos] == 'e':
                        rope.setHpr(76,0,0)
                        rope.setX(rope.getX() + 75)
                        rope.setY(rope.getY() + 5)
                    if ropeDir[pos] == 'n':
                        rope.setHpr(166,0,0)
                        rope.setY(rope.getY() + 65)
                    if ropeDir[pos] == 'w':
                        rope.setHpr(256,0,0)
                        rope.setX(rope.getX() - 60)
                        rope.setY(rope.getY() - 9)
                    if ropeDir[pos] == 's':
                        rope.setHpr(-14,0,0)
                        rope.setY(rope.getY() - 70)
                        rope.setX(rope.getX() + 15)
                rope.setTexture(goldTexture)
                rope.reparentTo(render)

    def lostGame(self):
        lose = loader.loadModel('models/walls')
        lose.reparentTo(self.camBall)
        lose.setColorScale(0.1,0.1,0.1,1)
        lose.setPos(-1,3,0)

    def showStart(self, task):
        startMsg = "Welcome to Daedalus's Creation." 
        startMsg2 = "You have to kill the minotaur, navegate the labyrinth, and save the others."+"You have 30 seconds to find the Minotaur before he wakes up and starts killing your people."
        startMsg3 = "Good luck doing what no man has done before."
        startMsg4 = "Press 'o' for instructions on how to play."

        if self.startMode == True and self.startTrig == True:
            self.start = OnscreenText(text=startMsg, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                shadow=(0, 0, 0, 1),parent=base.aspect2d, pos = (0,0.5), align=TextNode.ACenter, wordwrap= 15)
            self.start2 = OnscreenText(text=startMsg2, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                shadow=(0, 0, 0, 1),parent=base.aspect2d, align=TextNode.ACenter, pos = (0,0.2), wordwrap= 20)

            self.start3 = OnscreenText(text=startMsg3, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                shadow=(0, 0, 0, 1),parent=base.aspect2d, align=TextNode.ACenter, pos = (0,-0.2), wordwrap= 25)
            self.start4 = OnscreenText(text=startMsg4, style=1, fg=(1, 1, 1, 1), scale=0.1,
                                shadow=(0, 0, 0, 1),parent=base.aspect2d, align=TextNode.ACenter, pos = (0,-0.5), wordwrap= 25)
            self.startTrig = False

        if self.startMode == False and self.startDestroy == True: 
            self.start.destroy()
            self.start2.destroy()
            self.start3.destroy()
            self.start4.destroy()
            self.startDestroy = False

            task.remove()

        return Task.cont

    def showInstr(self):

        instrMsg = "Press the right and left arrow keys to move right and left."
        instrMsg1 = "Press the up and down arrow keys to move forwards and backwards."
        instrMsg2 = "Press the 'a' key to turn the camera left."
        instrMsg3 = "Press the 'd' key to turn the camera right."
        instrMsg4 = "Press the space key for a map of the labyrinth"
        instrMsg5 = "Press the 'w' key to attack." 
        instrMsg6 = "Press the 'p' key to start the game."

        if self.instrMode == True and self.instrTrig == True:

            self.instr = OnscreenText(text=instrMsg, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                    shadow=(0, 0, 0, 1),parent=base.aspect2d, pos = (0,0.7), align=TextNode.ACenter, wordwrap= 30)
            self.instr1 = OnscreenText(text=instrMsg1, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                    shadow=(0, 0, 0, 1),parent=base.aspect2d, pos = (0,0.5), align=TextNode.ACenter, wordwrap= 20)
            self.instr2 = OnscreenText(text=instrMsg2, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                    shadow=(0, 0, 0, 1),parent=base.aspect2d, align=TextNode.ACenter, pos = (0,0.2), wordwrap= 20)
            self.instr3 = OnscreenText(text=instrMsg3, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                    shadow=(0, 0, 0, 1),parent=base.aspect2d, align=TextNode.ACenter, pos = (0,0), wordwrap= 25)
            self.instr4 = OnscreenText(text=instrMsg4, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                    shadow=(0, 0, 0, 1),parent=base.aspect2d, align=TextNode.ACenter, pos = (0,-0.2), wordwrap= 25)
            self.instr5 = OnscreenText(text=instrMsg5, style=1, fg=(1, 1, 1, 1), scale=0.08,
                                    shadow=(0, 0, 0, 1),parent=base.aspect2d, align=TextNode.ACenter, pos = (0,-0.4), wordwrap= 25)
            self.instr6 = OnscreenText(text=instrMsg6, style=1, fg=(1, 1, 1, 1), scale=0.1,
                                    shadow=(0, 0, 0, 1),parent=base.aspect2d, align=TextNode.ACenter, pos = (0,-0.6), wordwrap= 25)
            self.instrTrig = False
            self.instrShown = True

    def endInstr(self):

        if self.instrMode == False and self.instrDestroy == True and self.instrShown == True: 
            self.instr.destroy()
            self.instr1.destroy()
            self.instr2.destroy()
            self.instr3.destroy()
            self.instr4.destroy()
            self.instr5.destroy()
            self.instr6.destroy()
            self.instrDestroy = False

    #make the person disappear when it's touched
    def disappear(self,task):

        for i in range(self.cHandler.getNumEntries()):

            entry = self.cHandler.getEntry(i)
            fromNode = entry.getFromNodePath()
            intoNode = entry.getIntoNodePath()
            intoName = entry.getIntoNode().getName()
            fromName = entry.getFromNode().getName()

            #if the collision was with a person
            if (intoName == 'pplCollision' and fromName == 'cameraCollision'):
                num = intoNode.getTag("personCNum")
                tag = '**/=personNum=' + num
                #finds the person player collided into and removes them
                person = render.find(tag)
                person.removeNode()

                #add one to saved counter
                self.saved += 1
                self.addSaved = True
                self.displSaved.destroy()
                return Task.cont


            if intoName == 'targetSave' and fromName == 'cameraCollision':
                print('saved!')
                self.target.removeNode()
                self.saved += 1
                self.addSaved = True
                return Task.cont
            
            if intoName == 'targetDie' and fromName == 'minCollision':
                print('ahhhhhhhhh!')
                self.target.removeNode()
                self.killDone = True
                return Task.cont

            #if minotaur gets stabbed by player
            if intoName == 'hit' and fromName == 'stab':

                if self.stabbing == True:
                    self.hit = True
                return Task.cont

            if intoName == 'cameraCollision' and fromName == 'attack':
                print('attacked!!!!!')
                self.attacked = True
                self.hurtTimeP = globalClock.getFrameTime()
                self.attackShow(task)

                if self.playerHealth < 0:
                    self.lostGame()
                return Task.cont

            if (intoName == 'battle' and fromName == 'cameraCollision' and self.killFlag == False) \
                or (intoName == 'minCollision' and fromName == 'cameraCollision' and self.killFlag == False):
                print('pause')
                self.killPause = True 
                return Task.cont

            else: 
                print('hereeeee')
                self.killPause = False

            print('killPause', self.killPause)
        return Task.cont

    #structure from panda3d bump mapping demo
    def controlCamera(self, task):

        dt = globalClock.getDt()
       
        self.camera.setHpr(self.heading, self.pitch, 0)
        self.camBall.setHpr(self.heading, self.pitch, 0)
        dir = self.camera.getMat().getRow3(1)

        camPos = (self.camBall.getPos()[0], self.camBall.getPos()[1], 6)
        self.camera.setPos(camPos)

        if self.keyMap["instrMode"] == True: 
            self.startMode = False
            self.instrMode = True
            self.showInstr()

        if self.keyMap["gameMode"] == True:
            self.instrMode = False
            self.gameMode = True
            self.bkGround.detachNode()
            self.endInstr()

        if self.gameMode == True:

            #move camera right and left
            if self.keyMap["left"]:
                self.camBall.setX(self.camBall, -10*dt)
            if self.keyMap["right"]:
                self.camBall.setX(self.camBall, +10*dt)
            if self.keyMap["forward"]:
                self.camBall.setY(self.camBall, +10*dt)
            if self.keyMap["backward"]:
                self.camBall.setY(self.camBall, -10*dt)
           

            #rotate camera
            if self.keyMap["cam-right"]:
                self.heading = self.heading -  100*dt
            if self.keyMap["cam-left"]:
                self.heading = self.heading +  100*dt
            self.focus = self.camera.getPos() + (dir * 5)
            self.last = task.time

            
            if self.keyMap['stab']:
                timer = globalClock.getFrameTime()
                if timer - self.stabDelay > 0.5:
                    self.stab(task)
                    self.stabDelay = timer
                    self.attack(task)
                    self.attackTrig = True
                    
            #show map 
            if self.keyMap["map"] == True:
                center = (len(self.ptGrid))/2*self.spacing
                self.camera.setPos(center,center, 1.8*len(self.ptGrid)*self.spacing)
                self.camera.lookAt(center, center, 0)
                self.sword.detachNode()
                if self.killFlag == False and self.killPause == True:
                    self.kill.pause()

                self.camBall.reparentTo(render)
                self.camBall.setScale(20)
                self.camBall.setColorScale(0, 0.5, 1, 1)

            if self.keyMap["map"] == False and self.startMode == False and self.instrMode == False:
                self.sword.reparentTo(self.camBall)
                self.camBall.setColorScaleOff()
                self.camBall.setScale(10)

        
        return Task.cont
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)
	#self.setupCD()

        # Set the background color to black
       # self.win.setClearColor((0.6, 0.6, 1.0, 1.0))
#	self.fog = Fog('myFog')
#	self.fog.setColor(0, 0, 0)
#	self.fog.setExpDensity(.05)
#	render.setFog(self.fog)	
       # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0, "c":0, "back":0, "space":0}

        # Post the instructions
        #self.title = addTitle(
         #   "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.06, "[ESC]: Quit")
        self.inst2 = addInstructions(0.12, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.18, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.24, "[Up Arrow]: Run Ralph Forward")
        #self.inst6 = addInstructions(0.30, "[A]: Rotate Camera Left")
        #self.inst7 = addInstructions(0.36, "[S]: Rotate Camera Right")


        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        #self.environ.reparentTo(render)

        self.room = loader.loadModel("models/room2.egg")
        self.room.reparentTo(render)
        #self.room.setScale(.1)
        self.room.setPos(0,0,-5)
        self.room.setShaderAuto()
	#self.room.writeBamFile("myRoom1.bam")
	#self.room.setColor(1,.3,.3,1)

	self.room2 = loader.loadModel("models/abstractroom2")
        self.room2.reparentTo(render)
        self.room2.setScale(.1)
        self.room2.setPos(-12,0,0)

        # Create the main character, Ralph

        #ralphStartPos = LVecBase3F(0,0,0) #self.room.find("**/start_point").getPos()

        self.ralph = Actor("models/ralph",
                           {"run": "models/ralph-run",
                            "walk": "models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(0,0,0)
	#cs = CollisionSphere(0, 0, 0, 1)
	#cnodePath = self.ralph.attachNewNode(CollisionNode('cnode'))
	#cnodePath.node().addSolid(cs)
	#cnodePath.node().setPos(0,0,0)
	#cnodePath.show()	
	
	self.gianteye = loader.loadModel("models/gianteye")
	self.gianteye.reparentTo(render)
	self.gianteye.setScale(.1)
	self.gianteye.setPos(10,10,0)	
	
	#self.bluefinal = loader.loadModel("models/chrysalis")
	#self.bluefinal.reparentTo(render)
	#self.bluefinal.setScale(.1)
	#self.bluefinal.setPos(7,7,0)	
	
	#self.blue = loader.loadModel("models/blue1")
	#self.blue.reparentTo(render)
	#self.blue.setScale(.1)
	#self.blue.setPos(10,5,0)
	
	self.chik = loader.loadModel("models/chik")
	self.chik.reparentTo(render)
	self.chik.setScale(.1)
	self.chik.setPos(3,13,0)	

        self.pawn = loader.loadModel("pawn")
        self.pawn.reparentTo(render)
        self.pawn.setPos(0,0,0)

        self.shot = loader.loadModel("models/icosphere.egg")
        self.shot.reparentTo(render)
        self.shot.setScale(.5)
        self.shot.setPos(0,0,1)
        self.shot.setColor(1,.3,.3,1)

        self.myShot = loader.loadModel("models/icosphere.egg")
        #self.myShot.reparentTo(render)
        self.myShot.setScale(.1)
        self.myShot.setPos(0,0,1)
        self.myShotVec = LVector3(0,0,0)

        self.lightpivot3 = render.attachNewNode("lightpivot3")
        self.lightpivot3.setPos(0, 0, 0)
        self.lightpivot3.hprInterval(10, LPoint3(0, 0, 0)).loop()
        plight3 = PointLight('plight2')
        plight3.setColor((0, .3,0, 1))
        plight3.setAttenuation(LVector3(0.7, 0.05, 0))
        plnp3 = self.lightpivot3.attachNewNode(plight3)
        plnp3.setPos(0, 0, 0)
        self.room2.setLight(plnp3)
        self.room.setLight(plnp3)
        sphere3 = loader.loadModel("models/icosphere")
        sphere3.reparentTo(plnp3)
        sphere3.setScale(0.1)
        sphere3.setColor((0,1,0,1))

        # Create a floater object, which floats 2 units above ralph.  We
        # use this as a target for the camera to look at.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.ralph)
        self.floater.setZ(8.0)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["back", True])
        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("s", self.setKey, ["cam-right", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["back", False])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-right", False])

        self.accept("space", self.setKey, ["space", True])
        self.accept("space-up", self.setKey, ["space", False])

        self.accept("c",self.setKey,["c",True])
        self.accept("c-up",self.setKey,["c",False])

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False
        self.jumping = False
        self.vz = 0

        # Set up the camera
        self.disableMouse()
        self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 7, 3)
        self.camLens.setFov(60)

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.

        def setupCollision(self):
	    cs = CollisionSphere(0,0,2,1)
	    cnodePath = self.ralph.attachNewNode(CollisionNode('cnode'))
	    cnodePath.node().addSolid(cs)
	    cnodePath.show()
	    #for o in self.OBS:
		#ct = CollisionTube(0,0,0, 0,0,1, 0.5)
		#cn = o.attachNewNode(CollisionNode('ocnode'))
		#cn.node().addSolid(ct)
		#cn.show()
	    eyecs = CollisionSphere(0,0,4,5)
	    cnodePath = self.gianteye.attachNewNode(CollisionNode('cnode'))
	    cnodePath.node().addSolid(eyecs)
	    cnodePath.show()	 
	    eyecs = CollisionSphere(0,0,4,2)
	    cnodePath = self.chik.attachNewNode(CollisionNode('cnode'))
	    cnodePath.node().addSolid(eyecs)
	    cnodePath.show()	    
    
	    pusher = CollisionHandlerPusher()
	    pusher.addCollider(cnodePath, self.player)
	    self.cTrav = CollisionTraverser()
	    self.cTrav.add_collider(cnodePath,pusher)
	    self.cTrav.showCollisions(render)
	self.walls = self.room2.find("**/wall_collide")
	#self.walls.node().setIntoCollideMask(BitMask32.bit(0))

        self.cTrav = CollisionTraverser()
        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 9)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()

        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)	

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 9)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.camGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()

        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        self.sphere = CollisionSphere(0,0,4,2)
        self.sphere2 = CollisionSphere(0,0,2,2)
        self.cnodePath = self.ralph.attachNewNode((CollisionNode('cnode')))
        self.cnodePath.node().addSolid(self.sphere)
        self.cnodePath.node().addSolid(self.sphere2)
        self.cnodePath.show()
        self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(self.cnodePath, self.ralph)
        self.cTrav.add_collider(self.cnodePath, self.pusher)
	
	self.eyecs = CollisionSphere(0,0,22,25)
	self.cnodePath1 = self.gianteye.attachNewNode(CollisionNode('cnode'))
	self.cnodePath1.node().addSolid(self.eyecs)
	self.cnodePath1.show()	
	self.pusher1 = CollisionHandlerPusher()
	self.pusher1.addCollider(self.cnodePath1, self.gianteye)
	self.cTrav.add_collider(self.cnodePath1, self.pusher1)	
	self.cTrav.showCollisions(render)
	
	self.eyeGroundRay = CollisionRay()
        self.eyeGroundRay.setOrigin(0, 0, 9)
        self.eyeGroundRay.setDirection(0, 0, -1)
        self.eyeGroundCol = CollisionNode('eyeRay')
        self.eyeGroundCol.addSolid(self.eyeGroundRay)
        self.eyeGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.eyeGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.eyeGroundColNp = self.gianteye.attachNewNode(self.eyeGroundCol)
        self.eyeGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.eyeGroundColNp, self.eyeGroundHandler)		

	self.chikcs = CollisionSphere(0,0,11,20)
	self.cnodePath2 = self.chik.attachNewNode(CollisionNode('cnode'))
	self.cnodePath2.node().addSolid(self.chikcs)
	self.cnodePath2.show()
	self.pusher2 = CollisionHandlerPusher()
	self.pusher2.addCollider(self.cnodePath, self.chik)
	self.cTrav.add_collider(self.cnodePath, self.pusher2)	
	self.cTrav.showCollisions(render)	
	
	self.chikGroundRay = CollisionRay()
        self.chikGroundRay.setOrigin(0, 0, 9)
        self.chikGroundRay.setDirection(0, 0, -1)
        self.chikGroundCol = CollisionNode('chikRay')
        self.chikGroundCol.addSolid(self.chikGroundRay)
        self.chikGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.chikGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.chikGroundColNp = self.chik.attachNewNode(self.chikGroundCol)
        self.chikGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.chikGroundColNp, self.chikGroundHandler)	
	

        # Uncomment this line to see the collision rays
        self.ralphGroundColNp.show()
        self.camGroundColNp.show()
	#self.ralphroom1ColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, .4))
        ambientLight2 = AmbientLight("ambientLight2")
        ambientLight2.setColor((1, 1, 1, 10))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((0, 0, -2))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        #self.environ.setLight(self.environ.attachNewNode(ambientLight2))
        render.setLight(render.attachNewNode(directionalLight))

        # Add a light to the scene.
        self.lightpivot = render.attachNewNode("lightpivot")
        self.lightpivot.setPos(0, 0, 1.6)
        self.lightpivot.hprInterval(20, LPoint3(360, 0, 0)).loop()
        plight = PointLight('plight')
        plight.setColor((.7, .3, 0, 1))
        plight.setAttenuation(LVector3(0.7, 0.05, 0))
        plnp = self.lightpivot.attachNewNode(plight)
        plnp.setPos(5, 0, 0)
        self.room.setLight(plnp)
        sphere = loader.loadModel("models/icosphere")
        sphere.reparentTo(plnp)
        sphere.setScale(0.1)
        sphere.setColor((1,1,0,1))

        self.lightpivot2 = render.attachNewNode("lightpivot")
        self.lightpivot2.setPos(-16, 0, 1.6)
        self.lightpivot2.hprInterval(20, LPoint3(360, 0, 0)).loop()
        plight2 = PointLight('plight2')
        plight2.setColor((0, .4,.8, 1))
        plight2.setAttenuation(LVector3(0.7, 0.05, 0))
        plnp2 = self.lightpivot2.attachNewNode(plight2)
        plnp2.setPos(5, 0, 0)
        self.room2.setLight(plnp2)
        sphere2 = loader.loadModel("models/icosphere")
        sphere2.reparentTo(plnp2)
        sphere2.setScale(0.2)
        sphere2.setColor((0,0,1,1))

        self.vec = LVector3(0,1,0) 
	
    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setZ(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setZ(self.camera, +20 * dt)

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if self.keyMap["left"]:
            self.ralph.setH(self.ralph.getH() + 150 * dt)
            #self.floater.setH(self.floater.getH() + 300 * dt)
            self.camera.setX(self.camera, +15.5 * dt)
        if self.keyMap["right"]:
            self.ralph.setH(self.ralph.getH() - 150 * dt)
            self.camera.setX(self.camera, -15.5 * dt)
        if self.keyMap["forward"]:
            self.ralph.setY(self.ralph, -35 * dt)
        if self.keyMap["back"]:
            self.ralph.setY(self.ralph, +35 * dt)
        if self.keyMap["c"]:
            if self.jumping is False:
            #self.ralph.setH(self.ralph.getH() + 300 * dt)
            #self.ralph.setZ(self.ralph.getZ() + 100 * dt)
                self.jumping = True
                self.vz = 7

        if self.keyMap["space"]:
            self.lightpivot3.setPos(self.ralph.getPos())
            self.lightpivot3.setZ(self.ralph.getZ() + .5)
            self.lightpivot3.setX(self.ralph.getX() - .25)
            #self.myShot.setHpr(self.ralph.getHpr())
            #parent
            node = NodePath("tmp")
            node.setHpr(self.ralph.getHpr())
            vec = render.getRelativeVector(node,(0,-1,0))
            self.myShotVec = vec

        self.lightpivot3.setPos(self.lightpivot3.getPos() + self.myShotVec * dt * 15 )

        if self.jumping is True:
            self.vz = self.vz - 16* dt
            self.ralph.setZ(self.ralph.getZ() + self.vz * dt )
            entries = list(self.ralphGroundHandler.getEntries())
            entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
            if len(entries) > 0 :
                if self.ralph.getZ() < 0:#entries[0].getSurfacePoint(render).getZ():
                    #self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
                    self.ralph.setZ(0)
                    self.jumping = False
        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["c"] or self.keyMap["forward"] or self.keyMap["back"]:
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True


        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        node = NodePath("tmp")
        node.setHpr(self.ralph.getHpr())
        vec = render.getRelativeVector(node,(1,0,0))

        #self.ralph.setPos(self.ralph.getPos() + vec * dt * 20)

        node = NodePath("tmp")
        #self.pawn.getH()
        node.setHpr(self.pawn.getHpr())
        vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
        self.shot.setPos(self.shot.getPos() + self.vec * dt * 10 )
        if self.shot.getY() < -15 or self.shot.getY() > 15 or self.shot.getX() < -15 or self.shot.getX() > 15:
            self.shot.setPos(self.pawn.getPos() + (0,0,0))
            self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
            self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - self.camera.getPos()
        #camvec.setZ(self.camera.getZ())
        camdist = camvec.length()
        x = self.camera.getZ()
        camvec.normalize()
        if camdist > 6.0:
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 6))
            camdist = 10.0
            #self.camera.setZ(self.camera, x)
        if camdist < 6.0:
            self.camera.setPos(self.camera.getPos() - camvec * (6 - camdist))
            camdist = 5.0
            #self.camera.setZ(self.camera, x)

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        #self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = list(self.ralphGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
        if self.jumping == False:
            if len(entries) > 0:# and entries[0].getIntoNode().getName() == "terrain":
                #self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
                pass
            else:
                self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        entries = list(self.camGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        #if len(entries) > 0 and entries[0].getIntoNode().getName() == "ground":
            #self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.5)
        if self.camera.getZ() < self.ralph.getZ() + 1 or self.camera.getZ() > self.ralph.getZ() + 1:
            self.camera.setZ(self.ralph.getZ() + 1)

        #self.camera.setZ(self.ralph.getZ() + 1.5)
        #self.camera.setP(self.camera, 130)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        self.camera.lookAt(self.floater)

        return task.cont
Beispiel #16
0
class Picker(object):
    '''
    A class for picking (Panda3d) objects.
    '''
    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

    def _pickBody(self, event):
        # handle body picking
        if event == self.pickKeyOn:
            # check mouse position
            if self.mouseWatcher.has_mouse():
                # Get to and from pos in camera coordinates
                pMouse = self.mouseWatcher.get_mouse()
                #
                pFrom = LPoint3f()
                pTo = LPoint3f()
                if self.camLens.extrude(pMouse, pFrom, pTo):
                    # Transform to global coordinates
                    rayFromWorld = self.render.get_relative_point(
                        self.camera, pFrom)
                    rayToWorld = self.render.get_relative_point(
                        self.camera, pTo)
                    # cast a ray to detect a body
                    # traverse downward starting at rayOrigin
                    self.pickerRay.set_direction(rayToWorld - rayFromWorld)
                    self.pickerRay.set_origin(rayFromWorld)
                    self.cTrav.traverse(self.render)
                    if self.collisionHandler.get_num_entries() > 0:
                        self.collisionHandler.sort_entries()
                        entry0 = self.collisionHandler.get_entry(0)
                        hitPos = entry0.get_surface_point(self.render)
                        # get the first parent with name
                        pickedObject = entry0.get_into_node_path()
                        while not pickedObject.has_tag(self.pickableTag):
                            pickedObject = pickedObject.getParent()
                            if not pickedObject:
                                return
                            if pickedObject == self.render:
                                return
                        #
                        self.pickedBody = pickedObject

                        self.oldPickingDist = (hitPos - rayFromWorld).length()
                        self.deltaDist = (
                            self.pickedBody.get_pos(self.render) - hitPos)
                        print(self.pickedBody.get_name(), hitPos)
                        if not self.dragging:
                            self.dragging = True
                            # create the task for updating picked body motion
                            self.updateTask = self.taskMgr.add(
                                self._movePickedBody, "_movePickedBody")
                            # set sort/priority
                            self.updateTask.set_sort(0)
                            self.updateTask.set_priority(0)
        else:

            if self.dragging:
                # remove pick body motion update task
                self.taskMgr.remove("_movePickedBody")
                self.updateTask = None
                self.dragging = False
                self.pickedBody = None

    def _movePickedBody(self, task):
        # handle picked body if any
        if self.pickedBody and self.dragging:
            # check mouse position
            if self.mouseWatcher.has_mouse():
                # Get to and from pos in camera coordinates
                pMouse = self.mouseWatcher.get_mouse()
                #
                pFrom = LPoint3f()
                pTo = LPoint3f()
                if self.camLens.extrude(pMouse, pFrom, pTo):
                    # Transform to global coordinates
                    rayFromWorld = self.render.get_relative_point(
                        self.camera, pFrom)
                    rayToWorld = self.render.get_relative_point(
                        self.camera, pTo)
                    # keep it at the same picking distance
                    direction = (rayToWorld - rayFromWorld).normalized()
                    direction *= self.oldPickingDist
                    self.pickedBody.set_pos(
                        self.render, rayFromWorld + direction + self.deltaDist)
                    #self.pickedBody.reparentTo(np)
                    #self.pickedBody.setMass(10.0)

        #
        return task.cont
Beispiel #17
0
class Character:
    def __init__(self, name, model):
        self.name = name
        self.node = NodePath(name + "_character")
        self.node.reparent_to(render)
        self.model = model
        self.model.reparent_to(self.node)
        self.traverser = CollisionTraverser()
        self.item_ray = self.ray("item", base.itemmask, point_b=(0, 1, 1))
        self.movement = Vec3(0, 0, 0)
        self.speed = 0.85
        self.keys = ""

    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
        }

    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
        }

    def fall(self):
        if self.fall_ray["handler"].get_num_entries() > 0:
            self.fall_ray["handler"].sort_entries()
            closest_entry = list(self.fall_ray["handler"].entries)[0]
            collision_position = closest_entry.get_surface_point(render)
            self.node.set_z(collision_position.get_z())
            self.movement.z = 0
        else:
            self.movement.z -= base.dt

    def open_doors(self):
        if self.item_ray["handler"].get_num_entries() > 0:
            closest_entry = list(self.item_ray["handler"].entries)[0]
            item = closest_entry.get_into_node_path()
            if item.name[0] == "d":
                door = base.map.doors[item.name]
                if not door.lock or door.lock in self.keys:
                    door.open = 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()