[API Noob] How to calculate a relative angle in CPP/UE4

I’m very new at UE4’s api and c++ in general but know my way around blueprints and have written some basic code, followed some basic tutorials.

I just need some guidance on how I would acheive the following, you can see my blueprint issues here Tait-Bryan (Nautical Angles) from Float degrees - Blueprint - Unreal Engine Forums

I have a target (AI) ship that is pointed -90d world rotation aka west assuming 0d is north in 0-180 for North to South clockwise and -180 to -0 for South to North CCW

I have my player ship pointed 0d aka north as in they are perpindicular.

I need to calculate what angle is from the line pointing +x (staright forward extending through the boat back to front) to the center of the player ship. The rotation of the players ship doesnt matter due to the second issue…

If the angle is 0-180 positive aka to the right I need to return a bool saying its to port (thats easy)

If its -180 to -0 aka 180-360 in a full circle clockwise rotation from that forward axis then the bool will return false aka to starboard. I’m talking aobut ships here.

How might I calculate this angle. I’ve done khan academys vector course, trig course, and can get all angles I need (over two dozen) except this one because its independant of the players rotation

Heres and image, I need (~)Bow

I have code for a std lib project that I linked in the BP forums post which I’ve ben struggeling with for almost a week on this one angle and I’m just going to try to reproduce it in ue4s api first, but if anyone has any tips that would be great.

Thanks.

Edit: I have the length of the target ship and the distance between the two points to measur the angle from so I should be able to use trig I would assume…

Hi I won’t give you the answer but can find it in this tutorial series

I will check it out. I wrote this code but it gives me the same results as the blueprint version which is horribly wrong. Thank you.



/*
The hardest angle to get. Looking towards the front of the ship on the target ship, whats the angle port (left) or starboard (right) 0-180deg
That the player ship is at. AoB = BearingToPlayerShip - (TargetShipRotation -  PlayerShipRotation) - 180 if on starbord. If on port its BearingToPlayership + ...
and if the result is not 0-360 range then add multiple of 360 until it is. I found that... it doesnt make much sense.
You can test this by rotating the tanker in the map and the AoB should be 90 stbd or 90 port depending on if its facing north or south.
*/
float UBPFuncLib_NauticalAngles::AngleOffTargetsBow(APawn* TargetPawn, APawn* PlyrShip)
{
	//Look into FMath::CartesianToPolar
	FVector v1 = TargetPawn->GetActorForwardVector();
	v1.Normalize();
	FVector v2 = PlyrShip->GetActorLocation();
	v2.Normalize();
	//float dp = FVector::DotProduct(TargetPawn->GetActorForwardVector.Normalize(0), PlyrShip.GetActorForwardVector.Normalize(0));
	float dp = FVector::DotProduct(v1, v2);
	float rads = FMath::Acos(dp);
	float angle = FMath::RadiansToDegrees(rads);
	UE_LOG(LogTemp, Warning, TEXT("The angle from the target ship forward to the location of the players ship is: %f"), angle);

	// ...
	if (!GEngine)
	{
		GEngine->AddOnScreenDebugMessage(0, 2.f, FColor::Cyan, "Debug on screen");
	}
	return angle;
}


Edit: Ive beenw atching khan academys trig and vector courses over and over but nothings clicking. All the other angles i can figure out for firing solution just not this one.

This should be doable, I’ll use the names you have in your image.


FVector LineOfSight = SubmarinePosition - TargetPosition;
float BowAngleInDegrees = FMath::RadiansToDegrees(Acos(FVector::DotProduct(Target.Forward, LineOfSight))); // Dot product describes the angle between Target and LineOfSight, taking the Arc Cosine gives you the actual angel in radians (0 - 2PI), we then convert that to degrees.
if (FVector::DotProduct(Target.Right, LineOfSight) < 0.0f) // We need one more dot product to actually figure out our winding
{
    BowAngleInDegrees *= -1;
}

That should give you a relative turning angle in degrees.

I will give it a try I havnt tried using the right vector 0,1,0 doesnt make sense to me in terms of trig with vectors.

I spent all night (and the past 8 days in blueprints) trying to solve this, on these/unity/coding forums, stackoverflow, looking at VictoryPlugin/Engine/C++ examples that calcultae this for open source games and could not get the proper angle… I’ve tested it from all different rotations and world locations.

