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