I want to make a game in Unity where a person can pick a surface and walk along all of its sides. I've gotten the movement working, but when I rotate my character around certain angles of corner the character flips 180 degrees in some direction (it's different depending on the corner) and when I want them to move forward the game freaks out as they keep going across the corner over and over again, turning, and going forward across the border again. I'd strongly prefer to keep my character from doing these 180-degree spins and I think it's just due to a flaw in the formula I use to calculate the angle they stand at (which is based around making sure their transform.up is aligned with the point they are meant to stand on). Any ideas on how I fix this rotation formula in Update?
Current formula:
angle = Vector3.Angle(closestPoint, transform.position);
var t = transform;
var angles = t.eulerAngles;
t.LookAt(GravityWellPoint.transform.position);
t.RotateAround(transform.position, -transform.right, 90);
transform.rotation = Quaternion.Lerp(transform.rotation, t.rotation, Time.deltaTime * 5.0f);
Got this solution from a different forum and it worked:
So this is actually not a trivial problem to solve. If you try doing it by calculating angles etc you almost always end up with a similar spinning/flipping issue in certain positions. You can solve it by doing the maths, but its a pain. I usually like to use Quaternion.LookRotation to solve this kind of problem. you can feed in the desired forward and upward directions. So you can calculate the desired upward direction like so:
Vector3 targetUpDirection = transform.position - GravityWellPoint.transform.position;
Then you would do the following:
transform.rotation = Quaternion.LookRotation(transform.forward,targetUpDirection);
but this doesnt quite work. LookRotation will ensure that your forward direction is exactly the one you specify, and then chooses the upward direction that's the closest possible to the one you specify. So you will find that we don't actually manage to point our object upwards in the way we intended. However, there is an unintuitive solution we can apply instead.
Calculate the upward direction in the same way, then use LookRotation to rotate our object to point its forward face in exactly our desired upwards direction, and its upward face towards the current forward direction:
Vector3 targetUpDirection = transform.position - GravityWellPoint.transform.position;
transform.rotation = Quaternion.LookRotation(targetUpDirection, transform.forward);
Now our object is aligned perfectly, but is the wrong way up. We can use LookRotation again, to swap the upwards and forwards directions:
transform.rotation = Quaternion.LookRotation(transform.up, transform.forward);
For clarity/TLDR here is the complete code for my solution:
//find the desired up direction:
Vector3 targetUpDirection = transform.position - other.position;
//face forward/upward via black magic
transform.rotation = Quaternion.LookRotation(targetUpDirection, transform.forward);
transform.rotation = Quaternion.LookRotation(transform.up, transform.forward);
Related
is there a way to apply a rotation for any arbitrarily orientation (Object A's rotation relative to Object B's local orientation)
I know I can simply get desired result if i do setParent thing, but i want to get without it
In my situation, my character holds water bottle and moves around the room holding it so I set its rotation like this
transform.rotation = mainCamera.transform.rotation;
but As bottle top pointing to the sky seems more natural, I want it to rotate 90 degree by its own X-axis
I tried below codes but it dosent work as i intended
`originalRotation = transform.rotation;
Quaternion rotationDelta = Quaternion.FromToRotation(Vector3.forward, mainCamera.transform.forward);
transform.rotation = rotationDelta * originalRotation;`
Yes, Like i said above if i make my character parent to the bottle will solve the issue, but i want to
do it without it.
Thank you
Try this one:
transform.forward = mainCamera.transform.up;
I started some programming in Unity just for fun a couple days ago.
So far my game (pretty much top-down shooter) consists of player flying in an asteroid field, in which lurk enemy ships. Player can shoot down asteroids and enemies, and enemy ships have missile turrets that "track" player.
Everything works fine until I decided that enemy ships shouldn't be able to rotate their turrets all the 360-way. Think of it as real-world battleship being unable to turn it's front turret (No.1) 180 degrees behind because turret No.2 is in the way.
Currently code for turret rotation is like this (this is not about making "gradual rotation", setting "rotation speed" or something, so please don't look at that!):
playerTarget = GameObject.FindGameObjectWithTag("Player");
chaseDirection = Quaternion.LookRotation(playerTarget.transform.position - transform.position);
newYaw = Mathf.Clamp(chaseDirection.eulerAngles.y, minYaw, maxYaw);
transform.rotation = Quaternion.Euler(0, newYaw, 0);
That works okay, until player flies behind enemy ship. As soon as player gets into turret's "possible rotation angle", it just snaps past "dead zone" to new direction if I don't turn it gradually with fixed angle, or is still stuck trying to rotate "past limit" until target (player) flies all around enemy ship so the angle to target is small enough for rotation direction to be calculated through "enabled" rotation zone, not through "dead zone".
An important thing is I am not looking for answer "how to make gradual rotation". I am looking about calculating rotation direction!
I thought about coding enemy to start rotating turret in counter-direction as soon as player passes "directly behind" the turret "forward facing" position. But the concept of how to do that eludes me.
Because as soon as turret rotates just a bit from limit, it's able to turn "towards" player again, and gets stuck at limit again.
Edited with the clarification in mind.
You need a function that will tell you if you should rotate clockwise or counter-clockwise, based on the enemy location.
First find the mid point, this will be:
var mid = (minYaw + maxYaw) / 2
In your example this will be 3 o'clock, straight right.
Now, if your current rotation is lower than mid, and the target is higher than mid, than you must rotate clockwise even if it's not the shortest rotation to get there.
If the target rotation is higher than mid, and the target is lower than mid, you must rotate counter-clockwise for the same reason. You may need to adjust for negative degrees.
Please note that this will create a secondary effect, where once the ship passes the half point of the dead zone (say moving from 10 o'clock to 8 o'clock in your example), the turret will start moving as if anticipating the flank. You may want to disable this movement in a special case.
I'll keep the second part of my answer as-is, for future references.
If you want it to move gradually, you need to use deltaTime or fixedDeltaTime in case of a fixed update. You can define how fast it will move by adding a speed property. Try something like this:
void update () {
var playerTarget = GameObject.FindGameObjectWithTag("Player");
var chaseDirection = Quaternion.LookRotation(playerTarget.transform.position - transform.position);
var newYaw = Mathf.Clamp(chaseDirection.eulerAngles.y, minYaw, maxYaw);
var currentRotation = transform.eulerAngles;
var desiredRotation= currentRotation;
var desiredRotation.y = newYaw;
transform.eulerAngles = Vector3.RotateTowards(currentRotation, desiredRotation, Time.deltaTime * RotationSpeed, 0.0f);
}
The chest bone of my player can be rotated while aiming.
Now I wanted to evaluate how much (minimum and maximum rotation) I should let the chest be rotatable.
To do that, I allowed all degrees of rotation and took a look at the Inspector.
For example, the minimum value that the chest should be rotatable to the left should be Y=-15.
At Y=-15 (seen in the Inspector), it still looked natural.
Now I wanted to code this.
To my surprise, chest.localRotation.Y was a completely different value than what the Inspector is showing.
I have then taken a look at the chest variable and extended the view.
I just can't see the rotation value that the Inspector is showing.
How should I go on in this case, please?
I'm using this to rotate the bone:
Chest.LookAt(ChestLookTarget.position);
Chest.rotation = Chest.rotation * Quaternion.Euler(Offset);
Thank you!
The reason why it doesn't work:
Quaternion is not a human readable value.
One Quaternion is allways unique but can have multiple (infinite?) different representations in Euler space! The other way round one Euler represents allways exactly one Quaternion value.
If you look at the docs it explicitly says
Don't modify this directly unless you know quaternions inside out.
Than as said what you see in the inspector is the localRotation in relation to the parent Transform.
Better said it is one of the many possible Euler inputs that result in the Quaternion. What you see in the debug at localEulerAngles is another possible Euler representation. Unity usually in localEulerAngles also gives you only values > 0.
It seems that the chest anyway will only rotate around the Y axis, right?
If this is the case you can simply get the Angle between the chest's original forward vector and the target. It is way easier to handle Vector3 values than Quaternions ;)
It seems to be the same use case as in this post
// get the target direction
Vector3 targetDir = ChestLookTarget.position - Chest.position;
// Reset any difference in the Y axis
// since it would change the angle as well if there was a difference I the height
// between the two objects
targetDir.y = 0;
// however you currently rotate
// instead rotate only the Vector3 variable without applying it to the transform yet
Vector3 newDir = Vector3.RotateTowards(Chest.forward, targetDir, RotationSpeed * Time.deltaTime, 0.0f);
// Compare the target direction to the parents forward vector
float newAngle = Vector3.Angle(Chest.parent.transform.forward, newDir);
if (newAngle > MaxRotationAngle)
{
// What should happen if angle gets bigger?
return;
}
// If angle still okey set the new direction
Chest.rotation = Quaternion.LookRotation(newDir);
I'm trying to create a game where a ball is launched off from a circle, much like a cannon, but it can be launched into any direction, 360ยบ because the circle which the ball is attached to can rotate. So, I was thinking of using Rigidbody2D.AddForce() but I'm not sure how to define the direction I want the force to be applied. I want it to be the direction perpendicular to the ball/player's movement but I don't know how to define that. Thanks for any help! :)
If you get the direction that the ball is travelling (as say degrees) you can add a certain angle to that and use the angle to determine the force that needs to be applied.
I'm assuming that the ball/player has no ridged body, if it does then you can just grab the direction directly. Also since your using circle to describe the spawned shape i'm going to assume your working in 2D.
Vector3 lastPosition;
void Update()
{
//launch the ball before updating the last position
lastPosition = transform.position;
}
Vector3 launchDirection()
{
Vector3 ballDirection = transform.position - lastPosition;
float angle = Mathf.Atan2(ballDirection.x, ballDirection.y) * Mathf.Rad2Deg;
//the direction should be perpendicular to direction of movement
float angle += 90;
return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
}
I haven't ran the code in unity but it looks like it should work. Basically to get the direction you store the last position and compare it to the current direction to work out the delta (if your using a ridged body to move around then grab the direction from that instead) then use atan2 to get the angle. To make the launch direction perpendicular to the ball I added 90 degrees (you might want -90 depending on what side you need the circle to launch from). Now that we have the angle that you want the ball to shoot out from, use that with Sin and Cos to get the XY of the angle.
There you have it that will get you the direction perpendicular to movement, you your using 3 dimensions it's basically the same maths just with a few numbers thrown in to pad the return value.
Oh if your object always faces the direction of movement transform.right also works :P
I am trying to make my character to avoid obstacles while moving.
the target is defined on click and character moves to it on every frame by updating transform.position (so no physics here).
every obstacle has collider and character has trigger. on TriggerStay event of the character I have managed to get some info about the contact point:
Vector3 point = other.ClosestPointOnBounds(transform.position);
Vector3 dist = point - transform.position;
and the best thing I came to is to:
Vector3 perp = Vector3.Cross(transform.forward, dist.normalized);
float dir = Vector3.Dot(perp, transform.up);
transform.position -= transform.right * dir;
but it does not work as I was expected. actually it does not work at all.
how to correct character position, So it appears to be smoothly deflected of obstacle, while moving to the target?
EDIT: here is the screenshot
white rays show the direction of contacts, so they are multiple.
what i want is that the character can avoid obstacles while moving to his target.
for now i came to new idea:
float correction = Vector3.Dot(transform.right, dist.normalized) / 10;
transform.position += transform.right * correction;
it somewhat works as i want, but character is constantly jumping from one place to another. don't know how to fix this.
also tried correcting direction of movement by substracting the vector of contact from vector of movement, but character is also moves jerky and rotates stupidly.
You can try something like:
Vector3 perp = Vector3.Cross(transform.forward, other.transform.up);
transform.position -= perp.normalized * other.bounds.size.x / 2f;
You seem to not use Vector3.Cross proper way. Read here about it: Unity3D docs link