Position and rotation of point in relation to two other points - c#

To give you the setting: I'm making a Vive game in zero-g, where the player moves by grabbing handles and propelling themselves.
What I'd like is for the player to be able to rotate themselves, by grabbing a handle with both hands. Imagine how you'd move in zero-g if you held on to a bar with both hands.
To illustrate:
On the left hand side the player has grabbed a handlebar with both hands. Left arm extended, right arm bent.
In the right hand side picture the player has now extended their right arm, which has rotated the player around the bar.
I guess it's easier to see it as if the player would be moving the entire world, when they do this.
My question is: How can I do this in Unity in 3 dimensions, either through math of Unity-trickery? It needs to roll, yaw and position the player relative to the hands.
Thank you!

Record the average of the three vectors. Then in the next frame, get the difference from the previous average. The difference can be used as euler angles to apply constant force to a rigidbody (or rotate an object by that amount, or other possibilities, depending on your goals).
https://docs.unity3d.com/ScriptReference/Transform.Rotate.html
https://docs.unity3d.com/ScriptReference/Rigidbody.AddForce.html
Vector3 previousCenterPoint;
void Update() {
Vector3 newCenterPoint = (leftHand.transform.position + rightHand.transform.position + player.transform.position) / 3f;
if (previousCenterPoint != null)
{
Vector3 someEulerAngles = newCenterPoint - previousCenterPoint;
someRigidBody.AddForce(someEulerAngles, ForceMode.VelocityChange);
}
previousCenterPoint = newCenterPoint;
}

Related

Off-center rotate object in Unity

I have a laser turret in Unity3D, which I'd like to turn towards the enemies. The turret consists of a "leg" and a "head" (selected on the picture 1). The head can pan and tilt around a spherical joint.
I do the following:
Vector3 targetDir = collision.gameObject.transform.position - turretHead.transform.position;
float step = turnSpeed * Time.deltaTime;
Vector3 newDir = Vector3.RotateTowards(turretHead.transform.forward, targetDir, step, 0.0f);
turretHead.transform.rotation = Quaternion.LookRotation(newDir);
The problem is that since the pivot of the head is not aligned with the laser beam, the turret turns into the almost right direction, but it shoots above the target. (It would hit perfectly, if the laser would come out of the red axis of the pivot.)
Is there a builtin method or some trick to achieve the correct functionality other then doing the calculation myself?
Okay, here's the quick and easy way to do this. It's probably "better" to do it with proper trig, but this should give you the result you want pretty quick:
If you don't already have a transform aligned with the barrel, then create an empty GameObject and line it up (make sure it's a child of the turret so they move together). Add a reference to your script for it's transform.
Then, in your first line, calculate from the new Barrel transform instead of the turretHead transform. Leave everything else the same. This way it calculates from the turret barrel, but moves the turret head.
Now, this approach isn't perfect. If the pivot center is too offset from the barrel transform, then it would be less accurate over large moves, or when aiming at something close by, because the expected position when aiming would be different than the initial position due to the rotation pivot being elsewhere. But this can be solved with iteration, as the calculation would become more accurate the closer it is to it's desired goal.

Set direction of rotation Unity C#

I am trying to make a spin wheel that is divided into 6 sections. Each section is marked with a gameObject that is centered in that section. After the player spins the wheel, it will rotate until its starts stopping and then the wheel moves and stops in the center based on the section that was selected (Randomly). I used the following code to rotate the wheel towards the 0 on X axis. this code works fine and the wheel rotates fine, but only if the selected section was on the positive X axis.
float rotateFloat = (((randomReward + 1) * 60) - 30) - transform.rotation.z;
Quaternion targetRotation = Quaternion.Euler(new Vector3(0, 0, rotateFloat));
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, f_difX * Time.deltaTime);
I did some digging and found that Quaternion.RotateTowards()finds the closest way towards the target and rotates using that direction (This caused a problem with the direction of rotation).
Example (Follow image): The player swipes and randomReward (Number 5 on spin wheel) and the wheel starts rotating. When the wheel slows down, it starts moving towards the center. Then it will stop spinning along the direction of the swipe and will rotate towards the other side (Because the distance to the center is closer from the left side).
How can I set it to follow the same direction of the swipe regardless of which is closer to the center. And maybe if there is a better way to do this, please enlighten me. Thanks.
I think the easiest way to rotate a GameObject is by using:
float Speed = 1f;
void Update()
{
// Rotate the object around its local X axis at 1 degree per second
transform.Rotate(Vector3.right * Time.deltaTime * Speed);
}
You can read more about his here
It can happen sometimes the center of the GameObject it´s not placed in the center of the mesh or sprite. If you can´t modify this for any reason, what you can do is place this model/sprite as a child of an Empty GameObject and then attach the rotation script to the Empty GameObject.
While i understand that you don't want people to rotate the disk to the reward they want. Why do you use a random reward and go through the trouble of lining the rotation to the reward?
You should be able to say catch a 'swipe time', then do some math to it (say so it turns at least once if the screen touch time is very short) and then add a random range to it, that is within the circumference of the disk. Then when the disk is done spinning do a ray cast at the top location to determine the reward? (could also link the spinning time to the swipe-time, so that the reward is offered in somewhat the same time interval).
//this comment would have been made as a comment if i would have had the rights to do so, as i think this response may help the question asker, it is provided as an answer instead. i do hope this doesn't piss any one off to much :(

How do I rotate an object to a specific position around another object? (Essentially orbiting to specified position)

