{"id":297,"date":"2024-05-22T19:06:17","date_gmt":"2024-05-22T11:06:17","guid":{"rendered":"https:\/\/www.vanforever.com.cn\/?p=297"},"modified":"2024-10-08T22:52:40","modified_gmt":"2024-10-08T14:52:40","slug":"ue-%e4%ba%92%e5%8a%a8%e5%ad%a6%e4%b9%a0%e4%b9%8b%e8%b7%af","status":"publish","type":"post","link":"https:\/\/www.vanforever.com.cn\/?p=297","title":{"rendered":"UE \u4e92\u52a8\u5b66\u4e60\u4e4b\u8def"},"content":{"rendered":"<p id=\"ue-\u4e92\u52a8\u5b66\u4e60\u4e4b\u8def\"><div  class='collapse-block shadow-sm collapse-block-transparent collapsed hide-border-left'><div class='collapse-block-title'><span class='collapse-block-title-inner'>\u67e5\u770b\u7279\u8272\u56fe\u7247<\/span><i class='collapse-icon fa fa-angle-down'><\/i><\/div><div class='collapse-block-body' style='display:none;'><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/Vanforever\/20240421\/wallhaven-l87pjy_3840x2400.png'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large\" data-original=\"https:\/\/pic.vanforever.com.cn\/Vanforever\/20240421\/wallhaven-l87pjy_3840x2400.png\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" width=\"3840\" height=\"2400\" \/><\/div><\/div><\/div><\/p>\n<h1 id=\"ue-\u4e92\u52a8\u5b66\u4e60\u4e4b\u8def\">UE \u4e92\u52a8\u5b66\u4e60\u4e4b\u8def<\/h1>\n<h2 id=\"\u706b\u836f\u6876\u7206\u70b8\">\u706b\u836f\u6876\u7206\u70b8<\/h2>\n<p>\u521b\u5efa\u4e00\u4e2aSExplosiveBarrel\u7c7b,\u57fa\u7c7b\u4e3aAActor\u3002\u8be5\u7c7b\u5305\u542b\u4e24\u4e2a\u5173\u952e\u7ec4\u4ef6\uff1aMeshComp\u548cForceComp\uff0c\u5206\u522b\u63a7\u5236\u6a21\u578b\u548c\u7206\u70b8\u7684\u529b\u573a\u3002<\/p>\n<p>\u7206\u70b8\u5176\u5b9e\u672c\u8d28\u662f\u53d7\u5230\u78b0\u649e\u68c0\u6d4b\u7684\u5f71\u54cd\uff0c\u901a\u8fc7\u4e0d\u540c\u7684\u78b0\u649e\u8bbe\u7f6e\u6211\u4eec\u53ef\u4ee5\u5b9e\u73b0\uff0c\u7206\u70b8\u662f\u5426\u5f71\u54cd\u5230\u81ea\u8eab<\/p>\n<p>\u5b8c\u6574\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/ SExplosiveBarrel.h\n\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"GameFramework\/Actor.h\"\n#include \"SExplosiveBarrel.generated.h\"\n\nclass URadialForceComponent;\nclass UStaticMeshComponent;\n\nUCLASS()\nclass ACTIONROGUELIKE_API ASExplosiveBarrel : public AActor\n{\n\tGENERATED_BODY()\n\t\npublic:\t\n\t\/\/ Sets default values for this actor's properties\n\tASExplosiveBarrel();\n\n\nprotected:\n\tUPROPERTY(VisibleAnywhere)\n\tTObjectPtr&lt;UStaticMeshComponent&gt; MeshComp;\n\n\tUPROPERTY(VisibleAnywhere)\n\tTObjectPtr&lt;URadialForceComponent&gt; ForceComp;\n\n\tvirtual void PostInitializeComponents() override;\n\n\n\tUFUNCTION()\n\tvoid OnActorHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,\n\t\t\t\t\tFVector NormalImpulse, const FHitResult&amp; Hit);\n\t\n\n};\n\n<\/code><\/pre>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/ SExplosiveBarrel.cpp\n\n\n#include \"SExplosiveBarrel.h\"\n#include \"PhysicsEngine\/RadialForceComponent.h\"\n#include \"DrawDebugHelpers.h\"\n\n\/\/ Sets default values\nASExplosiveBarrel::ASExplosiveBarrel()\n{\n\tMeshComp = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(\"MeshComp\");\n\tMeshComp-&gt;SetSimulatePhysics(true);\n\t\/\/ Enabling Simulate physics automatically changes the Profile to PhysicsActor in Blueprint, in C++ we need to change this manually.\n\tMeshComp-&gt;SetCollisionProfileName(UCollisionProfile::PhysicsActor_ProfileName); \n\tRootComponent = MeshComp;\n\n\tForceComp = CreateDefaultSubobject&lt;URadialForceComponent&gt;(\"ForceComp\");\n\tForceComp-&gt;SetupAttachment(MeshComp);\n\n\t\/\/ Leaving this on applies small constant force via component 'tick' (Optional)\n\tForceComp-&gt;SetAutoActivate(false);\n\n\tForceComp-&gt;Radius = 750.0f;\n\tForceComp-&gt;ImpulseStrength = 2500.0f; \/\/ Alternative: 200000.0 if bImpulseVelChange = false\n\t\/\/ Optional, ignores 'Mass' of other objects (if false, the impulse strength will be much higher to push most objects depending on Mass)\n\tForceComp-&gt;bImpulseVelChange = true;\n\n\t\/\/ Optional, default constructor of component already adds 4 object types to affect, excluding WorldDynamic\n\tForceComp-&gt;AddCollisionChannelToAffect(ECC_WorldDynamic);\n}\n\n\n\nvoid ASExplosiveBarrel::PostInitializeComponents()\n{\n\t\/\/ Don't forget to call parent function\n\tSuper::PostInitializeComponents();\n\n\tMeshComp-&gt;OnComponentHit.AddDynamic(this, &amp;ASExplosiveBarrel::OnActorHit);\n}\n\nvoid ASExplosiveBarrel::OnActorHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult&amp; Hit)\n{\n\tForceComp-&gt;FireImpulse();\n\n\tUE_LOG(LogTemp,Log,TEXT(\"OnActorHit in Explosive Barrel\"));\n\n\tUE_LOG(LogTemp,Warning,TEXT(\"OtherActor: %s , at the game time: %f\"), *GetNameSafe(OtherActor),GetWorld()-&gt;TimeSeconds);\n\n\n\tFString CombinedString = FString::Printf(TEXT(\"Hit at the location: %s\"), *Hit.ImpactPoint.ToString());\n\tDrawDebugString(GetWorld(),Hit.ImpactPoint,CombinedString,nullptr,FColor::Green,2.0f,true);\n}\n\n\n\n\n<\/code><\/pre>\n<p>\u5728UE\u4e2d\u521b\u5efaExplosiveBarrel\u84dd\u56fe\u7c7b\u7ee7\u627f\u81eaSExplosiveBarrel\uff0c\u5e76\u7ed9\u4ed6\u5206\u914d\u4e00\u4e2a\u7f51\u683c\u4f53\u548c\u6750\u8d28\u3002<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240522\/2024052201.png'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240522\/2024052201.png\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<h2 id=\"\u6253\u5f00\u7bb1\u5b50\">\u6253\u5f00\u7bb1\u5b50<\/h2>\n<h3 id=\"1-\u521b\u5efa\u7bb1\u5b50\u548cui\u7c7b\">1. \u521b\u5efa\u7bb1\u5b50\u548cUI\u7c7b<\/h3>\n<p>\u5728\u8fd9\u8282\u5185\u5bb9\uff0c\u9700\u8981\u5b9e\u73b0\u89d2\u8272\u6309\u4e0b\u952e\u76d8E\u6765\u6253\u5f00\u7269\u54c1\u7bb1\u3002\u9996\u5148\u5728UE\u4e2d\u521b\u5efa\u4e00\u4e2aSGameplayInterface\u7c7b\uff0c\u7ee7\u627f\u81eaUnreal\u63a5\u53e3\u7c7b\uff0c\u4f1a\u53d1\u73b0.h\u6587\u4ef6\u4e2d\u751f\u6210\u4e86\u4e24\u4e2a\u7c7b\uff1a<strong>U<\/strong>SGameplayInterface\u548c<strong>I<\/strong>SGameplayInterface\u3002\u6839\u636e\u4ee3\u7801\u6ce8\u91ca\uff0c\u7b2c\u4e00\u4e2a\u7c7b\u4e0d\u5e94\u8be5\u88ab\u4fee\u6539\uff0c\u76f8\u5173\u529f\u80fd\u9700\u8981\u6dfb\u52a0\u5230\u7b2c\u4e8c\u4e2a\u7c7b\u4e2d\u3002\u8fd9\u4e2a\u7c7b\u7684\u4f5c\u7528\u662f\u4f5c\u4e3a\u5171\u4eab\u7684\u516c\u5171\u63a5\u53e3\uff0c\u5177\u4f53\u5b9e\u73b0\u9700\u8981\u5176\u4ed6\u7c7b\u6765\u91cd\u5199<\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/ This class does not need to be modified.\nUINTERFACE(MinimalAPI)\nclass USGameplayInterface : public UInterface\n{\n\tGENERATED_BODY()\n};\n\n\/**\n * \n *\/\nclass ACTIONROGUELIKE_API ISGameplayInterface\n{\n\tGENERATED_BODY()\n\n\t\/\/ Add interface functions to this class. This is the class that will be inherited to implement this interface.\n};\n<\/code><\/pre>\n<p>\u5177\u4f53\u7684\u5b9e\u73b0\u65b9\u5f0f\uff0c \u662f\u4f7f\u7528UFUNCTION\u5b8f\u6765\u4fee\u9970\u6211\u4eec\u81ea\u5df1\u7f16\u5199\u7684Interact\u51fd\u6570\uff0c\u4f7f\u5176\u53ef\u4ee5\u5728UE\u84dd\u56fe\u4e2d\u4f7f\u7528\u548c\u7f16\u8f91\u3002\u540c\u65f6\u8bbe\u7f6e\u8fd9\u4e2a\u51fd\u6570\u7684\u8f93\u5165\uff0c\u53ef\u4ee5\u4f20\u5165\u4e0d\u540c\u7684APawn\u5bf9\u8c61\uff08\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570\u7684\u4e3b\u4f53\uff09\u6765\u65b9\u4fbf\u6211\u4eec\u63a7\u5236\u76f8\u5173\u52a8\u753b\u7684\u663e\u793a\u3002\u76f8\u5173\u7684UFUNCTION\u7528\u6cd5\u6709\uff1a<\/p>\n<figure class=\"table-figure\">\n<table>\n<thead>\n<tr>\n<th><strong>BlueprintCallable<\/strong><\/th>\n<th><strong>\u53ef\u5728\u84dd\u56fe\u4e2d\u8c03\u7528<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>BlueprintImplementableEvent<\/strong><\/td>\n<td><strong>\u53ef\u5728\u84dd\u56fe\u4e2d\u5b9e\u73b0<\/strong><\/td>\n<\/tr>\n<tr>\n<td><strong>BlueprintNativeEvent<\/strong><\/td>\n<td><strong>\u84dd\u56fe\u53ef\u8c03\u7528\u53ef\u5b9e\u73b0\uff1b\u9700\u8981\u88ab\u91cd\u5199\uff0c\u4f46\u4e5f\u6709\u9ed8\u8ba4\u5b9e\u73b0<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SGameplayInterface.h\n\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject\/Interface.h\"\n#include \"SGameplayInterface.generated.h\"\n\n\/\/ This class does not need to be modified.\nUINTERFACE(MinimalAPI)\nclass USGameplayInterface : public UInterface\n{\n\tGENERATED_BODY()\n};\n\n\/**\n * \n *\/\nclass ACTIONROGUELIKE_API ISGameplayInterface\n{\n\tGENERATED_BODY()\n\n\t\/\/ Add interface functions to this class. This is the class that will be inherited to implement this interface.\npublic:\n\n\tUFUNCTION(BlueprintCallable,BlueprintNativeEvent)\n\tvoid Interact(APawn* InstigatorPawn);\n};\n\n<\/code><\/pre>\n<p>\u7136\u540e\uff0c\u4eceAActor\u548cISGameplayInterface\u6d3e\u751f\u4e00\u4e2aSItemChest\u7bb1\u5b50\u7c7b\uff0c\u5e76\u6dfb\u52a0\u4e24\u4e2aMesh\u63a7\u4ef6\uff0c\u5206\u522b\u8868\u793a\u7bb1\u5b50\u7684\u5e95\u5ea7\u548c\u76d6\u5b50\u3002\u56e0\u4e3a\u7ed9Interact()\u8bbe\u7f6e\u4e86UFUNCTION(BlueprintNativeEvent)\uff0c\u5728UE\u4e2d\u89c4\u5b9a\u4e86\u9700\u8981\u4f7f\u7528\u5982\u4e0b\u8bed\u6cd5\u6765\u5b9e\u73b0\uff08\u91cd\u5199\uff1f\uff09\u8fd9\u4e2a\u51fd\u6570\u3002\u6839\u636e\u5b98\u65b9\u6587\u6863\u7684\u8bf4\u660e\uff0c\u8fd9\u79cd\u7528\u6cd5\u5f88\u7c7b\u4f3cC++\u4e2d\u591a\u6001\u7684\u5b9e\u73b0\u3002<\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/ SItemChest.h\nclass ACTIONROGUELIKE_API ASItemChest : public AActor,public ISGameplayInterface\n{\npublic:\n    \/\/ UFUNCTION(BlueprintNativeEvent)\u4fee\u9970\u540e\u5fc5\u987b\u6dfb\u52a0_Implementation\n    void Interact_Implementation(APawn* InstigatorPawn);\n\nprotected:\n\tUPROPERTY(VisibleAnywhere)\n\tUStaticMeshComponent* BaseMesh;\n\tUPROPERTY(VisibleAnywhere)\n\tUStaticMeshComponent* LidMesh;\n};\n\n\/\/ SItemChest.cpp\nASItemChest::ASItemChest()\n{\n\tBaseMesh = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(\"BaseMesh\");\n\tRootComponent = BaseMesh;\n\n\tLidMesh = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(\"LidMesh\");\n\tLidMesh-&gt;SetupAttachment(BaseMesh);\n}\n\n<\/code><\/pre>\n<h3 id=\"2-\u521b\u5efa\u84dd\u56fe\u7c7b\">2. \u521b\u5efa\u84dd\u56fe\u7c7b<\/h3>\n<p>\u5728UE\u4e2d\u521b\u5efa\u4e00\u4e2aSItemChest\u7684\u84dd\u56fe\u7c7b\u7bb1\u5b50\uff0c\u547d\u540d\u4e3aTreasureChest\u3002\u5728\u8bfe\u7a0b\u9879\u76ee\u63d0\u4f9b\u7684ExampleContent\u6587\u4ef6\u5939\u4e2d\u6709\u7bb1\u5b50\u7684\u7f51\u683c\u4f53\uff0c\u5c06\u5176\u5206\u522b\u8bbe\u7f6e\u7ed9TreasureChest\u7684Base\u548cLid\u5373\u53ef\u3002<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240522\/2024052202.png'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240522\/2024052202.png\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u7136\u540e\u901a\u8fc7\u201c\u53d8\u6362\u201d\u5c5e\u6027\u8c03\u6574\u4e00\u4e0b\u76d6\u5b50\u7684\u4f4d\u7f6e\uff0c\u4f7f\u5176\u521a\u597d\u8d34\u5408\u5728\u5e95\u5ea7\u7684\u4e0a\u65b9\u3002<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240522\/2024052203.png'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240522\/2024052203.png\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<h3 id=\"3-\u63a7\u5236\u7bb1\u5b50\u6253\u5f00\">3. \u63a7\u5236\u7bb1\u5b50\u6253\u5f00<\/h3>\n<p>\u6211\u4eec\u53ef\u4ee5\u5728\u89c6\u53e3\u4e2d\u8bd5\u9a8c\u4e00\u4e0b\uff0c\u62d6\u62fd\u8c03\u6574\u76d6\u5b50\u7684\u89d2\u5ea6\u5c31\u53ef\u4ee5\u5b9e\u73b0\u7bb1\u5b50\u7684\u5f00\u5408\u6548\u679c\uff0c\u8c03\u6574\u65f6\u53ef\u4ee5\u6ce8\u610f\u7ec6\u8282\u9762\u677f\u4e2d\u201c\u53d8\u6362\u201d -&gt; \u201c\u65cb\u8f6c\u201d\u5c5e\u6027\u7684\u53d8\u5316\uff0c\u53d1\u73b0\u662fPitch\u5728\u6539\u53d8\u3002<\/p>\n<p>\u56e0\u6b64\uff0c\u53ea\u8981\u901a\u8fc7\u6539\u53d8Pitch\u53d8\u91cf\u5c31\u53ef\u4ee5\u5b9e\u73b0\u7bb1\u5b50\u7684\u5f00\u5408\u52a8\u753b\u3002\u6b64\u5916\uff0c\u4e3a\u4e86\u66f4\u65b9\u4fbf\u7684\u63a7\u5236\u6253\u5f00\u7684\u89d2\u5ea6\uff0c\u5728.h\u4e2d\u58f0\u660e\u4e86\u6d6e\u70b9\u578bTargetPitch\u5e76\u4f7f\u7528UPROPEERTY(EditAnywhere)\u5b8f\u4fee\u9970\uff0c\u7136\u540e\u5728.cpp\u6784\u9020\u51fd\u6570\u4e2d\u8d4b\u521d\u503c\u3002<\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/ SItemChest.cpp\nvoid ASItemChest::Interact_Implementation(APawn* InstigatorPawn)\n{\n\tLidMesh-&gt;SetRelativeRotation(FRotator(TargetPitch,0,0));\n}\n<\/code><\/pre>\n<p>\u8fd9\u4e2a\u65b9\u6cd5\u5b9e\u73b0\u7684\u52a8\u753b\u6bd4\u8f83\u751f\u786c\u3002\u4f46\u76ee\u524d\u7684\u91cd\u5fc3\u4e0d\u5728\u5236\u4f5c\u52a8\u753b\uff0c\u540e\u7eed\u4f1a\u4f7f\u7528Tick\u51fd\u6570\u5b9e\u73b0\u66f4\u52a0\u7cbe\u786e\u4e1d\u6ed1\u7684\u52a8\u753b\u63a7\u5236\u3002<\/p>\n<h3 id=\"4-\u63a7\u5236\u52a8\u753b\">4. \u63a7\u5236\u52a8\u753b<\/h3>\n<p>\u8981\u5b9e\u73b0\u5f00\u7bb1\u52a8\u753b\u7684\u63a7\u5236\uff0c\u9996\u5148\u9700\u8981\u7ed1\u5b9a\u6309\u952e\u4e8b\u4ef6\uff0c\u6309\u4e0b\u540e\u6267\u884c\u67d0\u4e2a\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u53ef\u4ee5\u5224\u65ad\u89c6\u7ebf\u5185\u4e00\u5b9a\u8ddd\u79bb\u5185\u662f\u5426\u6709\u7bb1\u5b50\uff0c\u6709\u7684\u8bdd\u5c31\u5c06\u7bb1\u5b50\u6253\u5f00\u3002<\/p>\n<p>\u6839\u636e\u8bbe\u8ba1\u6a21\u5f0f\u7684\u76f8\u5173\u7406\u8bba\uff0c\u5f00\u53d1\u65f6\u8981\u5c3d\u91cf\u964d\u4f4e\u5404\u4e2a\u529f\u80fd\u6a21\u5757\u7684\u8026\u5408\u6027\uff0c\u4ece\u800c\u907f\u514d\u540e\u671f\u4ee3\u7801\u7684\u81c3\u80bf\u5197\u4f59\u3002\u56e0\u6b64\u5728\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\u65f6\uff0c\u5c31\u4e0d\u7ee7\u7eed\u5728SCharacter\u7c7b\u4e2d\u7f16\u5199\u5177\u4f53\u4ee3\u7801\uff0c\u800c\u662f\u521b\u5efa\u4e00\u4e2a\u7c7b\u6765\u4e13\u95e8\u8d1f\u8d23\u5b9e\u73b0\u8fd9\u90e8\u5206\u7684\u903b\u8f91\uff0c\u7136\u540e\u5c06\u5176\u4e0eSCharacter\u7c7b\u7ec4\u5408\u5373\u53ef\u3002\u540c\u65f6\u8bfe\u7a0b\u4e2d\u4e5f\u63d0\u5230\uff0c\u56e0\u4e3a\u6240\u6709\u89d2\u8272\u90fd\u53ef\u4ee5\u8fdb\u884c\u653b\u51fb\uff0c\u4e4b\u524d\u5b9e\u73b0\u7684\u653b\u51fb\u7684\u76f8\u5173\u4ee3\u7801\u6700\u597d\u4e5f\u5355\u72ec\u5c01\u88c5\u63d0\u4f9b\u8c03\u7528\uff0c\u8fd9\u5728\u540e\u7eed\u4f1a\u8fdb\u884c\u4f18\u5316\u3002<\/p>\n<p>\u8981\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u53ef\u4ee5\u4f7f\u7528UE\u4e2d\u7684ActorComponent\u7c7b\u3002\u987e\u540d\u601d\u4e49\uff0c\u8fd9\u4e2a\u7c7b\u53ef\u4ee5\u50cf\u666e\u901a\u7684Component\u4e00\u6837\u9644\u52a0\u5230Actor\u4e0a\u3002\u56e0\u6b64\u6d3e\u751f\u51faSInteractionComponent\u7c7b\uff0c\u6211\u4eec\u9700\u8981\u5728\u5176\u4e2d\u5b9e\u73b0\u68c0\u67e5\u5468\u56f4\u6709\u54ea\u4e9b\u7269\u4f53\u53ef\u4ee5\u4e92\u52a8\uff0c\u5373\u78b0\u649e\u67e5\u8be2\uff08collision query\uff09\uff0c\u6240\u4ee5\u5728.h\u4e2d\u58f0\u660ePrimaryInteract()\u6765\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\u9700\u6c42\u3002<\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SInteractionComponent.h\n\nUCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )\nclass ACTIONROGUELIKE_API USInteractionComponent : public UActorComponent\n{\n\tGENERATED_BODY()\n\npublic:\n\tvoid PrimaryInteract();\n\n}\n<\/code><\/pre>\n<p>\u7136\u540e\u5728SCharacter\u7684\u4e24\u4e2a\u6587\u4ef6\u4e2d\u58f0\u660e\u548c\u521b\u5efaSInteractionComponent\u7684\u5b9e\u4f8b\uff0c\u987a\u4fbf\u518d\u58f0\u660e\u4e00\u4e0b\u5c06\u8981\u7ed1\u5b9a\u7684\u6309\u952e\u64cd\u4f5cPrimaryInteract\u3002<\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SCharacter.h\nUCLASS()\nclass ACTIONROGUELIKE_API ASCharacter : public ACharacter\n{\n\tGENERATED_BODY()\n\n\tUPROPERTY(VisibleAnywhere)\n\tUSInteractionComponent* InteractionComp;\n\t\t\n\tvoid PrimaryInteract();\n}\n<\/code><\/pre>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SCharacter.cpp\nASCharacter::ASCharacter()\n{\n\tInteractionComp = CreateDefaultSubobject&lt;USInteractionComponent&gt;(\"InteractionComp\");\n}\n\nvoid ASCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)\n{\n\tSuper::SetupPlayerInputComponent(PlayerInputComponent);\n\tPlayerInputComponent-&gt;BindAction(\"PrimaryInteract\",IE_Pressed,this,&amp;ASCharacter::PrimaryInteract);\n}\n\nvoid ASCharacter::PrimaryInteract()\n{\n\tif(InteractionComp)\n\t{\n\t\tInteractionComp-&gt;PrimaryInteract();\n\t}\n}\n<\/code><\/pre>\n<p>\u8981\u5b9e\u73b0\u78b0\u649e\u68c0\u6d4b\uff0c\u6e38\u620f\u5f00\u53d1\u4e2d\u5e38\u7528\u53d1\u5c04\u5c04\u7ebf\u7684\u65b9\u6cd5\uff0c\u5373\u4ece\u6211\u4eec\u89d2\u8272\u7684\u773c\u955c\u53d1\u51fa\u4e00\u5b9a\u957f\u5ea6\u7684\u5c04\u7ebf\uff0c\u5f53\u5c04\u7ebf\u78b0\u649e\u5230\u7b2c\u4e00\u4e2a\u7269\u4f53\u540e\u5728\u51fd\u6570\u4e2d\u8fd4\u56de\u8fd9\u4e2a\u5bf9\u8c61\u3002\u5728UE\u4e2dLineTraceSingleByObjectType()\u51fd\u6570\u53ef\u4ee5\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u5176\u56db\u4e2a\u53c2\u6570\u5206\u522b\u4e3a\uff1a\u68c0\u6d4b\u7ed3\u679c\u3001\u5c04\u7ebf\u8d77\u70b9\u3001\u5c04\u7ebf\u7ec8\u70b9\u3001\u68c0\u6d4b\u53c2\u6570\u3002<\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SInteractionComponent.cpp\nvoid USInteractionComponent::PrimaryInteract()\n{\n\tFHitResult Hit; \/\/ \u68c0\u6d4b\u7ed3\u679c\n\n\tFVector EyeLocation; \/\/ \u89d2\u8272\u773c\u775b\u4f4d\u7f6e\n\tFRotator EyeRotation; \/\/ \u89d2\u8272\u89c6\u7ebf\u65b9\u5411\n\tAActor* MyOwner = GetOwner(); \/\/ \u83b7\u53d6\u63a7\u5236\u89d2\u8272\n\t\/\/ \u5c06\u73a9\u5bb6\u89c6\u7ebf\u7684\u4f4d\u7f6e\u548c\u65b9\u5411\u8f93\u51fa\u5230EyeLocation\u548cEyeRotation\n\tMyOwner-&gt;GetActorEyesViewPoint(EyeLocation, EyeRotation);\n\t\/\/ \u6cbf\u7740\u89c6\u7ebf\u65b9\u5411\uff0c\u6a21\u578b\u7684\u773c\u775b\u4f4d\u7f6e\u5f00\u59cb1000cm\u8ddd\u79bb\u7684\u70b9\u4e3a\u7ec8\u70b9\n\tFVector End = EyeLocation + (EyeRotation.Vector() * 1000);\n\n\tFCollisionObjectQueryParams ObjectQueryParams; \/\/ \u67e5\u8be2\u53c2\u6570\n\tObjectQueryParams.AddObjectTypesToQuery(ECC_WorldDynamic); \/\/ \u9009\u62e9\u67e5\u8be2\u573a\u666f\u52a8\u6001\u5bf9\u8c61\n\n\tGetWorld()-&gt;LineTraceSingleByObjectType(Hit, EyeLocation, End, ObjectQueryParams);\n}\n<\/code><\/pre>\n<p>\u6700\u540e\u662f\u6839\u636e\u78b0\u649e\u7ed3\u679c\u6765\u8c03\u7528\u6253\u5f00\u7bb1\u5b50\u7684\u51fd\u6570\uff0c\u7ec6\u8282\u5df2\u7ecf\u5728\u6ce8\u91ca\u4e2d\u8bf4\u660e\uff1a<\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SInteractionComponent.cpp\n\t\/\/ \u4ece\u5224\u65ad\u7ed3\u679c\u4e2d\u83b7\u53d6\u68c0\u6d4b\u5230\u7684Actor\uff0c\u6ca1\u68c0\u6d4b\u5230\u5219\u4e3a\u7a7a\n\tAActor* HitActor = Hit.GetActor();\n\tif (HitActor) {\n        \/\/ \u5982\u679c\u68c0\u6d4b\u5230actor\u4e0d\u4e3a\u7a7a\uff0c\u518d\u5224\u65adactor\u6709\u6ca1\u6709\u5b9e\u73b0SurGameplayInterface\u7c7b\n\t\tif (HitActor-&gt;Implements&lt;USurGameplayInterface&gt;()) {\n            \/\/ \u6211\u4eec\u5b9a\u4e49\u7684Interact()\u4f20\u5165\u4e3aPawn\u7c7b\u578b\uff0c\u56e0\u6b64\u505a\u7c7b\u578b\u8f6c\u6362\n\t\t\tAPawn* MyPawn = Cast&lt;APawn&gt;(MyOwner);\n\t\t\t\/\/ \u591a\u6001\uff0c\u6839\u636e\u4f20\u5165\u7684HitActor\u8c03\u7528\u76f8\u5e94\u51fd\u6570\n\t\t\t\/\/ \u7b2c\u4e00\u4e2a\u53c2\u6570\u4e0d\u80fd\u4e3a\u7a7a\uff0c\u6240\u4ee5\u5916\u5c42\u5df2\u7ecf\u5224\u7a7a\uff1b\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u81ea\u5b9a\u4e49\u7684\uff0c\u6682\u65f6\u6ca1\u6709\u5f71\u54cd\uff0c\u53ef\u4ee5\u4e0d\u5224\u7a7a\n\t\t\tISurGameplayInterface::Execute_Interact(HitActor, MyPawn);\n\t\t\t\/\/ \u7528\u4e8edebug\uff0c\u7ed8\u5236\u8fd9\u6761\u78b0\u649e\u68c0\u6d4b\u7684\u7ebf\uff0c\u7eff\u8272\n\t\t\tDrawDebugLine(GetWorld(), EyeLocation, End, FColor::Green, false, 3);\n\t\t}\n\t}\n\telse{ DrawDebugLine(GetWorld(), EyeLocation, End, FColor::Red, false, 3); }\n<\/code><\/pre>\n<p>\u6700\u540e\u5728UE\u4e2d\u7ed1\u5b9a\u952e\u76d8\u64cd\u4f5c\uff0c\u7136\u540e\u6d4b\u8bd5\u4ee3\u7801\u6548\u679c\uff0c\u53d1\u73b0\u89d2\u8272\u5df2\u7ecf\u53ef\u4ee5\u6210\u529f\u6253\u5f00\u7bb1\u5b50\u4e86<\/p>\n<h2 id=\"\u7b80\u6613\u5f00\u5173\">\u7b80\u6613\u5f00\u5173<\/h2>\n<h3 id=\"1\u521b\u5efa\u84dd\u56fe\u7c7b\">1.\u521b\u5efa\u84dd\u56fe\u7c7b<\/h3>\n<p>\u521b\u5efa\u4e00\u4e2a\u57fa\u4e8eActor\u7684\u84dd\u56fe\u7c7b\uff0c\u547d\u540d\u4e3a\u201cLeverBP\u201d\uff08BP\u8868\u793aBlue Prints\uff09\uff0c\u4f5c\u4e3a\u793a\u4f8b\u6240\u9700\u7684\u64cd\u4f5c\u6746\u3002\u7136\u540e\u6253\u5f00\u5176\u84dd\u56fe\u7f16\u8f91\u5668\uff0c\u5229\u7528\u754c\u9762\u5de6\u4e0a\u89d2\u7eff\u8272\u7684\u201c\u6dfb\u52a0\u7ec4\u4ef6\u201d\u6309\u94ae\u4e3a\u5b83\u6dfb\u52a0\u4e24\u4e2a\u9759\u6001\u7f51\u683c\u4f53\u3002\u901a\u8fc7\u9f20\u6807\u62d6\u62fd\uff0c\u5c06\u4e00\u4e2a\u7f51\u683c\u4f53\u53d8\u4e3a\u6839\u7ec4\u4ef6\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u5bf9\u5e94C++\u4e2d\u7684RootComponent = XXX;\u8bed\u53e5\u3002<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052301.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052301.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u7136\u540e\u5c06\u7236\u5b50\u7f51\u683c\u4f53\u4f9d\u6b21\u8bbe\u7f6e\u4e3a\u5e95\u5ea7\u548c\u628a\u624b,\u4e3a\u4e86\u540e\u7eed\u5f00\u53d1\u65b9\u4fbf\uff0c\u6211\u4eec\u53ef\u4ee5\u5206\u522b\u5c06\u6839\u63a7\u4ef6\u548c\u5b50\u63a7\u4ef6\u91cd\u547d\u540d\u4e3a\u201cBaseMesh\u201d\u548c\u201cHandleMesh\u201d\u3002<\/p>\n<p>\u968f\u540e\uff0c\u6211\u4eec\u5f00\u59cb\u5b9e\u73b0\u5f00\u5173\u7684\u63a7\u5236\u529f\u80fd\u3002\u5b9e\u73b0\u7684\u601d\u8def\u5f88\u7b80\u5355\uff0c\u5728\u64cd\u4f5c\u6746\u524d\u6309\u4e0bE\u952e\u540e\u5c06\u628a\u624b\u671d\u4e0b\uff0c\u7136\u540e\u6253\u5f00\u5b9d\u7bb1\u5373\u53ef\u3002\u5728\u4e0a\u8282\u5b9e\u73b0\u6253\u5f00\u7bb1\u5b50\u8fd9\u4e2a\u529f\u80fd\u65f6\uff0c\u6211\u4eec\u901a\u8fc7\u5b9e\u73b0SGamePlayInterface\u4e2d\u7684Interact\u51fd\u6570\u6765\u5b9e\u73b0\u5b9d\u7bb1\u6253\u5f00\uff0c\u56e0\u6b64\u5bf9\u4e8e\u64cd\u7eb5\u6746\u8fd9\u4e2a\u4ea4\u4e92\u6211\u4eec\u540c\u6837\u9700\u8981\u5b9e\u73b0\u8fd9\u4e2a\u63a5\u53e3\u3002\u6240\u4ee5\uff0c\u63a5\u4e0b\u6765\u7684\u64cd\u4f5c\u5c31\u662f\u628a\u4e0a\u4e00\u8282\u8bfe\u4e2dC++\u4ee3\u7801\u6362\u6210\u4e86\u84dd\u56fe\u64cd\u4f5c\u7684\u7248\u672c\uff0c\u5927\u5bb6\u53ef\u4ee5\u81ea\u884c\u5c06\u76f8\u5e94\u6b65\u9aa4\u8fdb\u884c\u5bf9\u7167\u6bd4\u8f83\u3002<\/p>\n<p>\u5728LeverBP\u7684\u84dd\u56fe\u7f16\u8f91\u5668 -&gt; \u6700\u4e0a\u65b9\u7684\u201c\u7c7b\u8bbe\u7f6e\u201d -&gt; \u201c\u5df2\u5b9e\u73b0\u7684\u63a5\u53e3\u201d -&gt; \u6dfb\u52a0SurGamePlayInterface\u7c7b\uff0c\u6b64\u65f6\u5728\u754c\u9762\u5de6\u4fa7\u201c\u6211\u7684\u84dd\u56fe\u201d\u4e2d\u5c31\u4f1a\u51fa\u73b0Interact\u63a5\u53e3\u3002\u53f3\u952eInteract\u63a5\u53e3 -&gt; \u5b9e\u73b0\u4e8b\u4ef6\uff0c\u5c31\u4f1a\u5728\u4e8b\u4ef6\u56fe\u8868\u4e2d\u521b\u5efa\u76f8\u5e94\u7684\u8282\u70b9\u3002<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052302.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052302.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<h3 id=\"2-\u6539\u53d8\u628a\u624b\u89d2\u5ea6\">2. \u6539\u53d8\u628a\u624b\u89d2\u5ea6<\/h3>\n<p>\u5c06HandMesh\u62d6\u62fd\u8fdb\u4e8b\u4ef6\u56fe\u8868\u4e2d\u521b\u5efa\u8282\u70b9\uff0c\u4ece\u8be5\u8282\u70b9\u4e2d\u62d6\u62fd\u4ee5\u8c03\u7528Set Relative Rotation\u51fd\u6570\uff0c\u4ece\u800c\u6539\u53d8\u628a\u624b\u7684\u89d2\u5ea6\u3002\u800c\u8981\u6539\u53d8\u7684\u89d2\u5ea6\u5c31\u7528Make Rotator\u8282\u70b9\u6765\u8bbe\u7f6e\uff0c\u5176\u503c\u53d6HandleMesh\u7684Pitch\u503c\u7684\u76f8\u53cd\u6570\u65e2\u53ef\u4ee5<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052303.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052303.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>UE\u7684\u84dd\u56fe\u7cfb\u7edf\u4e2d\uff0c\u767d\u7ebf\u662f\u6267\u884c\u7ebf\uff0c\u8868\u793a\u4ece\u5934\u5230\u5c3e\u4f9d\u6b21\u6267\u884c\u8282\u70b9\uff1b\u800c\u5176\u4ed6\u7684\u9ec4\u8272\u3001\u84dd\u8272\u3001\u7d2b\u8272\u7b49\u90fd\u662f\u6570\u636e\u7ebf\uff0c\u8868\u793a\u6570\u636e\u7684\u6d41\u5411\u3001\u51fd\u6570\u8f93\u5165\u8f93\u51fa\u3002\u4e8e\u662f\u5bf9\u4e0a\u8ff0\u8282\u70b9\u8fdb\u884c\u8fde\u63a5<\/p>\n<p>\u7a76\u5176\u539f\u7406\uff0c\u662f\u6211\u4eec\u5728\u7ed1\u5b9aE\u952e\u7684PrimaryInteract\u4e2d\u5199\u4e86\u5224\u65ad\u5c04\u7ebf\u68c0\u6d4b\u5bf9\u8c61\u662f\u5426\u5b9e\u73b0Interact\u7684\u8bed\u53e5\uff1aif (HitActor-&gt;Implements())\u3002\u6211\u4eec\u901a\u8fc7\u5728\u84dd\u56fe\u4e2d\u5b9e\u73b0Interact\uff0c\u4f7f\u5f97\u4ee3\u7801\u5f80\u4e0b\u8fd0\u884c\uff0c\u5e76\u4e14\u4f20\u5165\u4e86\u64cd\u7eb5\u6746\u7684HitActor\u4ee5\u8c03\u7528\u84dd\u56fe\u4e2d\u5b9e\u73b0\u7684\u5185\u5bb9\uff08\u66f4\u6539\u628a\u624b\u89d2\u5ea6\uff09\u3002<\/p>\n<h3 id=\"3-\u6253\u5f00\u5b9d\u7bb1\">3. \u6253\u5f00\u5b9d\u7bb1<\/h3>\n<p>\u5728\u5de6\u4fa7\u201c\u6211\u7684\u84dd\u56fe\u201d -&gt; \u53d8\u91cf\u4e2d\u65b0\u5efa\u201cSelectedActor\u201d\uff0c\u7528\u4e8e\u5b58\u653e\u9700\u8981\u6253\u5f00\u7684\u5b9d\u7bb1\u5bf9\u8c61\u3002\u5728\u5176\u53f3\u4fa7\u7684\u7ec6\u8282\u9762\u677f\u4e2d\uff0c\u5c06\u201c\u53d8\u91cf\u7c7b\u578b\u201d\u4ece\u5e03\u5c14\u503c\u66f4\u6539\u4e3aActor\uff08\u84dd\u8272\u56fe\u6807\uff09\uff0c\u7136\u540e\u52fe\u9009\u201c\u53ef\u7f16\u8f91\u5b9e\u4f8b\u201d\uff0c\u7f16\u8bd1\u4fdd\u5b58\u3002\u8fd9\u6837\u5c31\u53ef\u4ee5\u70b9\u51fb\u4e16\u754c\u4e2d\u7684\u64cd\u7eb5\u6746\u6a21\u578b\uff0c\u5e76\u5728\u5176\u53f3\u4fa7\u7684\u7ec6\u8282\u9762\u677f\u4e2d\u66f4\u52a0\u65b9\u4fbf\u5730\u8bbe\u7f6e\u8be5\u53d8\u91cf<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052304.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052304.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u8bbe\u7f6eLeverBP\u8c03\u7528\u7684Actor<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052306.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052306.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u56de\u5230SGameplayInterface.h\u4e2d\uff0c\u5c06void Interact(APawn* InstigatorPawn);\u7684\u5b8f\u53d8\u4e3aUFUNCTION(BlueprintCallable, BlueprintNativeEvent)\uff0c\u4fdd\u5b58\u7f16\u8bd1\uff0c\u4f7f\u8be5\u63a5\u53e3\u53ef\u4ee5\u5728\u84dd\u56fe\u4e2d\u88ab\u8c03\u7528\u3002<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052305.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240523\/2024052305.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<h2 id=\"\u56de\u8840\u70b9\">\u56de\u8840\u70b9<\/h2>\n<h3 id=\"1\u521b\u5efa\u57fa\u7c7b\">1.\u521b\u5efa\u57fa\u7c7b<\/h3>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SPowerupActor.h\n\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"GameFramework\/Actor.h\"\n#include \"SGameplayInterface.h\"\n#include \"SPowerupActor.generated.h\"\n\n\nclass USphereComponent;\n\n\nUCLASS()\nclass ACTIONROGUELIKE_API ASPowerupActor : public AActor, public ISGameplayInterface\n{\n\tGENERATED_BODY()\n\nprotected:\n\n\tUPROPERTY(EditAnywhere, Category = \"Powerup\")\n\tfloat RespawnTime;\n\n\tUFUNCTION()\n\tvoid ShowPowerup();\n\n\tvoid HideAndCooldownPowerup();\n\n\tvoid SetPowerupState(bool bNewIsActive);\n\n\tUPROPERTY(VisibleAnywhere, Category = \"Components\")\n\tUSphereComponent* SphereComp;\n\npublic:\n\n\tvoid Interact_Implementation(APawn* InstigatorPawn) override;\n\npublic:\n\n\tASPowerupActor();\n\n};\n\n\/\/SPowerupActor.cpp\n\n#include \"SPowerupActor.h\"\n#include \"Components\/SphereComponent.h\"\n\n\nASPowerupActor::ASPowerupActor()\n{\n\tSphereComp = CreateDefaultSubobject&lt;USphereComponent&gt;(\"SphereComp\");\n\tSphereComp-&gt;SetCollisionProfileName(\"Powerup\");\n\tRootComponent = SphereComp;\n\n\tRespawnTime = 10.0f;\n}\n\n\nvoid ASPowerupActor::Interact_Implementation(APawn* InstigatorPawn)\n{\n\t\/\/ logic in derived classes...\n}\n\n\nvoid ASPowerupActor::ShowPowerup()\n{\n\tSetPowerupState(true);\n}\n\n\nvoid ASPowerupActor::HideAndCooldownPowerup()\n{\n\tSetPowerupState(false);\n\n\tFTimerHandle TimerHandle_RespawnTimer;\n\tGetWorldTimerManager().SetTimer(TimerHandle_RespawnTimer, this, &amp;ASPowerupActor::ShowPowerup, RespawnTime);\n}\n\nvoid ASPowerupActor::SetPowerupState(bool bNewIsActive)\n{\n\tSetActorEnableCollision(bNewIsActive);\n\n\t\/\/ Set visibility on root and all children\n\tRootComponent-&gt;SetVisibility(bNewIsActive, true);\n}\n<\/code><\/pre>\n<h3 id=\"2\u65b0\u5efa\u56de\u8840\u70b9\">2.\u65b0\u5efa\u56de\u8840\u70b9<\/h3>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SPowerup_HealthPotion.h\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"SPowerupActor.h\"\n#include \"SPowerup_HealthPotion.generated.h\"\n\n\nclass UStaticMeshComponent;\n\n\n\/**\n * \n *\/\nUCLASS()\nclass ACTIONROGUELIKE_API ASPowerup_HealthPotion : public ASPowerupActor\n{\n\tGENERATED_BODY()\n\nprotected:\n\n\tUPROPERTY(VisibleAnywhere, Category = \"Components\")\n\tUStaticMeshComponent* MeshComp;\n\n\t\/\/ float healt amount?\n\npublic:\n\n\tvoid Interact_Implementation(APawn* InstigatorPawn) override;\n\n\tASPowerup_HealthPotion();\n};\n\n\/\/SPowerup_HealthPotion.cpp\n#include \"SPowerup_HealthPotion.h\"\n#include \"SAttributeComponent.h\"\n\n\n\n\n\n\nASPowerup_HealthPotion::ASPowerup_HealthPotion()\n{\n\tMeshComp = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(\"MeshComp\");\n\t\/\/ Disable collision, instead we use SphereComp to handle interaction queries\n\tMeshComp-&gt;SetCollisionEnabled(ECollisionEnabled::NoCollision);\n\tMeshComp-&gt;SetupAttachment(RootComponent);\n}\n\n\nvoid ASPowerup_HealthPotion::Interact_Implementation(APawn* InstigatorPawn)\n{\n\tif (!ensure(InstigatorPawn))\n\t{\n\t\treturn;\n\t}\n\n\tUSAttributeComponent* AttributeComp = Cast&lt;USAttributeComponent&gt;(InstigatorPawn-&gt;GetComponentByClass(USAttributeComponent::StaticClass()));\n\t\/\/ Check if not already at max health\n\tif (ensure(AttributeComp) &amp;&amp; !AttributeComp-&gt;IsFullHealth())\n\t{\n\t\t\/\/ Only activate if healed successfully\n\t\tif (AttributeComp-&gt;ApplyHealthChange(AttributeComp-&gt;GetHealthMax()))\n\t\t{\n\t\t\tHideAndCooldownPowerup();\n\t\t}\n\t}\n}\n<\/code><\/pre>\n<h2 id=\"\u91cd\u751f\u70b9\">\u91cd\u751f\u70b9<\/h2>\n<p>\u5220\u9664\u4e4b\u524d\u7684PlayerCharacter\uff0c\u521b\u5efa\u51e0\u4e2aPlayerStart<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240911\/2024091101.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240911\/2024091101.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u5728GameModeBP\u4e2d\u5c06Default Pawn Class\u8bbe\u7f6e\u4e3aPlayerCharacter<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240911\/2024091102.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240911\/2024091102.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u63a5\u4e0b\u6765\u5c06DefaultGameMode \u8bbe\u7f6e\u4e3a GameModeBase<\/p>\n<p>\u73b0\u5728\u6211\u4eec\u7684\u51fa\u751f\u70b9\u90fd\u662f\u968f\u673a\u7684<\/p>\n<h2 id=\"\u6539\u5584\u91cd\u751f\u70b9\">\u6539\u5584\u91cd\u751f\u70b9<\/h2>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SGameModeBase.h\nprotected:\nUFUNCTION()\nvoid RespawnPlayerElasped(AController* Controller);\n\n\npublic:\nvirtual void OnActorKilled(AActor* VictimActor,AActor* Killer);\n\n\n\/\/SGameModeBase.cpp\nvoid ASGameModeBase::RespawnPlayerElasped(AController* Controller)\n{\n\tif(ensure(Controller))\n\t{\n\t\tController-&gt;UnPossess();\n\t\tRestartPlayer((Controller));\n\t}\n}\n\nvoid ASGameModeBase::OnActorKilled(AActor* VictimActor, AActor* Killer)\n{\n\tASCharacter* Player = Cast&lt;ASCharacter&gt;(VictimActor);\n\tif (Player)\n\t{\n\t\tFTimerHandle TimerHandle_RespawnDelay;\n\n\t\tFTimerDelegate Delegate;\n\t\tDelegate.BindUFunction(this, \"RespawnPlayerElapsed\", Player-&gt;GetController());\n\n\t\tfloat RespawnDelay = 2.0f;\n\t\tGetWorldTimerManager().SetTimer(TimerHandle_RespawnDelay, Delegate, RespawnDelay, false);\n\t}\n\n\tUE_LOG(LogTemp, Log, TEXT(\"OnActorKilled: Victim: %s, Killer: %s\"), *GetNameSafe(VictimActor), *GetNameSafe(Killer));\n}\n\n\n\/\/SAttributeComponent.cpp\nbool USAttributeComponent::ApplyHealthChange(AActor* InstigatorActor,float Delta)\n{\t\n\t\/\/Died\n\tif(Delta &lt;0.0f &amp;&amp; Health == 0.0f)\n\t{\n\t\tASGameModeBase* GM = GetWorld()-&gt;GetAuthGameMode&lt;ASGameModeBase&gt;();\n\t\tif(GM)\n\t\t{\n\t\t\tGM-&gt;OnActorKilled(GetOwner(),InstigatorActor);\n\t\t}\n\t}\n}\n<\/code><\/pre>\n<h2 id=\"\u70b9\u6570\u7cfb\u7edf\u548c\u968f\u673a\u4ea7\u751f\u836f\u6c34\u74f6\u4e24\u4e2a\u90fd\u5931\u8d25\u4ee5\u540e\u627e\u627e\u539f\u56e0\">\u70b9\u6570\u7cfb\u7edf\u548c\u968f\u673a\u4ea7\u751f\u836f\u6c34\u74f6\uff08\u4e24\u4e2a\u90fd\u5931\u8d25\uff0c\u4ee5\u540e\u627e\u627e\u539f\u56e0\uff09<\/h2>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SGamemodeBase.h\n\nprotected:\n\/\/ Read\/write access as we could change this as our difficulty increases via Blueprint\n\tUPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = \"AI\")\n\tint32 CreditsPerKill;\n\n\tUPROPERTY(EditDefaultsOnly, Category = \"Powerups\")\n\tUEnvQuery* PowerupSpawnQuery;\n\n\t\/* All power-up classes used to spawn with EQS at match start *\/\n\tUPROPERTY(EditDefaultsOnly, Category = \"Powerups\")\n\tTArray&lt;TSubclassOf&lt;AActor&gt;&gt; PowerupClasses;\n\n\t\/* Distance required between power-up spawn locations *\/\n\tUPROPERTY(EditDefaultsOnly, Category = \"Powerups\")\n\tfloat RequiredPowerupDistance;\n\n\t\/* Amount of powerups to spawn during match start *\/\n\tUPROPERTY(EditDefaultsOnly, Category = \"Powerups\")\n\tint32 DesiredPowerupCount;\n\n\tUFUNCTION()\n\tvoid OnBotSpawnQueryCompleted(UEnvQueryInstanceBlueprintWrapper* QueryInstance, EEnvQueryStatus::Type QueryStatus);\n\n\tUFUNCTION()\n\tvoid OnPowerupSpawnQueryCompleted(UEnvQueryInstanceBlueprintWrapper* QueryInstance, EEnvQueryStatus::Type QueryStatus);\n\n\/\/SGamemodeBase.cpp\nASGameModeBase::ASGameModeBase()\n{\n\tSpawnTimerInterval = 2.0f;\n\n\tCreditsPerKill = 20;\n\n\tDesiredPowerupCount = 10;\n\tRequiredPowerupDistance = 2000;\n\n\tPlayerStateClass = ASPlayerState::StaticClass();\n}\n\nvoid ASGameModeBase::StartPlay()\n{\n\tSuper::StartPlay();\n\n\t\/\/ Continuous timer to spawn in more bots.\n\t\/\/ Actual amount of bots and whether its allowed to spawn determined by spawn logic later in the chain...\n\tGetWorldTimerManager().SetTimer(TimerHandle_SpawnBots, this, &amp;ASGameModeBase::SpawnBotTimerElapsed, SpawnTimerInterval, true);\n\t\/\/ Make sure we have assigned at least one power-up class\n\tif (ensure(PowerupClasses.Num() &gt; 0))\n\t{\n\t\t\/\/ Run EQS to find potential power-up spawn locations\n\t\tUEnvQueryInstanceBlueprintWrapper* QueryInstance = UEnvQueryManager::RunEQSQuery(this, PowerupSpawnQuery, this, EEnvQueryRunMode::AllMatching, nullptr);\n\t\tif (ensure(QueryInstance))\n\t\t{\n\t\t\tQueryInstance-&gt;GetOnQueryFinishedEvent().AddDynamic(this, &amp;ASGameModeBase::OnPowerupSpawnQueryCompleted);\n\t\t}\n\t}\n\n}\n\nvoid ASGameModeBase::OnPowerupSpawnQueryCompleted(UEnvQueryInstanceBlueprintWrapper* QueryInstance, EEnvQueryStatus::Type QueryStatus)\n{\n\tif (QueryStatus != EEnvQueryStatus::Success)\n\t{\n\t\tUE_LOG(LogTemp, Warning, TEXT(\"Spawn bot EQS Query Failed!\"));\n\t\treturn;\n\t}\n\n\tTArray&lt;FVector&gt; Locations = QueryInstance-&gt;GetResultsAsLocations();\n\n\t\/\/ Keep used locations to easily check distance between points\n\tTArray&lt;FVector&gt; UsedLocations;\n\n\tint32 SpawnCounter = 0;\n\t\/\/ Break out if we reached the desired count or if we have no more potential positions remaining\n\twhile (SpawnCounter &lt; DesiredPowerupCount &amp;&amp; Locations.Num() &gt; 0)\n\t{\n\t\t\/\/ Pick a random location from remaining points.\n\t\tint32 RandomLocationIndex = FMath::RandRange(0, Locations.Num() - 1);\n\n\t\tFVector PickedLocation = Locations[RandomLocationIndex];\n\t\t\/\/ Remove to avoid picking again\n\t\tLocations.RemoveAt(RandomLocationIndex);\n\n\t\t\/\/ Check minimum distance requirement\n\t\tbool bValidLocation = true;\n\t\tfor (FVector OtherLocation : UsedLocations)\n\t\t{\n\t\t\tfloat DistanceTo = (PickedLocation - OtherLocation).Size();\n\n\t\t\tif (DistanceTo &lt; RequiredPowerupDistance)\n\t\t\t{\n\t\t\t\t\/\/ Show skipped locations due to distance\n\t\t\t\t\/\/DrawDebugSphere(GetWorld(), PickedLocation, 50.0f, 20, FColor::Red, false, 10.0f);\n\n\t\t\t\t\/\/ too close, skip to next attempt\n\t\t\t\tbValidLocation = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t\/\/ Failed the distance test\n\t\tif (!bValidLocation)\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\t\/\/ Pick a random powerup-class\n\t\tint32 RandomClassIndex = FMath::RandRange(0, PowerupClasses.Num() - 1);\n\t\tTSubclassOf&lt;AActor&gt; RandomPowerupClass = PowerupClasses[RandomClassIndex];\n\n\t\tGetWorld()-&gt;SpawnActor&lt;AActor&gt;(RandomPowerupClass, PickedLocation, FRotator::ZeroRotator);\n\n\t\t\/\/ Keep for distance checks\n\t\tUsedLocations.Add(PickedLocation);\n\t\tSpawnCounter++;\n\t}\n}\n\nvoid ASGameModeBase::OnActorKilled(AActor* VictimActor, AActor* Killer)\n{\n\tUE_LOG(LogTemp, Log, TEXT(\"OnActorKilled: Victim: %s, Killer: %s\"), *GetNameSafe(VictimActor), *GetNameSafe(Killer));\n\n\t\/\/ Respawn Players after delay\n\tASCharacter* Player = Cast&lt;ASCharacter&gt;(VictimActor);\n\tif (Player)\n\t{\n\t\tFTimerHandle TimerHandle_RespawnDelay;\n\n\t\tFTimerDelegate Delegate;\n\t\tDelegate.BindUFunction(this, \"RespawnPlayerElapsed\", Player-&gt;GetController());\n\n\t\tfloat RespawnDelay = 2.0f;\n\t\tGetWorldTimerManager().SetTimer(TimerHandle_RespawnDelay, Delegate, RespawnDelay, false);\n\t}\n\n\t\/\/ Give Credits for kill\n\tAPawn* KillerPawn = Cast&lt;APawn&gt;(Killer);\n\tif (KillerPawn)\n\t{\n\t\tif (ASPlayerState* PS = KillerPawn-&gt;GetPlayerState&lt;ASPlayerState&gt;()) \/\/ &lt; can cast and check for nullptr within if-statement.\n\t\t{\n\t\t\tPS-&gt;AddCredits(CreditsPerKill);\n\t\t}\n\t}\n}\n<\/code><\/pre>\n<p>\u521b\u5efa\u4e24\u4e2a\u7c7b<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240919\/2024091901.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240919\/2024091901.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240919\/2024091902.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240919\/2024091902.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SPowerup_HealthPotion.h\nprotected:\n\tUPROPERTY(EditAnywhere, Category = \"HealthPotion\")\n\tint32 CreditCost;\n\n\/\/SPowerup_HealthPotion.cpp\nASPowerup_HealthPotion::ASPowerup_HealthPotion()\n{\n\tCreditCost = 50;\n}\n\nvoid ASPowerup_HealthPotion::Interact_Implementation(APawn* InstigatorPawn)\n{\n\tif (!ensure(InstigatorPawn))\n\t{\n\t\treturn;\n\t}\n\tUSAttributeComponent* AttributeComp = USAttributeComponent::GetAttributes(InstigatorPawn);\n\t\/\/ Check if not already at max health\n\tif (ensure(AttributeComp) &amp;&amp; !AttributeComp-&gt;IsFullHealth())\n\t{\n\t\t\/\/ Only activate if healed successfully\n\t\tif (ASPlayerState* PS = InstigatorPawn-&gt;GetPlayerState&lt;ASPlayerState&gt;())\n\t\t{\n\t\t\tif (PS-&gt;RemoveCredits(CreditCost) &amp;&amp; AttributeComp-&gt;ApplyHealthChange(this, AttributeComp-&gt;GetHealthMax()))\n\t\t\t{\n\t\t\t\t\/\/ Only activate if healed successfully\n\t\t\t\tHideAndCooldownPowerup();\n\t\t\t}\n\t\t}\n\t}\n}\n<\/code><\/pre>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SPowerup_Credits.h\n\/\/ Fill out your copyright notice in the Description page of Project Settings.\n\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"SPowerupActor.h\"\n#include \"SPowerup_Credits.generated.h\"\n\n\/**\n * \n *\/\nUCLASS()\nclass ACTIONROGUELIKE_API ASPowerup_Credits : public ASPowerupActor\n{\n\tGENERATED_BODY()\n\t\nprotected:\n\n\tUPROPERTY(VisibleAnywhere, Category = \"Components\")\n\tUStaticMeshComponent* MeshComp;\n\n\tUPROPERTY(EditAnywhere, Category = \"Credits\")\n\tint32 CreditsAmount;\n\npublic:\n\n\tvoid Interact_Implementation(APawn* InstigatorPawn) override;\n\n\tASPowerup_Credits();\n};\n\n\n\/\/SPowerup_Credits.cpp\n\/\/ Fill out your copyright notice in the Description page of Project Settings.\n\n\n#include \"SPowerup_Credits.h\"\n\n#include \"SPlayerState.h\"\n\nASPowerup_Credits::ASPowerup_Credits()\n{\n\tMeshComp = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(\"MeshComp\");\n\t\/\/ Disable collision, instead we use SphereComp to handle interaction queries\n\tMeshComp-&gt;SetCollisionEnabled(ECollisionEnabled::NoCollision);\n\tMeshComp-&gt;SetupAttachment(RootComponent);\n\n\tCreditsAmount = 80;\n}\n\n\nvoid ASPowerup_Credits::Interact_Implementation(APawn* InstigatorPawn)\n{\n\tif (!ensure(InstigatorPawn))\n\t{\n\t\treturn;\n\t}\n\n\tif (ASPlayerState* PS = InstigatorPawn-&gt;GetPlayerState&lt;ASPlayerState&gt;())\n\t{\n\t\tPS-&gt;AddCredits(CreditsAmount);\n\t\tHideAndCooldownPowerup();\n\t}\n}\n<\/code><\/pre>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SPlayerState.h\n\/\/ Fill out your copyright notice in the Description page of Project Settings.\n\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"GameFramework\/PlayerState.h\"\n#include \"SPlayerState.generated.h\"\n\nDECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnCreditsChanged, ASPlayerState*, PlayerState, int32, NewCredits, int32, Delta);\n\n\/**\n * \n *\/\nUCLASS()\nclass ACTIONROGUELIKE_API ASPlayerState : public APlayerState\n{\n\tGENERATED_BODY()\n\nprotected:\n\n\tint32 Credits;\n\npublic:\n\n\tUFUNCTION(BlueprintCallable, Category = \"PlayerState|Credits\") \/\/ &lt; Category|SubCategory\n\tvoid AddCredits(int32 Delta);\n\n\tUFUNCTION(BlueprintCallable, Category = \"PlayerState|Credits\")\n\tbool RemoveCredits(int32 Delta);\n\n\tUPROPERTY(BlueprintAssignable, Category = \"Events\")\n\tFOnCreditsChanged OnCreditsChanged;\n};\n\n\n\/\/SPlayerState.cpp\n\/\/ Fill out your copyright notice in the Description page of Project Settings.\n\n\n#include \"SPlayerState.h\"\n\nvoid ASPlayerState::AddCredits(int32 Delta)\n{\n\t\/\/ Avoid user-error of adding a negative amount or zero\n\tif (!ensure(Delta &gt; 0.0f))\n\t{\n\t\treturn;\n\t}\n\n\tCredits += Delta;\n\n\tOnCreditsChanged.Broadcast(this, Credits, Delta);\n}\n\n\nbool ASPlayerState::RemoveCredits(int32 Delta)\n{\n\t\/\/ Avoid user-error of adding a subtracting negative amount or zero\n\tif (!ensure(Delta &gt; 0.0f))\n\t{\n\t\treturn false;\n\t}\n\n\tif (Credits &lt; Delta)\n\t{\n\t\t\/\/ Not enough credits available\n\t\treturn false;\n\t}\n\n\tCredits -= Delta;\n\n\tOnCreditsChanged.Broadcast(this, Credits, -Delta);\n\n\treturn true;\n}\n<\/code><\/pre>\n<h2 id=\"\u4fdd\u5b58\u548c\u52a0\u8f7d\u6e38\u620f\">\u4fdd\u5b58\u548c\u52a0\u8f7d\u6e38\u620f<\/h2>\n<p>\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u7c7b<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092601.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092601.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SSaveGame.h\n\/\/ Fill out your copyright notice in the Description page of Project Settings.\n\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"GameFramework\/SaveGame.h\"\n#include \"SSaveGame.generated.h\"\n\n\/**\n * \n *\/\n\n\nUSTRUCT()\nstruct FActorSaveData\n{\n\tGENERATED_BODY()\n\npublic:\n\n\t\/* Identifier for which Actor this belongs to *\/\n\tUPROPERTY()\n\tFString ActorName;\n\n\t\/* For movable Actors, keep location,rotation,scale. *\/\n\tUPROPERTY()\n\tFTransform Transform;\n\n\tUPROPERTY()\n\tTArray&lt;uint8&gt; ByteData;\n};\n\n\nUCLASS()\nclass ACTIONROGUELIKE_API USSaveGame : public USaveGame\n{\n\tGENERATED_BODY()\n\npublic:\n\n\tUPROPERTY()\n\tint32 Credits;\n\n\tUPROPERTY()\n\tTArray&lt;FActorSaveData&gt; SavedActors;\n\n\t\n};\n\n\n\n\/\/SSaveGame.cpp\n<\/code><\/pre>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SGameModeBase.h\n\nprotected:\n\tFString SlotName;\n\n\tUPROPERTY()\n\tUSSaveGame* CurrentSaveGame;\n\npublic:\n\tvoid InitGame(const FString&amp; MapName, const FString&amp; Options, FString&amp; ErrorMessage) override;\n\n\tvoid HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer) override;\n\n\tUFUNCTION(BlueprintCallable, Category = \"SaveGame\")\n\tvoid WriteSaveGame();\n\n\tvoid LoadSaveGame();\n\n\n\/\/SGameModeBase.cpp\nASGameModeBase::ASGameModeBase()\n{\n\tSlotName = \"SaveGame01\";\n}\n\nvoid ASGameModeBase::InitGame(const FString&amp; MapName, const FString&amp; Options, FString&amp; ErrorMessage)\n{\n\tSuper::InitGame(MapName, Options, ErrorMessage);\n\n\tLoadSaveGame();\n}\n\nvoid ASGameModeBase::HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer)\n{\n\tSuper::HandleStartingNewPlayer_Implementation(NewPlayer);\n\n\tASPlayerState* PS = NewPlayer-&gt;GetPlayerState&lt;ASPlayerState&gt;();\n\tif (PS)\n\t{\n\t\tPS-&gt;LoadPlayerState(CurrentSaveGame);\n\t}\n}\n\nvoid ASGameModeBase::WriteSaveGame()\n{\n\t\/\/ Iterate all player states, we don't have proper ID to match yet (requires Steam or EOS)\n\tfor (int32 i = 0; i &lt; GameState-&gt;PlayerArray.Num(); i++)\n\t{\n\t\tASPlayerState* PS = Cast&lt;ASPlayerState&gt;(GameState-&gt;PlayerArray[i]);\n\t\tif (PS)\n\t\t{\n\t\t\tPS-&gt;SavePlayerState(CurrentSaveGame);\n\t\t\tbreak; \/\/ single player only at this point\n\t\t}\n\t}\n\n\tCurrentSaveGame-&gt;SavedActors.Empty();\n\n\t\/\/ Iterate the entire world of actors\n\tfor (FActorIterator It(GetWorld()); It; ++It)\n\t{\n\t\tAActor* Actor = *It;\n\t\t\/\/ Only interested in our 'gameplay actors'\n\t\tif (!Actor-&gt;Implements&lt;USGameplayInterface&gt;())\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\tFActorSaveData ActorData;\n\t\tActorData.ActorName = Actor-&gt;GetName();\n\t\tActorData.Transform = Actor-&gt;GetActorTransform();\n\n\t\t\/\/ Pass the array to fill with data from Actor\n\t\tFMemoryWriter MemWriter(ActorData.ByteData);\n\n\t\tFObjectAndNameAsStringProxyArchive Ar(MemWriter, true);\n\t\t\/\/ Find only variables with UPROPERTY(SaveGame)\n\t\tAr.ArIsSaveGame = true;\n\t\t\/\/ Converts Actor's SaveGame UPROPERTIES into binary array\n\t\tActor-&gt;Serialize(Ar);\n\n\t\tCurrentSaveGame-&gt;SavedActors.Add(ActorData);\n\t}\n\n\tUGameplayStatics::SaveGameToSlot(CurrentSaveGame, SlotName, 0);\n}\n\n\nvoid ASGameModeBase::LoadSaveGame()\n{\n\tif (UGameplayStatics::DoesSaveGameExist(SlotName, 0))\n\t{\n\t\tCurrentSaveGame = Cast&lt;USSaveGame&gt;(UGameplayStatics::LoadGameFromSlot(SlotName, 0));\n\t\tif (CurrentSaveGame == nullptr)\n\t\t{\n\t\t\tUE_LOG(LogTemp, Warning, TEXT(\"Failed to load SaveGame Data.\"));\n\t\t\treturn;\n\t\t}\n\n\t\tUE_LOG(LogTemp, Log, TEXT(\"Loaded SaveGame Data.\"));\n\n\n\t\t\/\/ Iterate the entire world of actors\n\t\tfor (FActorIterator It(GetWorld()); It; ++It)\n\t\t{\n\t\t\tAActor* Actor = *It;\n\t\t\t\/\/ Only interested in our 'gameplay actors'\n\t\t\tif (!Actor-&gt;Implements&lt;USGameplayInterface&gt;())\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (FActorSaveData ActorData : CurrentSaveGame-&gt;SavedActors)\n\t\t\t{\n\t\t\t\tif (ActorData.ActorName == Actor-&gt;GetName())\n\t\t\t\t{\n\t\t\t\t\tActor-&gt;SetActorTransform(ActorData.Transform);\n\n\t\t\t\t\tFMemoryReader MemReader(ActorData.ByteData);\n\n\t\t\t\t\tFObjectAndNameAsStringProxyArchive Ar(MemReader, true);\n\t\t\t\t\tAr.ArIsSaveGame = true;\n\t\t\t\t\t\/\/ Convert binary array back into actor's variables\n\t\t\t\t\tActor-&gt;Serialize(Ar);\n\n\t\t\t\t\tISGameplayInterface::Execute_OnActorLoaded(Actor);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tCurrentSaveGame = Cast&lt;USSaveGame&gt;(UGameplayStatics::CreateSaveGameObject(USSaveGame::StaticClass()));\n\n\t\tUE_LOG(LogTemp, Log, TEXT(\"Created New SaveGame Data.\"));\n\t}\n}\n<\/code><\/pre>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SPlayState.h\npublic:\n\tUFUNCTION(BlueprintNativeEvent)\n\tvoid SavePlayerState(USSaveGame* SaveObject);\n\n\tUFUNCTION(BlueprintNativeEvent)\n\tvoid LoadPlayerState(USSaveGame* SaveObject);\n\n\/\/SPlayState.cpp\nvoid ASPlayerState::LoadPlayerState_Implementation(USSaveGame* SaveObject)\n{\n\tif (SaveObject)\n\t{\n\t\tCredits = SaveObject-&gt;Credits;\n\t}\n}\n\nvoid ASPlayerState::SavePlayerState_Implementation(USSaveGame* SaveObject)\n{\n\t\n\tif (SaveObject)\n\t{\n\t\tSaveObject-&gt;Credits = Credits;\n\t}\n}\n\n<\/code><\/pre>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SGameplayInterface.h\npublic:\n\tUFUNCTION(BlueprintNativeEvent)\n\tvoid OnActorLoaded();\n<\/code><\/pre>\n<p>\u5728PlayControllerBP\u4e2d\u8bbe\u7f6e\uff0c\u5f53\u6211\u4eec\u6309\u4e0bL\u952e\u65f6\u4fdd\u5b58\u6e38\u620f<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092602.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092602.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u53ef\u4ee5\u770b\u5230\u6211\u4eec\u7684\u6e38\u620f\u88ab\u4fdd\u5b58\u4e86\uff0c\u4f46\u662f\u8fd9\u91cc\u5e76\u4e0d\u5b89\u5168\uff0c\u56e0\u4e3a\u5b83\u53ea\u6709\u4e24\u5b57\u8282<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092603.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092603.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u4fee\u6539Credits\u7684\u84dd\u56fe\uff0c\u4f7f\u5f97Credits\u5728\u91cd\u65b0\u8f7d\u5165\u540e\u6570\u636e\u548c\u4fdd\u5b58\u7684\u76f8\u540c<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092604.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092604.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<pre><code class=\"language-cpp\" lang=\"cpp\">\/\/SItemChest.h\npublic:\n\tvoid OnActorLoaded_Implementation();\n\n\nprotected:\n\tUPROPERTY(ReplicatedUsing=\"OnRep_LidOpened\", BlueprintReadOnly,SaveGame) \/\/ RepNotify\n\tbool bLidOpened;\n\n\n\n\/\/SItemChest.cpp\nvoid ASItemChest::OnActorLoaded_Implementation()\n{\n\tISGameplayInterface::OnActorLoaded_Implementation();\n\tOnRep_LidOpened();\n}\n<\/code><\/pre>\n<p>\u73b0\u5728\u6211\u4eec\u5982\u679c\u6539\u53d8\u5b9d\u7bb1\u7684\u4f4d\u7f6e\u6216\u8005\u72b6\u6001\uff0c\u70b9\u51fb\u4fdd\u5b58\u6e38\u620f\u540e\uff0c\u5b9d\u7bb1\u4ecd\u7136\u5ef6\u7eed\u4e4b\u524d\u7684\u72b6\u6001<\/p>\n<p>\u521b\u5efa\u4ee5Actor\u4e3a\u57fa\u7c7b\u7684\u84dd\u56fe<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092605.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092605.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092606.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092606.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u8fde\u63a5\u84dd\u56fe<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092607.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092607.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u521b\u5efa\u65b0\u7684\u53d8\u91cf<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092608.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092608.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u62c6\u5206\u4e4b\u524d\u7684\u529f\u80fd\uff0c\u521b\u5efa\u65b0\u7684event\u72ec\u7acb\u5b9e\u73b0<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092609.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092609.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n<p>\u66f4\u65b0\u6211\u4eec\u7684\u84dd\u56fe<\/p>\n<p><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092610.jpg'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" data-original=\"https:\/\/pic.vanforever.com.cn\/UE\/Interaction\/20240926\/2024092610.jpg\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" \/><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>UE \u4e92\u52a8\u5b66\u4e60\u4e4b\u8def \u706b\u836f\u6876\u7206\u70b8 \u521b\u5efa\u4e00\u4e2aSExplosiveBarrel\u7c7b,\u57fa\u7c7b\u4e3aAActor\u3002\u8be5\u7c7b\u5305\u542b\u4e24\u4e2a\u5173 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,27],"tags":[4,5],"class_list":["post-297","post","type-post","status-publish","format-standard","hentry","category-ue","category-cs193u","tag-c","tag-ue"],"_links":{"self":[{"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=\/wp\/v2\/posts\/297","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=297"}],"version-history":[{"count":5,"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=\/wp\/v2\/posts\/297\/revisions"}],"predecessor-version":[{"id":513,"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=\/wp\/v2\/posts\/297\/revisions\/513"}],"wp:attachment":[{"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=297"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=297"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vanforever.com.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=297"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}