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,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();
};