Beispiel #1
0
class Hobot:
    max_speed = 0.25
    acceleration = 0.5
    deceleration = 0.5

    def __init__(self, anim_root):
        self.move_root = base.render.attach_new_node('hobot')
        self.anim_root = anim_root

        self.model = Actor('hobot/hobot.bam')

        self.hand = self.model.expose_joint(None, 'modelRoot', 'hand')
        head = self.model.expose_joint(None, 'modelRoot', 'head')

        self.model.reparent_to(self.anim_root)
        self.model.set_two_sided(True)
        self.model.find("**/+GeomNode").set_transform(
            self.model.get_joint_transform_state('modelRoot',
                                                 'hobot root').get_inverse())
        self.model.set_z(0.1)
        self.facing = 1.0

        self.move_control = self.model.get_anim_control('move_forward')

        self.speed = 0.0
        self.locked = True

        self.model.wrt_reparent_to(self.move_root)
        self.model.hide()

        light_texture = loader.load_texture('hobot/light_on.png')
        light_texture.set_wrap_u(core.SamplerState.WM_clamp)
        light_texture.set_wrap_v(core.SamplerState.WM_clamp)
        cm = core.CardMaker('card')
        cm.set_frame(-0.15, 0.15, 0.15, 0.45)
        self.lightbulb = head.attach_new_node(cm.generate())
        self.lightbulb.set_texture(light_texture)
        self.lightbulb.set_attrib(
            core.ColorBlendAttrib.make(core.ColorBlendAttrib.M_add,
                                       core.ColorBlendAttrib.O_incoming_alpha,
                                       core.ColorBlendAttrib.O_one))
        self.lightbulb.set_depth_test(False)
        self.lightbulb.set_bin('fixed', 0)
        self.lightbulb.set_p(-90)
        self.lightbulb.set_billboard_point_eye()
        self.lightbulb.set_two_sided(True)
        self.lightbulb.hide()

        shadow_texture = loader.load_texture('hobot/drop_shadow.png')
        shadow_texture.set_wrap_u(core.SamplerState.WM_clamp)
        shadow_texture.set_wrap_v(core.SamplerState.WM_clamp)
        cm = core.CardMaker('card')
        cm.set_frame(-0.35, 0.35, -0.45, -0.1)
        self.shadow = self.model.attach_new_node(cm.generate())
        self.shadow.set_texture(shadow_texture)
        self.shadow.set_attrib(
            core.ColorBlendAttrib.make(
                core.ColorBlendAttrib.M_add, core.ColorBlendAttrib.O_zero,
                core.ColorBlendAttrib.O_one_minus_incoming_alpha))
        self.shadow.set_p(-90)
        self.shadow.set_depth_write(False)
        self.shadow.set_x(0.2)
        self.shadow.set_billboard_point_eye()
        self.shadow.set_two_sided(True)
        self.shadow.set_bin('transparent', 0)
        self.shadow.set_alpha_scale(0)
        self.shadow_fade = None

        self.ding_sfx = loader.load_sfx('hobot/sfx/ding.wav')
        self.ding_sfx.set_volume(0.5)
        self.move_sfx = loader.load_sfx('hobot/sfx/move.wav')
        self.move_sfx.set_loop(True)

        self.action_callback = None

    def destroy(self):
        if self.move_control.playing:
            self.move_control.stop()
            self.move_sfx.stop()

        # RIP hobot :-(
        self.model.cleanup()

    def set_action(self, callback):
        self.action_callback = callback
        if self.lightbulb.is_hidden():
            self.ding_sfx.play()
            self.lightbulb.show()

    def clear_action(self):
        self.action_callback = None
        self.lightbulb.hide()

    def do_action(self):
        if self.action_callback:
            self.action_callback()

    def lock(self):
        #self.model.wrt_reparent_to(self.anim_root)
        self.locked = True
        self.speed = 0.0

    def unlock(self):
        self.model.set_pos(self.anim_root.get_pos())
        self.locked = False
        self.model.set_hpr(0, 0, -90)
        self.model.show()

    def face(self, dir):
        if dir:
            self.facing = 1 if dir > 0 else -1
            self.model.set_sz(self.facing * -self.model.get_sx())

    def process_input(self, input, dt, level):
        if self.locked:
            return

        if input.get_action('interact'):
            self.do_action()

        move_x = input.get_axis('move-horizontal')
        move_y = input.get_axis('move-vertical')

        if move_x:
            self.speed += move_x * self.acceleration * dt
            self.face(move_x)
        elif self.speed > 0:
            self.speed = max(0, self.speed - self.deceleration * dt)
        elif self.speed < 0:
            self.speed = min(0, self.speed + self.deceleration * dt)

        delta = core.Vec2(0, 0)

        if move_y:
            delta.y = move_y * dt * MOVE_Y_SPEED

        if self.speed != 0:
            if self.speed > self.max_speed:
                self.speed = self.max_speed
            elif self.speed < -self.max_speed:
                self.speed = -self.max_speed

            delta.x = self.speed * dt
            pos_changed = True

            self.move_control.set_play_rate(self.speed * self.facing * 4.0)

            if not self.move_control.playing:
                self.move_control.loop(False)
                self.move_sfx.play()

        elif self.move_control.playing:
            self.move_control.stop()
            self.move_sfx.stop()

        if delta.length_squared() > 0:
            old_pos = self.model.get_pos()
            new_pos = level.adjust_move(old_pos.xy, delta)
            self.model.set_pos(core.LPoint3(new_pos, old_pos.z))
