feat: 实现游戏摄像机控制器并优化地图系统
重构地图系统,增加摄像机控制器管理相机行为。主要变更包括: - 新增 GameCameraController 类,支持跟随目标和调试模式 - 重构 GameMap 类,分离相机逻辑到控制器 - 优化地图资源加载和同步逻辑 - 改进动画系统的事件处理 - 添加地图测试场景用于快速验证
This commit is contained in:
@@ -44,7 +44,6 @@ struct MoveAreaTarget {
|
||||
struct TileInfo {
|
||||
std::string spritePath;
|
||||
int spriteIndex = 0;
|
||||
int imgPos = 0;
|
||||
};
|
||||
|
||||
struct MapConfig {
|
||||
@@ -52,6 +51,7 @@ struct MapConfig {
|
||||
std::string mapPath;
|
||||
std::string mapDir;
|
||||
int backgroundPos = 0;
|
||||
Vec2 tilePos = Vec2::Zero();
|
||||
int farSightScroll = 100;
|
||||
bool hasCameraLimit = false;
|
||||
int cameraLimitMinX = -1;
|
||||
|
||||
@@ -8,6 +8,15 @@
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
/**
|
||||
* @brief 地图运行时容器,负责把 map 配置组织成可显示/可交互的场景结构
|
||||
*
|
||||
* 这里不直接解析底层资源格式,而是消费 `GameDataLoader` 已经整理好的
|
||||
* `MapConfig/TileInfo`。GameMap 主要负责三件事:
|
||||
* 1. 按固定图层顺序挂载地板、背景动画、场景动画和动态对象
|
||||
* 2. 根据 camera limit 和可移动区域维护摄像机关注点
|
||||
* 3. 提供移动判定和切图区域查询给上层角色/场景逻辑使用
|
||||
*/
|
||||
class GameMap : public Actor {
|
||||
public:
|
||||
using MapMoveArea = game::MoveAreaTarget;
|
||||
@@ -15,40 +24,65 @@ public:
|
||||
GameMap();
|
||||
~GameMap() override = default;
|
||||
|
||||
/// 读取地图配置并重建当前地图内容。重复调用时会先清空旧地图运行态。
|
||||
bool LoadMap(const std::string& mapName);
|
||||
/// 地图进入场景后的初始化入口,目前主要负责音乐播放。
|
||||
void Enter();
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
/// 将运行时对象挂到 normal 层,并按 y 值设置基础排序。
|
||||
void AddObject(RefPtr<Actor> object);
|
||||
|
||||
/// 返回地图推荐的默认相机关注点。
|
||||
Vec2 GetDefaultCameraFocus() const;
|
||||
/// 根据 camera limit 和缩放约束修正相机关注点。
|
||||
Vec2 ClampCameraFocus(const Vec2& focus, float zoom) const;
|
||||
/// 将各层转换到屏幕空间;远景层在这里做视差滚动。
|
||||
void ApplyCameraFocus(const Vec2& focus);
|
||||
|
||||
/// 根据虚拟可行走区域限制位移,返回修正后的目标坐标。
|
||||
Vec3 CheckIsItMovable(const Vec3& curPos, const Vec3& posOffset) const;
|
||||
/// 检查当前位置是否进入 town move area,用于切图/传送判定。
|
||||
MapMoveArea CheckIsItMoveArea(const Vec3& curPos) const;
|
||||
const std::vector<MapMoveArea>& GetMoveAreaInfo() const;
|
||||
Rect GetMovablePositionArea(size_t index) const;
|
||||
|
||||
int GetMapLength() const { return mapLength_; }
|
||||
int GetMapHeight() const { return mapHeight_; }
|
||||
int GetBackgroundRepeatWidth() const { return backgroundRepeatWidth_; }
|
||||
|
||||
private:
|
||||
/// 初始化固定图层。图层名字与 DNF 地图层概念保持一致。
|
||||
void initLayers();
|
||||
/// 清理当前地图的运行态节点和缓存数据,但保留 GameMap 自身及图层骨架。
|
||||
void clearLayerChildren();
|
||||
/// 创建普通 tile 和扩展 tile,并推导背景平铺需要的横向覆盖宽度。
|
||||
void InitTile();
|
||||
/// 初始化背景动画层,必要时按横向覆盖宽度做横向平铺。
|
||||
void InitBackgroundAnimation();
|
||||
/// 初始化地图对象动画(门、特效、场景摆件等)。
|
||||
void InitMapAnimation();
|
||||
/// 初始化角色移动用的可行走区域。
|
||||
void InitVirtualMovableArea();
|
||||
/// 初始化切图/传送区域。
|
||||
void InitMoveArea();
|
||||
void updateCamera();
|
||||
void updateLayerPositions(const Vec2& cameraPos);
|
||||
/// 将各层转换到屏幕空间;远景层在这里做视差滚动。
|
||||
void updateLayerPositions(const Vec2& cameraFocus);
|
||||
|
||||
/// 原始地图配置,作为运行时装配地图内容的输入。
|
||||
game::MapConfig mapConfig_;
|
||||
/// 地图的固定图层集合,key 为地图层名。
|
||||
std::unordered_map<std::string, RefPtr<GameMapLayer>> layerMap_;
|
||||
/// bottom 层里的专用地板容器,固定放在该层最底部,避免地图动画被地板压住。
|
||||
RefPtr<Actor> tileRoot_;
|
||||
/// 角色可行走矩形区域。
|
||||
std::vector<Rect> movableArea_;
|
||||
/// 进入后会触发切图/传送的矩形区域。
|
||||
std::vector<Rect> moveArea_;
|
||||
int mapLength_ = 0;
|
||||
int mapHeight_ = 0;
|
||||
/// 地板铺设后推导出的横向覆盖宽度,用于背景动画横向平铺。
|
||||
int backgroundRepeatWidth_ = 0;
|
||||
/// 地图配置里的整体 Y 偏移;既影响层位置,也影响地板校准。
|
||||
int mapOffsetY_ = 0;
|
||||
bool debugMode_ = false;
|
||||
Vec2 cameraFocus_ = Vec2::Zero();
|
||||
/// 当前地图正在播放的背景音乐。
|
||||
Ptr<Music> currentMusic_;
|
||||
};
|
||||
|
||||
|
||||
24
Game/include/Actor/GameMapTestScene.h
Normal file
24
Game/include/Actor/GameMapTestScene.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Camera/GameCameraController.h"
|
||||
#include "GameMap.h"
|
||||
#include <frostbite2D/scene/scene.h>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class GameMapTestScene : public Scene {
|
||||
public:
|
||||
GameMapTestScene();
|
||||
~GameMapTestScene() override = default;
|
||||
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
private:
|
||||
GameCameraController cameraController_;
|
||||
bool initialized_ = false;
|
||||
RefPtr<GameMap> map_;
|
||||
};
|
||||
|
||||
} // namespace frostbite2D
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Camera/GameCameraController.h"
|
||||
#include "GameDataLoader.h"
|
||||
#include "GameMap.h"
|
||||
#include <frostbite2D/2d/actor.h>
|
||||
@@ -38,6 +39,7 @@ private:
|
||||
Vec2 sariaRoomPos_ = Vec2(-1.0f, -1.0f);
|
||||
std::vector<MapInfo> mapList_;
|
||||
int curMapIndex_ = -1;
|
||||
GameCameraController cameraController_;
|
||||
};
|
||||
|
||||
} // namespace frostbite2D
|
||||
|
||||
53
Game/include/Camera/GameCameraController.h
Normal file
53
Game/include/Camera/GameCameraController.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/2d/actor.h>
|
||||
#include <frostbite2D/types/type_math.h>
|
||||
|
||||
struct _SDL_GameController;
|
||||
typedef struct _SDL_GameController SDL_GameController;
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class GameMap;
|
||||
|
||||
class GameCameraController {
|
||||
public:
|
||||
GameCameraController() = default;
|
||||
~GameCameraController();
|
||||
|
||||
void SetMap(GameMap* map);
|
||||
void SetTarget(Actor* target);
|
||||
void ClearTarget();
|
||||
|
||||
void SetDebugEnabled(bool enabled);
|
||||
bool IsDebugEnabled() const { return debugEnabled_; }
|
||||
|
||||
void SetZoom(float zoom);
|
||||
float GetZoom() const { return zoom_; }
|
||||
|
||||
void SetFocus(const Vec2& focus);
|
||||
const Vec2& GetFocus() const { return focus_; }
|
||||
|
||||
void SnapToDefaultFocus();
|
||||
void Update(float deltaTime);
|
||||
|
||||
private:
|
||||
void openDebugController();
|
||||
void closeDebugController();
|
||||
void updateDebugInput(float deltaTime);
|
||||
void applyFocus() const;
|
||||
|
||||
GameMap* map_ = nullptr;
|
||||
Actor* target_ = nullptr;
|
||||
SDL_GameController* debugController_ = nullptr;
|
||||
Vec2 focus_ = Vec2::Zero();
|
||||
|
||||
bool debugEnabled_ = false;
|
||||
bool initialized_ = false;
|
||||
|
||||
float zoom_ = 1.2f;
|
||||
float followLerpSpeed_ = 8.0f;
|
||||
float debugMoveSpeed_ = 800.0f;
|
||||
};
|
||||
|
||||
} // namespace frostbite2D
|
||||
Reference in New Issue
Block a user