Hello everyone, I’m making a multiplayer game and at the moment I’m trying to implement the movement of a character on the ceiling, I chose the simplest option to just flip and raise the mesh to the ceiling, and leave the capsule in its place and at the moment I’m creating a task for the behavior tree in which it will do all this, but I have a problem when I try to release LineTrace to the ceiling to get its coordinates: this was nullptr
Task_GoToCeiling.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/BTTaskNode.h"
#include "ZombieEnemyCPP.h"
#include "Task_GoToCeiling.generated.h"
/**
*
*/
UCLASS()
class FIRSTGAME_API UTask_GoToCeiling : public UBTTaskNode
{
GENERATED_BODY()
private:
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp,
uint8* NodeMemory) override;
FHitResult HitResult;
public:
AZombieEnemyCPP* Zombie = Cast<AZombieEnemyCPP>(UGameplayStatics::GetPlayerController(GetWorld(), 0));
};
Task_GoToCeiling.cpp
#include "Task_GoToCeiling.h"
#include "LineTrace.h"
#include "Kismet/GameplayStatics.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "BTAIController.h"
#include "ZombieEnemyCPP.h"
EBTNodeResult::Type UTask_GoToCeiling::
ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
FVector StartCapsule = GetWorld()->GetFirstPlayerController()->
GetCharacter()->GetCapsuleComponent()->GetComponentLocation();
FVector EndCapsule = StartCapsule + GetWorld()->GetFirstPlayerController()->
GetCharacter()->GetCapsuleComponent()->GetComponentLocation() * 400.0f;
HitResult = Zombie->TraceCeiling(StartCapsule, EndCapsule, HitResult);
/*FHitResult HitResult = GetWorld()->GetFirstPlayerController()->
GetCharacter()->GetComponentByClass()->LineTraceSingle(StartCapsule, EndCapsule, true);*/
if (HitResult.bBlockingHit && HitResult.GetComponent()->ComponentHasTag("Ceiling"))
{
FRotator CeilingRotation = (FRotator(180.0f, -90.0f, Zombie->GetControlRotation().Yaw));
Zombie->GetMesh()->K2_SetWorldLocationAndRotation(HitResult.Location, CeilingRotation, true, HitResult, true);
}
else
{
return EBTNodeResult::Failed;
}
return EBTNodeResult::Succeeded;
}
ZombieEnemy.cpp
FHitResult AZombieEnemyCPP::TraceCeiling(FVector Start, FVector End, FHitResult HitResult)
{
HitResult = this->LineTraceComp->LineTraceSingle(Start, End, true); //nullptr here
return HitResult;
}
The code is not the most accurate due to my attempts to do it myself and fix other errors, I apologize in advance
Hi, try replacing the “*400.0f” with “-FVector(0,0,400.0f)”
Maybe try making the value larger, say 2000.0f.
If this still doesn’t return anything, it may help to visualize the trace with one of the two options mentioned in this post:
It seems I didn’t describe the error quite correctly, when I call the same function from the NPC class it works fine, but I need to register this function in Task and there is a problem with nullptr, it seems to me it can’t get LineTraceComp which is in my AI class
I see - can you show the code which sets the LineTraceComp variable?
ZombieEnemyCPP.h
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
class ULineTrace* LineTraceComp;
ZombieEnemyCPP.cpp
AZombieEnemyCPP::AZombieEnemyCPP()
{
LineTraceComp = CreateDefaultSubobject<ULineTrace>("LineTraceComponent");
}
LineTrace.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "LineTrace.generated.h"
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class FIRSTGAME_API ULineTrace : public UActorComponent
{
GENERATED_BODY()
public:
ULineTrace();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
FHitResult LineTraceSingle(FVector Start, FVector End);
FHitResult LineTraceSingle(FVector Start, FVector End, bool ShowDebugLine);
FHitResult SphereTrace(FVector Start, FVector End);
};
LineTrace.cpp
#include "LineTrace.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Engine/Engine.h"
#include "DrawDebugHelpers.h"
#include "Kismet/GameplayStatics.h"
#include <Kismet/KismetMathLibrary.h>
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Actor.h"
// Sets default values for this component's properties
ULineTrace::ULineTrace()
{
}
// Called when the game starts
void ULineTrace::BeginPlay()
{
Super::BeginPlay();
}
FHitResult ULineTrace::LineTraceSingle(FVector Start, FVector End)
{
FHitResult HitResult;
FCollisionObjectQueryParams CollisionParams;
FCollisionQueryParams CollisionQueryParams;
CollisionQueryParams.AddIgnoredActor(GetOwner());
if (GetWorld()->LineTraceSingleByObjectType(
OUT HitResult,
Start,
End,
CollisionParams,
CollisionQueryParams
))
{
return HitResult;
}
else
{
return HitResult;
}
}
FHitResult ULineTrace::LineTraceSingle(FVector Start, FVector End, bool ShowDebugLine)
{
FHitResult Actor = LineTraceSingle(Start, End);
if (ShowDebugLine) {
DrawDebugLine(
GetWorld(),
Start,
End,
FColor::Red,
false,
3.0f,
0,
5.0f
);
}
return Actor;
}
I can’t see any issues with that - what about the “Zombie” variable? it’s the “this” that is NULL
It seems to me the problem is that I cant get the zombie itself that is in the world, at the moment the Zombie is Cast(UGameplayStatics::GetPlayerController(GetWorld(), 0)); , but I dont know how to get an existing actor and at the same time access its LineTraceComp to check for a ceiling above it
Sorry, I’ve been sitting here laughing at myself - it reminds me of the Gag where one person is telling another about a person named “Hue” - who? Hue! yeah, that’s what I’m asking - who? etc I think I need some sleep.
Rather than set Zombie in the header there (as it’s most probably a nullptr at that point) try setting it as the first line in the ExecuteTask function.
yeah, but if you’ve still got the Zombie variable in your header you can just put
Zombie = Cast<...
it didn’t work, is there any way i can get it from GetWorld()?
You can use:
Zombie=(AZombieEnemyCPP*)UGameplayStatics::GetActorOfClass(AZombieEnemyCPP::StaticClass());
if there’s only one in the level, or you can do:
TArray<AActor*> zombieList;
UGameplayStatics::GetAllActorsOfClass(AZombieEnemyCPP::StaticClass(),zombieList);
if there are more than one, but then you’ll need to find which one it is that you’re wanting to move to the ceiling - maybe with a proximity test.
Anyway I’m going to have to tap out now and get some sleep - it’s been an almost 18hour work day.
I hope you manage to get it working!
Ok, thanks for your help, I’ll write here if I find a solution