Beispiel #2
0
class FloorBase:  #(FSM):

    walkable_path = None
    music_path = None
    sound_names = []

    walkable_y_offset = 0.0
    free_hobot_z = None

    def __init__(self, parent):
        actor = Actor(self.model_path)
        actor.set_two_sided(True)
        actor.reparent_to(parent)
        #print(actor.get_anim_names())
        #actor.list_joints()
        self.actor = actor
        self.actor.hide()

        if self.walkable_path:
            self.walk_map = PNMImage()
            self.load_walk_map(self.walkable_path)
        else:
            self.walk_map = None

        if self.music_path:
            self.music = base.loader.load_music(self.music_path)
            self.music.set_loop(True)
            self.music.set_volume(0.5)
            self.music.play()
        else:
            self.music = None

        self.sfx = {}
        for s in self.sound_names:
            self.sfx[s] = base.loader.load_sfx(
                Filename(self.sound_path, s + ".wav"))

        # Make subparts for hobot.
        actor.make_subpart('hobot', [
            'hobot root', 'chain_a', 'chain_b', 'hand', 'wheel', 'neck',
            'head', 'tuit', 'eyes'
        ])

        # Make a copy for inspection of the animations, specifically to be able
        # to obtain the starting position of hobot in each animation.
        self.shadow_actor = Actor(self.model_path)
        self.shadow_hobot_root = self.shadow_actor.expose_joint(
            None, 'modelRoot', 'hobot root')

        # Make sure hobot is in a defined state in the actor
        actor.pose('entrance', 0)

        self.hobot_root = actor.expose_joint(None, 'modelRoot', 'hobot root')
        self.hobot_hand = actor.expose_joint(None, 'modelRoot', 'hand')
        self.hobot = Hobot(self.hobot_root)

        shadow_texture = loader.load_texture('hobot/drop_shadow.png')
        shadow_texture.set_wrap_u(core.SamplerState.WM_clamp)
        shadow_texture.set_wrap_v(core.SamplerState.WM_clamp)
        cm = core.CardMaker('card')
        cm.set_frame(-0.35, 0.35, -0.45, -0.1)
        self.shadow = self.hobot_root.attach_new_node(cm.generate())
        self.shadow.set_texture(shadow_texture)
        self.shadow.set_attrib(
            core.ColorBlendAttrib.make(
                core.ColorBlendAttrib.M_add, core.ColorBlendAttrib.O_zero,
                core.ColorBlendAttrib.O_one_minus_incoming_alpha))
        self.shadow.set_p(-90)
        self.shadow.set_depth_write(False)
        self.shadow.set_x(0.2)
        self.shadow.set_billboard_point_eye()
        self.shadow.set_two_sided(True)
        self.shadow.set_bin('transparent', 0)
        self.shadow.set_alpha_scale(0)
        self.shadow_fade = None

        self.carrying_joint = None
        self.carrying_joint_name = None

    def destroy(self):
        self.actor.cleanup()
        self.hobot.destroy()
        if self.music:
            self.music.stop()
        self.actor.remove_node()
        for sound_name in self.sound_names:
            self.sfx[sound_name].stop()

    def start(self):
        pass

    def load_walk_map(self, path):
        path = Filename.expand_from('$MAIN_DIR/assets/' + path)
        if not self.walk_map.read(path):
            print("Failed to read {}".format(path))

    def grab_joint(self, name):
        print("Grabbing {}".format(name))
        self.carrying_joint_name = name
        self.hobot.model.set_pos(self.hobot.anim_root.get_pos())
        transform = self.actor.get_joint_transform_state('modelRoot', name)

        parent = self.actor.attach_new_node('parent')
        self.carrying_joint = self.actor.control_joint(
            parent.attach_new_node('joint'), 'modelRoot', name)
        self.carrying_joint.set_transform(transform)
        self.carrying_joint_initial_transform = transform
        self.carrying_joint_initial_hobot_hand_pos = self.hobot.hand.get_pos(
            self.actor)

    def release_joint(self, name):
        print("Releasing {}".format(name))
        self.actor.release_joint('modelRoot', name)
        self.carrying_joint = None
        self.carrying_joint_name = None

    def get_anim_starting_hobot_pos(self, anim):
        # Returns Hobot's starting position for a given animation.
        self.shadow_actor.pose(anim, 0)
        self.shadow_actor.update()
        return self.shadow_hobot_root.get_pos()

    def play(self,
             anim,
             parts=None,
             loop=False,
             extra_interval=None,
             from_frame=None,
             to_frame=None,
             callback=None,
             release_joint=None,
             sound=None):
        if parts is None:
            print("Playing {} on all parts".format(anim))
        else:
            print("Playing {} on {}".format(anim, list(parts)))

        if parts is None or 'hobot' in parts:
            # Move hobot to the position first
            self.hobot.model.show()
            self.hobot.lock()
            hobot_pos = self.get_anim_starting_hobot_pos(anim)

            delta = hobot_pos.x - self.hobot.model.get_x()
            self.hobot.face(delta)
            time = abs(delta) * 4

            anims = []
            for part in parts or (None, ):
                anims.append(
                    ActorInterval(self.actor,
                                  anim,
                                  startFrame=from_frame,
                                  endFrame=to_frame,
                                  partName=part))

            if extra_interval:
                anims.append(extra_interval)

            if sound:
                anims.append(Func(sound.play))

            if callback is None:
                callback = self.switch_to_free_hobot

            seq = Sequence(
                self.hobot.model.posInterval(time,
                                             hobot_pos,
                                             blendType='easeInOut'),
                Func(self.switch_to_scene_hobot), Parallel(*anims),
                Func(callback))

            if loop:
                seq.loop()
            else:
                seq.start()
        elif loop:
            if sound:
                sound.play()
            if not parts:
                self.actor.loop(anim, fromFrame=from_frame, toFrame=to_frame)
            else:
                for part in parts:
                    self.actor.loop(anim,
                                    fromFrame=from_frame,
                                    toFrame=to_frame,
                                    partName=part)
        else:
            if sound:
                sound.play()

            if callback:
                anims = []
                for part in parts or (None, ):
                    anims.append(
                        ActorInterval(self.actor,
                                      anim,
                                      startFrame=from_frame,
                                      endFrame=to_frame,
                                      partName=part))

                Sequence(Parallel(*anims), Func(callback)).start()
            else:
                if not parts:
                    self.actor.play(anim)
                else:
                    for part in parts:
                        self.actor.play(anim,
                                        fromFrame=from_frame,
                                        toFrame=to_frame,
                                        partName=part)

    def switch_to_scene_hobot(self):
        self.hobot.lock()
        self.hobot.model.hide()
        self.hobot.lightbulb.hide()
        self.actor.release_joint('modelRoot', 'hobot root')
        if self.carrying_joint_name and self.carrying_joint:
            self.actor.release_joint('modelRoot', self.carrying_joint_name)
            self.carrying_joint = None

        if self.shadow_fade is not None:
            self.shadow_fade.pause()
        self.shadow.set_alpha_scale(self.hobot.shadow.get_color_scale()[3])
        self.shadow_fade = self.shadow.colorScaleInterval(
            5.0, (1, 1, 1, 0), blendType='easeInOut')
        self.shadow_fade.start()

    def switch_to_free_hobot(self):
        if self.hobot.model.is_empty():
            return
        self.hobot.face(self.hobot_root.get_sz() * -1)
        self.hobot.model.show()
        bone = self.actor.control_joint(None, 'modelRoot', 'hobot root')
        bone.set_pos(-100, -100, -100)
        self.hobot.unlock()

        if self.hobot.shadow_fade is not None:
            self.hobot.shadow_fade.pause()
        self.hobot.shadow.set_alpha_scale(self.shadow.get_color_scale()[3])
        self.hobot.shadow_fade = self.hobot.shadow.colorScaleInterval(
            5.0, (1, 1, 1, 1), blendType='easeInOut')
        self.hobot.shadow_fade.start()

        if self.free_hobot_z is not None:
            self.hobot.model.set_z(self.free_hobot_z)

        if self.carrying_joint_name and not self.carrying_joint:
            self.grab_joint(self.carrying_joint_name)

    def hide_scene_hobot(self):
        print("Hiding hobot")
        self.actor.control_joint(None, 'modelRoot', 'hobot root').set_z(-10000)

    def adjust_move(self, pos, delta, slide=True):
        x = (pos[0] + 16 / 9 / 2) * (9 / 16.0) * self.walk_map.size.x
        y = -(pos[1] - self.walkable_y_offset) * 2 * self.walk_map.size.y

        new_pos = pos + delta
        new_x = (new_pos[0] + 16 / 9 / 2) * (9 / 16.0) * self.walk_map.size.x
        new_y = -(new_pos[1] -
                  self.walkable_y_offset) * 2 * self.walk_map.size.y

        if new_x < 0 or round(new_x) >= self.walk_map.size.x:
            return pos
        elif new_y < 0 or round(new_y) >= self.walk_map.size.y:
            return pos

        x = int(round(x))
        y = int(round(y))
        new_x = int(round(new_x))
        new_y = int(round(new_y))

        if self.walk_map.get_gray(new_x, new_y) > 0.5:
            return new_pos

        if not slide:
            return pos

        if delta[0] != 0 and self.walk_map.get_gray(new_x, y) > 0.5:
            return (new_pos[0], pos[1])
        elif delta[1] != 0 and self.walk_map.get_gray(x, new_y) > 0.5:
            return (pos[0], new_pos[1])
        elif delta[0] != 0 and delta[1] == 0:
            # Try 45 degree angle down and up
            new_pos = self.adjust_move(pos,
                                       Vec2(delta[0] * 0.894,
                                            delta[0] * 0.447),
                                       slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[0] * 0.894,
                                                delta[0] * -0.707),
                                           slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[0] * 0.707,
                                                delta[0] * 0.707),
                                           slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[0] * 0.707,
                                                delta[0] * -0.707),
                                           slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[0] * 0.447,
                                                delta[0] * 0.894),
                                           slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[0] * 0.447,
                                                delta[0] * -0.894),
                                           slide=False)
            return new_pos
        elif delta[0] == 0 and delta[1] != 0:
            # Try 45 degree angle left and right
            new_pos = self.adjust_move(pos,
                                       Vec2(delta[1] * 0.447,
                                            delta[1] * 0.894),
                                       slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[1] * -0.447,
                                                delta[1] * 0.894),
                                           slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[1] * 0.707,
                                                delta[1] * 0.707),
                                           slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[1] * -0.707,
                                                delta[1] * 0.707),
                                           slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[1] * 0.894,
                                                delta[1] * 0.447),
                                           slide=False)
            if new_pos == pos:
                new_pos = self.adjust_move(pos,
                                           Vec2(delta[1] * -0.894,
                                                delta[1] * 0.447),
                                           slide=False)
            return new_pos
        else:
            return pos

    def process_input(self, input, dt):
        if self.hobot.locked:
            return
        self.hobot.process_input(input, dt, self)

        if self.carrying_joint:
            pos = self.hobot.hand.get_pos(
                self.actor) - self.carrying_joint_initial_hobot_hand_pos
            self.carrying_joint.set_transform(
                TransformState.make_pos(
                    (self.hobot.model.get_z(), pos[1],
                     -pos[0])).compose(self.carrying_joint_initial_transform))

        self.check_interactions()

    def check_interactions(self):
        pass
