def main():
    disk_direction = normalize_vector(np.array([,1,0]))
    disk2_direction = normalize_vector(np.array([0,1,0]))

    world_radius = 50000

    objects_list = []

    black_hole = BlackHole(mass=1.989e30, origin=np.array([world_radius - 10000, world_radius, world_radius]))
    disk = Disk(
        origin=np.array([world_radius - 10000, world_radius, world_radius]),
        normal=disk_direction,
        inner_radius=black_hole.radius * 2.6,
        outer_radius=black_hole.radius * 6
    )
    # black_hole2 = BlackHole(mass=1.989e30, origin=np.array([world_radius + 10000, world_radius, world_radius]))
    # disk2 = Disk(
    #     origin=np.array([world_radius + 10000, world_radius, world_radius]),
    #     normal=disk_direction,
    #     inner_radius=black_hole.radius * 2.6,
    #     outer_radius=black_hole.radius * 6
    # )
    bg = Background()

    objects_list.append(black_hole)
    # objects_list.append(black_hole2)
    objects_list.append(disk)
    # objects_list.append(disk2)
    # objects_list.extend(generate_stars(10, world_radius))
    objects_list.append(bg)
    # disk = Disk()
    world = World(objects=objects_list, size=np.array([world_radius * 2] * 3))
    camera = Camera(resolution=(300, 200), fov=(1, 0.66), position=np.array([world_radius, world_radius, 0]))
    image = render(world, camera)
    image.save('test_render_binary_disks.png')
Beispiel #2
0
    def __init__(self):
        self.is_initialized = False
        self.mouseRight = False
        self.mouseMiddle = False
        self.mouseLeft = False
        self.mouseX = 0
        self.mouseY = 0
        self.mouseFirst = True
        self.background_color = Prop[RGBAf](RGBAf(0.3, 0.3, 0.5, 0.0))

        #
        # gizmos
        #
        self.gizmos = ListProp[Node]()
        self.gizmo_shader = shaders.GizmoShader

        # axis
        builder = MeshBuilder(self.gizmo_shader.vertex_layout)
        builder.create_axis(5)
        axis_mesh = Drawer.from_builder(builder, self.gizmo_shader)
        axis_node = Node('axis')
        axis_node.model.pos = lah.Vec3(0, 0.001, 0)
        axis_node.components.append(MeshComponent(axis_mesh))
        self.gizmos.append(axis_node)

        # grid
        builder = MeshBuilder(self.gizmo_shader.vertex_layout)
        builder.create_grid(1, 5)
        grid_mesh = Drawer.from_builder(builder, self.gizmo_shader)
        grid_node = Node('grid')
        grid_node.components.append(MeshComponent(grid_mesh))
        self.gizmos.append(grid_node)

        # camera
        self.camera = Camera()
        camera_node = Node('camera')
        self.gizmos.append(camera_node)

        # light
        self.lightDir = lah.Vec3(1, -3, 10).normalized
        light_node = Node('light')
        self.gizmos.append(light_node)

        #
        # nodes
        #
        self.nodes = ListProp[Node]()
Beispiel #3
0
def yaml_file_to_world_objects(file_path):
    tree = None
    with open(file_path, 'r') as f:
        tree = yaml.load(f, Loader=Loader)

    if tree is None:
        return []

    rv = {'camera': None, 'lights': [], 'world': [], 'config': None}

    defines = {}
    extends_map = {}

    for obj in tree:
        if "define" in obj:
            k = obj["define"]
            v = obj.get("value")
            opt = obj.get("extend")
            defines[k] = v
            if opt is not None:
                extends_map[k] = opt

    # replace 'extends' in defines map
    for obj_name in extends_map:
        parent_name = extends_map[
            obj_name]  # name of object which will be extended
        parent_value = defines[parent_name]
        child_value = defines[
            obj_name]  # name of object with 'extends' keyword
        new_parent_value = deepcopy(parent_value)
        if type(new_parent_value) == dict:
            # assume child value is same type
            for k in child_value:
                new_parent_value[k] = child_value[k]
            defines[obj_name] = new_parent_value

    expand_defines_in_tree(tree, defines)

    for obj in tree:
        if "add" in obj:
            if obj["add"] == "camera":
                rv['camera'] = Camera.from_yaml(obj)
            elif obj["add"] == "light":
                rv['lights'].append(Light.from_yaml(obj))
            elif obj['add'] == 'config':
                rv['config'] = GlobalConfig.from_yaml(obj)
            else:
                possible_item = recursive_add(obj, defines)
                if possible_item is not None:
                    rv['world'].append(possible_item)

    g = Group(material=Material(),
              transform=matrix4x4identity(),
              children=rv['world'])
    rv['world'] = [g]
    return rv
