Hi,
I want to move an enemy ship towards my player, no matter where he is. I read a few post about it on this forum and reddit, but everything I tried lead me to the enemy moving, but not towards my player. Instead of that, my enemy actor is moving in a straight line. I’m also rotating my actor towards my player, but it works (if that changes anything). Below is my tick function:
void ABasicEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//Responsible for rotating actor towards player
ABasePlayerShip* Player = Cast<ABasePlayerShip>(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetPawn());
if (Player)
{
FRotator NewRotation{ UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), Player->GetActorLocation()) };
SetActorRotation(NewRotation);
}
else
{
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, FString::Printf(TEXT("%lld"), "Player not found"));
}
//Responsible for moving actor towards the player
FVector CurrentLocation = GetActorLocation();
FVector PlayerCurrentLocation = Player->GetActorLocation();
FVector MovementVector = PlayerCurrentLocation - CurrentLocation;
FVector Velocity{ MovementVector.Normalize() * EnemySpeed * DeltaTime };
FVector NewLocation{ CurrentLocation - Velocity };
NewLocation.Z = 160.0f;
FRotator NewRotation{ NewLocation.Rotation() };
FHitResult Hit(1.f);
//RootComponent->MoveComponent(NewLocation, NewRotation, true, &Hit);
SetActorLocation(NewLocation);
//CurrentLocation.X -= EnemySpeed * DeltaTime;
//SetActorLocation(CurrentLocation);
}
Have you thought about using the AI controller/behaviour tree? There’s a MoveTo option within the Behaviour Tree that you could use to move your enemy ship towards the player.
My first thought was to use BT, but acceptable radius wasn’t working, and I also had problems with c++ inherited ships to work with BT. So i decided to use C++.
This should move the ship AWAY from the player, no?
This makes no sense. What you get if you just take a particular location and turn it into a location does not point from point A to point B. You already did it right after FindLookAtRotation.
Also: Note that you test for whether Player is null in the if statement, but then dereference it unconditionally after the test. Might want to even move all the code into the if, or remove the if and go with the assumption that there’s always a player, to clear up the code a bit.
NewRotation is just a leftover after some unconventional tries, and about CurrentLocation-Velocity: if I add these values instead of substracting them, my enemy is just moving in the opposite direction. The problem is that this code generates some sort of a straihght line that my enemy is following, changing the sign changes only whethet the enemy is moving up or down.
Edit: I moved this chunk of code to the ‘if’ statement and also deleted things I didn’t need (e.g NewRotation), but nothing changed.
Your code does not make sense at all.
1 GetActorLocation() inside a vector, gets your ship location.
2 FVector PlayerCurrentLocation = Player->GetActorLocation(); ( I don’t think you can get it like that, the player has a character class with a pawn)
FVector MovementVector = PlayerCurrentLocation - CurrentLocation; Calculate distance based on vector location xyz
FRotator NewRotation{ NewLocation.Rotation() }; You set the newlocation.Z axis to 160 so it’s just going to head that way on the Z axis, it’s going to rotate there and just head there 160 degree where it is rotated.
Your trace system is incomplete, it has to have start and end.
You set the actor location to new location so it’s going to move there where you set the Z axis.
At least
Set the location to PlayerCurrentLocation but that is just going to teleport you to the player, if it works because I don’t think you can get the player location coordinates like that.
You have to use something to get the player Vector on a rotator, that is a transformation matrix, to tranform elements so you get a visual line between the two.
Do this as practice.
Take two actors at the begining because it’s easy to do so and get actor location of each with GetActorLocation function
and then actorA - ActorB
since this is actor A that is trying to teleport to actor B then SetActorLocation to ActorB
Actor A should be teleported there.
This is a way to test your code if you are not sure you are getting the character so just do between actors (objects) cubes so on. First try to teleport it there. Then try to use deltatime and other things.
I tried to set my enemy’s location to plauer’s location and the enemy not only teleported, but when I moved my player the enemy also changed its location.
This will not work, it is invalid.
FRotator NewRotation{ NewLocation.Rotation() };
Also.
You are using the rotation function that is suppose to substitute a tranformation matrix but it’s not formulated properly. Find another way to use it.
I cannot write code for you, I can only help you with the code you got
Find another sintax mode for it.
This should move the ship AWAY from the player, no?
I thought you wanted the ship to follow you, not head away ?
The steps.
1 Get the actor location and the player location
2 Get some sense between them by calculating the distance, this will give you a vector with a path towards the character.
3 Now you have to transform “something”, because to head into that direction you got to “turn” so your path needs to be transformed to turn around ? your ship towards ?
4 Apply what ever you like by setting it with a forward vector or direction used with delta time to finally move the object once all is done
You could skip feeding the distance to a vector and feed it elsewhere.
Most important distance between Store to the Frotator this - this Rotate.
So Frotator var ObjectA - ObjectB Rotation()
Look you got it here
FVector MovementVector = PlayerCurrentLocation - CurrentLocation;
But you set it as a vector because you wanted then to feed the vector to that but it does not work that way because you are missing elements.
So why complicate things.
FRotator somestuff = some distance stuff between objects .Rotation();
You could do this in blue prints, but you chose C++ so you need to understand what you are doing, not just copy paste code. The idea is to store in your Rotator the distances between the objects, you chose another way to feed it to a vector there for you now have to tranform the vector to rotation, or maybe not so just use the function with the rotator.