You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 02:47:03