Beispiel #4
0
def enter_dead_mode(screen, hero):

    # pre_loading sprite
    for mnstr_id in sfg.COMMON_MONSTER_ID_LIST:
        mnstr_sfg = sfg.SPRITE_SETTING_MAPPING[mnstr_id]
        mnstr = ENEMY_CLASS_MAPPING[mnstr_id](mnstr_sfg, (0, 0), cfg.Direction.SOUTH)

    map_setting = util.load_map_setting(sfg.DeadMode.MAP_CHAPTER)

    camera = Camera(screen, map_size=map_setting["size"])
    game_map = GameMap(sfg.DeadMode.MAP_CHAPTER, map_setting)
    static_objects = StaticObjectGroup()
    allsprites = GameSpritesGroup()
    enemies = EnemyGroup(map_setting["monsters"], allsprites, hero, static_objects, game_map)
    game_world = GameWorld()

    # load hero
    hero.place(map_setting["hero"]["pos"], map_setting["hero"]["direction"])
    hero.activate(allsprites, enemies, static_objects, game_map)

    # load static objects
    chapter_static_objects = map_setting["static_objects"]
    for static_obj_init in chapter_static_objects:
        t, p = static_obj_init["id"], static_obj_init["pos"]
        static_obj = StaticObject(sfg.STATIC_OBJECT_SETTING_MAPPING[t], p)
        static_objects.add(static_obj)

    allsprites.add(hero)
    allsprites.add(enemies)

    game_world.batch_add(allsprites)
    game_world.batch_add(static_objects)

    game_director = GameDirector(sfg.DeadMode.MAP_CHAPTER, hero, enemies)

    add_enemy_timer = util.Timer(sfg.DeadMode.ADD_ENEMY_TIME_DELTA)
    enemy_add_num = sfg.DeadMode.ENEMY_ADD_INIT_NUM
    enemy_add_delta = sfg.DeadMode.ENEMY_ADD_DELTA
    current_round = 1

    clock = pygame.time.Clock()
    running = True

    battle_keys= {}
    for k in sfg.UserKey.ONE_PRESSED_KEYS:
        battle_keys[k] = {"pressed": False, "cd": 0, "full_cd": sfg.UserKey.ONE_PRESSED_KEY_CD}
    for k in sfg.UserKey.CONTINUE_PRESSED_KEYS:
        battle_keys[k] = {"pressed": False}
    battle_keys["last_direct_key_up"] = {"key": None, "time": None}

    while running:
        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                return {"status": cfg.GameControl.QUIT}

            if event.type == KEYDOWN:
                if event.key == sfg.UserKey.PAUSE:
                    if game_director.status == cfg.GameStatus.IN_PROGRESS:
                        game_director.status = cfg.GameStatus.PAUSE
                        bg_box.pause()
                        game_director.menu.index = 0
                    elif game_director.status == cfg.GameStatus.PAUSE:
                        game_director.status = cfg.GameStatus.IN_PROGRESS
                        bg_box.unpause()

                if event.key == sfg.UserKey.OK:
                    if game_director.status == cfg.GameStatus.HERO_WIN:
                        pass
                    elif game_director.status == cfg.GameStatus.HERO_LOSE:
                        return {"status": cfg.GameControl.DEAD_MODE}
                    elif game_director.status == cfg.GameStatus.PAUSE:
                        mark = game_director.menu.get_current_mark()
                        if mark == "continue":
                            game_director.status = cfg.GameStatus.IN_PROGRESS
                            bg_box.unpause()
                        elif mark == "main":
                            return {"status": cfg.GameControl.MAIN}
                        elif mark == "quit":
                            return {"status": cfg.GameControl.QUIT}

                if event.key in sfg.UserKey.ONE_PRESSED_KEYS and battle_keys[event.key]["cd"] == 0:
                    battle_keys[event.key]["pressed"] = True
                    battle_keys[event.key]["cd"] = battle_keys[event.key]["full_cd"]

                if game_director.status == cfg.GameStatus.PAUSE:
                    game_director.menu.update(event.key)

            if event.type == KEYUP:
                if event.key in sfg.UserKey.DIRECTION_KEYS:
                    battle_keys["last_direct_key_up"]["key"] = event.key
                    battle_keys["last_direct_key_up"]["time"] = time()

        pressed_keys = pygame.key.get_pressed()
        for k in sfg.UserKey.CONTINUE_PRESSED_KEYS:
            battle_keys[k]["pressed"] = pressed_keys[k]

        hero.event_handle(battle_keys, external_event=game_director.status)
        for enemy in enemies:
            if enemy_in_one_screen(hero, enemy):
                enemy.event_handle(external_event=game_director.status)

        time_passed = clock.tick(sfg.FPS)
        passed_seconds = time_passed * 0.001

        for k in sfg.UserKey.ONE_PRESSED_KEYS:
            battle_keys[k]["pressed"] = False
            battle_keys[k]["cd"] = max(battle_keys[k]["cd"] - passed_seconds, 0)
        for k in sfg.UserKey.CONTINUE_PRESSED_KEYS:
            battle_keys[k]["pressed"] = False

        # update hero, enemies, game_director in sequence
        hero.update(passed_seconds, external_event=game_director.status)
        for enemy in enemies:
            if enemy_in_one_screen(hero, enemy):
                enemy.update(passed_seconds, external_event=game_director.status)

        game_world.update(passed_seconds, game_director.status)

        game_director.update(passed_seconds)

        # judge enenmy nums
        if len(enemies) == 0:
            if add_enemy_timer.is_begin():
                if add_enemy_timer.exceed():
                    add_enemy_timer.clear()
                    hero.set_emotion(cfg.SpriteEmotion.ALERT)
                    for _a_useless_var in xrange(enemy_add_num):
                        monster_id = choice(sfg.COMMON_MONSTER_ID_LIST)
                        monster_setting = sfg.SPRITE_SETTING_MAPPING[monster_id]
                        monster = ENEMY_CLASS_MAPPING[monster_id](monster_setting, 
                            (randint(int(game_map.size[0] * 0.3), int(game_map.size[0] * 0.7)),
                                randint(int(game_map.size[1] * 0.3), int(game_map.size[1] * 0.7))),
                            choice(cfg.Direction.ALL))
                        monster_ai_setting = ai.AI_MAPPING[monster_id]
                        monster.activate(monster_ai_setting, allsprites, hero, static_objects, game_map)
                        monster.brain.set_target(hero)
                        monster.brain.set_active_state(cfg.SpriteState.CHASE)
                        enemies.add(monster)
                        game_world.add_object(monster)

                    allsprites.add(enemies)

                    enemy_add_num = min(enemy_add_num + enemy_add_delta, sfg.DeadMode.ENEMY_ADD_MAX)

            else:
                add_enemy_timer.begin()
                current_round += 1
                
                new_foods = []
                for _is_a_useless_var in xrange(3):
                    food = StaticObject(sfg.STATIC_OBJECT_SETTING_MAPPING[
                        choice(sfg.FOOD_ID_LIST)], 
                        (randint(int(game_map.size[0] * 0.2), int(game_map.size[0] * 0.5)),
                            randint(int(game_map.size[1] * 0.3), int(game_map.size[1] * 0.6)))
                    )
                    new_foods.append(food)
                    static_objects.add(food)

                game_world.batch_add(new_foods)


        camera.screen_follow(hero.pos)

        # 3 layers from bottom to top: floor -> sprites in the playground -> game info(player hp, ep etc)
        game_map.draw(camera)
        game_world.draw(camera)
        game_director.draw(camera)

        # say how many enemies left
        enemy_left_info = sfg.Font.MSYH_32.render(u"Ê£Óà¹ÖÎïÊý£º%s" % len(enemies), True, pygame.Color("white"))
        screen.blit(enemy_left_info, sfg.DeadMode.ENEMY_LEFT_INFO_BLIT_POS)

        # say current round
        current_round_info = sfg.Font.MSYH_32.render(u"µÚ%s²¨" % current_round, True, pygame.Color("white"))
        screen.blit(current_round_info, sfg.DeadMode.CURRENT_ROUND_INFO_BLIT_POS)

        if len(enemies) == 0 and add_enemy_timer.is_begin() and (not add_enemy_timer.exceed()):
            game_director.draw_count_down_number(camera, add_enemy_timer, sfg.DeadMode.ADD_ENEMY_TIME_DELTA)

        if COMMAND_DEBUG_MODE or sfg.DEBUG_MODE:
            debug_tools.run_debug_by_option_list(COMMAND_DEBUG_OPTIONS,
                camera, game_world, game_map, clock)
            if COMMAND_DEBUG_OPTIONS["god"]:
                hero.hp = hero.setting.HP
                hero.mp = hero.setting.MP
                hero.sp = hero.setting.SP
                hero.hp_status = hero.cal_sprite_status(hero.hp, hero.setting.HP)
                hero.attacker.refresh_skill()

        pygame.display.update()
