#include #include #include #include #include #include #include #include #include #include namespace boundard { namespace { std::shared_ptr create_actor(const ActorConfig& actor_config, Game& game, BehaviorRegistry& behaviors) { auto mesh = std::make_shared(); if (actor_config.mesh.shape == "quad") { *mesh = Mesh::quad(); } else { // 当前渲染器只提供 quad;未知形状先按 quad 创建,便于后续扩展。 *mesh = Mesh::quad(); } mesh->set_color(actor_config.mesh.color); mesh->texture = actor_config.mesh.texture; std::shared_ptr actor; if (actor_config.type == "camera") { actor = std::make_shared(actor_config.name, game); } else { actor = std::make_shared(actor_config.name, game, mesh); } actor->set_position(actor_config.position); actor->set_facing(actor_config.facing); if (auto* camera = dynamic_cast(actor.get())) { camera->set_zoom(actor_config.zoom); } for (const ActorConfig& child_config : actor_config.children) { actor->add_child(create_actor(child_config, game, behaviors)); } if (!actor_config.init_function.empty()) { auto handler = behaviors.init(actor_config.init_function); if (handler) { actor->set_init_handler(std::move(handler)); } else { std::fprintf(stderr, "未找到 init 处理函数: %s\n", actor_config.init_function.c_str()); } } if (!actor_config.tick_function.empty()) { auto handler = behaviors.tick(actor_config.tick_function); if (handler) { actor->set_tick_handler(std::move(handler)); } else { std::fprintf(stderr, "未找到 tick 处理函数: %s\n", actor_config.tick_function.c_str()); } } return actor; } std::shared_ptr build_scene(const SceneConfig& scene, Game& game, BehaviorRegistry& behaviors) { auto runtime_scene = std::make_shared(scene.name); if (scene.grid_background) { auto grid = std::make_shared("__grid", game, std::make_shared(Mesh::grid())); grid->mesh()->set_color({0.20F, 0.28F, 0.36F, 0.75F}); runtime_scene->add_actor(std::move(grid)); } for (const ActorConfig& actor_config : scene.actors) { auto actor = create_actor(actor_config, game, behaviors); runtime_scene->add_actor(std::move(actor)); } runtime_scene->set_default_camera(scene.default_camera); return runtime_scene; } const SceneConfig* find_scene(const std::vector& scenes, const std::string& name) { for (const SceneConfig& scene : scenes) { if (scene.name == name) { return &scene; } } return nullptr; } } // namespace int run_engine(int argc, char** argv, const char* default_config_path) { std::string config_path = default_config_path != nullptr ? default_config_path : "config.ceg"; if (argc > 1) { config_path = argv[1]; } ConfigLoader loader; if (!loader.load(config_path)) { std::fprintf(stderr, "%s\n", loader.last_error().c_str()); return 1; } const GameConfig& config = loader.config(); Game& game = Game::getInstance(); BehaviorRegistry& behaviors = BehaviorRegistry::getInstance(); std::vector scenes = config.scenes; if (scenes.empty() && !config.actors.empty()) { SceneConfig legacy; legacy.name = "default"; legacy.path = config_path; legacy.actors = config.actors; scenes.push_back(std::move(legacy)); } std::string start_scene = config.start_scene; if (start_scene.empty() && !scenes.empty()) { start_scene = scenes.front().name; } const SceneConfig* active_scene = find_scene(scenes, start_scene); if (active_scene == nullptr && !scenes.empty()) { active_scene = &scenes.front(); std::fprintf(stderr, "未找到起始场景 %s,已回退到 %s\n", start_scene.c_str(), active_scene->name.c_str()); } // 把配置文件中的场景包装为运行时 Scene,并注册到 Game。 for (const SceneConfig& scene_config : scenes) { std::shared_ptr runtime_scene = build_scene(scene_config, game, behaviors); game.add_scene(std::move(runtime_scene)); } render::RenderLoop render_loop; for (const InputBindingConfig& binding : config.input_bindings) { render_loop.input().add_action(binding.action); for (int key : binding.keys) { render_loop.input().bind_key(binding.action, key); } for (int button : binding.mouse_buttons) { render_loop.input().bind_mouse_button(binding.action, button); } } // 引擎级默认退出动作,不包含具体游戏逻辑。 render_loop.input().add_action("quit"); render_loop.input().bind_key("quit", 256); auto apply_scene = [&](const std::string& name) { std::shared_ptr scene = game.scene(name); if (scene == nullptr) { std::fprintf(stderr, "未找到场景: %s\n", name.c_str()); return; } scene->initialize(); game.set_current_scene(scene); render_loop.set_actors(scene->actors()); render_loop.set_camera(scene->primary_camera()); }; if (active_scene != nullptr) { apply_scene(active_scene->name); } render_loop.start(config.window.width, config.window.height, config.window.title.c_str()); auto last = std::chrono::steady_clock::now(); while (!render_loop.should_close()) { render_loop.poll_events(); if (render_loop.input().is_action_just_pressed("quit")) { break; } const std::string requested_scene = game.take_scene_request(); if (!requested_scene.empty() && requested_scene != game.current_scene_name()) { apply_scene(requested_scene); } const auto now = std::chrono::steady_clock::now(); const float dt = std::chrono::duration(now - last).count(); last = now; std::shared_ptr scene = game.current_scene(); if (scene != nullptr) { scene->process(dt, render_loop.input()); } render_loop.input().end_frame(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); } render_loop.stop(); return 0; } } // namespace boundard