Hey, i’m having some issues figuring this one out.
What i’m trying to achieve is a top down game where the players character rotates towards the mouse as well as rotating so that it has it’s feet towards a point in the world, in this case the player is standing on a sphere and is rotating so that it has it’s feet towards the middle of that sphere. What i’m trying to figure out is how to also rotate the character to the mouse while the character is tilted on the sphere.
It currently looks like this.
I have gotten so both parts on their own but i’m having some trouble putting them together.
Here is the code which makes the player rotate to the sphere. (This is from the spheres class)
FVector PlayerActorLoc = Player->GetActorLocation();
FVector Direction = PlayerActorLoc - GetActorLocation();
FRotator PlayerRot = FRotationMatrix::MakeFromZ(Direction).Rotator();
Player->SetActorRotation(PlayerRot);
And this is from the character class which makes the player rotate towards the mouse.
FVector MouseWorld;
FVector MouseDir;
PlayerController->DeprojectMousePositionToWorld(MouseWorld, MouseDir);
FRotator MouseDirection = MouseDir.Rotation();
SetActorRotation(FRotator(GetActorRotation().Pitch, MouseDirection.Yaw, GetActorRotation().Roll));
Anyone know how i can achieve having them both working simultaneously?
I’ll have to test some more with this in mind. Thanks.
Think of this more like a math problem. You rotate the player so that he is the right side up while his feet point inwards towards the circle. All you have to do is add a yaw rotation relative to that rotation to make him face the mouse. It is like matrix transformations, so you can’t just replace the Yaw with a mouse direction, but apply that yaw to the resulting rotation.
I have been testing around a bit but cannot seem to get the desired effect. I understand that if i first set the rotation of the player to be so that it rotates so it’s standing with it’s feet towards the sphere i will have to add the rotation for the mouse onto that rotation but i cannot get it down in code.
Any help is appriciated.
I am not too sure how this can be done with FRotators and FVectors exactly, but this is very doable from a mathematical standpoint. If you are managing to get the player on top of the ball with the correct rotation then half of the work is done :). The other half is: Get player facing direction vector, make a vector orthogonal (perpendicular) to it facing upwards. Make a plane from the point of actor location and that orthogonal vector. Project the mouse position onto that plane. Find out the difference (angle) between player facing direction and mouse direction. Rotate the Player facing direction vector around the orthogonal vector by the angle difference, and you are done! This is all purely ax+ by+ cz = d math, not specifically FVector and FRotator stuff. You could very easily convert rotators into vectors which would be the (x,y,z) and do operations on them. It’ll take some testing but should work. Someone else might have a better and easier solution, but this technically should work.
youd have to use a lot of trigonometry (cos,sin,tan) and math 3d vector rules to make this work, I suggest trying to understand what you need, writing the process down, and looking up/figure out how to do each step separately.
Sorry for not responding earlier, have not had much time to work with this.
But i have been testing around for a bit and made some progress i believe.
I think i managed to get the mouse location onto a plane that i created with the actors up vector and location. I also think that i managed to get the direction to the mouse by using the actor location. But i have gotten stuck on setting the actual rotation, i’m unsure how i should have the actor rotate around the orthogonal vector. Here is the current code.
// Create plane with actors up vector and players location
FVector ActorUp = GetActorUpVector();
FPlane Plane = FPlane(GetActorLocation(), ActorUp);
// Get mouse location in the world
FVector MouseDir;
FVector MousePosition;
PlayerController->DeprojectMousePositionToWorld(MousePosition, MouseDir);
// Project the mouse position onto the plane
FVector ProjPoint;
ProjPoint = FVector::PointPlaneProject(MousePosition, Plane);
// Find the direction to the projected point from the player
FVector ProjDirection = ProjPoint - GetActorLocation();
ProjDirection.Normalize();
// Difference between player direction and target direction - Not sure how to do this
FRotator RotationDiff = (ProjDirection.Rotation() - GetActorRotation());
Ok cool, after thinking about this for a couple of minutes I realized that the only thing youd really need is an accurate projection on the plane, then you can have the character face that point (vector) always instead of figuring out the difference of angle. By the way if you were curious this function was probably the one you need to rotate around an axis but anyways I dont think youll need it and we can shorten this algorithm a bit.
I am not sure the way you are doing your projection is accurate, since it will project it onto the world first then the plane which is not what we want, we want to project straight away the mouse position onto the plane. I recommend drawing a debug object to see where your final projection is ending up and trying different things until it is what you want. Once you have the final projection, just make a vector from that projection and the player location and set that as your rotation and youd be done :).
PS. We arent looking for a projection as much as we are looking for an intersection. We want to find out, given the camera position and the mouse projection to the world, if we make a line from those two points, where it would intersect the plane. If its too confusing, you earlier calculations are close so figure out the float angle between the two vectors and use the function i linked to rotate.
That sounds logical, so i’ll try to find the position where a line between the camera and the mouse world location intersects with the plane and then calculate the direction to the intersection location on the plane from the player.
Also, if I set the rotation of the player to be so that the player is correctly standing on the sphere before i create my plane and do my projection. Could i not directly set the rotation of the player to rotate towards the intersection since the plane is rotated to fit with the sphere rotation?
Hey, i have been working a bit more with this and i’m at the last step but have gotten stuck again. I would really appreciate if you could help me out one last time.
I managed to create the plane and find the intersect point on the plane, but i cannot set the rotation to that direction because it makes so that the player stops facing the sphere. So i started testing out FRotationMatrix::MakeFromXY and if the player has the mouse on the bottom half of the screen it works fine and the character rotates to the mouse while still standing on the sphere. But if i move the mouse to the top half the character flips upside-down for some reason.
Do you know how i could fix this?
This is in the function that first sets the rotation of the character to stand on the sphere and then calculates which direction the mouse is in.
FVector IntersectPoint;
IntersectPoint = FMath::LinePlaneIntersection(PlayerCamera->GetActorLocation(), MouseWorldPosition, RotationPlane);
FVector IntersectDirection = IntersectPoint - GetActorLocation();
FRotator LookDir = FRotationMatrix::MakeFromXY(IntersectDirection, GetActorRotation().Vector()).Rotator();
SetActorRotation(LookDir);
I’m not sure MakeFromXY is the correct function to use in this case. You have an up vector (pointing upwards from the sphere), and a forward vector (the Look direction which you are getting from the intersection with the plane). Something along the line of this function may do it. If you don’t find the c++ equivalent, look at the source code of that function, see what they are doing, and copy it. You don’t want to just point at the LookDir because you have to take into consideration the up vector aswell.
Sweet! I got it working finally.
I looked up the blueprint function you suggested and copied what they did which made the rotations work.
Thank you so much for helping me out, i have learned a lot. 
Awesome :). Some advice, the FRotator and FVector functionality that unreal provide is good for general purpose use, but for weird scenarios such as yours you are better off coding your own small library that use matrices so you can do multiple transformations easily and more efficiently, but nonetheless glad its working.