Beispiel #5
0
def enter_chapter(screen, chapter, hero):
    map_setting = util.load_map_setting(chapter)

    camera = Camera(screen, map_size=map_setting["size"])
    game_map = GameMap(chapter, map_setting)
    static_objects = StaticObjectGroup()
    allsprites = GameSpritesGroup()
    enemies = EnemyGroup(map_setting["monsters"], allsprites, hero, static_objects, game_map)
    game_world = GameWorld()

    # load hero
    hero.place(map_setting["hero"]["pos"], map_setting["hero"]["direction"])
    hero.activate(allsprites, enemies, static_objects, game_map)

    # load ambush
    game_world.init_ambush_list(map_setting.get("ambush_list", []))

    # load static objects
    chapter_static_objects = map_setting["static_objects"]
    for static_obj_init in chapter_static_objects:
        t, p = static_obj_init["id"], static_obj_init["pos"]
        static_obj = StaticObject(sfg.STATIC_OBJECT_SETTING_MAPPING[t], p)
        static_objects.add(static_obj)

    allsprites.add(hero)
    allsprites.add(enemies)

    game_world.batch_add(allsprites)
    game_world.batch_add(static_objects)

    game_director = GameDirector(chapter, hero, enemies)

    if COMMAND_DEBUG_MODE:
        # skip the init status in command debug mode
        game_director.status = cfg.GameStatus.IN_PROGRESS

    clock = pygame.time.Clock()
    running = True

    battle_keys= {}
    for k in sfg.UserKey.ONE_PRESSED_KEYS:
        battle_keys[k] = {"pressed": False, "cd": 0, "full_cd": sfg.UserKey.ONE_PRESSED_KEY_CD}
    for k in sfg.UserKey.CONTINUE_PRESSED_KEYS:
        battle_keys[k] = {"pressed": False}
    battle_keys["last_direct_key_up"] = {"key": None, "time": None}

    while running:
        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                return {"status": cfg.GameControl.QUIT}

            if event.type == KEYDOWN:
                if event.key == sfg.UserKey.PAUSE:
                    if game_director.status == cfg.GameStatus.IN_PROGRESS:
                        game_director.status = cfg.GameStatus.PAUSE
                        bg_box.pause()
                        game_director.menu.index = 0
                    elif game_director.status == cfg.GameStatus.PAUSE:
                        game_director.status = cfg.GameStatus.IN_PROGRESS
                        bg_box.unpause()

                if event.key == sfg.UserKey.OK:
                    if game_director.status == cfg.GameStatus.HERO_WIN:
                        util.save_chapter_win_screen_image(chapter, camera.screen)
                        dat = util.load_auto_save() or {}
                        dat["current_chapter"] = chapter
                        dat["level"] = hero.level
                        dat["exp"] = hero.exp
                        util.auto_save(dat)
                        return {"status": cfg.GameControl.NEXT}
                    elif game_director.status == cfg.GameStatus.HERO_LOSE:
                        return {"status": cfg.GameControl.AGAIN, "chapter": chapter}
                    elif game_director.status == cfg.GameStatus.PAUSE:
                        mark = game_director.menu.get_current_mark()
                        if mark == "continue":
                            game_director.status = cfg.GameStatus.IN_PROGRESS
                            bg_box.unpause()
                        elif mark == "main":
                            return {"status": cfg.GameControl.MAIN}
                        elif mark == "quit":
                            return {"status": cfg.GameControl.QUIT}

                if event.key in sfg.UserKey.ONE_PRESSED_KEYS and battle_keys[event.key]["cd"] == 0:
                    battle_keys[event.key]["pressed"] = True
                    battle_keys[event.key]["cd"] = battle_keys[event.key]["full_cd"]

                if game_director.status == cfg.GameStatus.PAUSE:
                    game_director.menu.update(event.key)

            if event.type == KEYUP:
                if event.key in sfg.UserKey.DIRECTION_KEYS:
                    battle_keys["last_direct_key_up"]["key"] = event.key
                    battle_keys["last_direct_key_up"]["time"] = time()

        pressed_keys = pygame.key.get_pressed()
        for k in sfg.UserKey.CONTINUE_PRESSED_KEYS:
            battle_keys[k]["pressed"] = pressed_keys[k]

        hero.event_handle(battle_keys, external_event=game_director.status)
        for enemy in enemies:
            if enemy_in_one_screen(hero, enemy):
                enemy.event_handle(external_event=game_director.status)

        time_passed = clock.tick(sfg.FPS)
        passed_seconds = time_passed * 0.001

        for k in sfg.UserKey.ONE_PRESSED_KEYS:
            battle_keys[k]["pressed"] = False
            battle_keys[k]["cd"] = max(battle_keys[k]["cd"] - passed_seconds, 0)
        for k in sfg.UserKey.CONTINUE_PRESSED_KEYS:
            battle_keys[k]["pressed"] = False

        # update hero, enemies, game_director in sequence
        hero.update(passed_seconds, external_event=game_director.status)
        for enemy in enemies:
            if enemy_in_one_screen(hero, enemy):
                enemy.update(passed_seconds, external_event=game_director.status)

        game_world.update(passed_seconds, game_director.status)
        game_world.update_ambush(passed_seconds, game_director, hero, allsprites, enemies,
            static_objects, game_map)

        game_director.update(passed_seconds)

        camera.screen_follow(hero.pos)

        # 3 layers from bottom to top: floor -> sprites in the playground -> game info(player hp, ep etc)
        game_map.draw(camera)
        game_world.draw(camera)
        game_director.draw(camera)

        if COMMAND_DEBUG_MODE or sfg.DEBUG_MODE:
            debug_tools.run_debug_by_option_list(COMMAND_DEBUG_OPTIONS,
                camera, game_world, game_map, clock)
            if COMMAND_DEBUG_OPTIONS["god"]:
                hero.hp = hero.setting.HP
                hero.mp = hero.setting.MP
                hero.sp = hero.setting.SP
                hero.hp_status = hero.cal_sprite_status(hero.hp, hero.setting.HP)
                hero.attacker.refresh_skill()

        pygame.display.update()
