[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"consumer-news-detail-941":3,"consumer-news-interaction-941":39,"consumer-news-related-941":42},{"detail":4,"item":35},{"card":5,"schemaVersion":22,"fields":23,"content":29},{"id":6,"kind":7,"targetType":8,"targetId":9,"subtype":7,"typeLabel":10,"title":11,"subtitle":12,"summary":13,"coverUrl":14,"badgeText":15,"href":16,"sourceName":12,"meta":17,"metrics":19,"tags":20,"resolved":21},"NEWS_ARTICLE:941","news","NEWS_ARTICLE",941,"资讯","【UE】动画蓝图参数屏幕调试工具","博客园","动画蓝图参数屏幕调试工具 这里用到的动画蓝图基类为自定义的UBaseAnimInstance 引脚 类型 默认值 \u002F 用法 Key FName 手动填写参数名称，不要加冒号 Value String 变量、转换结果、拼接结果或字符串常量均可 Key Color Linear Color 白色，包含自","https:\u002F\u002Fimg2024.cnblogs.com\u002Fblog\u002F3614909\u002F202609\u002F3614909-20260910131827752-546469957.png","","\u002Fnews\u002F941",[18],"2026",{},[],true,"consumer-content-detail-v1",{"sourceName":12,"authorName":24,"summary":13,"description":13,"publishTime":25,"updateTime":26,"sourceUrl":27,"language":28},"EanoJiang","2026-09-10T13:18","2026-09-11T15:21:59","https:\u002F\u002Fwww.cnblogs.com\u002Feanojiang\u002Fp\u002F22919927","中文",{"format":30,"policy":31,"normalized":21,"html":32,"text":33,"wordCount":34,"hasBody":21},"HTML","NEWS_CONTENT_V1","动画蓝图参数屏幕调试工具\n\u003Cblockquote>\n \u003Cp>这里用到的动画蓝图基类为自定义的\u003Ccode>UBaseAnimInstance\u003C\u002Fcode>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ctable>\n \u003Cthead>\n  \u003Ctr>\n   \u003Cth>引脚\u003C\u002Fth>\n   \u003Cth>类型\u003C\u002Fth>\n   \u003Cth>默认值 \u002F 用法\u003C\u002Fth>\n  \u003C\u002Ftr>\n \u003C\u002Fthead>\n \u003Ctbody>\n  \u003Ctr>\n   \u003Ctd>Key\u003C\u002Ftd>\n   \u003Ctd>FName\u003C\u002Ftd>\n   \u003Ctd>手动填写参数名称，不要加冒号\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n   \u003Ctd>Value\u003C\u002Ftd>\n   \u003Ctd>String\u003C\u002Ftd>\n   \u003Ctd>变量、转换结果、拼接结果或字符串常量均可\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n   \u003Ctd>Key Color\u003C\u002Ftd>\n   \u003Ctd>Linear Color\u003C\u002Ftd>\n   \u003Ctd>白色，包含自动添加的冒号\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n   \u003Ctd>Value Color\u003C\u002Ftd>\n   \u003Ctd>Linear Color\u003C\u002Ftd>\n   \u003Ctd>红色\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n   \u003Ctd>Location Offset\u003C\u002Ftd>\n   \u003Ctd>Vector\u003C\u002Ftd>\n   \u003Ctd>(0,-200,100)\u003C\u002Ftd>\n  \u003C\u002Ftr>\n \u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch2>使用效果\u003C\u002Fh2>\n\u003Cp>动画蓝图调用：\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fi1.wp.com\u002Fimg2024.cnblogs.com\u002Fblog\u002F3614909\u002F202609\u002F3614909-20260910131827752-546469957.png?w=720&amp;quality=65&amp;strip=all\" alt=\"1789017342449\">\u003C\u002Fp>\n\u003Cp>角色蓝图调用：\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fi1.wp.com\u002Fimg2024.cnblogs.com\u002Fblog\u002F3614909\u002F202609\u002F3614909-20260910131828163-1637059301.png?w=720&amp;quality=65&amp;strip=all\" alt=\"1789017311268\">\u003C\u002Fp>\n\u003Cp>效果(人物左侧显示))：\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fi1.wp.com\u002Fimg2024.cnblogs.com\u002Fblog\u002F3614909\u002F202609\u002F3614909-20260910131828746-270608583.png?w=720&amp;quality=65&amp;strip=all\" alt=\"1789017386936\">\u003C\u002Fp>\n\u003Ch2>迁移到自己的项目\u003C\u002Fh2>\n\u003Cp>将下面的声明及实现复制到目标 UAnimInstance 派生类中，替换类名和自身头文件名。前置声明放在类外，头文件 region 放在类内，generated.h 保持为最后一个 include。若已有生命周期函数，合并清理调用，不要重复定义。\u003C\u002Fp>\n\u003Cp>\u003Ccode>BaseAnimInstance.h\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre>\u003Ccode>class UCanvas;\nclass APlayerController;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode>#pragma region DrawDebugMessages\npublic:\n\tvirtual void NativeUninitializeAnimation() override;\n\tvirtual void BeginDestroy() override;\n\n\t\u002F\u002F 手动输入 Key 和 Value；独立颜色、共享位置偏移和自动分行。\n\tUFUNCTION(BlueprintCallable, Category = \"DebugDraw\")\n\tvoid DrawDebugKeyValueMessages(\n\t\tFName Key,\n\t\tconst FString&amp; Value,\n\t\tFLinearColor KeyColor = FLinearColor::White,\n\t\tFLinearColor ValueColor = FLinearColor::Red,\n\t\tFVector LocationOffset = FVector(0, -200, 100));\n\nprivate:\n\tstruct FDebugKeyValueMessage\n\t{\n\t\tFString KeyText;\n\t\tFString ValueText;\n\t\tFLinearColor KeyColor;\n\t\tFLinearColor ValueColor;\n\t\tFVector WorldLocation;\n\t};\n\n\tTArray&lt;FDebugKeyValueMessage&gt; DebugKeyValueMessages;\n\tuint64 DebugKeyValueFrame = MAX_uint64;\n\tFDelegateHandle DebugKeyValueDrawHandle;\n\tvoid DrawDebugKeyValueMessages(UCanvas* Canvas, APlayerController* PlayerController);\n\tvoid ClearDebugKeyValueMessages();\n#pragma endregion DrawDebugMessages\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>BaseAnimInstance.cpp\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre>\u003Ccode>#include \"BaseAnimInstance.h\"\n#include \"CanvasItem.h\"\n#include \"Debug\u002FDebugDrawService.h\"\n#include \"Engine\u002FCanvas.h\"\n#include \"Engine\u002FEngine.h\"\n#include \"GameFramework\u002FPlayerController.h\"\n#include \"SceneInterface.h\"\n#include \"SceneView.h\"\n#include \"Components\u002FSkeletalMeshComponent.h\"\n#include \"GameFramework\u002FPawn.h\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode>#pragma region DrawDebugMessages\n\nvoid UBaseAnimInstance::DrawDebugKeyValueMessages(\n\tconst FName Key,\n\tconst FString&amp; Value,\n\tconst FLinearColor KeyColor,\n\tconst FLinearColor ValueColor,\n\tconst FVector LocationOffset)\n{\n#if ENABLE_ANIM_DRAW_DEBUG\n\tif (!ensureMsgf(IsInGameThread(), TEXT(\"Draw Debug Key Value must run on the game thread.\")))\n\t{\n\t\treturn;\n\t}\n\tconst USkeletalMeshComponent* Mesh = GetSkelMeshComponent();\n\tconst AActor* Owner = Mesh ? Mesh-&gt;GetOwner() : nullptr;\n\tif (!Owner)\n\t{\n\t\treturn;\n\t}\n\n\tFVector DrawLocationOffset = LocationOffset;\n\tif (const APawn* PawnOwner = TryGetPawnOwner())\n\t{\n\t\tif (const APlayerController* PlayerController =\n\t\t\tCast&lt;APlayerController&gt;(PawnOwner-&gt;GetController()))\n\t\t{\n\t\t\tFVector ViewLocation;\n\t\t\tFRotator ViewRotation;\n\t\t\tPlayerController-&gt;GetPlayerViewPoint(ViewLocation, ViewRotation);\n\n\t\t\t\u002F\u002F XY 跟随完整相机旋转：X 沿视线前后，Y 沿相机左右。\n\t\t\t\u002F\u002F Z 单独叠加，继续保持世界向上。\n\t\t\tDrawLocationOffset = ViewRotation.RotateVector(\n\t\t\t\tFVector(LocationOffset.X, LocationOffset.Y, 0.0f))\n\t\t\t\t+ FVector(0.0f, 0.0f, LocationOffset.Z);\n\t\t}\n\t}\n\n\tif (DebugKeyValueFrame != GFrameCounter)\n\t{\n\t\tDebugKeyValueMessages.Reset();\n\t\tDebugKeyValueFrame = GFrameCounter;\n\t}\n\tDebugKeyValueMessages.Add({Key.ToString() + TEXT(\":\"), Value,\n\t\tKeyColor, ValueColor, Owner-&gt;GetActorLocation() + DrawLocationOffset});\n\tif (!DebugKeyValueDrawHandle.IsValid())\n\t{\n\t\tDebugKeyValueDrawHandle = UDebugDrawService::Register(TEXT(\"Game\"),\n\t\t\tFDebugDrawDelegate::CreateUObject(this, &amp;UBaseAnimInstance::DrawDebugKeyValueMessages));\n\t}\n#endif\n}\n\nvoid UBaseAnimInstance::DrawDebugKeyValueMessages(UCanvas* Canvas, APlayerController* PlayerController)\n{\n#if ENABLE_ANIM_DRAW_DEBUG\n\t\u002F\u002F Debug draw can be called for other editor\u002FPIE worlds. Never leak text into those views.\n\tif (!Canvas || !Canvas-&gt;Canvas || !Canvas-&gt;SceneView || !GEngine\n\t\t|| !Canvas-&gt;SceneView-&gt;Family || !Canvas-&gt;SceneView-&gt;Family-&gt;Scene\n\t\t|| Canvas-&gt;SceneView-&gt;Family-&gt;Scene-&gt;GetWorld() != GetWorld()\n\t\t|| DebugKeyValueFrame == MAX_uint64 || GFrameCounter - DebugKeyValueFrame &gt; 1)\n\t{\n\t\treturn;\n\t}\n\tUFont* Font = GEngine-&gt;GetSmallFont();\n\tif (!Font)\n\t{\n\t\treturn;\n\t}\n\t\u002F\u002F Reset for each viewport draw; stack this instance's messages in submission order.\n\tfloat LineOffsetY = 0.0f;\n\tconstexpr float LineSpacing = 4.0f;\n\tfor (const FDebugKeyValueMessage&amp; Message : DebugKeyValueMessages)\n\t{\n\t\tif (Canvas-&gt;SceneView-&gt;WorldToScreen(Message.WorldLocation).W &lt;= 0.0f)\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\tconst FVector ScreenLocation = Canvas-&gt;Project(Message.WorldLocation);\n\t\tconst FVector2D TextPosition(ScreenLocation.X, ScreenLocation.Y + LineOffsetY);\n\t\tfloat KeyWidth = 0.0f;\n\t\tfloat KeyHeight = 0.0f;\n\t\tCanvas-&gt;StrLen(Font, Message.KeyText, KeyWidth, KeyHeight);\n\t\tFCanvasTextItem KeyItem(TextPosition, FText::FromString(Message.KeyText), Font, Message.KeyColor);\n\t\tCanvas-&gt;DrawItem(KeyItem);\n\t\t\u002F\u002F Canvas does not reliably expand tabs; use an explicit screen-space gap.\n\t\tconstexpr float KeyValueGap = 24.0f;\n\t\tFCanvasTextItem ValueItem(TextPosition + FVector2D(KeyWidth + KeyValueGap, 0.0f),\n\t\t\tFText::FromString(Message.ValueText), Font, Message.ValueColor);\n\t\tCanvas-&gt;DrawItem(ValueItem);\n\t\tLineOffsetY += KeyHeight + LineSpacing;\n\t}\n#endif\n}\n\nvoid UBaseAnimInstance::ClearDebugKeyValueMessages()\n{\n\tif (DebugKeyValueDrawHandle.IsValid())\n\t{\n\t\tUDebugDrawService::Unregister(DebugKeyValueDrawHandle);\n\t\tDebugKeyValueDrawHandle.Reset();\n\t}\n\tDebugKeyValueMessages.Reset();\n\tDebugKeyValueFrame = MAX_uint64;\n}\n\nvoid UBaseAnimInstance::BeginDestroy()\n{\n\tClearDebugKeyValueMessages();\n\tSuper::BeginDestroy();\n}\n\nvoid UBaseAnimInstance::NativeUninitializeAnimation()\n{\n\tClearDebugKeyValueMessages();\n\tSuper::NativeUninitializeAnimation();\n}\n\n#pragma endregion DrawDebugMessages\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>编译与使用\u003C\u002Fh3>\n\u003Cp>目标运行时模块 Build.cs 确保依赖 Core、CoreUObject、Engine。\u003C\u002Fp>\n\u003Cp>关闭编辑器，完整编译 Development Editor，再重启并刷新蓝图节点。动画蓝图父类应为目标动画实例类；不要在线程安全动画更新中调用此函数。\u003C\u002Fp>\n\u003Ch2>多参数自动分行\u003C\u002Fh2>\n\u003Cblockquote>\n \u003Cp>\u003Cstrong>注意：要让多条参数自动排列成同一列，各个节点的 \u003Ccode>LocationOffset\u003C\u002Fcode>（X、Y、Z）必须保持一致。不要为每一行单独修改偏移，行距由工具自动累加；偏移不一致会导致文字错位或重叠。\u003C\u002Fstrong>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>同一帧连续调用多个节点，并使用相同的 \u003Ccode>LocationOffset\u003C\u002Fcode>。消息按调用顺序向屏幕下方排列，不需要逐条修改世界 Z。\u003C\u002Fp>\n\u003Cp>每绘制一条消息，累计屏幕偏移 \u003Ccode>LineOffsetY += KeyHeight + LineSpacing\u003C\u002Fcode>。\u003Ccode>LineSpacing\u003C\u002Fcode> 默认为 4 个画布像素，修改此常量可以调整额外行距；Key 与 Value 之间仍保持额外 24 像素间距。\u003C\u002Fp>\n\u003Cp>行偏移在每次视口绘制开始时重置，不会跨帧累计。镜头后方被跳过的消息不占行。同一个动画实例的消息共享这一行偏移；如果传入不同的 \u003Ccode>LocationOffset\u003C\u002Fcode>，还会在各自锚点上叠加累计行偏移。\u003C\u002Fp>\n\u003Cp>这是多条单行消息的自动分行，不是按屏幕宽度自动折行；Key 和 Value 建议均使用单行文本。需要持续显示时，每帧调用这些节点。\u003C\u002Fp>\n\u003Ch2>角色蓝图调用时\u003C\u002Fh2>\n\u003Cp>通过目标动画实例引用调用：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>目标 Skeletal Mesh Component\n    → Get Anim Instance\n    → Cast To BaseAnimInstance\n    → Draw Debug Key Value Messages（Target 接转换结果）\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>检查引用和 Cast 是否有效。文字跟随目标动画实例网格所属 Actor，而非另一个发起调用的 Actor。\u003C\u002Fp>","动画蓝图参数屏幕调试工具 这里用到的动画蓝图基类为自定义的UBaseAnimInstance 引脚 类型 默认值 \u002F 用法 Key FName 手动填写参数名称，不要加冒号 Value String 变量、转换结果、拼接结果或字符串常量均可 Key Color Linear Color 白色，包含自动添加的冒号 Value Color Linear Color 红色 Location Offset Vector (0,-200,100) 使用效果 动画蓝图调用： 角色蓝图调用： 效果(人物左侧显示))： 迁移到自己的项目 将下面的声明及实现复制到目标 UAnimInstance 派生类中，替换类名和自身头文件名。前置声明放在类外，头文件 region 放在类内，generated.h 保持为最后一个 include。若已有生命周期函数，合并清理调用，不要重复定义。 BaseAnimInstance.h class UCanvas; class APlayerController; #pragma region DrawDebugMessages public: virtual void NativeUninitializeAnimation() override; virtual void BeginDestroy() override; \u002F\u002F 手动输入 Key 和 Value；独立颜色、共享位置偏移和自动分行。 UFUNCTION(BlueprintCallable, Category = \"DebugDraw\") void DrawDebugKeyValueMessages( FName Key, const FString& Value, FLinearColor KeyColor = FLinearColor::White, FLinearColor ValueColor = FLinearColor::Red, FVector LocationOffset = FVector(0, -200, 100)); private: struct FDebugKeyValueMessage { FString KeyText; FString ValueText; FLinearColor KeyColor; FLinearColor ValueColor; FVector WorldLocation; }; TArray\u003CFDebugKeyValueMessage> DebugKeyValueMessages; uint64 DebugKeyValueFrame = MAX_uint64; FDelegateHandle DebugKeyValueDrawHandle; void DrawDebugKeyValueMessages(UCanvas* Canvas, APlayerController* PlayerController); void ClearDebugKeyValueMessages(); #pragma endregion DrawDebugMessages BaseAnimInstance.cpp #include \"BaseAnimInstance.h\" #include \"CanvasItem.h\" #include \"Debug\u002FDebugDrawService.h\" #include \"Engine\u002FCanvas.h\" #include \"Engine\u002FEngine.h\" #include \"GameFramework\u002FPlayerController.h\" #include \"SceneInterface.h\" #include \"SceneView.h\" #include \"Components\u002FSkeletalMeshComponent.h\" #include \"GameFramework\u002FPawn.h\" #pragma region DrawDebugMessages void UBaseAnimInstance::DrawDebugKeyValueMessages( const FName Key, const FString& Value, const FLinearColor KeyColor, const FLinearColor ValueColor, const FVector LocationOffset) { #if ENABLE_ANIM_DRAW_DEBUG if (!ensureMsgf(IsInGameThread(), TEXT(\"Draw Debug Key Value must run on the game thread.\"))) { return; } const USkeletalMeshComponent* Mesh = GetSkelMeshComponent(); const AActor* Owner = Mesh ? Mesh->GetOwner() : nullptr; if (!Owner) { return; } FVector DrawLocationOffset = LocationOffset; if (const APawn* PawnOwner = TryGetPawnOwner()) { if (const APlayerController* PlayerController = Cast\u003CAPlayerController>(PawnOwner->GetController())) { FVector ViewLocation; FRotator ViewRotation; PlayerController->GetPlayerViewPoint(ViewLocation, ViewRotation); \u002F\u002F XY 跟随完整相机旋转：X 沿视线前后，Y 沿相机左右。 \u002F\u002F Z 单独叠加，继续保持世界向上。 DrawLocationOffset = ViewRotation.RotateVector( FVector(LocationOffset.X, LocationOffset.Y, 0.0f)) + FVector(0.0f, 0.0f, LocationOffset.Z); } } if (DebugKeyValueFrame != GFrameCounter) { DebugKeyValueMessages.Reset(); DebugKeyValueFrame = GFrameCounter; } DebugKeyValueMessages.Add({Key.ToString() + TEXT(\":\"), Value, KeyColor, ValueColor, Owner->GetActorLocation() + DrawLocationOffset}); if (!DebugKeyValueDrawHandle.IsValid()) { DebugKeyValueDrawHandle = UDebugDrawService::Register(TEXT(\"Game\"), FDebugDrawDelegate::CreateUObject(this, &UBaseAnimInstance::DrawDebugKeyValueMessages)); } #endif } void UBaseAnimInstance::DrawDebugKeyValueMessages(UCanvas* Canvas, APlayerController* PlayerController) { #if ENABLE_ANIM_DRAW_DEBUG \u002F\u002F Debug draw can be called for other editor\u002FPIE worlds. Never leak text into those views. if (!Canvas || !Canvas->Canvas || !Canvas->SceneView || !GEngine || !Canvas->SceneView->Family || !Canvas->SceneView->Family->Scene || Canvas->SceneView->Family->Scene->GetWorld() != GetWorld() || DebugKeyValueFrame == MAX_uint64 || GFrameCounter - DebugKeyValueFrame > 1) { return; } UFont* Font = GEngine->GetSmallFont(); if (!Font) { return; } \u002F\u002F Reset for each viewport draw; stack this instance's messages in submission order. float LineOffsetY = 0.0f; constexpr float LineSpacing = 4.0f; for (const FDebugKeyValueMessage& Message : DebugKeyValueMessages) { if (Canvas->SceneView->WorldToScreen(Message.WorldLocation).W \u003C= 0.0f) { continue; } const FVector ScreenLocation = Canvas->Project(Message.WorldLocation); const FVector2D TextPosition(ScreenLocation.X, ScreenLocation.Y + LineOffsetY); float KeyWidth = 0.0f; float KeyHeight = 0.0f; Canvas->StrLen(Font, Message.KeyText, KeyWidth, KeyHeight); FCanvasTextItem KeyItem(TextPosition, FText::FromString(Message.KeyText), Font, Message.KeyColor); Canvas->DrawItem(KeyItem); \u002F\u002F Canvas does not reliably expand tabs; use an explicit screen-space gap. constexpr float KeyValueGap = 24.0f; FCanvasTextItem ValueItem(TextPosition + FVector2D(KeyWidth + KeyValueGap, 0.0f), FText::FromString(Message.ValueText), Font, Message.ValueColor); Canvas->DrawItem(ValueItem); LineOffsetY += KeyHeight + LineSpacing; } #endif } void UBaseAnimInstance::ClearDebugKeyValueMessages() { if (DebugKeyValueDrawHandle.IsValid()) { UDebugDrawService::Unregister(DebugKeyValueDrawHandle); DebugKeyValueDrawHandle.Reset(); } DebugKeyValueMessages.Reset(); DebugKeyValueFrame = MAX_uint64; } void UBaseAnimInstance::BeginDestroy() { ClearDebugKeyValueMessages(); Super::BeginDestroy(); } void UBaseAnimInstance::NativeUninitializeAnimation() { ClearDebugKeyValueMessages(); Super::NativeUninitializeAnimation(); } #pragma endregion DrawDebugMessages 编译与使用 目标运行时模块 Build.cs 确保依赖 Core、CoreUObject、Engine。 关闭编辑器，完整编译 Development Editor，再重启并刷新蓝图节点。动画蓝图父类应为目标动画实例类；不要在线程安全动画更新中调用此函数。 多参数自动分行 注意：要让多条参数自动排列成同一列，各个节点的 LocationOffset（X、Y、Z）必须保持一致。不要为每一行单独修改偏移，行距由工具自动累加；偏移不一致会导致文字错位或重叠。 同一帧连续调用多个节点，并使用相同的 LocationOffset。消息按调用顺序向屏幕下方排列，不需要逐条修改世界 Z。 每绘制一条消息，累计屏幕偏移 LineOffsetY += KeyHeight + LineSpacing。LineSpacing 默认为 4 个画布像素，修改此常量可以调整额外行距；Key 与 Value 之间仍保持额外 24 像素间距。 行偏移在每次视口绘制开始时重置，不会跨帧累计。镜头后方被跳过的消息不占行。同一个动画实例的消息共享这一行偏移；如果传入不同的 LocationOffset，还会在各自锚点上叠加累计行偏移。 这是多条单行消息的自动分行，不是按屏幕宽度自动折行；Key 和 Value 建议均使用单行文本。需要持续显示时，每帧调用这些节点。 角色蓝图调用时 通过目标动画实例引用调用： 目标 Skeletal Mesh Component → Get Anim Instance → Cast To BaseAnimInstance → Draw Debug Key Value Messages（Target 接转换结果） 检查引用和 Cast 是否有效。文字跟随目标动画实例网格所属 Actor，而非另一个发起调用的 Actor。",5457,{"id":6,"kind":7,"title":11,"summary":13,"image":14,"href":16,"meta":18,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":38},"#2563eb","16 \u002F 10",[7,8],{"targetType":8,"targetId":9,"likedByMe":40,"likeCount":41,"commentCount":41,"contentLikeCount":41,"contentCommentCount":41,"sourceLikeCount":41,"sourceCommentCount":41},false,0,[43,52,58,64,73,80,86,93],{"id":44,"kind":7,"title":45,"summary":46,"image":47,"href":48,"meta":49,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":50},"NEWS_ARTICLE:927","HelloCrab - 短视频开源爬虫，仅供学习参考","HelloCrab 基于 Avalonia、Playwright、AI与 FFmpeg 的跨平台桌面采集器，支持9大平台，以及 Android、iOS、Browser 远程控制端。 Made By ChatGPT &amp; Vincent with ❤ 平台 是否接入 哔哩哔哩 ✅ 抖音 ✅ 快手","https:\u002F\u002Fwww.cnblogs.com\u002Fhupo376787\u002Fp\u002FScreenshot\u002FWindows.jpg","\u002Fnews\u002F927","2026 · 软件开发",[51],"软件开发",{"id":53,"kind":7,"title":54,"summary":55,"image":15,"href":56,"meta":49,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":57},"NEWS_ARTICLE:929",".NET 异常处理的\"暗门\"：代码里写满 catch，你依然能抓住它——从一个 AI Agent 运行时的源码说起","一个健壮的系统，必然到处都是有意的 catch；异常被消化不等于问题不存在。 观测与韧性，是一个硬币的两面——降级逻辑保证系统不崩，FirstChance 保证你能看见它为什么降级。","\u002Fnews\u002F929",[51],{"id":59,"kind":7,"title":60,"summary":61,"image":15,"href":62,"meta":18,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":63},"NEWS_ARTICLE:928","架构师化繁为简，执行者化简为繁","新手改三天，你改三行——反而是你显得更不重要。因为化繁为简做得越纯熟，产出看起来越小。这篇聊聊两种能力的辩证关系，以及为什么'看不见'的那部分工作，恰恰是最难的部分。","\u002Fnews\u002F928",[7,8],{"id":65,"kind":7,"title":66,"summary":67,"image":68,"href":69,"meta":70,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":71},"NEWS_ARTICLE:930","基于 vLLM+Nginx 构建负载均衡推理集群","企业内部私有环境部署大模型推理集群时，很容易遇到流量调度混乱、节点负载失衡、会话上下文丢失、接口缺少鉴权防护等一系列问题，单 vLLM 推理节点难以支撑并发请求。本文基于 Ubuntu 22.04 系统环境，搭建 Nginx + vLLM-Semantic-Router + vLLM-Router","https:\u002F\u002Fimg2024.cnblogs.com\u002Fblog\u002F1379525\u002F202609\u002F1379525-20260910165534385-2022408098.png","\u002Fnews\u002F930","2026 · 人工智能",[72],"人工智能",{"id":74,"kind":7,"title":75,"summary":76,"image":77,"href":78,"meta":70,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":79},"NEWS_ARTICLE:932","2026年AI编程工具大全，33个主流工具一次看懂","事情是这样的，前两天看到一张图，是某个社区官网的「支持的工具」清单，我数了数，整整31个AI编程工具。 两年前这份清单撑死5个，现在直接31个，而且我居然每一个都认识。。。 干脆整理成一篇，顺手把最近字节的TraeWork和豆包工作也补了进来，凑成33个。 今天给大家推荐一遍，每个工具说说它是干什么","https:\u002F\u002Fimage.kjdaohang.com\u002Fimg\u002F20260909210838518.png","\u002Fnews\u002F932",[72],{"id":81,"kind":7,"title":82,"summary":83,"image":15,"href":84,"meta":18,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":85},"NEWS_ARTICLE:931","SH 中文化样例数据使用手册","在数据库演示与 PoC 场景中，Oracle 自带的 SH 示例模式虽然经典，但英文维度数据往往让国内演示效果打折扣。笔者整理了一套方案：保留 SH 标准英文对象名，同时装载中文化维度数据，并按参数生成可复现的销售历史数据，方便个人测试与概念验证。 01 | 环境准备 使用前请确认满足以下条件： O","\u002Fnews\u002F931",[7,8],{"id":87,"kind":7,"title":88,"summary":89,"image":90,"href":91,"meta":49,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":92},"NEWS_ARTICLE:933","写给 C++ 工程师的 OpenClaw.NET 上手指南：用你熟悉的 C++ 思维，跑起一个生产级 AI Agent","它像一个「基于 boost.asio + REST 端点的常驻服务」——对外是 HTTP \u002F WebSocket \u002F 各 IM 的 webhook，对内跑着一个能调工具、读写记忆、跨渠道对话的 AI Agent——只不过协程不用你手写 promise_type，内存不用你管 new\u002Fdelete。","https:\u002F\u002Fimg2024.cnblogs.com\u002Fblog\u002F510\u002F202609\u002F510-20260905070811424-1837144874.jpg","\u002Fnews\u002F933",[51],{"id":94,"kind":7,"title":95,"summary":96,"image":97,"href":98,"meta":70,"badge":10,"author":12,"stats":-1,"accent":36,"coverRatio":37,"tags":99},"NEWS_ARTICLE:935","[Agent Memory \u002F 强化学习] MemPO源码学习笔记 ---（1）--- 总体","[Agent Memory \u002F 强化学习] MemPO源码学习笔记 （1） 总体 目录[Agent Memory \u002F 强化学习] MemPO源码学习笔记 （1） 总体0x00 概要0x01 基础 &amp; 背景1.1 用RL训练记忆系统的要点1.2 主要难点1.3 主要思路1.4 RL训练方案1.","https:\u002F\u002Fimg2024.cnblogs.com\u002Fblog\u002F1850883\u002F202609\u002F1850883-20260906190854637-986949885.jpg","\u002Fnews\u002F935",[72]]