Unreal C++:从其他类修改可生成蓝图变量时编辑器崩溃问题求助
你的编辑器崩溃完全是因为错误实例化Unreal Actor对象导致的!在Unreal引擎中,所有继承自AActor的类(比如你的ADMProjectile)绝对不能像普通C++对象那样直接用栈实例化(ADMProjectile ProjectileClass;)或者new关键字创建——Unreal的Actor依赖引擎的对象管理系统,必须通过UWorld::SpawnActor()方法生成,而且只有在需要将实体放入游戏世界时才应该创建。
你当前代码里的栈对象ProjectileClass,它的组件(比如CollisionComp、ProjectileMovement)根本没有被引擎初始化,访问它的变量(哪怕是简单的isExplosiveBullets)都会触发内存访问错误,直接导致编辑器崩溃。
另外,你的逻辑也有问题:拾取PowerUp时,玩家还没有发射子弹,此时去操作一个不存在的子弹对象完全没必要。正确的思路是把“爆炸子弹”的状态存储在玩家角色身上,等玩家实际发射子弹时,再根据这个状态设置新生成的子弹属性。
步骤1:给玩家角色添加爆炸子弹状态变量
打开你的DMCharacter.h,添加一个跟踪PowerUp状态的布尔变量:
#pragma once // ... 其他头文件 ... #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "DMCharacter.generated.h" UCLASS() class ADM_API ADMCharacter : public ACharacter { GENERATED_BODY() // ... 其他已有代码 ... public: // ... 其他已有方法 ... // 标记玩家是否拥有爆炸子弹Buff UPROPERTY(VisibleAnywhere, Category = PowerUps) bool bHasExplosiveBullets = false; };
步骤2:修改PowerUp的重叠触发逻辑
更新ExplosiveBulletPowerUp.cpp中的OnOverlapBegin函数,将状态设置到玩家角色上,而不是操作不存在的子弹:
#include "ExplosiveBulletPowerUp.h" #include "DM/DMProjectile.h" #include "DM/DMCharacter.h" // ... 已有构造函数和BeginPlay ... void AExplosiveBulletPowerUp::OnOverlapBegin(class AActor* OverlappedActor, class AActor* OtherActor) { if (OtherActor->ActorHasTag("player")) { // 将重叠对象转换为玩家角色类(安全转换,避免类型错误) ADMCharacter* PlayerChar = Cast<ADMCharacter>(OtherActor); if (PlayerChar) { // 开启玩家的爆炸子弹状态 PlayerChar->bHasExplosiveBullets = true; UE_LOG(LogTemp, Warning, TEXT("玩家获得爆炸子弹Buff!")); // 销毁当前PowerUp道具 OverlappedActor->Destroy(); } } }
步骤3:在玩家发射子弹时应用状态
找到玩家角色中负责发射子弹的代码(比如Fire()方法),在生成子弹时根据玩家的状态设置isExplosiveBullets:
void ADMCharacter::Fire() { // 假设你已经定义了ProjectileClass作为子弹的类模板 if (ProjectileClass) { UWorld* const World = GetWorld(); if (World) { // 获取枪口位置和旋转(根据你的角色Socket调整) FVector SpawnLocation = GetMesh()->GetSocketLocation("MuzzleSocket"); FRotator SpawnRotation = GetControlRotation(); // 生成子弹(这才是Unreal中创建Actor的正确方式) ADMProjectile* Projectile = World->SpawnActor<ADMProjectile>(ProjectileClass, SpawnLocation, SpawnRotation); if (Projectile) { // 根据玩家当前的Buff状态设置子弹属性 Projectile->isExplosiveBullets = bHasExplosiveBullets; // 可以在这里同步其他属性,比如伤害 Projectile->WeaponDamage = WeaponDamage; } } } }
如果你的PowerUp有持续时间,可以在玩家角色中添加一个计时器,时间结束后自动将bHasExplosiveBullets重置为false:
// 在ADMCharacter的PowerUp获取逻辑中添加计时器 void ADMCharacter::ActivateExplosiveBullets(float Duration) { bHasExplosiveBullets = true; // 设置延迟回调,时间到了关闭Buff GetWorldTimerManager().SetTimer(ExplosiveBulletTimerHandle, this, &ADMCharacter::DeactivateExplosiveBullets, Duration, false); } void ADMCharacter::DeactivateExplosiveBullets() { bHasExplosiveBullets = false; GetWorldTimerManager().ClearTimer(ExplosiveBulletTimerHandle); }
内容的提问来源于stack exchange,提问作者lajson 22

