调用 AI MoveToLocation 时虚幻引擎崩溃
Unreal crashes when calling AI MoveToLocation
我先在蓝图中测试了下面的代码,想把它翻译成C++。我正在尝试创建一个带有 triggerSphere 的 npc,它激活 onOverlap 并让 Npc 沿着玩家来自的相反方向走开。当我在玩虚幻编辑器并接近 Npc 时,它崩溃了。问题出在 AiController 的 MoveToLocation 上,但我不确定为什么。
这是蓝图(如果质量不好请见谅)
这里是Npc的AiController文件
.h 文件:
#include "CoreMinimal.h"
#include "AIController.h"
#include "SpiderAIController.generated.h"
/**
*
*/
UCLASS()
class SPIDERPROJECT0710_API ASpiderAIController : public AAIController
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
public:
UFUNCTION()
void WalkAway(FVector Location, float Var);
};
.cpp
#include "SpiderAIController.h"
void ASpiderAIController::BeginPlay()
{
Super::BeginPlay();
}
void ASpiderAIController::WalkAway(FVector Location, float Var)
{
MoveToLocation(Location, Var);
}
这里是Npc的档案:
.h 文件的必要部分
private:
UPROPERTY(VisibleAnywhere, Category = "Switch Components") class USphereComponent* TriggerSphere;
UPROPERTY()
class ASpiderAIController* AIController;
UFUNCTION()
void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
//UFUNCTION()
//void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};
cpp 文件:
#include "SpiderCharacter.h"
#include "Components/SphereComponent.h"
#include "SpiderAIController.h"
// Sets default values
ASpiderCharacter::ASpiderCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
TriggerSphere = CreateDefaultSubobject<USphereComponent>(TEXT("Trigger Sphere"));
TriggerSphere->InitSphereRadius(105.0f);
TriggerSphere->SetCollisionProfileName(TEXT("Trigger"));
TriggerSphere->SetupAttachment(RootComponent);
TriggerSphere->OnComponentBeginOverlap.AddDynamic(this, &ASpiderCharacter::OnOverlapBegin);
AIController = Cast<ASpiderAIController>(GetController());
}
void ASpiderCharacter::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor && (OtherActor != this) && OtherComp)
{
//get Location and Roation of PlayerCharacter
FVector PlayerPosition = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation();
FRotator PlayerRotation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorRotation();
FVector NewLocation = FVector(PlayerPosition.X -500.f,PlayerPosition.Y - 500.f, PlayerPosition.Z);
float Var = 100.f;
SetActorRotation(PlayerRotation);
AIController->WalkAway(NewLocation, Var);
//SetActorLocation(NewLocation);
UE_LOG(LogTemp,Warning,TEXT("MyCharacter's Location is %s"), *OtherActor->GetName());
}
}
来自 Unreal 的错误消息:
LoginId:c4c2e10f47cd9a4f6992fd821aae5406 EpicAccountId:92760ac7ea0e4f249688fd7737d3a55d
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x00000000000003b0
UE4Editor_AIModule UE4Editor_SpiderProject0710_4739!ASpiderAIController::WalkAway() [C:\Users\alexa\OneDrive\Desktop\Udemy\Unreal Engine\SpiderProject0710\Source\SpiderProject0710\SpiderAIController.cpp:19]
UE4Editor_SpiderProject0710_4739!ASpiderCharacter::OnOverlapBegin() [C:\Users\alexa\OneDrive\Desktop\Udemy\Unreal Engine\SpiderProject0710\Source\SpiderProject0710\SpiderCharacter.cpp:62]
UE4Editor_SpiderProject0710_4739!ASpiderCharacter::execOnOverlapBegin() [C:\Users\alexa\OneDrive\Desktop\Udemy\Unreal Engine\SpiderProject0710\Intermediate\Build\Win64\UE4Editor\Inc\SpiderProject0710\SpiderCharacter.gen.cpp:38]
UE4Editor_CoreUObject
UE4Editor_CoreUObject
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Core
UE4Editor_Core
UE4Editor_Core
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_UnrealEd
UE4Editor_UnrealEd
UE4Editor
UE4Editor
UE4Editor
UE4Editor
UE4Editor
kernel32
ntdll
我发现了问题。我需要在 BeginPlay 上获取 PlayerPawn 和 AiController,而不是在 class 构造函数中。我也重构了代码。
npc.h:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "SpiderCharacter.generated.h"
UCLASS()
class SPIDERPROJECT0710_API ASpiderCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ASpiderCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
private:
UPROPERTY(VisibleAnywhere, Category = "Switch Components") class USphereComponent* TriggerSphere;
UPROPERTY()
class ASpiderAIController* AIController;
UPROPERTY()
class APawn* PlayerPawn;
UFUNCTION()
void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
//UFUNCTION()
//void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};
和 cpp:
#include "SpiderCharacter.h"
#include "Components/SphereComponent.h"
#include "SpiderAIController.h"
#include "Kismet/GameplayStatics.h"
// Sets default values
ASpiderCharacter::ASpiderCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
TriggerSphere = CreateDefaultSubobject<USphereComponent>(TEXT("Trigger Sphere"));
TriggerSphere->InitSphereRadius(105.0f);
TriggerSphere->SetCollisionProfileName(TEXT("Trigger"));
TriggerSphere->SetupAttachment(RootComponent);
TriggerSphere->OnComponentBeginOverlap.AddDynamic(this, &ASpiderCharacter::OnOverlapBegin);
}
// Called when the game starts or when spawned
void ASpiderCharacter::BeginPlay()
{
Super::BeginPlay();
AIController = Cast<ASpiderAIController>(GetController());
PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
//UE_LOG(LogTemp,Warning,TEXT("MyCharacter is %s"), *PlayerPawn->GetName());
}
// Called every frame
void ASpiderCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void ASpiderCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
//Overlap Function
void ASpiderCharacter::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor && (OtherActor != this) && OtherComp)
{
//get Location and Roation of PlayerCharacter
//FVector PlayerPosition = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation();
//FRotator PlayerRotation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorRotation();
FVector PlayerPosition = PlayerPawn->GetActorLocation();
FRotator PlayerRotation = PlayerPawn->GetActorRotation();
FVector NewLocation = FVector(PlayerPosition.X -500.f,PlayerPosition.Y - 500.f, PlayerPosition.Z);
float Var = 100.f;
SetActorRotation(PlayerRotation);
AIController->WalkAway(NewLocation, Var);
//SetActorLocation(NewLocation);
UE_LOG(LogTemp,Warning,TEXT("MyCharacter's Location is %s"), *OtherActor->GetName());
}
}
我先在蓝图中测试了下面的代码,想把它翻译成C++。我正在尝试创建一个带有 triggerSphere 的 npc,它激活 onOverlap 并让 Npc 沿着玩家来自的相反方向走开。当我在玩虚幻编辑器并接近 Npc 时,它崩溃了。问题出在 AiController 的 MoveToLocation 上,但我不确定为什么。
这是蓝图(如果质量不好请见谅)
这里是Npc的AiController文件 .h 文件:
#include "CoreMinimal.h"
#include "AIController.h"
#include "SpiderAIController.generated.h"
/**
*
*/
UCLASS()
class SPIDERPROJECT0710_API ASpiderAIController : public AAIController
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
public:
UFUNCTION()
void WalkAway(FVector Location, float Var);
};
.cpp
#include "SpiderAIController.h"
void ASpiderAIController::BeginPlay()
{
Super::BeginPlay();
}
void ASpiderAIController::WalkAway(FVector Location, float Var)
{
MoveToLocation(Location, Var);
}
这里是Npc的档案:
.h 文件的必要部分
private:
UPROPERTY(VisibleAnywhere, Category = "Switch Components") class USphereComponent* TriggerSphere;
UPROPERTY()
class ASpiderAIController* AIController;
UFUNCTION()
void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
//UFUNCTION()
//void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};
cpp 文件:
#include "SpiderCharacter.h"
#include "Components/SphereComponent.h"
#include "SpiderAIController.h"
// Sets default values
ASpiderCharacter::ASpiderCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
TriggerSphere = CreateDefaultSubobject<USphereComponent>(TEXT("Trigger Sphere"));
TriggerSphere->InitSphereRadius(105.0f);
TriggerSphere->SetCollisionProfileName(TEXT("Trigger"));
TriggerSphere->SetupAttachment(RootComponent);
TriggerSphere->OnComponentBeginOverlap.AddDynamic(this, &ASpiderCharacter::OnOverlapBegin);
AIController = Cast<ASpiderAIController>(GetController());
}
void ASpiderCharacter::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor && (OtherActor != this) && OtherComp)
{
//get Location and Roation of PlayerCharacter
FVector PlayerPosition = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation();
FRotator PlayerRotation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorRotation();
FVector NewLocation = FVector(PlayerPosition.X -500.f,PlayerPosition.Y - 500.f, PlayerPosition.Z);
float Var = 100.f;
SetActorRotation(PlayerRotation);
AIController->WalkAway(NewLocation, Var);
//SetActorLocation(NewLocation);
UE_LOG(LogTemp,Warning,TEXT("MyCharacter's Location is %s"), *OtherActor->GetName());
}
}
来自 Unreal 的错误消息:
LoginId:c4c2e10f47cd9a4f6992fd821aae5406 EpicAccountId:92760ac7ea0e4f249688fd7737d3a55d
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x00000000000003b0
UE4Editor_AIModule UE4Editor_SpiderProject0710_4739!ASpiderAIController::WalkAway() [C:\Users\alexa\OneDrive\Desktop\Udemy\Unreal Engine\SpiderProject0710\Source\SpiderProject0710\SpiderAIController.cpp:19]
UE4Editor_SpiderProject0710_4739!ASpiderCharacter::OnOverlapBegin() [C:\Users\alexa\OneDrive\Desktop\Udemy\Unreal Engine\SpiderProject0710\Source\SpiderProject0710\SpiderCharacter.cpp:62]
UE4Editor_SpiderProject0710_4739!ASpiderCharacter::execOnOverlapBegin() [C:\Users\alexa\OneDrive\Desktop\Udemy\Unreal Engine\SpiderProject0710\Intermediate\Build\Win64\UE4Editor\Inc\SpiderProject0710\SpiderCharacter.gen.cpp:38]
UE4Editor_CoreUObject
UE4Editor_CoreUObject
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Core
UE4Editor_Core
UE4Editor_Core
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_UnrealEd
UE4Editor_UnrealEd
UE4Editor
UE4Editor
UE4Editor
UE4Editor
UE4Editor
kernel32
ntdll
我发现了问题。我需要在 BeginPlay 上获取 PlayerPawn 和 AiController,而不是在 class 构造函数中。我也重构了代码。
npc.h:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "SpiderCharacter.generated.h"
UCLASS()
class SPIDERPROJECT0710_API ASpiderCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ASpiderCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
private:
UPROPERTY(VisibleAnywhere, Category = "Switch Components") class USphereComponent* TriggerSphere;
UPROPERTY()
class ASpiderAIController* AIController;
UPROPERTY()
class APawn* PlayerPawn;
UFUNCTION()
void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
//UFUNCTION()
//void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};
和 cpp:
#include "SpiderCharacter.h"
#include "Components/SphereComponent.h"
#include "SpiderAIController.h"
#include "Kismet/GameplayStatics.h"
// Sets default values
ASpiderCharacter::ASpiderCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
TriggerSphere = CreateDefaultSubobject<USphereComponent>(TEXT("Trigger Sphere"));
TriggerSphere->InitSphereRadius(105.0f);
TriggerSphere->SetCollisionProfileName(TEXT("Trigger"));
TriggerSphere->SetupAttachment(RootComponent);
TriggerSphere->OnComponentBeginOverlap.AddDynamic(this, &ASpiderCharacter::OnOverlapBegin);
}
// Called when the game starts or when spawned
void ASpiderCharacter::BeginPlay()
{
Super::BeginPlay();
AIController = Cast<ASpiderAIController>(GetController());
PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
//UE_LOG(LogTemp,Warning,TEXT("MyCharacter is %s"), *PlayerPawn->GetName());
}
// Called every frame
void ASpiderCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void ASpiderCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
//Overlap Function
void ASpiderCharacter::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor && (OtherActor != this) && OtherComp)
{
//get Location and Roation of PlayerCharacter
//FVector PlayerPosition = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation();
//FRotator PlayerRotation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorRotation();
FVector PlayerPosition = PlayerPawn->GetActorLocation();
FRotator PlayerRotation = PlayerPawn->GetActorRotation();
FVector NewLocation = FVector(PlayerPosition.X -500.f,PlayerPosition.Y - 500.f, PlayerPosition.Z);
float Var = 100.f;
SetActorRotation(PlayerRotation);
AIController->WalkAway(NewLocation, Var);
//SetActorLocation(NewLocation);
UE_LOG(LogTemp,Warning,TEXT("MyCharacter's Location is %s"), *OtherActor->GetName());
}
}