I'm trying to make a 3D compass in unity, like the one in scene mode.
But its not looking to bright.
At the moment
end goal How do I better emulate the scene mode transform compass? and keep the GamObject "3DCompass" always in view? (without putting it under the Main Camera)
//Compass3D
public class Compass3D : MonoBehaviour
{
public Vector3 NorthDir;
public Transform Player; // Camera
public GameObject NorthLayer;
// Update is called once per frame
void Update()
{
ChangeNorthDir();
}
public void ChangeNorthDir()
{
NorthDir.z = Player.eulerAngles.y; //May need to change
NorthLayer.transform.eulerAngles = NorthDir;
}
}
Hm...
Well, firstly, you need to realize that the compass' orientation never changes. That's kind of the point of it. The compass always points the same way, meaning it doesn't rotate.
Meaning there's no need for you to do anything in update, you just set where the north is supposed to point to, and leave it at that. The illusion of it rotating comes from person rotating, while the compass keeps pointing the same (global) direction.
The second thing is a big, lazy, awesome secret I'm going to tell you about:
Quaternion.LookRotation
So what you need to do is just rotate the compass correctly on Start, meaning rotate it so that its "Forward direction" is Vector3.forwards (that's a global Z+), and its upward is Vector3.up (global y+). And then never touch the rotation again.
But you want it to stay in view (without being childed to the camera), so what you'll do in update is that:
public class Compass3D : MonoBehaviour
{
public Vector3 NorthDir;
public Transform Player; // Camera
public Vector3 offsetFromPlayer; //needed to keep position from camera. this basically determines where on screen the compass will be positioned. 0,0,0 would be at the same position as the camera, experiment with other values to find one which positions compass relative to camera in such way that it displays on screen where you want it
public GameObject NorthLayer;
void Start()
{
//northDir can be whatever you want, I'm going to assume you want it to point along Unity's forward axis
NorthDir = Vector3.forward;
//set the compass to point to north (assuming its "N" needle points in the direction of model's forward axis (z+). if not, change the model, or nest it into a gameobject within which you'll rotate the model so that the N points along the parent gameobject's z+ axis
NorthLayer.transform.rotation = Quaternion.LookRotation(NorthDir, Vector3.up);
//nothing else needed, the rotation will be fine forever now. if you want to change it later, just do the above line again, and supply it the new NorthDir
}
// Update is called once per frame
void Update()
{
//only thing you need to do in update, is keep the relative position to camera. tbh, easiest way would be to parent the compass, but you said you don't want that, so...
transform.position = Player.position + (Player.rotation * offsetFromPlayer);
//you need to make sure that the compass' offset from camera rotates with the direction of the camera itself, otherwise when camera rotates, the compass will get out of view. that's what multiplying by Player.rotation is there for. you rotate Vectors by multiplying them with quaternions (which is how we express rotations).
}
}
What this code does: first it sets the compass so it points towards north. And then it never touches that again, because once the compass points towards north, if it's not parented to anything (which I assume it's not), it will keep pointing north. IF it is parented to anything else, just copypaste that line from start to Update too, so that when the orientation of compass' parent changes, the compass fixes its pointing back to global north.
Then, in update, it only updates its position, to keep at the same place relative to camera. The important thing to note is that the position needs to take the camera's direction into account, so that when camera rotates, the compass moves similarly to if you had your hand outstretched in front of you, and you rotated your whole body. If the compass is not parented to anything, that motion the tip of your hand does is still just a position change, but it is position relative to your whole body and its direction, so that position change needs to take that into account.
In this code, if you put the offsetFromPlayer as Vector3(0,0,1), that would mean "one unit along the way the camera is looking". If you put it as Vector3(1,0,1), that would mean "one unit along the way the camera is looking, and one unit to the right". So you'll need to experiment with that value to find one that makes the compass display where you actually want it to be on the screen.
I'm learning Unity3D and having some trouble on my 3D radar. My radar is a child of my Player game object which is rotating around as I fly. The radar itself is rotated 45 degrees so it faces the user. There is a Cube that is supposed to be the radar blip of the enemy plane. The Cube is a child of Radar so should inherit its rotation. There is a script on the Cube to update itself every update(). Here is the hierarchy:
Enemy Plane
Player
-- Camera
-- Radar
------ Cube (radar representation of Enemy Plane)
The problem is that while the Cube itself is rotated, with the Radar, its motion is not. As I get closer to the enemy plane, the Cube just gets closer to the camera (which is good) but I would expect its motion to follow the 45 degree rotation of the parent Radar object?
public class RadarGlyph : MonoBehaviour
{
GameObject radarSource;
GameObject trackedObject;
Vector3 radarScaler;
void Start()
{
this.radarSource = GameObject.Find("Radar");
this.trackedObject = GameObject.Find("Enemy Fighter");
this.radarScaler = new Vector3(0.001f, 0.001f, 0.001f);
}
void Update()
{
Vector3 vDelta = this.trackedObject.transform.position - this.radarSource.transform.position;
vDelta.Scale(this.radarScaler);
this.transform.localPosition = this.transform.InverseTransformDirection(vDelta);
}
}
For a complete solution, you have to get the position of the target wrt the ship first and then recreate it within the context of the blip and the radar.
As a quick fix, you can try changing your last line like this:
this.transform.localPosition = this.parent.localRotation * this.transform.InverseTransformDirection(vDelta);
or (apparently not good as you mentioned)
this.transform.localPosition = Quaternion.Inverse(this.parent.localRotation) * this.transform.InverseTransformDirection(vDelta);
one of these is bound to work. (The first one did)
Edit: here's a third alternative
this.transform.localPosition = this.transform.parent.parent.InverseTransformDirection(vDelta);
This one gets the position in Player's space and applies it in radar's space.
The first and third are trying to do the same thing. Since you were transforming the direction into the blip's coordinate frame, any rotations that its parents have are canceled out. Instead, the correct thing to do is to get the position relative to the Player first. Then apply it to the blip in the radar. The third line of code I have here is attempting to do that.
I have a finger object. It is just three cubes representing the finger parts.
The 2nd cube is the child of the 1st one. And the 3rd cube is the child of the 2nd one.
This is the heirarchy: Cube1 -> Cube2 -> Cube3
My goal is to apply a rotation angle to the first cube and let the other cubes do the same locally.
Example: Apply 30 degrees Z rotation to the first cube, 30 degrees Z rotation to the 2nd cube, and also the 3rd one.
This will make a finger that look like this:
(Forgive me if it doesn't look like a finger)
In every Update() frame, I will change the angle (it's just one number) and it will rotate every cube for me.
My question is:
How do I make all these cubes collide properly with other objects?
I tried putting the Rigidbody on all of them and set isKinematic=false because I want to transform them myself. But I still cannot use transform.rotation to update my rotation because it will miss the collision with a ball very easily (especially the tip of the finger because it moves faster than other parts). Continuous detection doesn't help.
So I tried using rigidbody.MoveRotation() and rigidbody.MovePosition() instead, which is a pain because they need absolute values. They worked but the animation is so jumpy when I change the angle quickly.
I'm guessing that the animation is jumpy because there are many Rigidbodies or because the physics engine cannot interpolate the position of each box properly when I use MoveRotation() and MovePosition().
I need to use MovePosition() also because when I use only child.MoveRotation(transform.parent.rotation * originalChildLocalRotation * Quaternion.Euler(0, 0, angle)), the position doesn't move relative to the parent. So I have to compute child.MovePosition(parent.TransformPoint(originalLocalPositionOfTheChild)) every frame too.
I'm a beginner and I'm currently trying to create a 3D Tetris. Since 1-2 Weeks im trying to rotate my Tetromino properly, but it's not working the way I want.
So this is my "T" Tetromino. It's made of 4 Cubes, which are combined with an empty gameobject like this:
When I rotate the "T" gameobject with transform.Rotate(0, 0, -90), optically every cube moves, but not really. There is a blue dot on the first Picture. When i rotate my gameobject, it rotates around this point. After the rotation, every cube gets its new transform.position expect the middle one. Optically it moves one unit, but its transform.position doesn't change.
The same with the other figures. There is always one Cube, which transform.position doesn't update. I kinda know why its position doesn't change, but i still don't know what to do.
I tried many stuff, but i failed. Summarized I want my gameobject to rotate and update its position. Is there a way to do this?
Best regards
I am creating a program using Unity3D in which the player fires an arrow at a target. What is the best way to ensure that the arrow is flying through the air at a rotation which depends on it's angle of movement? (ie the arrow head is facing upward of ascent and downward on descent)
I've had a look at the transform.LookAt and Quaternion.lookRotation functions I'm but now sure how they can apply. Here's the code which dictates the arrows velocity:
newArrow.GetComponent<Rigidbody>().velocity = new Vector3 (5*(transform.position.x - mousePos.x), 10*(transform.position.y - mousePos.y), 0);
Set the constraints on the rigidbody. In your case it should only rotate around the x axis so that it aims up and then down.
For the rest, you just set the initial rotation on throw:
newArrow.transform.rotation = Quaternion.LookRotation(velocity);
This may need some tweak based on your model initial orientation.