Beispiel #3
0
class MonsterActor:
    _anim_warnings = collections.defaultdict(set)
    _ANIMS = None
    _ANIM_FILE = 'models/golem_animations.bam'

    def __init__(self, form, parent_node=None, weapon=None):
        self.form = form

        mesh = self.form.mesh

        if hasattr(builtins, 'base'):
            if self._ANIMS is None:
                anim_root = base.loader.load_model(self._ANIM_FILE)
                self.__class__._ANIMS = p3d.NodePath('anims')
                for bundle in anim_root.find_all_matches('**/+AnimBundleNode'):
                    bundle.reparent_to(self._ANIMS)
            model = base.loader.load_model('models/{}.bam'.format(
                mesh['bam_file']))
            root_node = model.find('**/{}'.format(mesh['root_node']))
            if root_node.is_empty():
                print(f"Warning: root node ({mesh['root_node']}) not found in "
                      f"bam_file ({mesh['bam_file']}) for {form.id}")
            else:
                self._ANIMS.instance_to(root_node)
            self._path = Actor(root_node)
            if weapon:
                self.update_weapon(weapon)
            self.play_anim('idle', loop=True)
            if parent_node:
                self._path.reparent_to(parent_node)
        else:
            self._path = Actor()

    def update_weapon(self, weapon):
        if isinstance(weapon, str):
            gdb = gamedb.get_instance()
            weapon = gdb['weapons'][weapon]

        meshname = weapon.mesh['root_node']
        if meshname == '':
            return
        weapon_joint = self._path.expose_joint(None, 'modelRoot', 'weapon')
        modelroot = base.loader.load_model('models/{}.bam'.format(
            weapon.mesh['bam_file']))
        mesh = modelroot.find(f'**/{meshname}')
        if mesh.is_empty():
            print(f'Warning: could not find weapon {meshname}')
            modelroot.ls()
            return
        elif weapon_joint is None:
            print(f'Warning: could not find weapon joint on {self.form.name}')
            return

        # Update weapon transform
        weaponxf = self.form.weapon_offset
        pos, hpr, scale = weaponxf['position'][:], weaponxf[
            'hpr'][:], weaponxf['scale'][:]
        pos = [i * 0.1 for i in pos]
        pos[1] += 0.4
        mesh.set_pos(mesh.get_pos() + p3d.LVector3(*pos))
        mesh.set_hpr(*hpr)
        scale = [
            scale[idx] / inv
            for idx, inv in enumerate(weapon_joint.get_scale())
        ]
        mesh.set_scale(*scale)
        mesh.instance_to(weapon_joint)

    def __getattr__(self, name):
        return getattr(self._path, name)

    def __estattr__(self, name, value):
        return setattr(self._path, name, value)

    @property
    def as_nodepath(self):
        return self._path

    def _anim_warning(self, anim):
        if isinstance(anim, str):
            baseanim = anim
        else:
            baseanim = anim[-1]
        if baseanim not in self._anim_warnings[self.form.id]:
            print(f'Warning: {self.form.name} is missing an animation: {anim}')
            self._anim_warnings[self.form.id].add(baseanim)

    def play_anim(self, anim, *, loop=False):
        self._path.stop()
        mapped_anim = self.get_anim(anim)
        if mapped_anim is None:
            self._anim_warning(anim)
            return
        if loop:
            self._path.loop(mapped_anim)
        else:
            self._path.play(mapped_anim)

    def get_anim(self, anims):
        if isinstance(anims, str):
            anims = [anims]

        for anim in anims:
            if anim in self._path.get_anim_names():
                return anim
            if anim in self.form.anim_map:
                return self.form.anim_map[anim]

        return None

    def actor_interval(self, anim):
        mapped_anim = self.get_anim(anim)
        if mapped_anim is None:
            self._anim_warning(anim)
            return intervals.Sequence()
        return self._path.actor_interval(mapped_anim)
