建档
This commit is contained in:
116
source_game/Asset/Character/Chr_Animation.cpp
Normal file
116
source_game/Asset/Character/Chr_Animation.cpp
Normal 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);
|
||||
}
|
||||
50
source_game/Asset/Character/Chr_Animation.h
Normal file
50
source_game/Asset/Character/Chr_Animation.h
Normal 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;
|
||||
};
|
||||
122
source_game/Asset/Character/Chr_Controller.cpp
Normal file
122
source_game/Asset/Character/Chr_Controller.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
24
source_game/Asset/Character/Chr_Controller.h
Normal file
24
source_game/Asset/Character/Chr_Controller.h
Normal 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; }
|
||||
};
|
||||
38
source_game/Asset/Character/Chr_Equipment.cpp
Normal file
38
source_game/Asset/Character/Chr_Equipment.cpp
Normal 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;
|
||||
}
|
||||
19
source_game/Asset/Character/Chr_Equipment.h
Normal file
19
source_game/Asset/Character/Chr_Equipment.h
Normal 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);
|
||||
};
|
||||
75
source_game/Asset/Character/Chr_StateMachine.cpp
Normal file
75
source_game/Asset/Character/Chr_StateMachine.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
source_game/Asset/Character/Chr_StateMachine.h
Normal file
22
source_game/Asset/Character/Chr_StateMachine.h
Normal 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);
|
||||
};
|
||||
Reference in New Issue
Block a user