コード例 #1
0
ファイル: manager.py プロジェクト: lopalo/tricky_ninja
class Manager(object):

    def __init__(self, map_name):
        self.main_node = render.attachNewNode('main_node')
        self.blocked_squares = set()
        self.bodies = {}
        self.map = Map(map_name)
        self.map_builder = MapBuilder(self.map, self.main_node)
        self.map_builder.build()
        self.map_builder.clear_map_textures()
        self.player = Player(self, self.map.start_pos)
        self.set_npcs()
        self.setup_graphics()

        if S.show_view_field:
            self.view_fields = defaultdict(set)
            taskMgr.doMethodLater(1, self.update_view_fields, 'fields')
        if S.show_pathes:
            self.pathes = defaultdict(set)
            taskMgr.doMethodLater(1, self.update_pathes, 'pathes')

    def set_npcs(self):
        self.npcs = {}
        for data in self.map.npcs:
            for _ in range(data['count']):
                _data = data.copy()
                route = deque(self.map.routes[data['route']])
                free = [i for i in route if i not in self.npcs]
                assert free, 'all postions are occupated'
                pos = choice(free)
                while pos != route[0]:
                    route.rotate(1)
                _data['route'] = route
                NPC(self, **_data)#.dead = True # for debugging
        data = self.map.target_npc.copy()
        if not data:
            return
        route = deque(self.map.routes[data['route']])
        data['route'] = route
        TargetNPC(self, **data)

    def is_available(self, pos):
        return (pos in self.map and
                (pos != self.player.pos or self.player.walking) and
                (pos not in self.npcs or self.npcs[pos].walking) and
                pos not in self.bodies)

    def __call__(self, task):
        self.player.update_action()
        for npc in tuple(self.npcs.values()):
            if not npc and npc.action is None:
                if isinstance(npc, TargetNPC):
                    self.finish(True)
                del self.npcs[npc.pos]
                Body(npc, self)
                continue
            npc.update_action()
            if isinstance(npc, TargetNPC) and npc.pos == self.map.escape_position:
                self.finish(False)
        return task.cont

    def finish(self, win):
        base.finish_game(win)

    def on_player_moved(self, prev_pos, pos):
        map = self.map
        if prev_pos is None:
            prev_group = None
        elif map[prev_pos]['kind'] != 'model_field':
            prev_group = map[prev_pos]['ident']
        else:
            prev_group = map[prev_pos]['group']
        if map[pos]['kind'] != 'model_field':
            group = map[pos]['ident']
        else:
            group = map[pos]['group']
        if prev_group == group:
            return
        if prev_group is not None:
            for pos in map.groups[prev_group]:
                model = self.map_builder.get_model(pos)
                if model is None:
                    continue
                model.setAlphaScale(1)
        for pos in map.groups[group]:
            model = self.map_builder.get_model(pos)
            if model is None:
                continue
            model.setAlphaScale(S.graphics['transparency'])

    def alert(self, pos, target=None):
        for npc in self.npcs.values():
            if not npc:
                continue
            length = hypot(npc.pos[0] - pos[0], npc.pos[1] - pos[1])
            if length <= S.npc['alert_radius']:
                if isinstance(npc, TargetNPC):
                    npc.target = self.map.escape_position
                    npc.speed = S.target_npc['escape_speed']
                else:
                    npc.set_alert_texture()
                    #FIXME: don't set target if path to it doesn't exist
                    npc.target = target or self.player
                    npc.speed = S.npc['excited_speed']
                    npc.view_radius = S.npc['excited_view_radius']
                    npc.view_angle = S.npc['excited_view_angle']

    def setup_graphics(self):
        angle = self.map.hour * 15 - 90
        light_factor = max(sin(radians(angle)), 0)
        mnode = self.main_node
        alight = AmbientLight('alight')
        color = S.graphics['ambient_light_color'] + [light_factor]
        alight.setColor(VBase4(*color))
        alnp = mnode.attachNewNode(alight)
        mnode.setLight(alnp)

        dlight = DirectionalLight('dlight')
        color = S.graphics['light_color'] + [light_factor]
        dlight.setColor(VBase4(*color))
        dlnp = mnode.attachNewNode(dlight)
        dlnp.setHpr(0, -angle, 0)
        mnode.setLight(dlnp)

        if S.graphics['enable_shadows']:
            self.main_node.setShaderAuto() # doesn't work in multithreading mode
            lens = OrthographicLens()
            lens.setFilmSize(30, 30)
            lens.setNearFar(-1000, 1000)
            dlight.setLens(lens)
            ss = S.graphics['shadow_size']
            dlight.setShadowCaster(True, ss, ss)
            dlnp.reparentTo(self.player.node)
        if S.graphics['enable_cartoon']:
            # set for models separately
            self.main_node.setShaderAuto() # doesn't work in multithreading mode

    def update_view_fields(self, task):
        """ It is a very expensive funciton. Use only for debugging """
        for npc in self.npcs.values():
            key = id(npc)
            for marker in self.view_fields[key]:
                marker.removeNode()
            del self.view_fields[key]
            radius, c_angle = npc.view_radius, npc.view_angle
            angle = int(npc.actor.getHpr()[0] - 90) % 360
            pred = lambda pos: 'see' in self.map[pos]['actions']
            field = self.map.view_field(npc.pos, angle,
                                        c_angle, radius, pred)
            for pos in field:
                marker = loader.loadModel(S.model('plane'))
                marker.setHpr(0, -90, 0)
                marker.reparentTo(self.main_node)
                marker.setPos(pos[0], pos[1], 0.1)
                self.view_fields[key].add(marker)
        return task.again

    def update_pathes(self, task):
        """ It is a very expensive funciton. Use only for debugging """

        map = self.map
        for npc in self.npcs.values():
            key = id(npc)
            for marker in self.pathes[key]:
                marker.removeNode()
            del self.pathes[key]
            target = npc.target
            end_pos = target if isinstance(target, tuple) else target.pos
            pred = lambda pos: ('walk' in map[pos]['actions'] and
                                map.is_available(pos) and
                                (pos not in self.npcs or
                                self.npcs[pos].walking) and
                                pos not in self.bodies)
            path = map.get_path(npc.pos, end_pos, pred)
            if path is None:
                continue

            for pos in path:
                marker = loader.loadModel(S.model('plane'))
                marker.setHpr(0, -90, 0)
                marker.reparentTo(self.main_node)
                marker.setPos(pos[0], pos[1], 0.1)
                self.pathes[key].add(marker)
        return task.again