Beispiel #4
0
    def __init__(self, parent):
        actor = Actor(self.model_path)
        actor.set_two_sided(True)
        actor.reparent_to(parent)
        #print(actor.get_anim_names())
        #actor.list_joints()
        self.actor = actor
        self.actor.hide()

        if self.walkable_path:
            self.walk_map = PNMImage()
            self.load_walk_map(self.walkable_path)
        else:
            self.walk_map = None

        if self.music_path:
            self.music = base.loader.load_music(self.music_path)
            self.music.set_loop(True)
            self.music.set_volume(0.5)
            self.music.play()
        else:
            self.music = None

        self.sfx = {}
        for s in self.sound_names:
            self.sfx[s] = base.loader.load_sfx(
                Filename(self.sound_path, s + ".wav"))

        # Make subparts for hobot.
        actor.make_subpart('hobot', [
            'hobot root', 'chain_a', 'chain_b', 'hand', 'wheel', 'neck',
            'head', 'tuit', 'eyes'
        ])

        # Make a copy for inspection of the animations, specifically to be able
        # to obtain the starting position of hobot in each animation.
        self.shadow_actor = Actor(self.model_path)
        self.shadow_hobot_root = self.shadow_actor.expose_joint(
            None, 'modelRoot', 'hobot root')

        # Make sure hobot is in a defined state in the actor
        actor.pose('entrance', 0)

        self.hobot_root = actor.expose_joint(None, 'modelRoot', 'hobot root')
        self.hobot_hand = actor.expose_joint(None, 'modelRoot', 'hand')
        self.hobot = Hobot(self.hobot_root)

        shadow_texture = loader.load_texture('hobot/drop_shadow.png')
        shadow_texture.set_wrap_u(core.SamplerState.WM_clamp)
        shadow_texture.set_wrap_v(core.SamplerState.WM_clamp)
        cm = core.CardMaker('card')
        cm.set_frame(-0.35, 0.35, -0.45, -0.1)
        self.shadow = self.hobot_root.attach_new_node(cm.generate())
        self.shadow.set_texture(shadow_texture)
        self.shadow.set_attrib(
            core.ColorBlendAttrib.make(
                core.ColorBlendAttrib.M_add, core.ColorBlendAttrib.O_zero,
                core.ColorBlendAttrib.O_one_minus_incoming_alpha))
        self.shadow.set_p(-90)
        self.shadow.set_depth_write(False)
        self.shadow.set_x(0.2)
        self.shadow.set_billboard_point_eye()
        self.shadow.set_two_sided(True)
        self.shadow.set_bin('transparent', 0)
        self.shadow.set_alpha_scale(0)
        self.shadow_fade = None

        self.carrying_joint = None
        self.carrying_joint_name = None