阶段性合并:动画重定向、碎裂共享库、第三人称玩法、编辑器面板与 vendored ufbx
- 动画:HumanoidRig 三层架构(standard 标准槽 / dialects 方言映射 / mapper 配对), 指/趾统一走世界增量两遍式烘焙;AnimationAttach 拆为纯算法 + facade;修正 HumanoidBasis 行走基朝向与跨骨架去重、根运动通道 - 物理:CharacterController 角色互碰撞 / shapeOffset / 接触事件;PhysicsWorld 接触合成与 字符冲量判定 - 渲染与材质:Model 多材质按材质拆子 mesh 与贴图路径解析、DDS 直传、GLB 内嵌纹理落盘、 不透明通道 alpha 固定 1.0、glTF FlipUVs 对齐;SceneSerializer 支持 meshIndex 与材质覆盖 - 脚本:FractureLib 抽为共享库(HostView 桥接)、WallFracture 参数直绑、新增 ThirdPersonCamera / Follower / WASDMove 玩法;移除 GameDirector / PlayerController / Target - 编辑器:新增 GamepadPanel、LogPanel(LogRing),改进 Inspector / 材质 / 统计 / 视口面板 - 依赖:vendored ufbx(FBX 5.x/6.x/7.x 全版本解析,替代 assimp 对 FBX 6.1 的拒读)
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
//
|
||||
// GamepadPanel.cpp:手柄输入可视化回显(极简手柄视图)。
|
||||
//
|
||||
// 一块画布 = 手柄俯视图:顶部扳机条 + 肩键,左上左摇杆、左下十字键、
|
||||
// 右上 ABXY(Xbox 语义色)、右下右摇杆,中央 Back/Guide/Start 小键。
|
||||
// 按下即亮蓝(面键亮语义色),无数值无卡片——位置即实体,一眼对上
|
||||
// 手里的手柄。数据源 = Window::PollGamepad(GLFW 原始轴值/按键)。
|
||||
//
|
||||
|
||||
#include "GamepadPanel.h"
|
||||
|
||||
#include <Engine/Core/Window.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
|
||||
// GLFW 标准布局下标
|
||||
enum PadBtn {
|
||||
kA = 0, kB = 1, kX = 2, kY = 3,
|
||||
kLB = 4, kRB = 5, kBack = 6, kStart = 7, kGuide = 8,
|
||||
kLS = 9, kRS = 10, kUp = 11, kRight = 12, kDown = 13, kLeft = 14,
|
||||
};
|
||||
|
||||
constexpr ImU32 kLit = IM_COL32(90, 170, 250, 255); // 按下亮蓝
|
||||
constexpr ImU32 kFill = IM_COL32(52, 52, 60, 255); // 暗态填充
|
||||
constexpr ImU32 kEdge = IM_COL32(104, 104, 114, 255); // 暗态描边
|
||||
constexpr ImU32 kTxt = IM_COL32(215, 215, 220, 255); // 标签文字
|
||||
|
||||
// 块状键(肩键 / Back / Start)
|
||||
void Block(ImDrawList* dl, const ImVec2& c, float w, float h,
|
||||
const char* label, bool pressed)
|
||||
{
|
||||
const ImVec2 mn(c.x - w * 0.5f, c.y - h * 0.5f);
|
||||
const ImVec2 mx(c.x + w * 0.5f, c.y + h * 0.5f);
|
||||
dl->AddRectFilled(mn, mx, pressed ? kLit : kFill, 5.0f);
|
||||
dl->AddRect(mn, mx, pressed ? IM_COL32(160, 210, 255, 255) : kEdge,
|
||||
5.0f);
|
||||
const ImVec2 ts = ImGui::CalcTextSize(label);
|
||||
dl->AddText(ImVec2(c.x - ts.x * 0.5f, c.y - ts.y * 0.5f), kTxt, label);
|
||||
}
|
||||
|
||||
// 圆键(Guide)
|
||||
void Circle(ImDrawList* dl, const ImVec2& c, float r, const char* label,
|
||||
bool pressed)
|
||||
{
|
||||
dl->AddCircleFilled(c, r, pressed ? kLit : kFill);
|
||||
dl->AddCircle(c, r, pressed ? IM_COL32(160, 210, 255, 255) : kEdge, 0,
|
||||
1.5f);
|
||||
const ImVec2 ts = ImGui::CalcTextSize(label);
|
||||
dl->AddText(ImVec2(c.x - ts.x * 0.5f, c.y - ts.y * 0.5f), kTxt, label);
|
||||
}
|
||||
|
||||
// Xbox 语义色面键
|
||||
void Face(ImDrawList* dl, const ImVec2& c, float r, char label,
|
||||
bool pressed)
|
||||
{
|
||||
ImU32 col;
|
||||
switch (label)
|
||||
{
|
||||
case 'A': col = IM_COL32(32, 150, 40, 255); break;
|
||||
case 'B': col = IM_COL32(200, 45, 45, 255); break;
|
||||
case 'X': col = IM_COL32(50, 110, 220, 255); break;
|
||||
default: col = IM_COL32(225, 185, 40, 255); break;
|
||||
}
|
||||
dl->AddCircleFilled(c, r, pressed ? col : IM_COL32(col & 0xFF,
|
||||
(col >> 8) & 0xFF,
|
||||
(col >> 16) & 0xFF,
|
||||
60));
|
||||
dl->AddCircle(c, r, pressed ? col : kEdge, 0, 2.0f);
|
||||
const ImVec2 ts = ImGui::CalcTextSize(&label, &label + 1);
|
||||
dl->AddText(ImVec2(c.x - ts.x * 0.5f, c.y - ts.y * 0.5f),
|
||||
pressed ? IM_COL32(255, 255, 255, 255) : kTxt, &label);
|
||||
}
|
||||
|
||||
// 摇杆画布(底座 + 死区圈 + 轴点)
|
||||
void Stick(ImDrawList* dl, const ImVec2& c, float r, float ax, float ay,
|
||||
float deadzone)
|
||||
{
|
||||
dl->AddCircleFilled(c, r, IM_COL32(32, 32, 37, 255));
|
||||
dl->AddCircle(c, r, kEdge, 0, 1.5f);
|
||||
dl->AddCircle(c, r * deadzone, IM_COL32(90, 140, 210, 110), 0, 1.2f);
|
||||
dl->AddLine(ImVec2(c.x - r * 0.93f, c.y), ImVec2(c.x + r * 0.93f, c.y),
|
||||
IM_COL32(50, 50, 58, 255), 1.0f);
|
||||
dl->AddLine(ImVec2(c.x, c.y - r * 0.93f), ImVec2(c.x, c.y + r * 0.93f),
|
||||
IM_COL32(50, 50, 58, 255), 1.0f);
|
||||
const float mag = std::sqrt(ax * ax + ay * ay);
|
||||
const float cl = (mag > 1.0f) ? 1.0f / mag : 1.0f;
|
||||
const ImVec2 pt(c.x + ax * cl * (r - 8.0f),
|
||||
c.y + ay * cl * (r - 8.0f));
|
||||
if (mag > deadzone)
|
||||
{
|
||||
dl->AddCircleFilled(pt, 10.0f, IM_COL32(90, 170, 250, 70));
|
||||
}
|
||||
dl->AddCircleFilled(pt, 7.0f,
|
||||
mag > deadzone ? kLit
|
||||
: IM_COL32(140, 140, 148, 255));
|
||||
}
|
||||
|
||||
// 十字键(真十字形,按下臂亮)
|
||||
void Dpad(ImDrawList* dl, const ImVec2& c, float arm, float w,
|
||||
const bool* b)
|
||||
{
|
||||
const ImVec2 l0(c.x - arm, c.y - w * 0.5f);
|
||||
const ImVec2 l1(c.x, c.y + w * 0.5f);
|
||||
const ImVec2 r0(c.x, c.y - w * 0.5f);
|
||||
const ImVec2 r1(c.x + arm, c.y + w * 0.5f);
|
||||
const ImVec2 u0(c.x - w * 0.5f, c.y - arm);
|
||||
const ImVec2 u1(c.x + w * 0.5f, c.y);
|
||||
const ImVec2 d0(c.x - w * 0.5f, c.y);
|
||||
const ImVec2 d1(c.x + w * 0.5f, c.y + arm);
|
||||
dl->AddRectFilled(l0, l1, b[kLeft] ? kLit : kFill, 4.0f);
|
||||
dl->AddRectFilled(r0, r1, b[kRight] ? kLit : kFill, 4.0f);
|
||||
dl->AddRectFilled(u0, u1, b[kUp] ? kLit : kFill, 4.0f);
|
||||
dl->AddRectFilled(d0, d1, b[kDown] ? kLit : kFill, 4.0f);
|
||||
dl->AddRect(l0, l1, kEdge, 4.0f);
|
||||
dl->AddRect(r0, r1, kEdge, 4.0f);
|
||||
dl->AddRect(u0, u1, kEdge, 4.0f);
|
||||
dl->AddRect(d0, d1, kEdge, 4.0f);
|
||||
}
|
||||
|
||||
// 线性扳机条(GLFW -1..1 → 0..1 填充)
|
||||
void Trigger(ImDrawList* dl, const ImVec2& mn, const ImVec2& mx,
|
||||
float raw)
|
||||
{
|
||||
dl->AddRectFilled(mn, mx, IM_COL32(32, 32, 37, 255), 4.0f);
|
||||
const float t = (raw + 1.0f) * 0.5f;
|
||||
if (t > 0.02f)
|
||||
{
|
||||
dl->AddRectFilled(mn, ImVec2(mn.x + (mx.x - mn.x) * t, mx.y),
|
||||
IM_COL32(235, 120, 55, 255), 4.0f);
|
||||
}
|
||||
dl->AddRect(mn, mx, kEdge, 4.0f);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void GamepadPanel::Draw(const EditorContext& ctx)
|
||||
{
|
||||
if (!m_Open)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!ImGui::Begin("Gamepad", &m_Open))
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
Engine::GamepadState gp;
|
||||
const bool connected =
|
||||
ctx.app && ctx.app->GetWindow().PollGamepad(gp);
|
||||
|
||||
if (!connected)
|
||||
{
|
||||
ImGui::TextColored(ImVec4(0.60f, 0.60f, 0.60f, 1.0f),
|
||||
"○ Not connected (JOYSTICK_1)");
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
ImGui::TextColored(ImVec4(0.40f, 0.85f, 0.40f, 1.0f), "● Connected");
|
||||
ImGui::Spacing();
|
||||
|
||||
// ---- 手柄画布(固定尺寸,元素 = 手柄真实位置;无背景板)----
|
||||
constexpr float kW = 440.0f, kH = 262.0f;
|
||||
constexpr float kDead = 0.15f; // = InputMap kRadialDeadZone
|
||||
ImGui::BeginChild("pad", ImVec2(kW, kH), false);
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
const ImVec2 o = ImGui::GetWindowPos();
|
||||
auto C = [&](float x, float y) { return ImVec2(o.x + x, o.y + y); };
|
||||
|
||||
// 顶部:线性扳机条 + 肩键
|
||||
Trigger(dl, C(52, 8), C(122, 20), gp.axes[4]); // LT
|
||||
Trigger(dl, C(kW - 122, 8), C(kW - 52, 20), gp.axes[5]); // RT
|
||||
Block(dl, C(78, 40), 76.0f, 20.0f, "LB", gp.buttons[kLB]);
|
||||
Block(dl, C(kW - 78, 40), 76.0f, 20.0f, "RB", gp.buttons[kRB]);
|
||||
|
||||
// 左上:左摇杆|左下:十字键(向右错开——真实手柄摇杆与十字不对齐)
|
||||
Stick(dl, C(76, 118), 46.0f, gp.axes[0], gp.axes[1], kDead);
|
||||
Dpad(dl, C(128, 210), 36.0f, 24.0f, gp.buttons);
|
||||
|
||||
// 中央:Back / Guide / Start
|
||||
Block(dl, C(184, 74), 40.0f, 16.0f, "Back", gp.buttons[kBack]);
|
||||
Circle(dl, C(220, 58), 13.0f, "G", gp.buttons[kGuide]);
|
||||
Block(dl, C(256, 74), 40.0f, 16.0f, "Start", gp.buttons[kStart]);
|
||||
|
||||
// 右上:ABXY 菱形|右下:右摇杆(对称错开,向中心收)
|
||||
const ImVec2 fc = C(360, 118);
|
||||
Face(dl, ImVec2(fc.x, fc.y - 24), 17.0f, 'Y', gp.buttons[kY]);
|
||||
Face(dl, ImVec2(fc.x - 24, fc.y), 17.0f, 'X', gp.buttons[kX]);
|
||||
Face(dl, ImVec2(fc.x + 24, fc.y), 17.0f, 'B', gp.buttons[kB]);
|
||||
Face(dl, ImVec2(fc.x, fc.y + 24), 17.0f, 'A', gp.buttons[kA]);
|
||||
Stick(dl, C(312, 210), 46.0f, gp.axes[2], gp.axes[3], kDead);
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::End();
|
||||
}
|
||||
Reference in New Issue
Block a user