I'm getting from a sensor 4 parameters every frame, O (origin), W (UP), V(FORWARD) and U(RIGHT), they are Vector3 elements, with this values i can know the position of my object is in space, but i can't find out the rotation to represent all movemets that the object does.
this is what i get so far(this run every frame with new values for entry vector):
Vector3 vetO = new Vector3(entry[0], entry[4], entry[8]); //o
Vector3 vetU = new Vector3(entry[1], entry[5], entry[9]); //u
Vector3 vetV = new Vector3(entry[2], entry[6], entry[10]); //v
Vector3 vetW = new Vector3(entry[3], entry[7], entry[11]); //w
//Here i'm doing this to analize the rotation of a plan
vetW.x = 0;
vetU.z = 0;
vetV.y = 0;
float angleX = Vector3.Angle(vetW, Vector3.up);
float angleY = Vector3.Angle(vetV, Vector3.forward);
float angleZ = Vector3.Angle(vetU, Vector3.right);
//This is because unity bug, when angle is up to 180º
angleX = vetW.z < 0 ? -angleX : angleX;
angleY = vetV.x < 0 ? -angleY : angleY;
angleZ = vetU.y < 0 ? -angleZ : angleZ;
Vector3 angles = new Vector3(angleX, angleY, angleZ);
transform.eulerAngles = angles;
transform.localPosition = vetO;
If I understand you correctly, you want to get the rotation of a certain gameobject, right?
To do this, you can use YourGameObject.transform.rotation.eulerAngles to give you a rotation in the form of Vector3. If you wanted to get just one angle you can use YourGameObject.transform.rotation.eulerAngles.x,YourGameObject.transform.rotation.eulerAngles.y or YourGameObject.transform.rotation.eulerAngles.z
Related
Hello there everybody!
I'm trying to create a variable where you can put the number of points and the radius of a circle, and it will divide those points uniformly around the circle.
I'm trying to not use the Euler angles to set rotation or the Rotate or RotateAroundmethods.
But I am not having success...
These are how my code looks until the moment
public class PowerUps : MonoBehaviour
{
public GameObject PowerUpPrefab;
public GameObject Player;
public int PowerUpCount = 3;
public float PowerUpRadius = 1;
public Vector3 newPowerupSpace;
public GameObject[] SpawnPowerUps()
{
//get player positin
Vector3 anchorPoint = Player.transform.position;
GameObject[] SpawnPowerUps = new GameObject[PowerUpCount];
float angleStep = Mathf.HalfToFloat((ushort)(360.0 / PowerUpCount));
for (int i = 0; i < PowerUpCount; i++)
{
float theta = i * angleStep;
newPowerupSpace.x = anchorPoint.x + (PowerUpRadius * Mathf.Cos(theta));
newPowerupSpace.y = anchorPoint.y + (PowerUpRadius * Mathf.Sin(theta));
SpawnPowerUps[i] = (GameObject)Instantiate(PowerUpPrefab, newPowerupSpace, Quaternion.identity);
}
return null;
}
}
Any suggestions?
Update:
I changed the
float angleStep = Mathf.HalfToFloat((ushort)(360.0 / PowerUpCount));
to
float angleStep = ((ushort)((360.0 / PowerUpCount) * Mathf.Deg2Rad));
and now is working.
I feel kind of stupid....
Update 2:
After doing some tests, I notice that some numbers don't divide uniformly across the circle. That's because I was converting de circle degrees to radium in the wrong part.
Here's how the code looks like now:
public GameObject[] SpawnPowerUps()
{
Vector3 anchorPoint = Player.transform.position;
GameObject[] SpawnPowerUps = new GameObject[PowerUpCount];
float angleStep = ((ushort)(360.0 / PowerUpCount));
for (int i = 0; i < PowerUpCount; i++)
{
float theta = i * angleStep;
newPowerupSpace.x = anchorPoint.x + (PowerUpRadius * Mathf.Cos(theta * Mathf.Deg2Rad));
newPowerupSpace.y = anchorPoint.y + (PowerUpRadius * Mathf.Sin(theta * Mathf.Deg2Rad));
SpawnPowerUps[i] = (GameObject)Instantiate(PowerUpPrefab, newPowerupSpace, Quaternion.identity);
}
return null;
}
}
To describe a circle in 3D it should have three parameters, Position, Radius and Normal. The normal can be used to create a transform from the unit circle to the 3D space. This example uses instance methods instead of static methods for cross/dot/normalization, but it should be trivial to translate to the unity3D conventions.
First we create an arbitrary vector that is orthogonal to the normal:
public static Vector3 GetOrthogonal(this Vector3 self)
{
self = self.Normalized();
if (Math.Abs(self.Dot(Vector3.UnitX)) > 0.9)
{
return self.Cross(Vector3.UnitY).Normalized();
}
return self.Cross(Vector3.UnitX).Normalized();
}
We can then create two vectors that are orthogonal to the normal, and to each other:
var xAxis = normal.GetOrthogonal();
var yAxis = xAxis.Cross(normal).Normalized();
Getting the points is then simply multiplying each coordinate with the corresponding axis:
var x = xAxis * (PowerUpRadius * Mathf.Cos(theta * Mathf.Deg2Rad));
var y = yAxis * (PowerUpRadius * Mathf.Sin(theta * Mathf.Deg2Rad));
newPowerupSpace = x + y + anchorPoint;
You could do the same by producing a transform matrix and transforming the 2D points. But this is fairly simple to do.
I'm trying to change the eulerAngle X of a camera rotation while keeping y and z at 0.
However, the following IEnumerator results in strange eulerAngles like 10, -74.653, 0.
I don't understand how the y value can change within the following function:
private IEnumerator LerpCameraNormalRot()
{
float duration = 0.5f;
for (float t = 0f; t < duration; t += Time.deltaTime)
{
float f = Mathf.Lerp(camera.transform.eulerAngles.x, 10, t / duration);
Vector3 vNew = new Vector3(f, 0, 0);
camera.transform.eulerAngles = vNew;
yield return 0;
}
}
Isn't this strange? I never change the Y and Z values!
I only want to change the X rotation (eulerAngle.x) from its current value to 10.
Thank you for the help!
You are setting the eulerAngles but that will result in different localEulerAngles which are indicated by the red box in your image. If the object has any ancestors that are rotated, they will probably not match!
To fix your immediate problem, you could use localEulerAngles instead of eulerAngles:
float f = Mathf.Lerp(camera.transform.localEulerAngles.x, 10, t / duration);
Vector3 vNew = new Vector3(f, 0, 0);
camera.transform.localEulerAngles= vNew;
The problem with this is that it does not account for the ability to go from 359 degrees around to 0 degrees. Better yet would be to use Quaternion.Euler and Quaternion.Slerp to use Quaternions rather than Euler angles:
private IEnumerator LerpCameraNormalRot()
{
float duration = 0.5f;
Quaternion startRotation = camera.transform.localRotation;
Quaternion goalRotation = Quaternion.Euler(10f, 0f, 0f);
for (float t = 0f; t < duration; t += Time.deltaTime)
{
camera.transform.localRotation = Quaternion.Slerp(startRotation, goalRotation, t/duration);
yield return 0;
}
camera.transform.localRotation = goalRotation;
}
Unity uses two representation of rotation, position, eulerAngles, etc
one is in worldspace
the other is in local space
The values not including local in their name are in world space.
If your object has than any parents that are rotated/scaled/translated you won't see the values you set in Unity since the Transform inspector displays the local coordinates.
If you want to set the local coordinates to the exact values instead use localPosition, localRotation or localEulerAngles instead.
For me it looks like you want to rotate the Camera around its local x axis by 10° in 0.5 secons.
So I think you could instead do it like
private IEnumerator LerpCameraNormalRot()
{
float duration = 0.5f;
float initialRotationX = camera.transform.localEulerAngles.x;
float targetRotationX = 10;
for (float t = 0f; t < duration; t += Time.deltaTime)
{
float currentX = Mathf.Lerp(initialRotationX, targetRotationX, t / duration);
camera.transform.localEulerAngles = new Vector3(currentX , 0, 0);
// Which would be the same as using
// camera.transform.localRotation = Quaternion.Euler(new Vector3(currentX, 0, 0));
yield return null;
}
// to be sure you have no overshooting you could set the target rotation fix here as well
camera.transform.localEulerAngles = new Vector3(targetRotation, 0 ,0);
// or
// camera.transform.localRotation = Quaternion.Euler(new Vector3(targetRotation, 0, 0));
}
My camera has to focus on an GameObject that can be scaled over time. How can I compute the camera position so that it is always at the same distance from this GameObject? I've already tried to do something like
camera.position.y += object.scaleFactor / 2;
camera.position.z -= object.scaleFactor / 2;
But the bigger the object becomes, the lesser it works. I'm thinking about using a bounding box, do you think it would work ?
Thanks a lot !
use this:
// compute this when scale is 1.0f
Vector3 originalPosition = camera.position;
Vector3 originalDistance = camera.position - gameObject.position;
// then use:
camera.position = originalPosition + originalDistance * gameObject.scaleFactor;
if this does not work, please describe your situation in more detail and i will edit the answer
for example: if you want that the camera keeps the distance to the object, you will have to use BoundingSphere.radius:
// compute this when scale is 1.0f
Vector3 originalPosition = camera.position;
Vector3 temp = camera.position - gameObject.position;
Vector3 originalDirection = temp.normalized;
float originalDistance = temp.magnitude - boundingSphere.radius;
// use this when object is scaled:
camera.position = originalPosition + originalDirection * (boundingSphere.radius + originalDistance);
public class ObjectRelativeScale : MonoBehaviour
{
public float ObjectScale = 1.0f;
private Vector3 _initialScale;
void Start()
{
_initialScale = transform.localScale;
}
void Update()
{
var cameraMainTransform = Camera.main.transform;
var plane = new Plane(cameraMainTransform.forward, cameraMainTransform.position);
float dist = plane.GetDistanceToPoint(transform.position);
transform.localScale = _initialScale * dist * ObjectScale;
}
}
Basically the way around is better, scale the object depending on the camera position.
Cheers!
I wish to launch my Arrow GameObject at an angle of 30˚ and a velocity of 30 m/s. In a script I add a rigidbody to this Arrow. However, I am also trying to launch this Arrow in the direction of the player (away from the enemy) in a 3D scene. I cannot figure out how to plug in these variables to get the Vector3 for the "arrowRigidbody.velocity"
//THE VARIABLES REFERENCED ABOVE APPEAR LIKE SO:
Rigidbody arrowRigidbody;
Transform playerTransform;
Transform enemyTransform;
float angle = 30f;
float velocity = 30f;
//How do I use these variables in order to shoot the projectile at a speed
//of 30 m/s and an angle of 30˚ in the direction of the player in 3D scene
arrowRigidbody.velocity = /*????*/;
Thank you for your time and patience :)
Assuming you only shoot 'forward' you can use the simplified:
var targetDirn = transform.forward;
var elevationAxis = transform.right;
var releaseAngle = 30f;
var releaseSpeed = 30f;
var releaseVector = Quaternion.AngleAxis(releaseAngle, elevationAxis) * targetDirn;
arrowRigidbody.velocity = releaseVector * releaseSpeed;
If you need to shoot 'off-axis', you can replace the first two lines:
var targetDirn = (target.transform.position - transform.position).normalized;
var elevationAxis = Vector3.Cross(targetDirn, Vector3.up);
Using some geometry, knowing that vector will have a magnitude (m) of 1, the y-component will be m/2 and the x-component will be m*(3^.5)/2. Which will make your final value:
arrowRigidbody.velocity = new Vector2(Mathf.Pow(3, .5f)/2, 1/2) * velocity;
For a changing angle, you know that the x component will be m * cos(angle) and the y component will be m * sin(angle), leaving you with:
float velx = velocity * Mathf.Cos(angle * Mathf.Deg2Rad);
float vely = velocity * Mathf.Sin(angle * Mathf.Deg2Rad);
arrowRigidbody.velocity = new Vector2(velx, vely);
I have a scene that my camera doesn't follow my player. When player reaches the end of camera I want player to can't go further (out of camera view). How can I do this?
My codes for movement
public class PlayerBlueController : MonoBehaviour {
public float speed;
private float x;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void FixedUpdate () {
x = Input.GetAxis ("Horizontal") / 100 * speed;
transform.Translate (x,0,0);
}
}
As you can see from this. It gets out of camera's view.
I noticed you used a Collider2D. You should be using Rigidbody2D.MovePosition instead of transform.Translate or you'll likely run into issues when transform.Translate is used.
1.Take the final move position and convert it to new position in ViewPortPoint with Camera.main.WorldToViewportPoint
2.Apply a limit with Mathf.Clamp to the result in #1.
3.Convert the ViewPortPoint back to world point with Camera.main.ViewportToWorldPoint.
4.Finally, move it with Rigidbody2D.MovePosition.
The code below is modified from this answer to include restriction to screen boundary.
Move without Rigidbody:
Use only if collision and physics are NOT required:
public float speed = 100;
public Transform obj;
public void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
//Move only if we actually pressed something
if ((h > 0 || v > 0) || (h < 0 || v < 0))
{
Vector3 tempVect = new Vector3(h, v, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
Vector3 newPos = obj.transform.position + tempVect;
checkBoundary(newPos);
}
}
void checkBoundary(Vector3 newPos)
{
//Convert to camera view point
Vector3 camViewPoint = Camera.main.WorldToViewportPoint(newPos);
//Apply limit
camViewPoint.x = Mathf.Clamp(camViewPoint.x, 0.04f, 0.96f);
camViewPoint.y = Mathf.Clamp(camViewPoint.y, 0.07f, 0.93f);
//Convert to world point then apply result to the target object
obj.position = Camera.main.ViewportToWorldPoint(camViewPoint);
}
Move Object with Rigidbody2D:
Use if collision and physics are required:
public float speed = 100;
public Rigidbody2D rb;
public void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
//Move only if we actually pressed something
if ((h > 0 || v > 0) || (h < 0 || v < 0))
{
Vector3 tempVect = new Vector3(h, v, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
//rb.MovePosition(rb.transform.position + tempVect);
Vector3 newPos = rb.transform.position + tempVect;
checkBoundary(newPos);
}
}
void checkBoundary(Vector3 newPos)
{
//Convert to camera view point
Vector3 camViewPoint = Camera.main.WorldToViewportPoint(newPos);
//Apply limit
camViewPoint.x = Mathf.Clamp(camViewPoint.x, 0.04f, 0.96f);
camViewPoint.y = Mathf.Clamp(camViewPoint.y, 0.07f, 0.93f);
//Convert to world point then apply result to the target object
Vector3 finalPos = Camera.main.ViewportToWorldPoint(camViewPoint);
rb.MovePosition(finalPos);
}
image not respond .
but you can check player location
x = Input.GetAxis ("Horizontal") / 100 * speed;
if(gameobject.transform.x > someValue)
x=0
gameobject will be OBJECT in scene that u attach class to it.
another way is place 2 empty gameobject with collider as invisibleWall and get collider to player
Possible solution is:
1.Get the coordinates of your screen cornes (top left, top right, bottom left, bottom right). You can get this coordinates using Screen.height and Screen.width.
2.Convert this coordinates using the camera you need with Camera.ScreenToWorldPoint.
3.Get your player coordinates and check that they are inside the rect which is formed by 4 coordinates of the screen corners.
You need to limit your transform's position based on the edges of the camera. Here is an answer describing the different coordinate systems in unity
You're probably looking to do something like this:
float xMin = Camera.main.ViewportToWorldPoint(Vector3.zero).x;
float xMax = Camera.main.ViewportToWorldPoint(Vector3.one).x;
Vector3 currentPos = transform.position;
float dx = Input.GetAxis ("Horizontal") / 100 * speed;
Vector3 desiredPos = new Vector3(currentPos.x + dx, currentPos.y, currentPos.z);
Vector3 realPos = desiredPos;
if(desiredPos.x > xMax)
realPos.x = xMax;
else if(desiredPos.x < xMin)
realPos.x = xMin;
transform.position = realPos;
Read up here for more info on ViewportToWorldPoint(), it's extremely useful to become comfortable with the different coordinate spaces and how you can convert between them.