I have a planet and a moon. The moon is parented to a dummy object, which is located at the center of the planet (essentially 0,0,0). The moon is free to rotate around (to any position on) the planet. It should maintain a constant distance from the planet.
I have a specific point in mind that I want to rotate the moon to, though it needs to stay upright. That is, the moon should consistently point "up" relative to the planet's surface. Basically it's like a "moveTo" script only in my case the moon should "rotate" around the planet until it reaches the point I'm looking for.
Here's what I have so far, though I can't work out the correct logic to use:
Vector3 targetDir = moveToPos - moon.transform.position;
float angle = Vector3.Angle( targetDir, moon.transform.up );
dummy.transform.RotateAround (moveToPos, moon.transform.up, angle);
Am I thinking of this correctly? Once I get this working, I'd like to feed the moon different Vector3 positions and have the moon rotate to them on the surface of the planet. I have searched for something similar but can't find what I'm looking for.
The marker displayed in this screenshot should say "Rotate here", but this is essentially what my scene looks like:
You've already made things a lot easier by nesting your moon inside an empty transform. If it's properly set up*, this means you won't have to directly manipulate the moon's transform - you just need to rotate the container object until it faces the target position.
*By this, I mean the container object is at (0, 0, 0) relative to the planet, and the moon is only locally translated along the z-axis so it lines up with the container's transform.forward vector.
The problem is easier to approach if we break it down into smaller steps:
Determining the target direction the container needs to face. We can get this by just subtracting the container's position from the target position.
Calculating the required rotation for the container to face the target direction. This is a good place for Quaternion.LookRotation().
Rotating the container until its direction matches the target direction. Quaternion.Lerp() can be used to achieve this.
Here's how you might implement these steps:
Quaternion targetRotation;
Quaternion startRotation;
float progress = 1;
void SetTargetPosition(Vector3 position)
{
// Calculating the target direction
Vector3 targetDir = position - dummy.transform.position;
// Calculating the target rotation for the container, based on the target direction
targetRotation = Quaternion.LookRotation(targetDir);
startRotation = dummy.transform.rotation;
// Signal the rotation to start
progress = 0;
}
void Update()
{
if (progress < 1)
{
// If a rotation is occurring, increment the progress according to time
progress += Time.deltaTime;
// Then, use the progress to determine the container's current rotation
dummy.transform.rotation = Quaternion.Lerp(startRotation, targetRotation, progress);
}
}
Note: If the moon is rotating too quickly (it will currently complete the rotation in ~1 second), just add less to progress every frame, eg. Divide it by a factor.
As long as the container is centered in the planet, the moon should remain a constant distance away from the surface at all times, and by this method will always keep a consistent "up" direction relative to the planet's surface.
Hope this helps! Let me know if you have any questions.

Player camera targeting/locking another object

I am developing a game that uses a third person camera view, character centralized, no issues with that. But I can't find a way to "lock" on another object while keeping my character in view (Rocket League ball cam: https://youtu.be/FDcO04gXihM ).
I am aware of lookAt() method but it's not enough on its own. I still need to calculate the position of the camera to avoid staying between the player and the target. The problem: http://imgur.com/a/MdO9m
This is what I'm currently doing to move the camera (the "free cam"):
if (freeCam) {
transform.position = Vector3.Lerp(transform.position, camTarget.transform.position, speed);
transform.rotation = Quaternion.Lerp(transform.rotation, camTarget.transform.rotation, speed);
} else {
// Lock cam
}
The camTarget is a game object parented to the player.
I now understand what your problem is and try to explain the solution.
Let's say you have the player object as PO and the target object TO and the camera object CO.
So when you want to achieve, to follow with the camera view always the target object and keep the player object in between, all you have to do ->
The CO needs to travel around the PO in an orbit (orbital camera) with a fixed distance.
Next create a vector from the point TO to PO (the center of the orbit of CO)
Then calculate the 2 hit points of the vector (TO|PO) with the orbit. You now have an enter hit point ENP and an exit hit point EXP.
As of vectors have always a direction the EXP will always be the further point if you keep the direction from TO to PO.
Set the CO position to EXP and lookat at TO
Apply an fixed offset to EXP corresponding to the world.upvector to always sit above the PO.
[optional] If surface exists, do a collision detection with EXP against the surface. If hit, set EXP to collision detection point, and set PO render to false. As soon EXP is no longer colliding with surface set PO render to true.
[optional] If want to achieve to always have a good view rather then always a good look at PO, take the angle of the forward vector of CO. If it is quarter I of IV (position of a angle in math) you can assume, that ur currently just seeing the PO and not TO because the camera sits right beyond PO and looks to TO right through PO. If this happens set PO render to false. As soon as CO forward vector angle is quarter II-IV set PO render to true.
That's it. I will try to give u more in depth code tonight, because right now I'm at work.
Maybe you could check if the camera's position is between the player and the target and just rotate it 180º

Orbit Collision Angle

I am working on a game, and I currently have objects continuously orbiting around a sphere at a fixed distance. I need to allow the object to bounce off of each other. Does anyone know how I can go about doing this?
I have the collision detection working, and each object has a bounding sphere. I am able to get the point of collision, I just need to take the current rotation vector from each object and get the resulting "bounce" angle (vector to rotate around) and have each object continue orbiting around it's new vector.
Let me know if that doesn't make sense or if you need anything else! I should mention that this is done using Unity3D (I am not using rigidbodies, or the built in physics engine for performance reasons)
Edit:
Here is what I've tried:
public void OnTriggerEnter(Collider collider)
{
// Determine resultant rotation axis
Vector3 collisionNormal = collider.ClosestPointOnBounds(thisTransform.position);
rotationAxis = Vector3.Reflect(rotationAxis, collisionNormal);
}
Here is a link to the Vector3.Reflect() method in the Unity3D docs: Vector3.Reflect()
At this point the objects don't start moving in a new direction they collide and then don't bounce off. They just appear to stop when the collision occurs.

Categories

Resources