545 lines
17 KiB
C++
545 lines
17 KiB
C++
#include "GameMap.h"
|
||
#include "Asset/AssetManager.h"
|
||
#include "Asset/Asset_SoundPack.h"
|
||
#include "EngineCore/Game.h"
|
||
#include "EngineFrame/Scene/Scene.h"
|
||
#include "EngineFrame/Component/Animation.h"
|
||
#include "Global/Global_Game.h"
|
||
#include "Actor/Object/CharacterObject.h"
|
||
|
||
GameMap::GameMap()
|
||
{
|
||
_LayerMap["contact"] = new GameMapLayer();
|
||
_LayerMap["distantback"] = new GameMapLayer();
|
||
_LayerMap["middleback"] = new GameMapLayer();
|
||
_LayerMap["bottom"] = new GameMapLayer();
|
||
_LayerMap["closeback"] = new GameMapLayer();
|
||
_LayerMap["normal"] = new GameMapLayer();
|
||
_LayerMap["close"] = new GameMapLayer();
|
||
_LayerMap["cover"] = new GameMapLayer();
|
||
_LayerMap["max"] = new GameMapLayer();
|
||
|
||
// 设置图层渲染顺序
|
||
_LayerMap["contact"]->SetZOrder(10000);
|
||
_LayerMap["distantback"]->SetZOrder(50000);
|
||
_LayerMap["middleback"]->SetZOrder(100000);
|
||
_LayerMap["bottom"]->SetZOrder(150000);
|
||
_LayerMap["closeback"]->SetZOrder(200000);
|
||
_LayerMap["normal"]->SetZOrder(250000);
|
||
_LayerMap["close"]->SetZOrder(300000);
|
||
_LayerMap["cover"]->SetZOrder(350000);
|
||
_LayerMap["max"]->SetZOrder(400000);
|
||
|
||
AddChild(_LayerMap["contact"]);
|
||
AddChild(_LayerMap["distantback"]);
|
||
AddChild(_LayerMap["middleback"]);
|
||
AddChild(_LayerMap["bottom"]);
|
||
AddChild(_LayerMap["closeback"]);
|
||
AddChild(_LayerMap["normal"]);
|
||
AddChild(_LayerMap["close"]);
|
||
AddChild(_LayerMap["cover"]);
|
||
AddChild(_LayerMap["max"]);
|
||
}
|
||
|
||
GameMap::~GameMap()
|
||
{
|
||
}
|
||
|
||
void GameMap::InitConfiguration(std::string mapName)
|
||
{
|
||
ScriptData Data = AssetManager::GetInstance().GetScriptInfo(mapName);
|
||
_MapInfo["wide_mode_camer_vertical_correction"] = 0;
|
||
_MapInfo["background_pos"] = 0;
|
||
_MapPath = mapName;
|
||
_MapDir = mapName.substr(0, mapName.find_last_of("/") + 1);
|
||
while (!Data.IsEnd())
|
||
{
|
||
std::string Segment = Data.Get();
|
||
if (Segment == "[background pos]")
|
||
{
|
||
int Offset = std::stoi(Data.Get());
|
||
MapOffsetY = Offset;
|
||
_MapInfo["background_pos"] = Offset;
|
||
}
|
||
else if (Segment == "[map name]")
|
||
{
|
||
_MapInfo["name"] = Data.Get();
|
||
}
|
||
else if (Segment == "[limit map camera move]")
|
||
{
|
||
std::vector<int> limit;
|
||
limit.push_back(std::stoi(Data.Get()));
|
||
limit.push_back(std::stoi(Data.Get()));
|
||
limit.push_back(std::stoi(Data.Get()));
|
||
limit.push_back(std::stoi(Data.Get()));
|
||
_MapInfo["limit_map_camera_move"] = limit;
|
||
}
|
||
else if (Segment == "[wide mode camera vertical correction]")
|
||
{
|
||
_MapInfo["wide_mode_camer_vertical_correction"] = std::stoi(Data.Get());
|
||
}
|
||
else if (Segment == "[tile]")
|
||
{
|
||
std::vector<std::string> tileArry;
|
||
while (true)
|
||
{
|
||
auto tiledata = Data.Get();
|
||
if (tiledata == "[/tile]")
|
||
break;
|
||
tileArry.push_back(_MapDir + Tool_toLowerCase(tiledata));
|
||
}
|
||
_MapInfo["tile"] = tileArry;
|
||
}
|
||
else if (Segment == "[extended tile]")
|
||
{
|
||
std::vector<std::string> tileArry;
|
||
while (true)
|
||
{
|
||
auto tiledata = Data.Get();
|
||
if (tiledata == "[/extended tile]")
|
||
break;
|
||
tileArry.push_back(_MapDir + Tool_toLowerCase(tiledata));
|
||
}
|
||
_MapInfo["extended_tile"] = tileArry;
|
||
}
|
||
else if (Segment == "[far sight scroll]" || Segment == "[middle sight scroll]" || Segment == "[near sight scroll]")
|
||
{
|
||
_MapInfo[Segment.substr(1, Segment.length() - 2)] = std::stoi(Data.Get());
|
||
}
|
||
else if (Segment == "[background animation]")
|
||
{
|
||
std::vector<BackGroundAni> Arr;
|
||
while (true)
|
||
{
|
||
std::string aniData = Data.Get();
|
||
if (aniData == "[/background animation]")
|
||
break;
|
||
if (aniData == "[ani info]")
|
||
{
|
||
BackGroundAni ani;
|
||
Data.Get();
|
||
ani.filename = Tool_RegRealPath(_MapDir + Tool_toLowerCase(Data.Get()));
|
||
Data.Get();
|
||
ani.layer = Data.Get();
|
||
Data.Get();
|
||
ani.order = Data.Get();
|
||
Arr.push_back(ani);
|
||
}
|
||
}
|
||
_MapInfo["background_animation"] = Arr;
|
||
}
|
||
else if (Segment == "[sound]")
|
||
{
|
||
std::map<std::string, bool> soundArry;
|
||
while (true)
|
||
{
|
||
std::string sounddata = Data.Get();
|
||
if (sounddata == "[/sound]")
|
||
break;
|
||
soundArry[sounddata] = true;
|
||
}
|
||
_MapInfo["sound"] = soundArry;
|
||
}
|
||
else if (Segment == "[animation]")
|
||
{
|
||
std::vector<MapAni> aniArry;
|
||
while (true)
|
||
{
|
||
std::string aniData = Data.Get();
|
||
if (aniData == "[/animation]")
|
||
break;
|
||
MapAni info;
|
||
info.filename = Tool_RegRealPath(_MapDir + Tool_toLowerCase(aniData));
|
||
info.layer = Data.Get();
|
||
info.XPos = std::stoi(Data.Get());
|
||
info.YPos = std::stoi(Data.Get());
|
||
info.ZPos = std::stoi(Data.Get());
|
||
aniArry.push_back(info);
|
||
}
|
||
_MapInfo["animation"] = aniArry;
|
||
}
|
||
else if (Segment == "[NPC]")
|
||
{
|
||
std::vector<MapNpc> npcArry;
|
||
while (true)
|
||
{
|
||
std::string npcData = Data.Get();
|
||
if (npcData == "[/NPC]")
|
||
break;
|
||
MapNpc info;
|
||
info.id = std::stoi(npcData);
|
||
info.direction = Data.Get();
|
||
info.XPos = std::stoi(Data.Get());
|
||
info.YPos = std::stoi(Data.Get());
|
||
info.ZPos = std::stoi(Data.Get());
|
||
npcArry.push_back(info);
|
||
}
|
||
_MapInfo["NPC"] = npcArry;
|
||
}
|
||
else if (Segment == "[town movable area]")
|
||
{
|
||
std::vector<int> town_movable_area;
|
||
std::vector<MapMoveArea> town_movable_area_info;
|
||
while (true)
|
||
{
|
||
std::string areadata = Data.Get();
|
||
if (areadata == "[/town movable area]")
|
||
break;
|
||
int x1 = std::stoi(areadata);
|
||
int y1 = std::stoi(Data.Get());
|
||
int x2 = std::stoi(Data.Get());
|
||
int y2 = std::stoi(Data.Get());
|
||
town_movable_area.push_back(x1);
|
||
town_movable_area.push_back(y1);
|
||
town_movable_area.push_back(x2);
|
||
town_movable_area.push_back(y2);
|
||
MapMoveArea T;
|
||
T.town = std::stoi(Data.Get());
|
||
T.area = std::stoi(Data.Get());
|
||
town_movable_area_info.push_back(T);
|
||
}
|
||
_MapInfo["town_movable_area"] = town_movable_area;
|
||
_MapInfo["town_movable_area_info"] = town_movable_area_info;
|
||
}
|
||
else if (Segment == "[virtual movable area]")
|
||
{
|
||
std::vector<int> virtual_movable_area;
|
||
while (true)
|
||
{
|
||
std::string areadata = Data.Get();
|
||
if (areadata == "[/virtual movable area]")
|
||
break;
|
||
virtual_movable_area.push_back(std::stoi(areadata));
|
||
virtual_movable_area.push_back(std::stoi(Data.Get()));
|
||
virtual_movable_area.push_back(std::stoi(Data.Get()));
|
||
virtual_movable_area.push_back(std::stoi(Data.Get()));
|
||
}
|
||
_MapInfo["virtual_movable_area"] = virtual_movable_area;
|
||
}
|
||
}
|
||
}
|
||
|
||
void GameMap::InitTile()
|
||
{
|
||
if (!_MapInfo.count("tile"))
|
||
return;
|
||
// 普通地板数量
|
||
int NormalTileCount = 0;
|
||
// 普通地板高度
|
||
int NormalTileHeight = 560;
|
||
std::vector<std::string> tileArr;
|
||
std::vector<std::string> extileArr;
|
||
|
||
tileArr = std::get<std::vector<std::string>>(_MapInfo["tile"]);
|
||
|
||
// 拓展地板不一定有
|
||
if (_MapInfo.count("extended_tile"))
|
||
{
|
||
extileArr = std::get<std::vector<std::string>>(_MapInfo["extended_tile"]);
|
||
}
|
||
|
||
_Tile = new Tile(this, tileArr, extileArr);
|
||
_Tile->SetPosition(0, -200 - std::get<int>(_MapInfo["background_pos"]));
|
||
_LayerMap["bottom"]->AddChild(_Tile);
|
||
}
|
||
|
||
void GameMap::InitBackgroundAnimation()
|
||
{
|
||
float Rate = _MapInfo.count("far_sight_scroll") ? std::get<int>(_MapInfo["far_sight_scroll"]) / 100.0f : 1.0f;
|
||
(void)Rate;
|
||
// TODO 摄像机
|
||
if (_MapInfo.count("background_animation"))
|
||
{
|
||
std::vector<BackGroundAni> aniArr = std::get<std::vector<BackGroundAni>>(_MapInfo["background_animation"]);
|
||
for (auto &ani : aniArr)
|
||
{
|
||
std::string path = ani.filename;
|
||
std::vector<RefPtr<Animation>> AniList;
|
||
RefPtr<Animation> AniObj = new Animation(path);
|
||
int width = AniObj->GetSize().width;
|
||
AniList.push_back(AniObj);
|
||
for (int i = 0; i < (_MapLength * Rate) / width; i++)
|
||
{
|
||
RefPtr<Animation> AniObj = new Animation(path);
|
||
AniList.push_back(AniObj);
|
||
}
|
||
for (int i = 0; i < (int)AniList.size(); i++)
|
||
{
|
||
AniList[i]->SetPosition(i * width, -120);
|
||
AniList[i]->SetZOrder(-1000000);
|
||
std::string layer = ani.layer;
|
||
layer = layer.substr(1, layer.length() - 2);
|
||
if (_LayerMap.count(layer))
|
||
{
|
||
_LayerMap[layer]->AddChild(AniList[i]);
|
||
}
|
||
else
|
||
{
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void GameMap::InitMapAnimation()
|
||
{
|
||
if (_MapInfo.count("animation"))
|
||
{
|
||
std::vector<MapAni> aniArr = std::get<std::vector<MapAni>>(_MapInfo["animation"]);
|
||
for (auto &ani : aniArr)
|
||
{
|
||
std::string path = ani.filename;
|
||
RefPtr<Animation> AniObj = new Animation(path);
|
||
AniObj->SetPosition(ani.XPos, ani.YPos - ani.ZPos);
|
||
AniObj->SetZOrder(ani.YPos);
|
||
std::string layer = ani.layer;
|
||
layer = layer.substr(1, layer.length() - 2);
|
||
if (_LayerMap.count(layer))
|
||
{
|
||
_LayerMap[layer]->AddChild(AniObj);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void GameMap::InitVirtualMovableArea()
|
||
{
|
||
std::vector<int> Info = std::get<std::vector<int>>(_MapInfo["virtual_movable_area"]);
|
||
if (Info.size() > 0)
|
||
{
|
||
for (int i = 0; i < Info.size(); i += 4)
|
||
{
|
||
float x = Info[i];
|
||
float y = Info[i + 1];
|
||
float w = Info[i + 2];
|
||
float h = Info[i + 3];
|
||
if (_DebugMode)
|
||
_LayerMap["max"]->AddDebugFeasibleAreaInfo(Vec2(x, y), VecSize(w, h), 0);
|
||
_MovableArea.push_back(SDL_FRect{x, y, w, h});
|
||
}
|
||
}
|
||
}
|
||
|
||
void GameMap::InitMoveArea()
|
||
{
|
||
std::vector<int> Info = std::get<std::vector<int>>(_MapInfo["town_movable_area"]);
|
||
if (Info.size() > 0)
|
||
{
|
||
for (int i = 0; i < Info.size(); i += 4)
|
||
{
|
||
float x = Info[i];
|
||
float y = Info[i + 1];
|
||
float w = Info[i + 2];
|
||
float h = Info[i + 3];
|
||
if (_DebugMode)
|
||
_LayerMap["max"]->AddDebugFeasibleAreaInfo(Vec2(x, y), VecSize(w, h), 1);
|
||
_MoveArea.push_back(SDL_FRect{x, y, w, h});
|
||
}
|
||
}
|
||
}
|
||
|
||
void GameMap::LoadMap(std::string mapName)
|
||
{
|
||
// 读取脚本配置
|
||
InitConfiguration(mapName);
|
||
// 初始化地板
|
||
InitTile();
|
||
// 初始化背景动画
|
||
InitBackgroundAnimation();
|
||
// 初始化场景Ani
|
||
InitMapAnimation();
|
||
// 初始化可行区域
|
||
InitVirtualMovableArea();
|
||
// 初始化传送区域
|
||
InitMoveArea();
|
||
}
|
||
|
||
void GameMap::Enter()
|
||
{
|
||
auto &Audio = Asset_SoundPack::GetInstance();
|
||
// 获取背景音乐
|
||
auto bgmIt = _MapInfo.find("sound");
|
||
if (bgmIt != _MapInfo.end())
|
||
{
|
||
std::map<std::string, bool> bgmlist = std::get<std::map<std::string, bool>>(_MapInfo["sound"]);
|
||
// 获取正在播放的背景音乐
|
||
std::map<std::string, int> curmap = Audio.GetBackgroudMusicVector();
|
||
for (auto &it : curmap)
|
||
{
|
||
std::string name = it.first;
|
||
// 判断正在播放的背景音乐是否与当前地图背景音乐相同
|
||
if (!bgmlist.count(name))
|
||
{
|
||
Audio.StopAudio(name);
|
||
}
|
||
}
|
||
// 播放当前地图背景音乐
|
||
for (auto &it : bgmlist)
|
||
{
|
||
std::string name = it.first;
|
||
if (!curmap.count(name))
|
||
Audio.PlayAudio(name);
|
||
}
|
||
}
|
||
}
|
||
|
||
void GameMap::OnUpdate(float deltaTime)
|
||
{
|
||
Actor::OnUpdate(deltaTime);
|
||
|
||
RefPtr<GameCamera> Cam = Global_Game::GetInstance().GetCamera();
|
||
if (Cam == nullptr)
|
||
return;
|
||
float targetX = Cam->_currentPosition.x;
|
||
float targetY = Cam->_currentPosition.y;
|
||
// 屏幕中心
|
||
float width_Separate = 1280.0f / 1.2f / 2.0f;
|
||
float height_Separate = 600.0f / 2.0f;
|
||
|
||
// 获取摄像机可行区域限制
|
||
auto limitIt = _MapInfo.find("limit_map_camera_move");
|
||
if (limitIt != _MapInfo.end())
|
||
{
|
||
std::vector<int> limit = std::get<std::vector<int>>(_MapInfo["limit_map_camera_move"]);
|
||
float X_Limit_Min = limit[0];
|
||
float X_Limit_Max = limit[1];
|
||
float Y_Limit_Min = limit[2];
|
||
float Y_Limit_Max = limit[3];
|
||
// 应用地图边界限制
|
||
targetX = std::clamp(targetX, width_Separate, (float)_MapLength - width_Separate);
|
||
targetY = std::clamp(targetY, height_Separate, (float)_MapHeight - height_Separate);
|
||
// 应用自定义摄像机移动限制
|
||
if (X_Limit_Min != -1)
|
||
targetX = std::max(targetX, X_Limit_Min);
|
||
if (X_Limit_Max != -1)
|
||
targetX = std::min(targetX, X_Limit_Max);
|
||
if (Y_Limit_Min != -1)
|
||
targetY = std::max(targetY, Y_Limit_Min);
|
||
if (Y_Limit_Max != -1)
|
||
targetY = std::min(targetY, Y_Limit_Max);
|
||
}
|
||
|
||
// 更新图层位置
|
||
for (auto &Layer : _LayerMap)
|
||
{
|
||
float posX = -targetX + width_Separate;
|
||
float posY = -targetY + height_Separate + MapOffsetY;
|
||
if (Layer.first == "distantback")
|
||
{
|
||
posX *= BackgroundMoveSpeed;
|
||
posX /= 100.0f;
|
||
}
|
||
Layer.second->SetPosition(posX, posY);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
void GameMap::AddObject(RefPtr<BaseObject> object)
|
||
{
|
||
object->_AffMap = this;
|
||
_LayerMap["normal"]->AddObject(object);
|
||
// 如果是角色对象
|
||
if (object->m_objecttype == ObjectType::CHARACTER)
|
||
{
|
||
CharacterObject *chr = (CharacterObject *)(object.Get());
|
||
Global_Game::GetInstance().GetCamera()->SetFromActor(chr);
|
||
}
|
||
}
|
||
|
||
VecFPos3 GameMap::CheckIsItMovable(VecFPos3 CurPos, VecFPos3 PosOffset)
|
||
{
|
||
// 初始化结果为原坐标(默认不移动)
|
||
VecFPos3 result = CurPos;
|
||
|
||
// 如果没有可移动区域限制,直接全量位移
|
||
if (_MovableArea.empty())
|
||
{
|
||
result.x += PosOffset.x;
|
||
result.y += PosOffset.y;
|
||
result.z += PosOffset.z; // Z轴不受限
|
||
return result;
|
||
}
|
||
|
||
// 计算X轴单独位移后的目标位置
|
||
float targetX = CurPos.x + PosOffset.x;
|
||
// 计算Y轴单独位移后的目标位置
|
||
float targetY = CurPos.y + PosOffset.y;
|
||
|
||
// 检查X轴位移是否合法(固定Y为当前值,仅移动X)
|
||
SDL_FPoint xTestPoint{targetX, CurPos.y};
|
||
bool isXValid = false;
|
||
for (auto &area : _MovableArea)
|
||
{
|
||
if (SDL_PointInFRect(&xTestPoint, &area))
|
||
{
|
||
isXValid = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 检查Y轴位移是否合法(固定X为当前值,仅移动Y)
|
||
SDL_FPoint yTestPoint{CurPos.x, targetY};
|
||
bool isYValid = false;
|
||
for (auto &area : _MovableArea)
|
||
{
|
||
if (SDL_PointInFRect(&yTestPoint, &area))
|
||
{
|
||
isYValid = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 应用合法的位移
|
||
if (isXValid)
|
||
{
|
||
result.x = targetX; // X轴允许移动
|
||
}
|
||
if (isYValid)
|
||
{
|
||
result.y = targetY; // Y轴允许移动
|
||
}
|
||
// Z轴不受限制,直接应用位移
|
||
result.z += PosOffset.z;
|
||
|
||
return result;
|
||
}
|
||
|
||
GameMap::MapMoveArea GameMap::CheckIsItMoveArea(VecFPos3 ChrPos)
|
||
{
|
||
|
||
MapMoveArea invalidArea;
|
||
invalidArea.town = -2;
|
||
invalidArea.area = -2;
|
||
|
||
if (_MoveArea.size() && _MapInfo.count("town_movable_area_info"))
|
||
{
|
||
SDL_FPoint CurPos = {ChrPos.x, ChrPos.y};
|
||
|
||
for (int i = 0; i < _MoveArea.size(); i++)
|
||
{
|
||
if (SDL_PointInFRect(&CurPos, &_MoveArea[i]))
|
||
{
|
||
const std::vector<MapMoveArea> &tma = std::get<std::vector<MapMoveArea>>(_MapInfo["town_movable_area_info"]);
|
||
return tma[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
// 所有矩形都不命中,返回无效值
|
||
return invalidArea;
|
||
}
|
||
|
||
std::vector<GameMap::MapMoveArea> &GameMap::GetMoveAreaInfo()
|
||
{
|
||
return std::get<std::vector<GameMap::MapMoveArea>>(_MapInfo["town_movable_area_info"]);
|
||
}
|
||
|
||
SDL_Rect GameMap::GetMovablePositionArea(int Index)
|
||
{
|
||
auto Vertex = std::get<std::vector<int>>(_MapInfo["town_movable_area"]);
|
||
int FindIndex = Index * 4;
|
||
SDL_Rect Buf = {Vertex[FindIndex], Vertex[FindIndex + 1], Vertex[FindIndex + 2], Vertex[FindIndex + 3]};
|
||
return Buf;
|
||
}
|