Beispiel #6
0
class Scene:
    """
    [CLASSES] Controllerクラスは、glglueの規約に沿って以下のコールバックを実装する
    """
    def __init__(self):
        self.is_initialized = False
        self.mouseRight = False
        self.mouseMiddle = False
        self.mouseLeft = False
        self.mouseX = 0
        self.mouseY = 0
        self.mouseFirst = True
        self.background_color = Prop[RGBAf](RGBAf(0.3, 0.3, 0.5, 0.0))

        #
        # gizmos
        #
        self.gizmos = ListProp[Node]()
        self.gizmo_shader = shaders.GizmoShader

        # axis
        builder = MeshBuilder(self.gizmo_shader.vertex_layout)
        builder.create_axis(5)
        axis_mesh = Drawer.from_builder(builder, self.gizmo_shader)
        axis_node = Node('axis')
        axis_node.model.pos = lah.Vec3(0, 0.001, 0)
        axis_node.components.append(MeshComponent(axis_mesh))
        self.gizmos.append(axis_node)

        # grid
        builder = MeshBuilder(self.gizmo_shader.vertex_layout)
        builder.create_grid(1, 5)
        grid_mesh = Drawer.from_builder(builder, self.gizmo_shader)
        grid_node = Node('grid')
        grid_node.components.append(MeshComponent(grid_mesh))
        self.gizmos.append(grid_node)

        # camera
        self.camera = Camera()
        camera_node = Node('camera')
        self.gizmos.append(camera_node)

        # light
        self.lightDir = lah.Vec3(1, -3, 10).normalized
        light_node = Node('light')
        self.gizmos.append(light_node)

        #
        # nodes
        #
        self.nodes = ListProp[Node]()

    def add_mesh(self, name, mesh: Drawer):
        mesh_node = Node(name)
        mesh_node.components.append(MeshComponent(mesh))
        self.nodes.reset(mesh_node)

    def onResize(self, w: int, h: int):
        glViewport(0, 0, w, h)
        self.camera.resize(w, h)

    def onLeftDown(self, x, y):
        #logger.debug('onLeftDown: %d, %d', x, y)
        pass

    def onLeftUp(self, x, y):
        #logger.debug('onLeftUp: %d, %d', x, y)
        pass

    def onMiddleDown(self, x, y):
        self.mouseMiddle = True
        self.mouseX = x
        self.mouseY = y

    def onMiddleUp(self, x, y):
        self.mouseMiddle = False
        self.mouseX = x
        self.mouseY = y

    def onRightDown(self, x, y):
        self.mouseRight = True
        self.mouseX = x
        self.mouseY = y

    def onRightUp(self, x, y):
        self.mouseRight = False
        self.mouseX = x
        self.mouseY = y

    def onMotion(self, x, y):
        dx = x - self.mouseX
        dy = y - self.mouseY
        #logger.debug("onMotion %d x %d => %d x %d", x, y, dx, dy)
        self.mouseX = x
        self.mouseY = y
        if self.mouseFirst:
            self.mouseFirst = False
            return

        if self.mouseMiddle:
            self.camera.shift(dx, dy)

        if self.mouseRight:
            self.camera.yaw_pitch(dx, dy)

    def onWheel(self, d):
        self.camera.dolly(d.y())

    def onKeyDown(self, keycode):
        logger.debug('onKeyDown: %d', keycode)

    def update(self, delta):
        pass

    def initialize(self):
        logger.info(glGetString(GL_VERSION))
        logger.info(glGetString(GL_SHADING_LANGUAGE_VERSION))
        logger.info('OpenGL%d.%d', glGetInteger(GL_MAJOR_VERSION),
                    glGetInteger(GL_MINOR_VERSION))
        # self.scene.initialize()

        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)
        self.is_initialized = True

    def draw(self):
        if not self.is_initialized:
            self.initialize()

        # clear
        background_color = self.background_color.value
        glClearColor(background_color.red, background_color.green,
                     background_color.blue, background_color.alpha)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        #
        # update
        #

        #
        # render
        #
        context = RenderContext(self.camera, self.lightDir)

        for x in self.gizmos.values:
            context.set_model(x.model)
            x.render(context)

        for x in self.nodes.values:
            context.set_model(x.model)
            x.render(context)
