I'm trying to rotate a parent GameObject along it's z axis in Unity so that a child of that object faces a certain target point.
This piece of code works as long as the child's position is zeroed out. The script is attached to the parent object, and I'm working in a 2D project.
Vector3 parentDir = (targetPoint - transform.position).normalized;
offset = Vector2.SignedAngle(transform.right, child.transform.right);
float rotationZ = (Mathf.Atan2(parentDir .y, parentDir .x) * Mathf.Rad2Deg) - offset;
transform.rotation = Quaternion.Euler(0, 0, rotationZ);
When the child's position is not zero however, for the offset value it obviously won't be enough to calculat the signed angle between the parent and child's x axes, but I cannot wrap my head around the problem.
This answer looks promising, but I just cannot seem to convert the 3D part of it to 2D.
Thanks in advance!
using UnityEngine;
public class Parent : MonoBehaviour
{
[SerializeField] private Transform _child;
[SerializeField] private Transform _target;
private void Update()
{
// Can be cached (Start/Awake) if relative child position not changed.
var childToParent = transform.rotation * Quaternion.Inverse(_child.rotation);
var directionTarget = (_target.position - transform.position).normalized;
var angleToTarget = Vector3.SignedAngle(Vector3.right, directionTarget, Vector3.forward);
var toTargetRotation = Quaternion.AngleAxis(angleToTarget, Vector3.forward);
transform.rotation = childToParent * toTargetRotation;
}
}
Related
So what I want is to move an item around the player in a circle but the item is moving along the circle depending on the mouse position. Im trying to do this as a sort of item equip thing and I can't get it to work.
What I have so far is the item moving in a circle around the player but not along the circle depending on the mouse position.
using UnityEngine;
public class Item : MonoBehaviour
{
public Transform target;
public SpriteRenderer renderer;
public float circleRadius = 1f;
public float rotationSpeed = 1f;
public float elevationOffset = 0f;
Vector2 positionOffset;
float angle;
void FixedUpdate()
{
positionOffset.Set(
Mathf.Cos(angle) * circleRadius,
Mathf.Sin(angle) * circleRadius
);
transform.position = new Vector3(target.position.x + positionOffset.x, target.position.y + positionOffset.y);
angle += Time.fixedDeltaTime * rotationSpeed;
}
}
If we assume that target is the "player" then we can:
Get the mouse position, as a world co-ordinate
Normalise the difference between the mouse and the player, times radius
Position the item along that normalised direction
private void Update ( )
{
var worldPosition = Camera.main.ScreenToWorldPoint( Input.mousePosition );
var positionOnCircle = (worldPosition - target.position).normalized * circleRadius;
transform.position = target.position + positionOnCircle;
}
As shown in the picture above, I have two GameObjects: the car and the circle. The car follows the circle, and the circle is moving with the cursor. Currently, my car is following the circle from a distance. When the circle moves along the x-axis, I want to rotate the car like it's drifting.
Here is my car follow script:
public class Follow : MonoBehaviour
{
public Transform leader;
public float followSharpness = 0.1f;
Vector3 _followOffset;
void Start()
{
// Cache the initial offset at time of load/spawn:
_followOffset = transform.position - leader.position;
}
void LateUpdate()
{
// Apply that offset to get a target position.
Vector3 targetPosition = leader.position + _followOffset;
//GetComponent<Rigidbody2D>().rotation = 1.5f;
// Keep our y position unchanged.
//targetPosition.y = transform.position.y;
// Smooth follow.
transform.position += (targetPosition - transform.position) * followSharpness;
}
}
You could try to use Transform.LookAt:
void LateUpdate()
{
Vector3 targetPosition = leader.position + _followOffset;
transform.position += (targetPosition - transform.position) * followSharpness;
transform.LookAt(leader);
}
Disclaimer: I'm not able to test that this code works right now, you'll have to try it out and see if it produces the desired result.
So from what you described, is you want to make the car always facing the cursor, so it is always "looking at" the cursor, here is how you can do it:
Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
diff.Normalize();
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rot_z - 90);
From Answer: LookAt 2D Equivalent ?
I'm using the standard camera2DFollow script that comes with Unity 5. But I have a problem with the position of the camera. I've rotated my main camera and it looks like this now.
You see that my player is on top of the screen instead of the middle.
This is the default script in C# for the people who don't have it.
using System;
using UnityEngine;
namespace UnityStandardAssets._2D
{
public class Camera2DFollow : MonoBehaviour
{
public Transform target;
public float damping = 1;
public float lookAheadFactor = 3;
public float lookAheadReturnSpeed = 0.5f;
public float lookAheadMoveThreshold = 0.1f;
private float m_OffsetZ;
private Vector3 m_LastTargetPosition;
private Vector3 m_CurrentVelocity;
private Vector3 m_LookAheadPos;
// Use this for initialization
private void Start()
{
m_LastTargetPosition = target.position;
m_OffsetZ = (transform.position - target.position).z;
transform.parent = null;
}
// Update is called once per frame
private void Update()
{
// only update lookahead pos if accelerating or changed direction
float xMoveDelta = (target.position - m_LastTargetPosition).x;
bool updateLookAheadTarget = Mathf.Abs(xMoveDelta) > lookAheadMoveThreshold;
if (updateLookAheadTarget)
{
m_LookAheadPos = lookAheadFactor*Vector3.right*Mathf.Sign(xMoveDelta);
}
else
{
m_LookAheadPos = Vector3.MoveTowards(m_LookAheadPos, Vector3.zero, Time.deltaTime*lookAheadReturnSpeed);
}
Vector3 aheadTargetPos = target.position + m_LookAheadPos + Vector3.forward*m_OffsetZ;
Vector3 newPos = Vector3.SmoothDamp(transform.position, aheadTargetPos, ref m_CurrentVelocity, damping);
transform.position = newPos;
m_LastTargetPosition = target.position;
}
}
}
I want to change the Y to a +3 of the current position. So if my camera is on Y 2 than put it on Y 5. (This makes it so the player is in the middle and not on the top).
Thanks for the help!
You can do this by adding 3 to the camera's position at the end of each frame but I recommend against it.
What I would do, is create an empty object, name it "PlayerCameraCenter" and make the player parent to this object; then place the camera center wherever you want relative to the player, like y = 3, and make the camera follow this object instead of the player.
This way you can easily change the position of the camera, through the editor without fiddling with code.
I'm having an issue with a prefab I'm instantiating in my script. What I'm attempting to do is simulate the physics behind the projectile motion of a cannonball. I have the following script attached to my prefab:
using UnityEngine;
using System.Collections;
public class ShootPhysics : MonoBehaviour {
// vectors & angles to be calculated
private float fx = 0f;
private float fy = 0f;
private float angle;
// forces acting upon object
private float gravity = 9.8f;
private float force = 1.2f;
// new distance & vector variables
private float dis_x = 0f;
private float dis_y = 0f;
// Script & CannonBall transform
private CannonPhysics cannon_angle;
void Start() {
cannon_angle = GameObject.FindWithTag("Gun").GetComponent<CannonPhysics>();
angle = cannon_angle.getAngle ();
fx = Mathf.Round (force * Mathf.Cos(Mathf.Deg2Rad * angle));
fy = Mathf.Round (force * Mathf.Sin(Mathf.Deg2Rad * angle));
}
void FixedUpdate() {
dis_x = (float)(fx * Time.timeSinceLevelLoad);
dis_y = (float)(fy + Time.timeSinceLevelLoad + (0.5) * (-gravity) * Time.timeSinceLevelLoad * Time.timeSinceLevelLoad);
Debug.Log (dis_x+", "+dis_y);
gameObject.transform.Translate (new Vector2(dis_x, dis_y));
}
}
And the prefab will be instantiated from the following script:
using UnityEngine;
using System.Collections;
public class CannonPhysics : MonoBehaviour {
// This will be our script to rotate our cannon
private float angle = 0f;
// cannonball object
public Transform FirePoint;
GameObject cannon = null;
void Update() {
if(Input.GetKey(KeyCode.UpArrow)) {
angle = angle + 1;
}
if(Input.GetKey(KeyCode.DownArrow)) {
angle = angle - 1;
}
// update cannon angle
transform.rotation = Quaternion.Euler (new Vector3(0, 0, angle));
if(Input.GetMouseButtonDown(0)) {
CreateCannon();
}
}
public float getAngle() {
return angle;
}
private void CreateCannon() {
cannon = Instantiate (Resources.Load("Prefabs/CannonBall"), FirePoint.position, FirePoint.rotation) as GameObject;
Destroy (cannon, 3f);
}
}
The object gets instantiated as it should, and the object is destroyed after 3 seconds as it should, however the object x and y position do not change at all, and are not what i should expect them to be. Let me give you an example:
These are the x and y coordinates i should expect which i have displaying in the console.
However these are the actual coordinates displayed in Unity's inspector:
What's strange too, is that these coordinates will not change for each object, they will literally stay the same, even after the object has been destroyed. Can anyone explain why this is happening? And perhaps offer a solution?
Edit: For a more clear example:
Each time i instantiate my cannonball object the x and y coordinates for the next object to be instantiated are referenced from the last. Here are the result of my first instantiated object after being destroyed.
And here they are after instantiating a second object.
Now what I'm expecting is that each new object instantiated should start from it "original" position (figuratively speaking) and the x and y values should reset and start again effectively.
There are a few things happening in the code you have provided in the FixedUpdate() portion of your code which I have copied below:
void FixedUpdate()
{
dis_x = (float)(fx * Time.timeSinceLevelLoad);
dis_y = (float)(fy + Time.timeSinceLevelLoad + (0.5) * (-gravity) * Time.timeSinceLevelLoad * Time.timeSinceLevelLoad);
Debug.Log (dis_x+", "+dis_y);
gameObject.transform.Translate (new Vector2(dis_x, dis_y));
}
First, Time.timeSinceLevelLoad provides you the time, in seconds, that has passed since your level was loaded. What this means for your code is that dis_x and dis_y always have larger values the longer you have your application open. So, when you spawn a new prefab, the d_x and d_y values are already at a position that seems as if it's using the position of the last prefab.
Instead, if you want to calculate the new position of an object given it's velocity, you'd typically want to use the deltaTime instead. For example:
dx = vel.x * Time.fixedDeltaTime;
dy = vel.y * Time.fixedDeltaTime;
In this example, dx and dy represent the change in position given the velocity of the object. Time.fixedDeltaTime represents the amount of time in seconds that has passed since the last time FixedUpdate() was called. You would then add dx and dy to your position to get the new position.
Secondly, gameObject.transform.Translate() translates the position of the GameObject; it does not set the position of the GameObject. Translate will just add the Vector3 to your current position. This is why your debugging output looks so strange; dis_x and dis_y are not your positions; they are how far you moved the GameObject by calling Translate().
To set the position of the GameObject, do this instead:
gameobject.transform.position = newPosition;
...where newPosition is a Vector3 that represents the new position of your gameobject.
I want to rotate camera around an fbx object when a key is being pressed using unity 3d.How it do? I tried some examples but its not working. First i create a game object and add main camera child of it.
public class CameraOrbit : MonoBehaviour
{
public Transform target;
public float speed = 1f;
private float distance;
private float currentAngle = 0;
void Start()
{
distance = (new Vector3(transform.position.x, 0, transform.position.z)).magnitude;
}
void Update()
{
currentAngle += Input.GetAxis("Horizontal") * speed * Time.deltaTime;
Quaternion q = Quaternion.Euler(0, currentAngle, 0);
Vector3 direction = q * Vector3.forward;
transform.position = target.position - direction * distance + new Vector3(0, transform.position.y, 0);
transform.LookAt(target.position);
}
}
I dont have access to unity at the moment so i might have messed something up.
The idea is keep an angle that you change based on input. Create a Quaternion from the angle (the Quaternion say how to rotate a vector to a certain direction), then rotate a Vector to that direction. Starting from the targets position move in that direction a certain distance and then look at the targets position.
This only implements rotation around the y axis, if you want rotation around the x axis all you need is another angle variable and then change to this Quaternion.Euler(currentAngleX, currentAngleY, 0);