This commit is contained in:
2025-10-06 04:18:49 +08:00
commit df2cacdb92
2784 changed files with 1280840 additions and 0 deletions

View File

@@ -0,0 +1,369 @@
#include "GameMap.h"
#include "Asset/AssetManager.h"
#include "EngineFrame/Scene/Scene.h"
#include "EngineFrame/Component/Animation.h"
#include "Actor/Map/GameMapCamera.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"]->SetRenderZOrder(10000);
_LayerMap["distantback"]->SetRenderZOrder(50000);
_LayerMap["middleback"]->SetRenderZOrder(100000);
_LayerMap["bottom"]->SetRenderZOrder(150000);
_LayerMap["closeback"]->SetRenderZOrder(200000);
_LayerMap["normal"]->SetRenderZOrder(250000);
_LayerMap["close"]->SetRenderZOrder(300000);
_LayerMap["cover"]->SetRenderZOrder(350000);
_LayerMap["max"]->SetRenderZOrder(400000);
}
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]")
{
_MapInfo["background_pos"] = std::stoi(Data.Get());
}
else if (Segment == "[map name]")
{
_MapInfo["name"] = Data.Get();
}
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 = _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::vector<std::string> soundArry;
while (true)
{
std::string sounddata = Data.Get();
if (sounddata == "[/sound]")
break;
soundArry.push_back(sounddata);
}
_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;
town_movable_area.push_back(std::stoi(areadata));
town_movable_area.push_back(std::stoi(areadata));
town_movable_area.push_back(std::stoi(areadata));
town_movable_area.push_back(std::stoi(areadata));
MapMoveArea T;
T.town = std::stoi(areadata);
T.area = std::stoi(areadata);
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;
std::vector<std::string> tileArr = std::get<std::vector<std::string>>(_MapInfo["tile"]);
if (tileArr.size() > 0)
{
NormalTileCount = tileArr.size();
_MapLength = NormalTileCount * 224;
for (int i = 0; i < NormalTileCount; i++)
{
std::string path = tileArr[i];
RefPtr<Tile> tile = new Tile(path);
tile->SetPos(VecFPos{i * 224, -200 - std::get<int>(_MapInfo["background_pos"])});
_LayerMap["bottom"]->AddComponent(tile);
}
_MapHeight = 560;
}
if (_MapInfo.count("extended_tile"))
{
std::vector<std::string> extileArr = std::get<std::vector<std::string>>(_MapInfo["extended_tile"]);
if (extileArr.size() > 0)
{
int ExTileCount = extileArr.size();
int Buffer = (ExTileCount / NormalTileCount);
_MapHeight += (Buffer < 1 ? 1 : Buffer) * 40;
for (int i = 0; i < ExTileCount; i++)
{
std::string path = extileArr[i];
RefPtr<Tile> tile = new Tile(path);
int xbuf = i % NormalTileCount * 224;
int ybuf = 560 - 200 - std::get<int>(_MapInfo["background_pos"]) + 40 * (i / NormalTileCount);
tile->SetPos(VecFPos{xbuf, ybuf});
_LayerMap["bottom"]->AddComponent(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]->SetPos(VecFPos{i * width, -120});
AniList[i]->SetRenderZOrder(-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->SetPos(VecFPos{ani.XPos, ani.YPos - ani.ZPos});
AniObj->SetRenderZOrder(ani.YPos);
std::string layer = ani.layer;
layer = layer.substr(1, layer.length() - 2);
if (_LayerMap.count(layer))
{
_LayerMap[layer]->AddChild(AniObj);
}
}
}
}
void GameMap::LoadMap(std::string mapName)
{
// 读取脚本配置
InitConfiguration(mapName);
// 初始化地板
InitTile();
// 初始化背景动画
InitBackgroundAnimation();
// 初始化场景Ani
InitMapAnimation();
RefPtr<CharacterObject> obj = new CharacterObject();
obj->SetPosition({620, 200, 0});
obj->Construction(0);
_LayerMap["normal"]->AddObject(obj);
}
void GameMap::Enter(Scene *scene)
{
scene->AddChild(_LayerMap["contact"]);
scene->AddChild(_LayerMap["distantback"]);
scene->AddChild(_LayerMap["middleback"]);
scene->AddChild(_LayerMap["bottom"]);
scene->AddChild(_LayerMap["closeback"]);
scene->AddChild(_LayerMap["normal"]);
scene->AddChild(_LayerMap["close"]);
scene->AddChild(_LayerMap["cover"]);
scene->AddChild(_LayerMap["max"]);
// TODO
int HSU = 230;
_LayerMap["contact"]->SetPos(VecFPos{0, HSU});
_LayerMap["distantback"]->SetPos(VecFPos{0, HSU});
_LayerMap["middleback"]->SetPos(VecFPos{0, HSU});
_LayerMap["bottom"]->SetPos(VecFPos{0, HSU});
_LayerMap["closeback"]->SetPos(VecFPos{0, HSU});
_LayerMap["normal"]->SetPos(VecFPos{0, HSU});
_LayerMap["close"]->SetPos(VecFPos{0, HSU});
_LayerMap["cover"]->SetPos(VecFPos{0, HSU});
_LayerMap["max"]->SetPos(VecFPos{0, HSU});
}
void GameMap::HandleEvents(SDL_Event *e)
{
}
void GameMap::Update(float deltaTime)
{
// this->_Camera->Update(deltaTime);
// if (this->_Camera)
// {
// int CamearXpos = this->_Camera->X;
// int CamearYpos = this->_Camera->Y;
// int CamearZpos = this->_Camera->Z;
// SDL_Log("Camera Pos: %d, %d", CamearXpos, CamearYpos);
// // 遍历
// for (auto &pair : _LayerMap)
// {
// // pair.first 是 keystd::string
// std::string key = pair.first;
// // pair.second 是 valueRefPtr<GameMapLayer>
// RefPtr<GameMapLayer> &value = pair.second;
// if (key == "distantback")
// {
// value->SetPos(VecPos{(-CamearXpos + 553), (-CamearYpos + CamearZpos + 300 + 120 + 80)});
// }
// else
// {
// value->SetPos(VecPos{(-CamearXpos + 553), (-CamearYpos + CamearZpos + 300 + 120 + 80)});
// }
// }
// }
}

View File

@@ -0,0 +1,87 @@
#pragma once
#include "Actor/Map/GameMapLayer.h"
#include "Asset/Asset_Script.h"
#include "Actor/Map/Tile.h"
#include <unordered_map>
#include <vector>
#include <variant>
class BaseObject;
class GameMapCamera;
class GameMap
{
struct BackGroundAni
{
std::string filename;
std::string layer;
std::string order;
};
struct MapAni
{
std::string filename;
std::string layer;
int XPos;
int YPos;
int ZPos;
};
struct MapNpc
{
int id;
std::string direction;
int XPos;
int YPos;
int ZPos;
};
struct MapMoveArea
{
int town;
int area;
};
using MapInfoBody = std::variant<
int,
std::string,
std::vector<BackGroundAni>,
std::vector<MapAni>,
std::vector<MapNpc>,
std::vector<MapMoveArea>,
std::vector<int>,
std::vector<std::string>>;
public:
// 地图信息
std::unordered_map<std::string, MapInfoBody> _MapInfo;
// 地图路径
std::string _MapPath;
// 地图文件夹
std::string _MapDir;
// 地图宽度
int _MapLength = 0;
// 地图高度
int _MapHeight = 0;
public:
// 图层Map 图层类型 显示对象
std::unordered_map<std::string, RefPtr<GameMapLayer>> _LayerMap;
// 摄像机对象
GameMapCamera *_Camera;
public:
GameMap(/* args */);
~GameMap();
void LoadMap(std::string mapName);
void InitConfiguration(std::string mapName);
void InitTile();
void InitBackgroundAnimation();
void InitMapAnimation();
void Enter(Scene *scene);
void HandleEvents(SDL_Event *e);
void Update(float deltaTime);
public:
};

View File

@@ -0,0 +1,54 @@
#include "GameMapCamera.h"
#include "Actor/Map/GameMap.h"
#include "Actor/Object/BaseObject.h"
#include <algorithm>
GameMapCamera::GameMapCamera()
{
}
GameMapCamera::~GameMapCamera()
{
}
void GameMapCamera::SetParentMap(GameMap *map)
{
this->_ParentMap = map;
_ParentMap->_Camera = this;
}
void GameMapCamera::SetFromActor(BaseObject *actor)
{
this->_FromActor = actor;
}
void GameMapCamera::Update(float deltaTime)
{
SyncPosByFromParent(deltaTime);
}
void GameMapCamera::SetPos(int x, int y, int z)
{
this->X = x;
this->Y = y;
this->Z = z;
}
void GameMapCamera::AddPos(int x, int y, int z)
{
this->X += x;
this->Y += y;
this->Z += z;
}
void GameMapCamera::SyncPosByFromParent(float deltaTime)
{
if (this->_FromActor != nullptr)
{
// int R_X, R_Y, R_Z;
// R_X = std::min(std::max(this->_FromActor->X, 533), MovableAreaX - 533);
// R_Y = std::min(std::max(this->_FromActor->Y, 300), MovableAreaY - 300);
// R_Z = 0;
// SetPos(R_X, R_Y, R_Z);
}
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include "EngineFrame/Actor/Actor.h"
class GameMap;
class BaseObject;
class GameMapCamera : public Actor
{
private:
GameMap *_ParentMap = nullptr;
// 跟随对象
BaseObject *_FromActor = nullptr;
public:
// 摄像机坐标
int X = 0;
int Y = 0;
int Z = 0;
// 镜头可行坐标
int MovableAreaX = 0;
int MovableAreaY = 0;
// 背景偏移量
int BackgroundOffset = 0;
// 背景层移动速率
int BackgroundMoveSpeed = 1.0;
// 人物中线长度
int CharacterLineLength = 0;
// 摄像机朝向
int Direction = 1;
// 摄像机朝向时间
float DirectionTime = 0.f;
// 缩放比率
float CameraRate = 1.0;
public:
GameMapCamera();
~GameMapCamera();
void SetParentMap(GameMap *map);
void SetFromActor(BaseObject *actor);
void Update(float deltaTime);
void SetPos(int x, int y, int z);
void AddPos(int x, int y, int z);
void SyncPosByFromParent(float deltaTime);
};

View File

@@ -0,0 +1,14 @@
#include "GameMapLayer.h"
GameMapLayer::GameMapLayer()
{
}
GameMapLayer::~GameMapLayer()
{
}
void GameMapLayer::AddObject(RefPtr<Actor> obj)
{
this->AddChild(obj);
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "EngineFrame/Actor/Actor.h"
#include "EngineFrame/Component/Sprite.h"
class BaseObject;
class GameMapLayer : public Actor
{
private:
// 地图对象
std::vector<RefPtr<Component>> ObjectManager;
public:
GameMapLayer(/* args */);
~GameMapLayer();
public:
void AddObject(RefPtr<Actor> obj); // 添加对象
};

View File

@@ -0,0 +1,45 @@
#include "Tile.h"
#include "Tool/Tool_String.h"
Tile::Tile()
{
}
Tile::Tile(std::string Path) : Sprite()
{
InitInfo(Path);
if (std::get<std::string>(m_data["path"]) == "")
m_data["path"] = "sprite/character/common/circlecooltime.img";
m_texture = new Texture(std::get<std::string>(m_data["path"]), std::get<int>(m_data["idx"]));
Sprite::Init();
}
Tile::~Tile()
{
}
void Tile::SetPos(VecFPos pos)
{
pos.y += std::get<int>(m_data["pos"]);
Sprite::SetPos(pos);
}
void Tile::InitInfo(std::string Path)
{
ScriptData Data = AssetManager::GetInstance().GetScriptInfo(Path);
m_data["pos"] = 0;
while (!Data.IsEnd())
{
std::string Segment = Data.Get();
if (Segment == "[IMAGE]")
{
std::string PathBuf = Tool_toLowerCase(Data.Get());
m_data["path"] = "sprite/" + PathBuf;
m_data["idx"] = std::stoi(Data.Get());
}
else if (Segment == "[img pos]")
{
m_data["pos"] = std::stoi(Data.Get());
}
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "Asset/AssetManager.h"
#include "EngineFrame/Component/Sprite.h"
class Tile : public Sprite
{
using TileInfoBody = std::variant<
int,
std::string>;
private:
std::unordered_map<std::string, TileInfoBody> m_data;
public:
Tile(/* args */);
Tile(std::string Path);
~Tile();
void SetPos(VecFPos pos) override;
void InitInfo(std::string Path);
};

View File

@@ -0,0 +1,50 @@
#include "ActiveObject.h"
void ActiveObject::SetPosition(VecFPos3 pos)
{
BaseObject::SetPosition(pos);
BaseObject::SetRenderZOrder(this->Position.y);
}
void ActiveObject::SetYpos(float y)
{
BaseObject::SetYpos(y);
BaseObject::SetRenderZOrder(this->Position.y);
}
void ActiveObject::SetSpeed(VecSpeed3 speed)
{
this->Speed = speed;
}
VecSpeed3 ActiveObject::GetSpeed()
{
return this->Speed;
}
void ActiveObject::Update(float deltaTime)
{
// X Y 轴方向的加速度计算
if (Speed.x != 0 || Speed.y != 0)
{
MoveBy(Speed.x * deltaTime, Speed.y * deltaTime, 0);
}
// Z轴只在Z轴大于0时 或者 Z轴速度向上时才会有重力
if (Position.z > 0 || Speed.z > 0)
{
// TODO 还没有写角色属性 要读了角色属性以后才是正确的
float Gravity = 68000.0 / 1000.0 * 15.0;
Speed.z -= Gravity * deltaTime;
MoveBy(0, 0, Speed.z * deltaTime);
}
// Z轴小于0时要修正
else if (Position.z < 0)
{
Position.z = 0;
Speed.z = 0;
SetPosition(Position);
SDL_LogError(0, "修正Z轴");
}
// 执行父对象的更新
BaseObject::Update(deltaTime);
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "Actor/Object/BaseObject.h"
class ActiveObject : public BaseObject
{
public:
VecSpeed3 Speed;
public:
void SetPosition(VecFPos3 pos) override;
void SetYpos(float y) override;
void SetSpeed(VecSpeed3 speed);
VecSpeed3 GetSpeed();
public:
void Update(float deltaTime) override;
};

View File

@@ -0,0 +1,97 @@
#include "BaseObject.h"
BaseObject::BaseObject()
{
Init(); // 调用了RenderBase的Init函数 对象才会被执行回调
SetAnchor({0.5f, 0.5f});
}
BaseObject::~BaseObject()
{
}
void BaseObject::SetPosition(VecFPos3 pos)
{
this->Position = pos;
Actor::SetPos(VecFPos{this->Position.x, this->Position.y - this->Position.z});
}
VecFPos3 BaseObject::GetPosition()
{
return this->Position;
}
void BaseObject::SetXpos(float x)
{
this->Position.x = x;
Actor::SetPos({this->Position.x, this->Position.y - this->Position.z});
}
void BaseObject::SetYpos(float y)
{
this->Position.y = y;
Actor::SetPos({this->Position.x, this->Position.y - this->Position.z});
}
void BaseObject::SetZpos(float z)
{
this->Position.z = z;
Actor::SetPos({this->Position.x, this->Position.y - this->Position.z});
}
int BaseObject::GetXpos()
{
return this->Position.x;
}
int BaseObject::GetYpos()
{
return this->Position.y;
}
int BaseObject::GetZpos()
{
return this->Position.z;
}
void BaseObject::MoveBy(VecFPos3 pos)
{
this->Position.x += pos.x;
this->Position.y += pos.y;
this->Position.z += pos.z;
Actor::SetPos({this->Position.x, this->Position.y - this->Position.z});
}
void BaseObject::MoveBy(float x, float y, float z)
{
this->Position.x += x;
this->Position.y += y;
this->Position.z += z;
Actor::SetPos({this->Position.x, this->Position.y - this->Position.z});
}
void BaseObject::SetDirection(int dir)
{
this->Direction = dir;
VecFPos sc = GetScale();
// 朝右
if (dir == 0)
{
SetScale(VecFPos({SDL_fabsf(sc.x), sc.y}));
}
// 朝左
else if (dir == 1)
{
SetScale(VecFPos({-SDL_fabsf(sc.x), sc.y}));
}
}
int BaseObject::GetDirection()
{
return this->Direction;
}
ObjectVars &BaseObject::GetObjectVars()
{
return _ObjectVars;
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include "EngineFrame/Actor/Actor.h"
#include "Asset/Common/ObjectVars.h"
class BaseObject : public Actor
{
private:
/* data */
public:
VecFPos3 Position; // 位置
int Direction = 0; // 方向
public:
BaseObject(/* args */);
~BaseObject();
// 数据储存器
ObjectVars _ObjectVars;
public:
virtual void SetPosition(VecFPos3 pos);
virtual void SetXpos(float x);
virtual void SetYpos(float y);
virtual void SetZpos(float z);
VecFPos3 GetPosition();
int GetXpos();
int GetYpos();
int GetZpos();
void MoveBy(VecFPos3 pos);
void MoveBy(float x, float y, float z);
void SetDirection(int dir);
int GetDirection();
ObjectVars &GetObjectVars();
};

View File

@@ -0,0 +1,57 @@
#include "CharacterObject.h"
#include "Asset/Squirrel/SquirrelManager.h"
CharacterObject::~CharacterObject()
{
}
void CharacterObject::Update(float deltaTime)
{
ActiveObject::Update(deltaTime);
}
void CharacterObject::Render()
{
ActiveObject::Render();
}
void CharacterObject::Construction(int job)
{
// 创建装备管理器
_EquipmentManager = new Chr_Equipment();
_EquipmentManager->Init(this);
// 创建动画管理器(一定要先创建装备管理器再创建动画管理器 因为需要读取身上的装备)
_AnimationManager = new Chr_Animation();
_AnimationManager->Init(this);
// 创建状态机
_StateMachine = new Chr_StateMachine();
_StateMachine->Init(this);
// 开启控制器
EnableController();
}
void CharacterObject::EnableController()
{
this->_Controller = new Chr_Controller();
_Controller->Init(this);
AddChild(_Controller);
}
void CharacterObject::DisableController()
{
this->RemoveChild(_Controller);
this->_Controller = nullptr;
}
void CharacterObject::ControllerMsg(CONTROLLER_MSG_TYPE msgType, void *msgData)
{
// 摇杆移动(左)
if (msgType == CONTROLLER_MSG_TYPE::CONTROLLER_MSG_TYPE_LEFT_JOYSTICK_MOVE)
{
VecFPos *pos = (VecFPos *)msgData;
std::vector<float> movedata = {pos->x, pos->y};
this->GetObjectVars().SetArray("_move_data_", movedata);
this->_StateMachine->ChangeState(BASE_STATE::MOVE);
}
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include "Actor/Object/ActiveObject.h"
#include "Asset/Character/Chr_Animation.h"
#include "Asset/Character/Chr_Equipment.h"
#include "Asset/Character/Chr_Controller.h"
#include "Asset/Character/Chr_StateMachine.h"
#include "Global/Global_Enum.h"
class CharacterObject : public ActiveObject
{
public:
// 角色动画管理器
RefPtr<Chr_Animation> _AnimationManager = nullptr;
// 装备管理器
RefPtr<Chr_Equipment> _EquipmentManager = nullptr;
// 角色控制器
RefPtr<Chr_Controller> _Controller = nullptr;
// 角色状态机
RefPtr<Chr_StateMachine> _StateMachine = nullptr;
// 职业
int Job = 0;
// 转职职业 如果是-1则没有转职
int GrowType = -1;
public:
~CharacterObject();
public:
void Update(float deltaTime) override;
void Render() override;
// 通过职业创建角色
void Construction(int job);
// 开启控制器
void EnableController();
// 关闭控制器
void DisableController();
// 控制器信息
void ControllerMsg(CONTROLLER_MSG_TYPE msgType, void* msgData);
};

View File

@@ -0,0 +1,116 @@
#include "Chr_Animation.h"
#include "Global/Global_Game.h"
#include "Actor/Object/CharacterObject.h"
#include "Asset/Character/Chr_Equipment.h"
std::string Chr_Animation::FormatImgPath(std::string ImgPath, Animation::ReplaceData data)
{
size_t pos = ImgPath.find("%04d");
if (pos != std::string::npos)
{
ImgPath.replace(pos, 4, "%02d%02d");
}
char buffer[256];
snprintf(buffer, sizeof(buffer), ImgPath.c_str(), data.Param1, data.Param2);
std::string newPath = buffer;
return newPath;
}
void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string slotName, std::string path)
{
// 皮肤在没有穿戴的情况下 格式化参数为0
if (slotName == "skin_avatar")
{
// 如果穿戴了皮肤时装 读取variation
RefPtr<Equipment> Equip = ((CharacterObject *)m_Parent)->_EquipmentManager->GetEquip(slotName);
if (Equip)
{
Animation::ReplaceData Data(0, 0);
for (auto &Variation : Equip->JobAni[this->chr_parent->Job])
{
Data.Param1 = Variation.ImgFormat[0];
Data.Param2 = Variation.ImgFormat[1];
// 构造好Ani以后 统一设置为不可见 然后放入ActionAnis表
RefPtr<Animation> Ani = new Animation(path, FormatImgPath, Data);
Ani->SetVisible(false);
Ani->SetRenderZOrder(Variation.Layer);
this->AddChild(Ani);
ActionAnis[actionName].push_back(Ani);
}
}
}
else
{
RefPtr<Equipment> Equip = ((CharacterObject *)m_Parent)->_EquipmentManager->GetEquip(slotName);
if (Equip)
{
// SDL_Log("CreateSkinmationBySlot %s", slotName.c_str());
Animation::ReplaceData Data(0, 0);
for (auto &Variation : Equip->JobAni[this->chr_parent->Job])
{
Data.Param1 = Variation.ImgFormat[0];
Data.Param2 = Variation.ImgFormat[1];
// 读取装备路径
std::string EquipPath = Tool_TruncatePath(Equip->m_EquipmentPath);
// 组装动画路径
std::string AniPath = EquipPath + Variation.AnimationGroup + path.substr(path.find_last_of("/"), path.length());
// 构造好Ani以后 统一设置为不可见 然后放入ActionAnis表
RefPtr<Animation> Ani = new Animation(AniPath, FormatImgPath, Data);
Ani->SetVisible(false);
Ani->SetRenderZOrder(Variation.Layer);
this->AddChild(Ani);
ActionAnis[actionName].push_back(Ani);
}
}
}
}
void Chr_Animation::Init(CharacterObject *parent)
{
// 调用RenderBase类的初始化 才能挂上标签
RenderBase::Init();
parent->AddChild(this);
chr_parent = parent;
GlobalCharacterScript::CharacterConfig Config = Global_Game::GetInstance().CharacterConfigs[parent->Job];
// 遍历所有动作Ani路径
for (const auto &pair : Config.animationPath)
{
std::string ActionName = pair.first;
std::string Path = std::string("character/" + Config.jobTag + "/" + Tool_toLowerCase(pair.second));
// 遍历所有时装部位构造Ani
for (auto &AvatarPartPair : AvatarPart)
{
std::string AvatarPartName = AvatarPartPair.first;
CreateSkinmationBySlot(ActionName, AvatarPartName, Path);
}
}
// 设置初始动作
SetAction("rest");
}
void Chr_Animation::SetAction(std::string actionName)
{
// 先将原动作的Ani设置为不可见
for (auto Ani : ActionAnis[CurrentActionTag])
{
Ani->Reset();
Ani->SetVisible(false);
}
// 再将新动作的Ani设置为可见
for (auto Ani : ActionAnis[actionName])
{
Ani->SetVisible(true);
}
CurrentActionTag = actionName;
}
void Chr_Animation::Update(float deltaTime)
{
RenderBase::Update(deltaTime);
// SDL_Log("Position %d %d", this->GetTransform().position.x, this->GetTransform().position.y);
// SDL_Log("IterPosition %d %d", this->GetIterationTransform().position.x, this->GetIterationTransform().position.y);
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include "EngineFrame/Component/Animation.h"
#include <string>
#include <vector>
#include <unordered_map>
class CharacterObject;
class Chr_Animation : public RenderBase
{
// 动作动画集合
using ActionAniList = std::map<std::string, std::vector<RefPtr<Animation>>>;
public:
inline static const std::unordered_map<std::string, std::string>
AvatarPart = {
{"weapon_avatar", "武器装扮"},
{"aurora_avatar", "光环装扮"},
{"hair_avatar", "头部装扮"},
{"hat_avatar", "帽子装扮"},
{"face_avatar", "脸部装扮"},
{"breast_avatar", "胸部装扮"},
{"coat_avatar", "上衣装扮"},
{"skin_avatar", "皮肤装扮"},
{"waist_avatar", "腰部装扮"},
{"pants_avatar", "下装装扮"},
{"shoes_avatar", "鞋子装扮"},
{"weapon", "武器"},
};
private:
// 父对象
CharacterObject *chr_parent;
// 时装部位对应的动作动画集合
ActionAniList ActionAnis;
// 当前动作Tag
std::string CurrentActionTag = "waiting";
public:
static std::string FormatImgPath(std::string path, Animation::ReplaceData data);
public:
void CreateSkinmationBySlot(std::string actionName, std::string slotName, std::string path);
public:
// 初始化时 只完成基础的职业皮肤设置
void Init(CharacterObject *parent);
// 设置动作
void SetAction(std::string actionName);
void Update(float deltaTime) override;
};

View File

@@ -0,0 +1,122 @@
#include "Chr_Controller.h"
#include "Actor/Object/CharacterObject.h"
float Chr_Controller::ConvertAxisValue(Sint16 rawValue)
{
float value = 0.f;
// SDL的轴值范围通常是-32768到32767
if (rawValue > 0)
{
value = static_cast<float>(rawValue) / 32767.0f;
}
else
{
value = static_cast<float>(rawValue) / 32768.0f;
}
// 小于0.1的值视为0
if (fabs(value) < 0.1f)
{
value = 0.f;
}
// 大于0.95的值视为1
else if (fabs(value) > 0.95f)
{
value = (value > 0) ? 1.f : -1.f;
}
return value;
}
void Chr_Controller::Init(CharacterObject *pCharacter)
{
addTag(Tag::HANDEL_EVENT);
m_pCharacter = pCharacter;
}
void Chr_Controller::HandleEvents(SDL_Event *e)
{
// 处理控制器相关事件
switch (e->type)
{
case SDL_CONTROLLERDEVICEADDED:
{
SDL_Log("手柄连接 - 设备ID: %d", e->cdevice.which);
int deviceIndex = e->cdevice.which;
if (SDL_IsGameController(deviceIndex))
{
SDL_GameController *controller = SDL_GameControllerOpen(deviceIndex);
if (controller)
{
SDL_Log("已连接并打开控制器: %s", SDL_GameControllerName(controller));
}
else
{
SDL_Log("连接了控制器但无法打开! SDL错误: %s", SDL_GetError());
}
}
break;
}
case SDL_CONTROLLERDEVICEREMOVED:
{
SDL_Log("手柄断开 - 设备ID: %d", e->cdevice.which);
break;
}
case SDL_CONTROLLERDEVICEREMAPPED:
{
SDL_Log("手柄重映射 - 设备ID: %d", e->cdevice.which);
break;
}
case SDL_CONTROLLERBUTTONDOWN:
{
SDL_Log("手柄按钮按下 - 控制器ID: %d, 按钮: %d",
e->cbutton.which, e->cbutton.button);
break;
}
case SDL_CONTROLLERBUTTONUP:
{
SDL_Log("手柄按钮释放 - 控制器ID: %d, 按钮: %d",
e->cbutton.which, e->cbutton.button);
break;
}
case SDL_CONTROLLERAXISMOTION:
{
// 转换原始轴值到-1到1范围
float value = ConvertAxisValue(e->caxis.value);
// 根据不同的轴更新对应的摇杆位置
switch (e->caxis.axis)
{
case SDL_CONTROLLER_AXIS_LEFTX:
LeftStick.x = value;
break;
case SDL_CONTROLLER_AXIS_LEFTY:
LeftStick.y = value;
break;
case SDL_CONTROLLER_AXIS_RIGHTX:
RightStick.x = value;
break;
case SDL_CONTROLLER_AXIS_RIGHTY:
RightStick.y = value;
break;
default:
break;
}
// 如果父对象存在 调用父对象的消息处理
if (m_pCharacter)
{
// 左摇杆变动时
if (e->caxis.axis == SDL_CONTROLLER_AXIS_LEFTX || e->caxis.axis == SDL_CONTROLLER_AXIS_LEFTY)
{
m_pCharacter->ControllerMsg(CONTROLLER_MSG_TYPE::CONTROLLER_MSG_TYPE_LEFT_JOYSTICK_MOVE, &LeftStick);
}
// 右摇杆变动时
else if (e->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX || e->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY)
{
m_pCharacter->ControllerMsg(CONTROLLER_MSG_TYPE::CONTROLLER_MSG_TYPE_RIGHT_JOYSTICK_MOVE, &RightStick);
}
}
break;
}
default:
// 可以处理其他类型的事件或忽略
break;
}
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "EngineFrame/Base/BaseNode.h"
#include "Tool/Common.h"
class CharacterObject;
class Chr_Controller : public BaseNode
{
private:
CharacterObject *m_pCharacter = nullptr;
public:
VecFPos LeftStick = {0.f, 0.f};
VecFPos RightStick = {0.f, 0.f};
// 用于将SDL的轴值(-32768到32767)转换为-1到1之间的浮点数
float ConvertAxisValue(Sint16 rawValue);
public:
void Init(CharacterObject *pCharacter);
void HandleEvents(SDL_Event *e) override;
// 获取摇杆位置的方法
const VecFPos &GetLeftStick() const { return LeftStick; }
const VecFPos &GetRightStick() const { return RightStick; }
};

View File

@@ -0,0 +1,38 @@
#include "Chr_Equipment.h"
#include "Global/Global_Game.h"
#include "Actor/Object/CharacterObject.h"
void Chr_Equipment::Init(CharacterObject *parent)
{
// 判断是否转职读取不同的配置
GlobalCharacterScript::JobConfig JobInfo;
if (parent->GrowType == -1)
{
JobInfo = Global_Game::GetInstance().CharacterConfigs[parent->Job].baseJobConfig;
}
else
{
GlobalCharacterScript::CharacterConfig Config = Global_Game::GetInstance().CharacterConfigs[parent->Job];
JobInfo = Config.growtypeJobConfig[parent->GrowType];
}
// 读取默认时装
for (auto &pair : JobInfo.defaultAvatarList)
{
std::string PartName = pair.first;
int Index = pair.second;
RefPtr<Equipment> equip = new Equipment();
equip->Init(Index);
this->_default_equip[PartName] = equip;
}
}
RefPtr<Equipment> Chr_Equipment::GetEquip(std::string part)
{
// 先看真实穿戴 如果没有 看默认 如果没有 返回空
if (_real_equip.count(part) > 0)
return _real_equip[part];
if (_default_equip.count(part) > 0)
return _default_equip[part];
return nullptr;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "EngineFrame/Component/Component.h"
#include "Asset/Common/Equipment.h"
class CharacterObject;
class Chr_Equipment : public Component
{
public:
// 默认装备
std::map<std::string, RefPtr<Equipment>> _default_equip;
// 真实穿戴装备
std::map<std::string, RefPtr<Equipment>> _real_equip;
public:
// 初始化
void Init(CharacterObject *parent);
// 获取部位穿戴的装备
RefPtr<Equipment> GetEquip(std::string part);
};

View File

@@ -0,0 +1,75 @@
#include "Chr_StateMachine.h"
#include "Actor/Object/CharacterObject.h"
#include "Asset/Squirrel/SquirrelManager.h"
void Chr_StateMachine::Init(CharacterObject *parent)
{
chr_Parent = parent;
addTag(Tag::UPDATE);
parent->AddChild(this);
}
void Chr_StateMachine::ChangeState(int state)
{
// 对象存在
if (chr_Parent)
{
// 检查是否可以切换状态
SQBool CheckFlag = SQFalse;
HSQUIRRELVM v = SquirrelEx::GetInstance().GetSquirrelVM();
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("StateMachine_checkCanChangeState"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, chr_Parent);
sq_pushinteger(v, chr_Parent->Job);
sq_pushinteger(v, state);
sq_call(v, 4, SQTrue, SQTrue);
sq_getbool(v, -1, &CheckFlag);
}
sq_settop(v, top);
if (CheckFlag == SQTrue)
{
sq_pushroottable(v);
sq_pushstring(v, _SC("StateMachine_SetState"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, chr_Parent);
sq_pushinteger(v, chr_Parent->Job);
sq_pushinteger(v, state);
sq_call(v, 4, SQFalse, SQTrue);
}
sq_settop(v, top);
this->State = state;
}
}
}
void Chr_StateMachine::Update(float deltaTime)
{
if (deltaTime == 0.f)
return;
if (chr_Parent)
{
if (this->State != -1)
{
HSQUIRRELVM v = SquirrelEx::GetInstance().GetSquirrelVM();
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("StateMachine_ProcState"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, chr_Parent);
sq_pushinteger(v, chr_Parent->Job);
sq_pushinteger(v, this->State);
sq_pushfloat(v, deltaTime);
sq_call(v, 5, SQFalse, SQTrue);
}
sq_settop(v, top);
}
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "EngineFrame/Component/Component.h"
#include "Global/Global_Enum.h"
class CharacterObject;
class Chr_StateMachine : public Component
{
private:
// 父对象
CharacterObject *chr_Parent;
// 状态
int State = -1;
// 状态时间
int StateTime = 0;
public:
void Init(CharacterObject *parent);
void ChangeState(int state);
int GetState() { return State; };
void Update(float deltaTime);
};

View File

@@ -0,0 +1,169 @@
#include "Equipment.h"
#include "Global/Global_Game.h"
#include "Asset/AssetManager.h"
int Equipment::GetJobIndex(std::string JobName)
{
if (JobName == "[swordman]")
return 0;
else if (JobName == "[fighter]")
return 1;
else if (JobName == "[gunner]")
return 2;
else if (JobName == "[mage]")
return 3;
else if (JobName == "[priest]")
return 4;
else if (JobName == "[atgunner]")
return 5;
else if (JobName == "[thief]")
return 6;
else if (JobName == "[atfighter]")
return 7;
else if (JobName == "[atmage]")
return 8;
else if (JobName == "[demonic swordman]")
return 9;
else if (JobName == "[creatormage]")
return 10;
return -1;
}
ATTACH_TYPE Equipment::GetTradeType(std::string TradeType)
{
if (TradeType == "[free]")
return ATTACH_TYPE::FREE;
else if (TradeType == "[sealing]")
return ATTACH_TYPE::SEALING;
else if (TradeType == "[trade]")
return ATTACH_TYPE::TRADE;
else if (TradeType == "[account]")
return ATTACH_TYPE::ACCOUNT;
else if (TradeType == "[trade delete]")
return ATTACH_TYPE::TRADE_DELETE;
else if (TradeType == "[sealing trade]")
return ATTACH_TYPE::SEALING_TRADE;
return ATTACH_TYPE::FREE;
}
bool Equipment::IsEmpty()
{
if (m_EquipmentPath.empty())
return false;
return true;
}
void Equipment::Init(int Index)
{
ConstructionByIndex(Index);
}
void Equipment::Init(int Index, int Quality)
{
this->m_Quality = Quality;
ConstructionByIndex(Index);
}
void Equipment::ConstructionByIndex(int Index)
{
// 检查装备list有没有这件装备
if (Global_Game::GetInstance().EquipmentPathMap.count(Index))
{
m_EquipmentPath = Global_Game::GetInstance().EquipmentPathMap[Index];
// 读取装备信息
ScriptData Data = AssetManager::GetInstance().GetScriptInfo(m_EquipmentPath);
while (!Data.IsEnd())
{
std::string Segment = Data.Get();
if (Segment == "[name]")
{
this->Name = Data.Get();
}
else if (Segment == "[name2]")
{
this->Name2 = Data.Get();
}
else if (Segment == "[grade]")
{
this->Grade = std::stoi(Data.Get());
}
else if (Segment == "[rarity]")
{
this->Rarity = std::stoi(Data.Get());
}
else if (Segment == "[usable job]")
{
while (true)
{
std::string Buf = Data.Get();
if (Buf == "[/usable job]")
break;
this->UsableJob[GetJobIndex(Buf)] = true;
}
}
else if (Segment == "[attach type]")
{
this->TradeType = GetTradeType(Data.Get());
}
else if (Segment == "[minimum level]")
{
this->MinimumLevel = std::stoi(Data.Get());
}
else if (Segment == "[price]")
{
this->Price = std::stoi(Data.Get());
}
else if (Segment == "[repair price]")
{
this->RepairPrice = std::stoi(Data.Get());
}
else if (Segment == "[animation job]")
{
std::string JobString = Data.Get();
int JobIndex = GetJobIndex(JobString);
this->JobAni[JobIndex].clear();
if (Data.Get() == "[variation]")
{
int Parm1 = std::stoi(Data.Get());
int Parm2 = std::stoi(Data.Get());
while (true)
{
JobAnimation JobAniBuffer;
JobAniBuffer.ImgFormat.clear();
JobAniBuffer.ImgFormat.push_back(Parm1);
JobAniBuffer.ImgFormat.push_back(Parm2);
std::string buf = Data.Get();
if (buf == "[layer variation]")
{
JobAniBuffer.Layer = std::stoi(Data.Get());
JobAniBuffer.AnimationGroup = Data.Get();
this->JobAni[JobIndex].push_back(JobAniBuffer);
// 调用两次 跳过原来的 [equipment ani script] 这个没有用
std::string B1 = Data.Get();
std::string B2 = Data.Get();
}
// 皮肤没有图层也没有动画组名称
else if (m_EquipmentPath.find("skin") != std::string::npos)
{
JobAniBuffer.Layer = 0;
JobAniBuffer.AnimationGroup = "null";
this->JobAni[JobIndex].push_back(JobAniBuffer);
break;
}
else
{
Data.Back();
break;
}
}
}
}
}
}
else
{
SDL_LogError(0, "没有编号为: %d 这件装备", Index);
}
}

View File

@@ -0,0 +1,62 @@
#pragma once
#include "EngineFrame/Component/Component.h"
#include "Global/Global_Enum.h"
class Equipment : public Component
{
public:
// 职业动画结构体
struct JobAnimation
{
// 图层
int Layer;
// 动画组名称
std::string AnimationGroup;
// IMG替换编号
std::vector<int> ImgFormat = {0, 0};
};
public:
// 装备在PVF中的路径
std::string m_EquipmentPath;
// 装备的品质
int m_Quality = -1;
public:
// 编号
int Index = -1;
// 名字
std::string Name;
// 别名
std::string Name2;
// 等级组
int Grade = -1;
// 稀有度
int Rarity = -1;
// 可用职业
std::map<int, bool> UsableJob;
// 交易类型
ATTACH_TYPE TradeType;
// 最小佩戴等级
int MinimumLevel = 1;
// 价值
int Price = 0;
// 维修价格
int RepairPrice = 0;
// 职业动画
std::map<int, std::vector<JobAnimation>> JobAni;
// 装备的属性
public:
// 通过职业名字获取职业编号
int GetJobIndex(std::string JobName);
// 通过交易类型文字获取枚举值
ATTACH_TYPE GetTradeType(std::string TradeType);
bool IsEmpty();
void Init(int Index);
void Init(int Index, int Quality);
// 通过装备编号构造装备
void ConstructionByIndex(int Index);
};

View File

@@ -0,0 +1,126 @@
#pragma once
#include "Global/Global_Type.h"
#include <optional>
#include <stdexcept>
class ObjectVars
{
private:
// 底层存储key -> 数组始终是vector即使只有一个元素
ObjectVarsMap _data;
public:
ObjectVars() = default;
~ObjectVars() = default;
// 禁止拷贝(按需开启)
ObjectVars(const ObjectVars &) = delete;
ObjectVars &operator=(const ObjectVars &) = delete;
// 允许移动
ObjectVars(ObjectVars &&) = default;
ObjectVars &operator=(ObjectVars &&) = default;
// 1. 向key对应的数组添加元素核心接口无论添加几个元素都用这个
template <typename T>
void Add(const std::string &key, const T &value)
{
static_assert(std::is_constructible_v<ObjectVarsType, T>, "不支持的类型未在ObjectVarsType中定义");
_data[key].push_back(ObjectVarsType{value}); // 直接追加到数组,保证始终是数组形式
}
// 2. 批量添加元素(一次添加多个值到数组)
template <typename T>
void AddAll(const std::string &key, const std::vector<T> &values)
{
static_assert(std::is_constructible_v<ObjectVarsType, T>, "不支持的类型未在ObjectVarsType中定义");
for (const auto &val : values)
{
_data[key].push_back(ObjectVarsType{val});
}
}
// 3. 替换key对应的整个数组覆盖原有所有元素
template <typename T>
void SetArray(const std::string &key, const std::vector<T> &values)
{
static_assert(std::is_constructible_v<ObjectVarsType, T>, "不支持的类型未在ObjectVarsType中定义");
// 先清空原有数据,再添加新数组
_data[key].clear();
AddAll(key, values);
}
// 4. 获取key对应的整个数组返回指定类型的vector类型不匹配的元素会被过滤
template <typename T>
std::vector<T> GetArray(const std::string &key) const
{
std::vector<T> result;
auto it = _data.find(key);
if (it == _data.end())
{
return result; // key不存在返回空数组
}
// 只提取类型匹配的元素
for (const auto &var : it->second)
{
if (const auto *val = std::get_if<T>(&var))
{
result.push_back(*val);
}
}
return result;
}
// 5. 获取数组中指定索引的元素返回optional索引越界或类型不匹配则返回nullopt
template <typename T>
std::optional<T> GetAt(const std::string &key, size_t index) const
{
auto it = _data.find(key);
if (it == _data.end() || index >= it->second.size())
{
return std::nullopt; // key不存在或索引越界
}
// 检查类型是否匹配
if (const auto *val = std::get_if<T>(&it->second[index]))
{
return *val;
}
return std::nullopt; // 类型不匹配
}
// 6. 检查key是否存在无论数组是否为空
bool Has(const std::string &key) const
{
return _data.find(key) != _data.end();
}
// 7. 获取数组长度key不存在则返回0
size_t GetSize(const std::string &key) const
{
auto it = _data.find(key);
return (it != _data.end()) ? it->second.size() : 0;
}
// 8. 清空key对应的数组保留key但数组为空
void ClearArray(const std::string &key)
{
auto it = _data.find(key);
if (it != _data.end())
{
it->second.clear();
}
}
// 9. 删除整个key包括数组
void Remove(const std::string &key)
{
_data.erase(key);
}
// 10. 清空所有数据
void ClearAll()
{
_data.clear();
}
};

View File

@@ -0,0 +1,57 @@
#pragma once
#include "squirrel/SquirrelEx.h"
#include "Actor/Object/ActiveObject.h"
static ActiveObject *GetActiveObject(HSQUIRRELVM v)
{
SQUserPointer ptr;
sq_getuserpointer(v, 2, &ptr);
ActiveObject *obj = (ActiveObject *)ptr;
return obj;
}
static SQInteger SQR_SetSpeed(HSQUIRRELVM v)
{
ActiveObject *obj = GetActiveObject(v);
SQFloat speedX, speedY, speedZ;
sq_getfloat(v, 3, &speedX);
sq_getfloat(v, 4, &speedY);
sq_getfloat(v, 5, &speedZ);
obj->SetSpeed(VecSpeed3(speedX, speedY, speedZ));
return 0;
}
static SQInteger SQR_GetSpeed(HSQUIRRELVM v)
{
ActiveObject *obj = GetActiveObject(v);
VecSpeed3 speed = obj->GetSpeed();
sq_newtable(v);
sq_pushstring(v, _SC("x"), -1);
sq_pushfloat(v, speed.x);
sq_newslot(v, 3, SQFalse);
sq_pushstring(v, _SC("y"), -1);
sq_pushfloat(v, speed.y);
sq_newslot(v, 3, SQFalse);
sq_pushstring(v, _SC("z"), -1);
sq_pushfloat(v, speed.z);
sq_newslot(v, 3, SQFalse);
return 1;
}
static void RegisterActiveObjectNutApi(const SQChar *funcName, SQFUNCTION funcAddr, HSQUIRRELVM v)
{
sq_pushroottable(v);
sq_pushstring(v, funcName, -1);
sq_newclosure(v, funcAddr, 0);
sq_newslot(v, -3, false);
sq_poptop(v);
}
static void RegisterActiveObject()
{
SDL_Log("初始化 动态对象-松鼠脚本!");
HSQUIRRELVM v = SquirrelEx::GetInstance().GetSquirrelVM();
// 设置速度
RegisterActiveObjectNutApi(_SC("sq_SetSpeed"), SQR_SetSpeed, v);
RegisterActiveObjectNutApi(_SC("sq_GetSpeed"), SQR_GetSpeed, v);
}

View File

@@ -0,0 +1,197 @@
#pragma once
#include "squirrel/SquirrelEx.h"
#include "Actor/Object/BaseObject.h"
static BaseObject *GetBaseObject(HSQUIRRELVM v)
{
SQUserPointer ptr;
sq_getuserpointer(v, 2, &ptr);
BaseObject *obj = (BaseObject *)ptr;
return obj;
}
static SQInteger SQR_GetPosition(HSQUIRRELVM v)
{
SQUserPointer ptr;
sq_getuserpointer(v, 2, &ptr);
BaseObject *obj = (BaseObject *)ptr;
VecFPos3 Pos = obj->GetPosition();
sq_newtable(v);
sq_pushstring(v, _SC("x"), -1);
sq_pushfloat(v, Pos.x);
sq_newslot(v, 3, SQFalse);
sq_pushstring(v, _SC("y"), -1);
sq_pushfloat(v, Pos.y);
sq_newslot(v, 3, SQFalse);
sq_pushstring(v, _SC("z"), -1);
sq_pushfloat(v, Pos.z);
sq_newslot(v, 3, SQFalse);
return 1;
}
static SQInteger SQR_SetPosition(HSQUIRRELVM v)
{
SQUserPointer ptr;
sq_getuserpointer(v, 2, &ptr);
BaseObject *obj = (BaseObject *)ptr;
SQFloat PosX, PosY, PosZ;
sq_getfloat(v, 3, &PosX);
sq_getfloat(v, 4, &PosY);
sq_getfloat(v, 5, &PosZ);
obj->SetPosition(VecFPos3(PosX, PosY, PosZ));
return 0;
}
static SQInteger SQR_GetDirection(HSQUIRRELVM v)
{
BaseObject *obj = GetBaseObject(v);
sq_pushinteger(v, obj->GetDirection());
return 1;
}
static SQInteger SQR_SetDirection(HSQUIRRELVM v)
{
BaseObject *obj = GetBaseObject(v);
SQInteger Dir;
sq_getinteger(v, 3, &Dir);
obj->SetDirection(Dir);
return 0;
}
static SQInteger SQR_GetVars(HSQUIRRELVM v)
{
SQUserPointer ptr;
sq_getuserpointer(v, 2, &ptr);
BaseObject *obj = (BaseObject *)ptr;
const SQChar *KeyBuf;
const SQChar *TypeBuf;
sq_getstring(v, 3, &KeyBuf);
sq_getstring(v, 4, &TypeBuf);
std::string Key(KeyBuf);
std::string Type(TypeBuf);
if (Type == "int")
{
std::vector<int> ArrBuf = obj->GetObjectVars().GetArray<int>(Key);
sq_newarray(v, 0);
for (int i = 0; i < ArrBuf.size(); i++)
{
sq_pushinteger(v, ArrBuf[i]);
sq_arrayappend(v, -2);
}
}
else if (Type == "float")
{
std::vector<float> ArrBuf = obj->GetObjectVars().GetArray<float>(Key);
sq_newarray(v, 0);
for (int i = 0; i < ArrBuf.size(); i++)
{
sq_pushfloat(v, ArrBuf[i]);
sq_arrayappend(v, -2);
}
}
else if (Type == "string")
{
std::vector<std::string> ArrBuf = obj->GetObjectVars().GetArray<std::string>(Key);
sq_newarray(v, 0);
for (int i = 0; i < ArrBuf.size(); i++)
{
sq_pushstring(v, ArrBuf[i].c_str(), -1);
sq_arrayappend(v, -2);
}
}
return 1;
}
static SQInteger SQR_SetVars(HSQUIRRELVM v)
{
SQUserPointer ptr;
sq_getuserpointer(v, 2, &ptr);
BaseObject *obj = (BaseObject *)ptr;
const SQChar *KeyBuf;
const SQChar *TypeBuf;
sq_getstring(v, 3, &KeyBuf);
sq_getstring(v, 4, &TypeBuf);
std::string Key(KeyBuf);
std::string Type(TypeBuf);
if (Type == "int")
{
std::vector<int> ArrBuf;
sq_pushnull(v); // null iterator
while (SQ_SUCCEEDED(sq_next(v, 5)))
{
SQInteger value;
sq_getinteger(v, -1, &value);
const SQChar *key;
sq_getstring(v, -2, &key);
ArrBuf.push_back(value);
sq_pop(v, 2);
}
sq_pop(v, 1);
obj->GetObjectVars().AddAll(Key, ArrBuf);
}
else if (Type == "float")
{
std::vector<float> ArrBuf;
sq_pushnull(v); // null iterator
while (SQ_SUCCEEDED(sq_next(v, 5)))
{
SQFloat value;
sq_getfloat(v, -1, &value);
const SQChar *key;
sq_getstring(v, -2, &key);
ArrBuf.push_back(value);
sq_pop(v, 2);
}
sq_pop(v, 1);
obj->GetObjectVars().SetArray(Key, ArrBuf);
}
else if (Type == "string")
{
std::vector<std::string> ArrBuf;
sq_pushnull(v); // null iterator
while (SQ_SUCCEEDED(sq_next(v, 5)))
{
const SQChar *value;
sq_getstring(v, -1, &value);
const SQChar *key;
sq_getstring(v, -2, &key);
ArrBuf.push_back(value);
sq_pop(v, 2);
}
sq_pop(v, 1);
obj->GetObjectVars().AddAll(Key, ArrBuf);
}
return 0;
}
static void RegisterBaseObjectNutApi(const SQChar *funcName, SQFUNCTION funcAddr, HSQUIRRELVM v)
{
sq_pushroottable(v);
sq_pushstring(v, funcName, -1);
sq_newclosure(v, funcAddr, 0);
sq_newslot(v, -3, false);
sq_poptop(v);
}
static void RegisterBaseObject()
{
SDL_Log("初始化 基础对象-松鼠脚本!");
HSQUIRRELVM v = SquirrelEx::GetInstance().GetSquirrelVM();
// 坐标
RegisterBaseObjectNutApi(_SC("sq_GetPosition"), SQR_GetPosition, v);
RegisterBaseObjectNutApi(_SC("sq_SetPosition"), SQR_SetPosition, v);
// 朝向
RegisterBaseObjectNutApi(_SC("sq_GetDirection"), SQR_GetDirection, v);
RegisterBaseObjectNutApi(_SC("sq_SetDirection"), SQR_SetDirection, v);
// 数据储存器
RegisterBaseObjectNutApi(_SC("sq_GetVars"), SQR_GetVars, v);
RegisterBaseObjectNutApi(_SC("sq_SetVars"), SQR_SetVars, v);
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include "squirrel/SquirrelEx.h"
#include "Actor/Object/CharacterObject.h"
static CharacterObject *GetCharacterObject(HSQUIRRELVM v)
{
SQUserPointer ptr;
sq_getuserpointer(v, 2, &ptr);
CharacterObject *obj = (CharacterObject *)ptr;
return obj;
}
static SQInteger SQR_GetState(HSQUIRRELVM v)
{
CharacterObject *obj = GetCharacterObject(v);
sq_pushinteger(v, obj->_StateMachine->GetState());
return 1;
}
static SQInteger SQR_SetState(HSQUIRRELVM v)
{
CharacterObject *obj = GetCharacterObject(v);
SQInteger state;
sq_getinteger(v, 3, &state);
obj->_StateMachine->ChangeState(state);
return 0;
}
static SQInteger SQR_SetAction(HSQUIRRELVM v)
{
CharacterObject *obj = GetCharacterObject(v);
const SQChar *ActionNameBuf;
sq_getstring(v, 3, &ActionNameBuf);
obj->_AnimationManager->SetAction(ActionNameBuf);
return 0;
}
static void RegisterCharacterObjectNutApi(const SQChar *funcName, SQFUNCTION funcAddr, HSQUIRRELVM v)
{
sq_pushroottable(v);
sq_pushstring(v, funcName, -1);
sq_newclosure(v, funcAddr, 0);
sq_newslot(v, -3, false);
sq_poptop(v);
}
static void RegisterCharacterObject()
{
SDL_Log("初始化 角色对象-松鼠脚本!");
HSQUIRRELVM v = SquirrelEx::GetInstance().GetSquirrelVM();
// 获取状态
RegisterCharacterObjectNutApi(_SC("sq_GetState"), SQR_GetState, v);
// 设置状态
RegisterCharacterObjectNutApi(_SC("sq_SetState"), SQR_SetState, v);
// 设置动画
RegisterCharacterObjectNutApi(_SC("sq_SetAction"), SQR_SetAction, v);
}

View File

@@ -0,0 +1,12 @@
#include "SquirrelManager.h"
void SquirrelManager::Init()
{
SDL_Log("开始初始化sqr管理器!");
// 基础对象
RegisterBaseObject();
// 动态对象
RegisterActiveObject();
// 角色对象
RegisterCharacterObject();
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "Asset/Squirrel/Sqr_BaseObject.hpp"
#include "Asset/Squirrel/Sqr_ActiveObject.hpp"
#include "Asset/Squirrel/Sqr_CharacterObject.hpp"
class SquirrelManager
{
public:
// 删除拷贝构造和赋值运算符,确保无法复制
SquirrelManager(const SquirrelManager &) = delete;
SquirrelManager &operator=(const SquirrelManager &) = delete;
// 移动构造和赋值也删除,避免意外转移
SquirrelManager(SquirrelManager &&) = delete;
SquirrelManager &operator=(SquirrelManager &&) = delete;
// 全局访问点
static SquirrelManager &GetInstance()
{
static SquirrelManager instance; // 局部静态变量,保证只初始化一次
return instance;
}
private:
// 构造函数和析构函数设为私有,防止外部创建和销毁
SquirrelManager() = default;
~SquirrelManager() = default;
public:
// 初始化
void Init();
};

View File

@@ -0,0 +1,36 @@
#pragma once
// 交易类型
enum ATTACH_TYPE
{
FREE, // 无限制
SEALING, // 封装
TRADE, // 不可交易
ACCOUNT, // 账号绑定
TRADE_DELETE, // 无法交易、删除
SEALING_TRADE // 封装且不可交易
};
// 控制器消息类型
enum CONTROLLER_MSG_TYPE
{
// 摇杆移动(左)
CONTROLLER_MSG_TYPE_LEFT_JOYSTICK_MOVE,
// 摇杆移动(右)
CONTROLLER_MSG_TYPE_RIGHT_JOYSTICK_MOVE
};
// 基础状态
enum BASE_STATE
{
REST, // 站立
MOVE, // 移动
DASH, // 冲刺
JUMP, // 跳跃
};

View File

@@ -0,0 +1,37 @@
#include "Global_Game.h"
Global_Game::Global_Game()
{
}
Global_Game::~Global_Game()
{
}
void Global_Game::Init()
{
// 初始化ttf字体资源
TTF_Font *FontBuf = TTF_OpenFont("Fonts/LXGWWenKai-Regular.ttf", 24);
// TTF_Font *FontBuf = TTF_OpenFont("Fonts/Gothica-Book.ttf", 24);
// TTF_Font *FontBuf = TTF_OpenFont("Fonts/Gasinamu.ttf", 24);
if (!FontBuf)
{
SDL_LogError(0, "字体加载失败: %s", TTF_GetError());
}
Fonts.push_back(FontBuf);
}
void Global_Game::InitGame()
{
// 读取角色配置文件
CharacterConfigs = GlobalCharacterScript::InitCharacterLst();
// 读取装备配置文件
EquipmentPathMap = GlobalEquipmentScript::InitEquipmentLst();
// 初始化松鼠脚本管理器
SquirrelManager::GetInstance().Init();
// 读取存档
SavaManager::GetInstance().Init();
// 游戏初始化完成标志
InitFlag = true;
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include "EngineCore/Game.h"
#include "Global/Script/CharacterConfig.h"
#include "Global/Script/EquipmentConfig.h"
#include "Global/Save/SavaManager.h"
#include "Asset/Squirrel/SquirrelManager.h"
class Global_Game
{
public:
Global_Game(const Global_Game &) = delete;
Global_Game &operator=(const Global_Game &) = delete;
Global_Game(Global_Game &&) = delete;
Global_Game &operator=(Global_Game &&) = delete;
// 全局访问点
static Global_Game &GetInstance()
{
static Global_Game instance; // 局部静态变量,保证只初始化一次
return instance;
}
// 游戏资源加载之前的初始化
void Init();
// 游戏资源加载之后的初始化
void InitGame();
public:
// 当前游戏状态 0未初始化
int game_state = 0;
public:
// 字体资源
std::vector<TTF_Font *> Fonts;
// 角色配置文件
std::vector<GlobalCharacterScript::CharacterConfig> CharacterConfigs;
// 装备路径Map
std::map<int, std::string> EquipmentPathMap;
// 游戏资源初始化标志
bool InitFlag = false;
private:
Global_Game(/* args */);
~Global_Game();
};

View File

@@ -0,0 +1,10 @@
#pragma once
#include <variant>
#include <map>
#include <vector>
#include <string>
// 定义变量类型变体
using ObjectVarsType = std::variant<int, float, bool, std::string>;
// 定义对象变量映射类型
using ObjectVarsMap = std::map<std::string, std::vector<ObjectVarsType>>;

View File

@@ -0,0 +1,59 @@
#include "SavaManager.h"
#include <json.hpp>
#include <dirent.h>
#include <string>
#include <fstream>
#include <SDL.h>
SavaManager::SavaManager()
{
}
SavaManager::~SavaManager()
{
}
void SavaManager::Init()
{
DIR *dir;
struct dirent *ent;
std::string path = "Save/";
dir = opendir(path.c_str());
while ((ent = readdir(dir)))
{
// 跳过.和..目录
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
continue;
std::string RealPath = path + ent->d_name;
SDL_Log("RealPath: %s", RealPath.c_str());
}
Save();
}
void SavaManager::Save()
{
int Level = 1;
int Job = 0;
int GrowType = -1;
int Exp = 0;
int Fatigue = 0;
nlohmann::json SaveJson;
SaveJson["Level"] = Level;
SaveJson["Job"] = Job;
SaveJson["GrowType"] = GrowType;
SaveJson["Exp"] = Exp;
SaveJson["Fatigue"] = Fatigue;
SaveJson["WearEquipment"] = nlohmann::json::object();
nlohmann::json weapon;
weapon["id"] = 26058;
SaveJson["WearEquipment"]["weapon"] = weapon;
std::ofstream OutFile("Save/Save_0.sav");
OutFile << SaveJson.dump(4);
OutFile.close();
}

View File

@@ -0,0 +1,29 @@
#pragma once
class SavaManager
{
public:
// 删除拷贝构造和赋值运算符,确保无法复制
SavaManager(const SavaManager &) = delete;
SavaManager &operator=(const SavaManager &) = delete;
// 移动构造和赋值也删除,避免意外转移
SavaManager(SavaManager &&) = delete;
SavaManager &operator=(SavaManager &&) = delete;
// 全局访问点
static SavaManager &GetInstance()
{
static SavaManager instance; // 局部静态变量,保证只初始化一次
return instance;
}
private:
// 构造函数和析构函数设为私有,防止外部创建和销毁
SavaManager();
~SavaManager();
public:
void Init();
void Save();
};

View File

@@ -0,0 +1,135 @@
#include "CharacterConfig.h"
#include "Asset/AssetManager.h"
#include "Tool/Tool_String.h"
namespace GlobalCharacterScript
{
JobConfig InitJobConfig(std::string JobInfoPath)
{
JobConfig Config;
ScriptData Data = AssetManager::GetInstance().GetScriptInfo(JobInfoPath);
while (!Data.IsEnd())
{
std::string Segment = Data.Get();
if (Segment == "[职业名称]")
Config.name = Data.Get();
else if (Segment == "[生命值上限]")
Config.maxHP = std::stof(Data.Get());
else if (Segment == "[魔法值上限]")
Config.maxMP = std::stof(Data.Get());
else if (Segment == "[生命值回复速率]")
Config.hpRecoverRate = std::stof(Data.Get());
else if (Segment == "[魔法值回复速率]")
Config.mpRecoverRate = std::stof(Data.Get());
else if (Segment == "[力量]")
Config.strength = std::stof(Data.Get());
else if (Segment == "[智力]")
Config.intelligence = std::stof(Data.Get());
else if (Segment == "[体力]")
Config.stamina = std::stof(Data.Get());
else if (Segment == "[精神]")
Config.spirit = std::stof(Data.Get());
else if (Segment == "[移动速度]")
Config.moveSpeed = std::stof(Data.Get());
else if (Segment == "[攻击速度]")
Config.attackSpeed = std::stof(Data.Get());
else if (Segment == "[释放速度]")
Config.castSpeed = std::stof(Data.Get());
else if (Segment == "[硬直]")
Config.stunResist = std::stof(Data.Get());
else if (Segment == "[跳跃力]")
Config.jumpPower = std::stof(Data.Get());
else if (Segment == "[跳跃速度]")
Config.jumpSpeed = std::stof(Data.Get());
else if (Segment == "[火属性抗性]")
Config.fireResist = std::stof(Data.Get());
else if (Segment == "[冰属性抗性]")
Config.iceResist = std::stof(Data.Get());
else if (Segment == "[光属性抗性]")
Config.lightResist = std::stof(Data.Get());
else if (Segment == "[暗属性抗性]")
Config.darkResist = std::stof(Data.Get());
else if (Segment == "[默认技能]")
{
while (true)
{
std::string Ret = Data.Get();
if (Ret == "[/默认技能]")
break;
Config.skillList.push_back(std::stoi(Ret));
}
}
else if (Segment == "[默认时装]")
{
while (true)
{
std::string Ret = Data.Get();
if (Ret == "[/默认时装]")
break;
std::string Index = Data.Get();
Config.defaultAvatarList[Ret] = std::stoi(Index);
}
}
}
return Config;
}
CharacterConfig InitCharacterConfig(std::string JobInfoPath)
{
CharacterConfig Config;
ScriptData Data = AssetManager::GetInstance().GetScriptInfo(std::string("character/") + JobInfoPath);
while (!Data.IsEnd())
{
std::string Segment = Data.Get();
if (Segment == "[职业标签]")
{
std::string JobTab = Data.Get();
Config.jobTag = JobTab.substr(1, JobTab.size() - 2);
}
else if (Segment == "[基础职业属性]")
{
Config.baseGrowtypePath = Data.Get();
Config.baseJobConfig = InitJobConfig(Tool_toLowerCase(Config.baseGrowtypePath));
}
else if (Segment == "[转职职业属性]")
{
while (true)
{
std::string Ret = Data.Get();
if (Ret == "[/转职职业属性]")
break;
Config.growtypePath.push_back(Ret);
Config.growtypeJobConfig.push_back(InitJobConfig(Tool_toLowerCase(Ret)));
}
}
else if (Segment == "[动作动画]")
{
while (true)
{
std::string Ret = Data.Get();
if (Ret == "[/动作动画]")
break;
std::string path = Data.Get();
Config.animationPath[Ret] = path;
}
}
}
return Config;
}
std::vector<CharacterConfig> InitCharacterLst()
{
std::vector<CharacterConfig> Config;
// 先读取角色职业lst
ScriptData Data = AssetManager::GetInstance().GetScriptInfo("character/character.lst");
while (!Data.IsEnd())
{
std::string Index = Data.Get();
std::string JobInfoPath = Data.Get();
// 读取职业 //TODO 现在只有鬼剑士更改了文件 其他职业读了会炸
if (std::stoi(Index) <= 0)
Config.push_back(InitCharacterConfig(Tool_toLowerCase(JobInfoPath)));
}
return Config;
}
}

View File

@@ -0,0 +1,79 @@
#pragma once
#include <string>
#include <vector>
#include <map>
namespace GlobalCharacterScript
{
// 职业配置
struct JobConfig
{
// 职业名称
std::string name;
// HP最大值
float maxHP;
// MP最大值
float maxMP;
// HP恢复速率
float hpRecoverRate;
// MP恢复速率
float mpRecoverRate;
// 力量
float strength;
// 智力
float intelligence;
// 体力
float stamina;
// 精神
float spirit;
// 移动速度
float moveSpeed;
// 攻击速度
float attackSpeed;
// 释放速度
float castSpeed;
// 硬直
float stunResist;
// 跳跃力
float jumpPower;
// 跳跃速度
float jumpSpeed;
// 火属性抗性
float fireResist;
// 冰属性抗性
float iceResist;
// 光属性抗性
float lightResist;
// 暗属性抗性
float darkResist;
// 初始技能列表
std::vector<int> skillList;
// 默认时装列表
std::map<std::string, int> defaultAvatarList;
};
// 角色类信息
struct CharacterConfig
{
// 基础职业标识
std::string jobTag;
// 基础职业路径
std::string baseGrowtypePath;
// 基础职业配置
JobConfig baseJobConfig;
// 转职配置路径
std::vector<std::string> growtypePath;
// 转职职业配置
std::vector<JobConfig> growtypeJobConfig;
// 动画路径
std::map<std::string, std::string> animationPath;
};
// 读取角色Lst信息
std::vector<CharacterConfig> InitCharacterLst();
// 读取角色信息
CharacterConfig InitCharacterConfig(std::string JobInfoPath);
// 读取职业信息
JobConfig InitJobConfig(std::string JobConfigPath);
}

View File

@@ -0,0 +1,19 @@
#include "EquipmentConfig.h"
#include "Asset/AssetManager.h"
#include "Tool/Tool_String.h"
namespace GlobalEquipmentScript
{
std::map<int, std::string> InitEquipmentLst()
{
std::map<int, std::string> EquipList;
ScriptData Data = AssetManager::GetInstance().GetScriptInfo("equipment/equipment.lst");
while (!Data.IsEnd())
{
std::string Index = Data.Get();
std::string EquipInfoPath = std::string("equipment/") + Data.Get();
EquipList[std::stoi(Index)] = EquipInfoPath;
}
return EquipList;
}
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include <string>
#include <vector>
#include <map>
namespace GlobalEquipmentScript
{
std::map<int, std::string> InitEquipmentLst();
}

View File

@@ -0,0 +1,65 @@
#include "Scene/Scene_Loading_UI.h"
#include "Scene/Scene_SelectCharacter_UI.hpp"
#include "Scene/Scene_Test.h"
#include "Scene_Loading_UI.h"
#include "EngineFrame/Component/Sprite.h"
#include "EngineFrame/Component/Text.h"
#include "Global/Global_Game.h"
#include "Asset/Asset_Script.h"
void Scene_Loading_UI::Enter()
{
// 加载OGG文件
music = Mix_LoadMUS("Music/characterSelectStage.ogg");
if (music)
{
Mix_PlayMusic(music, 1);
}
RefPtr<Actor> actor = new Actor;
AddChild(actor);
RefPtr<Sprite> BackGroundSp = new Sprite("ImagePacks2/Loading1.png");
actor->AddComponent(BackGroundSp);
RefPtr<Sprite> BackGround2Sp = new Sprite("ImagePacks2/Loading0.png");
BackGround2Sp->SetPos(VecFPos{0, 686});
actor->AddComponent(BackGround2Sp);
RefPtr<Sprite> LoadCircleSp = new Sprite("ImagePacks2/Loading2.png");
LoadCircleSp->SetName("LoadCircle");
LoadCircleSp->SetPos(VecFPos{1280 - 60, 686 - 60});
LoadCircleSp->SetBlendMode(SDL_BLENDMODE_ADD);
LoadCircleSp->SetAnchor(VecFPos{0.5f, 0.5f});
actor->AddComponent(LoadCircleSp);
actor->SetCallbackOnUpdate([LoadCircleSp](float deltaTime) mutable
{
float angle = LoadCircleSp->GetRotation();
LoadCircleSp->SetRotation(angle + 180.0f * deltaTime); });
// 文字测试
// RefPtr<Text> text = new Text("测试文字加载中...", Global_Game::GetInstance().Fonts[0], SDL_Color{255, 255, 255, 255}, SDL_Color{0, 0, 0, 255}, 4);
// actor->AddComponent(text);
}
void Scene_Loading_UI::Update(float deltaTime)
{
Scene::Update(deltaTime);
if (Global_Game::GetInstance().InitFlag)
{
// 设定游戏层场景
RefPtr<Scene_Test> scene = new Scene_Test;
Game::GetInstance().ChangeScene(scene);
// 设定UI层场景
RefPtr<Scene_SelectCharacter_UI> sceneUI = new Scene_SelectCharacter_UI;
Game::GetInstance().ChangeUIScene(sceneUI);
}
}
void Scene_Loading_UI::Exit()
{
if (music)
{
Mix_FreeMusic(music);
music = nullptr;
}
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "EngineFrame/Scene/Scene.h"
#include <SDL2/SDL_mixer.h>
class Scene_Loading_UI : public Scene
{
private:
/* data */
public:
void Enter() override;
void Update(float deltaTime) override;
void Exit() override;
// 加载界面音乐
Mix_Music *music = nullptr;
};

View File

@@ -0,0 +1,88 @@
#pragma once
#include "EngineFrame/Scene/Scene.h"
#include "Asset/AssetManager.h"
#include "EngineFrame/Component/Animation.h"
#include "Actor/Map/GameMap.h"
#include "Actor/Map/GameMapCamera.h"
class Scene_SelectCharacter_UI : public Scene
{
private:
/* data */
GameMap *map;
RefPtr<GameMapCamera> camera = nullptr;
public:
Scene_SelectCharacter_UI(/* args */) {
};
~Scene_SelectCharacter_UI() {
};
public:
void Enter() override
{
map = new GameMap;
map->LoadMap("map/cataclysm/town/elvengard/new_elvengard.map");
map->Enter(this);
camera = new GameMapCamera;
AddChild(camera);
return;
RefPtr<Actor> actor = new Actor;
actor->SetPos(VecFPos{450, 350});
// actor->SetAnchor(VecFPos{0.5, 0.5});
actor->SetScale(VecFPos{-1.f, 1.f});
AddChild(actor);
RefPtr<Actor> actor2 = new Actor;
actor->AddChild(actor2);
RefPtr<Animation> ani4 = new Animation("map/cataclysm/town/hendonmyre/animation/object/gateall_02.ani");
// ani4->SetScale(VecFPos{-1.0, 1.0});
actor2->AddChild(ani4);
// RefPtr<Animation> ani3 = new Animation("map/cataclysm/town/elvengard/animation/obj/serialight01_right.ani");
// ani3->SetPos(VecPos{300, 300});
// actor->AddChild(ani3);
// RefPtr<Animation> ani4 = new Animation("map/cataclysm/town/hendonmyre/animation/object/gateall_02.ani");
// ani4->SetPos(VecPos{300, 500});
// actor->AddChild(ani4);
// for (size_t i = 0; i < 400; i++)
// {
// RefPtr<Actor> actor = new Actor;
// AddChild(actor);
// // RefPtr<Animation> ani3 = new Animation("common/commoneffect/animation/priestslowheal1.ani");
// // actor->AddComponent(ani3);
// // ani3->SetRenderZOrder(1000);
// // RefPtr<Animation> ani = new Animation("common/anton/main.ani");
// // actor->AddComponent(ani);
// // ani->SetRenderZOrder(500);
// RefPtr<Sprite> sprite = new Sprite("sprite/item/avatar/swordman/0sm_acap.img", 0);
// actor->AddComponent(sprite);
// // RefPtr<Animation> ani2 = new Animation("common/anton/face/0/0.ani");
// // actor->AddComponent(ani2);
// // ani2->SetRenderZOrder(1000);
// }
// SDL_Log("进入了选择角色场景!");
};
void HandleEvents(SDL_Event *e) override
{
Scene::HandleEvents(e);
map->HandleEvents(e);
};
void Update(float deltaTime) override
{
Scene::Update(deltaTime);
map->Update(deltaTime);
};
// void Render() override;
// void Exit() override;
};

View File

@@ -0,0 +1,33 @@
#include "Scene_Test.h"
#include <memory>
#include <EngineCore/Game.h>
Scene_Test::Scene_Test()
{
}
Scene_Test::~Scene_Test()
{
SDL_Log("Scene_Test::我的ID是%d --- 我被释放了!", this->MyId);
}
void Scene_Test::Enter()
{
SDL_Log("进入测试场景!");
}
void Scene_Test::HandleEvents(SDL_Event *e)
{
}
void Scene_Test::Update(float deltaTime)
{
}
void Scene_Test::Render()
{
}
void Scene_Test::Exit()
{
SDL_Log("Scene_Test::退出测试场景!当前引用计数%d", this->GetRefCount());
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include "EngineFrame/Scene/Scene.h"
class Scene_Test : public Scene
{
private:
/* data */
public:
Scene_Test(/* args */);
~Scene_Test();
public:
void Enter() override;
void HandleEvents(SDL_Event *e) override;
void Update(float deltaTime) override;
void Render() override;
void Exit() override;
public:
int MyId = 0;
};

90
source_game/main.cpp Normal file
View File

@@ -0,0 +1,90 @@
// 电脑的IP地址和端口
#define PC_IP "192.168.200.3"
#define PC_SCRIPT_PORT "39018"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#ifdef __SWITCH__
#include <switch.h>
#include <sys/socket.h>
#include <curl/curl.h>
#else
#include <windows.h>
#endif
#include "Asset/Asset_ImagePack.h"
#include "Asset/Asset_Script.h"
#include "squirrel/SquirrelEx.h"
#include "Tool/Logger.h"
#include "EngineCore/Game.h"
#include "Scene/Scene_Loading_UI.h"
#include "Tool/RefPtr.h"
#include "Global/Global_Game.h"
#include "Tool/ThreadPool.h"
void InitScript()
{
// 初始化脚本资源系统
Asset_Script::GetInstance().Init();
// 初始化Image资源系统
Asset_ImagePack::GetInstance().Init();
// 更改全局游戏类初始化标志
Global_Game::GetInstance().InitGame();
}
void RunSetup()
{
// 初始化全局游戏类
Global_Game::GetInstance().Init();
// 初始化Squirrel脚本引擎
SquirrelEx::GetInstance().Run();
// 设定UI层场景
RefPtr<Scene_Loading_UI> sceneUI = new Scene_Loading_UI;
Game::GetInstance().ChangeUIScene(sceneUI);
ThreadPool::GetInstance().enqueueToThread(2, InitScript);
}
int main(int argc, char *argv[])
{
#ifdef __SWITCH__
socketInitializeDefault();
nxlinkStdio(); // 启用nxlink调试输出
curl_global_init(CURL_GLOBAL_DEFAULT); // 初始化libcurl
chdir("/switch/Lenheart/");
#else
AllocConsole();
SetConsoleTitleA("Yosin & Engine");
SetConsoleOutputCP(65001);
#endif
// 初始化Image资源系统
Asset_ImagePack::GetInstance();
// 初始化脚本资源系统
Asset_Script::GetInstance();
// 初始化线程池
ThreadPool::GetInstance();
// 初始化日志系统
// Logger::GetInstance().Init();
// 初始化Squirrel脚本系统
SquirrelEx::GetInstance().Init();
// 初始化游戏引擎
Game &game = Game::GetInstance();
// 初始化各项目
game.Init(RunSetup);
// 进入游戏循环逻辑
game.Run();
game.Clear();
#ifdef __SWITCH__
socketExit();
curl_global_cleanup();
#endif
return 0;
}