gameobject that rotate away from the facing direction of another game object - unity3d

Trying to figure this out, but without success.
I have a AI that get to point X; facing that object, since I use transform.lookAt().
Now, I would like to turn the AI away, 180 degree, so it can face the same direction that the other agent is facing. I did try to add 180 to the transform once the AI get to destination but it doesn't work, sice the AI may arrive from any position, so the 180 degree rotation is not always the same as the direction in which the other agent is facing.
Is there a way to know or set, in which direction an object/AI/GameObject, is facing? Math wise, I believe it should be the vector3 related to when the object is imported in game, at 0.0.0 coordinates; although I can't really keep track of the orientation of every GO I have in the application; so I was hoping that there is some way to either set a direction, to which a GO is pointing at (even if it is not moving), or retrieve the orientation.

Have you tried looking at Transform.forward?
Edited for completeness:
Since transform.lookAt() is working for you currently, you can try this to face the target from any direction:
var lookPos = target.position - transform.position;
lookPos.y = 0;
var rotation = Quaternion.LookRotation(lookPos);
and then add 180 degrees to the rotation

Related

Rotation flipping when moving around the sides of objects

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);

Unity: Calculate angular velocity of rigidbody to always face specific direction

I'm trying to make a pick up objects mechanic like the one in Amnesia. It's easy to calculate needed rigidbody's velocity, so that the held object stays in front of camera, but my problem is that the object doesn't rotate at all when I hold it. And I would rather have it always be rotated towards the camera. This could easily be achieved with simply parenting the object to player's camera, but...
The behaviour I'm after is as follows: if the bottle I picked up was standing on a table, with neck of the bottle facing ceiling, I would like to see this bottle always with its neck facing ceiling while I hold it. But if this bottle collides with something, it should behave like it actually bumped onto something, so it should rotate some small amount, but it should always try to return to its "original" rotation (in this case, neck facing ceiling).
I think that I need to calculate angular velocity for that and probably have some lerp to return to original rotation, but I'm at a loss on how to do that properly.
I think that the first thing I would need to do is to store the initial direction the moment player picks object up:
Vector3 targetDirection = playerCamera.transform.position - transform.position;
Script is on the held object, so "transform" refers to it. In FixedUpdate() I probably need to have some interpolation, so that angular velocity always tries to rotate the object to original rotation:
rigidbody.angularVelocity = Vector3.Lerp(rigidbody.angularVelocity, targetAngularVelocity, lerpSpeed * Time.fixedDeltaTime);
I don't know how to calculate targetAngularVelocity, because after all I would like the held object to return to original rotation smoothly. I'm not even sure if that's the right way to do this thing and perhaps I should do something else than to calculate angular velocity needed to rotate object properly. I tried just interpolating localRotation to original local rotation, but that did not allow the held object to bump on stuff (the movement then was very jittery). Any ideas?
You need a stabilizer. A script which will add torque/angular velocity to the object, whose angle is different from the target one. Say, you have two variables: targetDirection and currentDirection aka transform.forward. Then you write something like this in fixed update:
var rotation = Quaternion.FromToRotation(currentDirection, targetDirection).eulerAngles * sensitivity;
rigidbody.angularVelocity = rotation;
I recommend to set sensitivity about 0.05 and then increase it if the object stabilizes too slow.
Probably I confused the order, so you should put minus somewhere, but the approach itself is applicable.

How to determine turret rotation direction if rotation angle has to be limited, and target "passed behind"?

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);
}

Unity rotation issues

I'm trying to have a model rotate 90 degrees when a button is pressed - should be simple, right?
Well, the entire system is a buggy mess for some odd reason. I would appreciate some help fixing it
transform.parent.rotation = Quaternion.Euler(transform.parent.rotation.x, transform.parent.rotation.y , transform.parent.rotation.z);
Instead, the model just rotates in random directions that seem like they shouldn't at all be related to my code.
I started up the game to rotate the model while it's in play-mode, but the way it rotates seems like it just suddenly changes out of the blue.
I'm really confused by this & would appreciate some help in fixing it
You code doesnt work like your think.
Quaterinion.Euler expects input in the form of Euler angles, but you are inputing the (x,y,z) of a Quaterinon which consists of (x,y,z,w) which is why you get really funky rotation.
https://docs.unity3d.com/ScriptReference/Quaternion.html
To get the current Euler Angles of your transform, simply use transform.eulerAngles (or in your case, transform.parent.eulerAngles)
var euler = transform.parent.eulerAngles;
transform.parent.rotation = Quaternion.Euler(euler.x, euler.y, euler.z);
However this doesnt change the rotation in anyway.
If you want to rotate 90 degrees around the Y-axis, you could add 90 like this
var euler = transform.parent.eulerAngles;
transform.parent.rotation = Quaternion.Euler(euler.x, euler.y+90, euler.z);
An even simpler way to rotate 90 degrees around Y is ofcourse
transform.Rotate(0, 90, 0);

Check if camera if facing a specific direction

I'm working to let a character push objects around. The problem is that as soon as he touches an object he starts moving it, even when the touch was accidental and the character isn't facing the direction of the object.
What I want to do is get the direction the object when a collision happens, and if the camara is really facing that direction allow the player to move it.
Right now I only managed to get the direction of the object, but I don't know how to compare that with the direction of the camera.
This is what I'm trying now:
void OnCollisionEnter(Collision col) {
float maxOffset = 1f;
if (col.gameObject.name == "Sol") {
// Calculate object direction
Vector3 direction = (col.transform.position - transform.position).normalized;
// Check the offset with the camera rotation (this doesn't work)
Vector3 offset = direccion - Camera.main.transform.rotation.eulerAngles.normalized;
if(offset.x + offset.y + offset.z < maxOffset) {
// Move the object
}
}
You can try to achieve this in several different ways. And it is a bit dependent on how precise you mean facing the box.
You can get events when an object is visible within a certain camera, and when it enters or leaves using the following functions. With these commands from the moment the box gets rendered with that camera (so even if just a edge is visible) your collision will trigger.
OnWillRenderObject, Renderer.isVisible Renderer.OnBecameVisible, OnBecameInvisible
Or you could attempt to calculate whether and objects bounding box falls within the camera's view frustum, there for you could use the following geometry commands
GeometryUtility.CalculateFrustumPlanes, GeometryUtility.TestPlanesAABB
Or if you rather have a very precise facing you could also go for a Physics.Raycast So then you will only trigger the event when the ray is hitting the object.
Hope this helps ya out.
Take a compass obj and align it to ur device sorry object than when you move it you can always know where it points to.
theoretically it should work but maybe your object just moves around because of a bug in your simulator motion engine.