Edit and correct me if I’m wrong but line of sight (line from players boat to target boat angle independant would just be the vectors multiplied right? or wouldit be the dot product so its scalar. The LoS is the range so i have that, the rotation doesnt really matter at this point that would just be targets course across my boats course sin i think opp/hyp
Just for fun I made two empty actors that are located at 0,0,0 with rotation 0,0,0 and then used every combination of atan2, acos, vector2d, cross-prod, dot-prod, up vector, forwad vector, world rotation, world location, vector multiplication/sub/add/divide (rise/run), delta rotation, find look at at rotation and no avail… they tell me the rotation is 137 degrees… It should be 0 or 180 or 360 since they are the exact same…

I’ve got this saved offline for testing later should be able to figureit out math - Direction of two points - Stack Overflow

Its quite embarressing that I can calculate all the angles needed for fire control with 3 moving targets except a core essential one, this one. Infuriating haha.

I’m not clearly sure what you trying to achieve there but




toTarget = target.position - submarine.position;

relativeHeading = submarine.Heading.Dot(target.heading); // heading is normalized vector pointing in heading direction 

if(toTarget.Dot(submarine.heading) > 0 &&  (relativeHeading < -0.95)) // acos(0.95) = 18 degs
{
  target is ahead of submarine
}
else
{
  target is not ahead 
}


So I did your example exactly and got these results with the following code

.H



public:

	//Functions
	UFUNCTION(BlueprintCallable, Category = "cpp")
	static float AngleOnBow(APawn* TargetShip, APawn* PlyrShip);


.CPP



float UBPFuncLib_TDChelper::AngleOnBow(APawn* TargetShip, APawn* PlyrShip)
{
	FVector LineSight = (PlyrShip->GetActorLocation() - TargetShip->GetActorLocation());
	float BowAngleInDeg = FMath::RadiansToDegrees(FGenericPlatformMath::Acos(FVector::DotProduct(TargetShip->GetActorForwardVector(), LineSight)));
	
	if (FVector::DotProduct(TargetShip->GetActorRightVector(), LineSight) < 0.0f) // We need one more dot product to actually figure out our winding
	{
		BowAngleInDeg *= -1;
	}
	return BowAngleInDeg;
}


But then I normalize it and it APPEARS to work. Will get back with more details.



float UBPFuncLib_TDChelper::AngleOnBow(APawn* TargetShip, APawn* PlyrShip)
{
	FVector LineSight = (PlyrShip->GetActorLocation() - TargetShip->GetActorLocation());
	LineSight.Normalize();
	float BowAngleInDeg = FMath::RadiansToDegrees(FGenericPlatformMath::Acos(FVector::DotProduct(TargetShip->GetActorForwardVector(), LineSight)));
	
	if (FVector::DotProduct(TargetShip->GetActorRightVector(), LineSight) < 0.0f) // We need one more dot product to actually figure out our winding
	{
		BowAngleInDeg *= -1;
	}
	return BowAngleInDeg;
}


What would be the best way to set it to 180d if its say 0.1 to - 0.1 (Your directly in the front of the ship, it should still return 180 not 0)

I think this is workable regardless! Thank you! :slight_smile: :smiley: :slight_smile: :smiley:

You welcome m8 I can’t remember the actual code as I’m not in possession of this book anymore, the book is called Programming game AI by example written by Mat Buckland it’s great it includes many great code examples and it covers nearly everything you need to code game AI Vectors, state driven agents, steering behaviors, graphs graph algorithms, obstacle avoidance, fuzzy logic, autonomously moving agents to name just a few, great reed I encourage everyone to read it

Yes, you would have to normalize the LineOfSight vector. A Dot product will only return -1 to 1 if both vectors are normalized. All your movement vectors should be normalized anyway, but that one (since you created it) would have to be normalized. I caught that after I posted the reply last night but figured you’d figure it out on your own. :smiley:

If you re-arrange the code just a little bit, it should work



float UBPFuncLib_TDChelper::AngleOnBow(APawn* TargetShip, APawn* PlyrShip)
{
	FVector LineSight = (PlyrShip->GetActorLocation() - TargetShip->GetActorLocation());
	LineSight.Normalize();
 	float BowAngleInRadians= FGenericPlatformMath::Acos(FVector::DotProduct(TargetShip->GetActorForwardVector(), LineSight));
	
	if (FVector::DotProduct(TargetShip->GetActorRightVector(), LineSight) < 0.0f) // We need one more dot product to actually figure out our winding
  	{
		BowAngleInRadians = TWO_PI - BowAngleInRadians;
	}
        
        BowAngleInRadians = FMath::Clamp(BowAngleInRadians - PI, -PI, PI); // Subtract PI from our radians and clamp us in the -PI, PI space (-180, 180)

        return FMath::RadiansToDegrees(BowAngleInRadians);
}


Radians are your friend and the Unit Circle makes stuff like this pretty easy to figure out (once you wrap your head around it). I’m doing all this in my head, but I think that should give you what you want (or at least give you a push in the right direction). :slight_smile: