UE4中被玩家Projectile击中时修改Actor材质的问题求助
问题分析与修复方案
核心错误点
- 运行时滥用
ConstructorHelpers::FObjectFinder:该工具仅能在类构造函数中加载资源,运行时调用会触发引擎崩溃,因为它依赖初始化阶段的资源加载机制。 - 致命的类型不匹配赋值:原代码第54行
CubeMesh = GreenMat;完全错误——CubeMesh是UStaticMeshComponent*类型,GreenMat是FObjectFinder<UMaterial>实例,直接赋值会破坏内存结构,这是崩溃的直接诱因。 - 材质切换逻辑失效:两个
if语句会覆盖mInterface变量,最终永远只会使用RedMat(若存在),完全没有实现“切换”功能。 - 动态材质实例重复创建:每次调用
ChangeColor都生成新的动态材质实例,既浪费性能,也不符合切换需求。
修复后的完整代码
头文件(ColorChangingCube.h)
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "ColorChangingCube.generated.h" UCLASS() class YOURPROJECT_API AColorChangingCube : public AActor { GENERATED_BODY() public: // 构造函数 AColorChangingCube(); // 供外部调用的颜色切换函数 UFUNCTION(BlueprintCallable, Category = "Color Control") void ChangeColor(); protected: virtual void BeginPlay() override; public: virtual void Tick(float DeltaTime) override; private: // 立方体网格组件 UPROPERTY(VisibleAnywhere, Category = "Mesh") UStaticMeshComponent* CubeMesh; // 缓存绿色材质 UPROPERTY() UMaterial* GreenMaterial; // 缓存红色材质 UPROPERTY() UMaterial* RedMaterial; // 当前使用的动态材质实例 UPROPERTY() UMaterialInstanceDynamic* CurrentMatInstance; // 标记当前颜色状态(绿色/红色) bool bIsGreen; };
实现文件(ColorChangingCube.cpp)
#include "ColorChangingCube.h" #include "UObject/ConstructorHelpers.h" // Sets default values AColorChangingCube::AColorChangingCube() { PrimaryActorTick.bCanEverTick = true; // 初始化网格组件 CubeMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CubeMesh")); RootComponent = CubeMesh; // 加载立方体静态网格 static ConstructorHelpers::FObjectFinder<UStaticMesh> CubeMeshAsset(TEXT("StaticMesh'/Game/Geometry/Meshes/1M_Cube.1M_Cube'")); if (CubeMeshAsset.Succeeded()) { CubeMesh->SetStaticMesh(CubeMeshAsset.Object); } // 在构造函数中加载绿色材质并缓存 static ConstructorHelpers::FObjectFinder<UMaterial> GreenMatAsset(TEXT("Material'/Game/FirstPerson/Material/Green.Green'")); if (GreenMatAsset.Succeeded()) { GreenMaterial = GreenMatAsset.Object; } // 在构造函数中加载红色材质并缓存 static ConstructorHelpers::FObjectFinder<UMaterial> RedMatAsset(TEXT("Material'/Game/FirstPerson/Material/Red.Red'")); if (RedMatAsset.Succeeded()) { RedMaterial = RedMatAsset.Object; } // 初始化状态:默认绿色 bIsGreen = true; // 初始设置绿色材质 if (GreenMaterial) { CurrentMatInstance = UMaterialInstanceDynamic::Create(GreenMaterial, this); CubeMesh->SetMaterial(0, CurrentMatInstance); } } void AColorChangingCube::BeginPlay() { Super::BeginPlay(); } void AColorChangingCube::Tick(float DeltaTime) { Super::Tick(DeltaTime); } void AColorChangingCube::ChangeColor() { // 检查材质是否加载成功 if (!GreenMaterial || !RedMaterial) { UE_LOG(LogTemp, Warning, TEXT("Missing Green or Red material asset!")); return; } // 切换颜色状态 bIsGreen = !bIsGreen; // 选择目标材质 UMaterial* TargetMaterial = bIsGreen ? GreenMaterial : RedMaterial; // 更新动态材质实例:复用已有实例,避免重复创建 if (CurrentMatInstance) { CurrentMatInstance->SetParentMaterial(TargetMaterial); } else { CurrentMatInstance = UMaterialInstanceDynamic::Create(TargetMaterial, this); CubeMesh->SetMaterial(0, CurrentMatInstance); } }
额外说明
- 确保将
YOURPROJECT_API替换为你项目的实际API宏(在项目的Build.cs中定义)。 - 原Projectile的
OnHit代码无需修改,只要确保ChangeColor函数在头文件中正确声明为UFUNCTION(BlueprintCallable)或公共成员函数即可。
内容的提问来源于stack exchange,提问作者John Elstang
相关产品推荐
相关产品推荐