Beispiel #7
0
def run(chapter):
    clock = pygame.time.Clock()

    map_setting = util.load_map_setting(chapter)

    screen = pygame.display.set_mode(sfg.Screen.SIZE)
    pygame.display.set_caption("Renne Map Editor")
    camera = Camera(screen, map_size=map_setting["size"])
    game_world = GameWorld()
    game_map = GameMap(chapter, map_setting)

    # load hero
    hero = Renne(sfg.Renne, map_setting["hero"]["pos"], map_setting["hero"]["direction"])
    game_world.add_object(hero)

    # load monsters
    monster_init_list = map_setting.get("monsters", [])
    for monster_init in monster_init_list:
        monster_id, pos, direct = monster_init["id"], monster_init["pos"], monster_init["direction"]
        monster = Enemy(sfg.SPRITE_SETTING_MAPPING[monster_id], pos, direct)
        game_world.add_object(monster)

    # load static objects
    chapter_static_objects = map_setting.get("static_objects", [])
    for static_obj_init in chapter_static_objects:
        t, p = static_obj_init["id"], static_obj_init["pos"]
        static_obj = StaticObject(sfg.STATIC_OBJECT_SETTING_MAPPING[t], p)
        game_world.add_object(static_obj)

    # hack an attrbute ambush into game_world for easy saving
    game_world.ambush_list = []
    # some monsters is in ambush list
    ambush_init_list = map_setting.get("ambush_list", [])
    for ambush_init in ambush_init_list:
        ambush = Ambush(ambush_init["ambush"]["pos"], sfg.Ambush.SURROUND_AREA_WIDTH,
            sfg.Ambush.ENTER_AREA_WIDTH, ambush_init["ambush"]["type"])
        for monster_init in ambush_init["monsters"]:
            monster_id, pos, direct = monster_init["id"], monster_init["pos"], monster_init["direction"]
            monster = Enemy(sfg.SPRITE_SETTING_MAPPING[monster_id], pos, direct)
            game_world.add_object(monster)
            ambush.add(monster)
        game_world.ambush_list.append(ambush)

    running = True
    key_vec = Vector2()
    selected_object = None
    while running:
        mouse_pos = pygame.mouse.get_pos()
        map_pos_for_mouse = get_map_pos_for_mouse(camera.rect, mouse_pos)

        for event in pygame.event.get(): 
            if event.type == pygame.QUIT: 
                running = False

            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    if object_can_be_shift(selected_object) \
                        and put_down_selected_object(selected_object, game_world):
                        selected_object = None
                    elif isinstance(selected_object, Ambush) \
                        and put_down_ambush(selected_object, game_world):
                        selected_object = None

                if event.key == sfg.MapEditor.KEY_STATIC_OBJECT:
                    # static object
                    selected_object = selected_object_shift(selected_object, cfg.GameObject.TYPE_STATIC)
                elif event.key == sfg.MapEditor.KEY_ENEMY:
                    # enemy
                    selected_object = selected_object_shift(selected_object, cfg.GameObject.TYPE_DYNAMIC)
                elif event.key == sfg.MapEditor.KEY_AMBUSH:
                    # ambush
                    selected_object = mouse_ambush_toggle(selected_object)

                if event.key == sfg.MapEditor.KEY_ERASE_SELECTED_OBJECT:
                    selected_object = None

                if event.key == sfg.MapEditor.KEY_TURN_DIRECTION:
                    if isinstance(selected_object, GameSprite):
                        selected_object = turn_sprite_direction(selected_object)

                key_mods = pygame.key.get_mods()
                if key_mods & KMOD_CTRL and event.key == sfg.MapEditor.KEY_CTRL_SAVE:
                    # ctrl+s to save map setting
                    change_map_setting(map_setting, game_world, game_map)
                    util.save_map_setting(chapter, map_setting)
                    print "save chapter %s map setting" % chapter

                if key_mods & KMOD_ALT:

                    # debug draw switch
                    if event.key == sfg.MapEditor.KEY_ALT_SWITCH_POS:
                        DEBUG_DRAW["pos"] = not DEBUG_DRAW["pos"]
                    elif event.key == sfg.MapEditor.KEY_ALT_SWITCH_AREA:
                        DEBUG_DRAW["area"] = not DEBUG_DRAW["area"]
                    elif event.key == sfg.MapEditor.KEY_ALT_SWITCH_WAYPOINT:
                        DEBUG_DRAW["waypoints"] = not DEBUG_DRAW["waypoints"]
                    elif event.key == sfg.MapEditor.KEY_ALT_SWITCH_BLOCK_POINT:
                        DEBUG_DRAW["block_points"] = not DEBUG_DRAW["block_points"]

            elif event.type == MOUSEBUTTONDOWN:
                if event.button == 1:
                    # left click
                    if selected_object is None:
                        # pick up "this" unit if the mouse is over it
                        selected_object = select_unit(map_pos_for_mouse, game_world)
                    else:
                        # put down the current selected unit if no "collision" happen
                        if (isinstance(selected_object, GameSprite) or \
                            isinstance(selected_object, StaticObject)) \
                            and put_down_selected_object(selected_object, game_world):
                            if pygame.key.get_mods() & KMOD_CTRL:
                                selected_object = create_new_instance(selected_object)
                            else:
                                selected_object = None

                        elif isinstance(selected_object, Ambush) \
                            and put_down_ambush(selected_object, game_world):
                            selected_object = None

                    change_map_setting(map_setting, game_world, game_map)


        pressed_keys = pygame.key.get_pressed()
        key_vec.x = key_vec.y = 0.0
        if pressed_keys[K_LEFT]:
           key_vec.x -= 1.0
        if pressed_keys[K_RIGHT]:
            key_vec.x += 1.0
        if pressed_keys[K_UP]:
            key_vec.y -= 1.0
        if pressed_keys[K_DOWN]:
            key_vec.y += 1.0

        time_passed = clock.tick(sfg.FPS)
        passed_seconds = time_passed * 0.001

        camera.screen_move(key_vec, sfg.MapEditor.SCREEN_MOVE_SPEED, passed_seconds)
        if selected_object is not None:
            if isinstance(selected_object, GameSprite) \
                or isinstance(selected_object, StaticObject):
                set_selected_object_follow_mouse(map_pos_for_mouse, selected_object)
            elif isinstance(selected_object, Ambush):
                set_ambush_follow_mouse(map_pos_for_mouse, selected_object)

        game_map.draw(camera)

        # draw ambush before all objects, because they are "close" to the floor
        for ambush in game_world.ambush_list:
            ambush.draw(camera)

        for sp in sorted(game_world.yield_all_objects(), key=lambda sp: sp.pos.y):
            if sp.setting.GAME_OBJECT_TYPE == cfg.GameObject.TYPE_DYNAMIC:
                sp.animation.adjust_rect()
                # select current image for corresponding direction
                sp.animation.image = sp.animation.sprite_image_contoller.get_surface(
                    cfg.SpriteAction.STAND)[sp.direction]
                sp.animation.draw_shadow(camera)

            sp.draw(camera)

        if selected_object is not None:
            if isinstance(selected_object, GameSprite) \
                or isinstance(selected_object, StaticObject):
                # render selected_object
                selected_object_name = sfg.Font.ARIAL_32.render(
                    selected_object.setting.NAME, True, pygame.Color("black"))
                camera.screen.blit(selected_object_name, (5, 5))
                if isinstance(selected_object, GameSprite):
                    selected_object.animation.draw_shadow(camera)
                    selected_object.animation.image = selected_object.animation.sprite_image_contoller.get_surface(
                        cfg.SpriteAction.STAND)[selected_object.direction]
                selected_object.draw(camera)
                draw_block_points_for_selected_object(camera, selected_object)
            
            elif isinstance(selected_object, Ambush):
                camera.screen.blit(sfg.Font.ARIAL_32.render("Ambush", True, pygame.Color("black")), (5, 5))
                selected_object.draw(camera)

        # debug drawings
        for sp in game_world.yield_all_objects():
            if DEBUG_DRAW["pos"]:
                debug_tools.draw_pos(camera, sp)
            if DEBUG_DRAW["area"]:
                debug_tools.draw_area(camera, sp)

        if DEBUG_DRAW["waypoints"]:
            debug_tools.draw_waypoins(camera, game_map.waypoints)
        if DEBUG_DRAW["block_points"]:
            debug_tools.draw_block_points(camera, game_map.block_points)

        pygame.display.update()