I want rotated 'transform.forward' with not rotate transform.
but have problem result of 'rot * tf.forward'
I have to make a lot of rotate transform.forward.
I know transform.Rotate is high cost.
Why are those different?
Transform tf = transform;
Quaternion rot = Quaternion.Euler(90f, 0f, 0f);
Vector3 eulerRot1 = rot * tf.forward * Mathf.Rad2Deg;
tf.roration *= rot;
Vector3 eulerRot2 = tf.forward * Mathf.Rad2Deg;
if(eulerRot1 == eulerRot2)
{
Debug.Log("Same");
}
else
{
Debug.Log("Not same");
}
tf.forward does not rotate your gameobject forward. tf.forward is a vector point forward relative to your game object.
transform.Rotate is not high cost, moving your game object directly via it's transform is never expensive. Moving it with it's physics component is expensive
Related
Consider this working script, that handles a FPS camera movement:
using UnityEngine;
public class CameraHandler : MonoBehaviour {
public Transform target;
float dragSpeed = 10f;
float lookAtSensitivity = 200f;
float xRot;
Transform parentGO;
private void Start() {
parentGO = transform.parent;
}
void goToPivot(Transform pivot) {
parentGO.position = Vector3.Lerp(transform.position, pivot.position, 0.05f);
transform.rotation = Quaternion.Lerp(transform.rotation, pivot.rotation, 0.05f);
}
void resetCamRot() {
xRot = 0;
float yRot = transform.localEulerAngles.y;
parentGO.transform.eulerAngles += new Vector3(0, yRot, 0);
transform.localEulerAngles -= new Vector3(0, yRot, 0);
}
void LateUpdate() {
if (Input.GetKey(KeyCode.Mouse1)) {
float touchX = Input.GetAxis("Mouse X") * lookAtSensitivity * Time.deltaTime;
float touchY = Input.GetAxis("Mouse Y") * lookAtSensitivity * Time.deltaTime;
xRot -= touchY;
xRot = Mathf.Clamp(xRot, -90f, 90f);
transform.localRotation = Quaternion.Euler(xRot, 0f, 0f);
parentGO.transform.Rotate(Vector3.up * touchX);
}
if (Input.GetKey(KeyCode.Space)) {
goToPivot(target);
}
if (Input.GetKeyUp(KeyCode.Space)) {
resetCamRot();
}
}
}
Check how the rotations take place in different gameobjects in their respective axis, so that each of rotations are kept independent and everything works.
transform.localRotation = Quaternion.Euler(xRot, 0f, 0f); //camera GO only rotates in local x
parentGO.transform.Rotate(Vector3.up * touchX); //parent GO only rotates in global y
Problem comes when I need to "force" the camera look a certain direction without the inputs, to the FPS movement rules break, and for example the camera gameobject rotates also in the Y xis. That is why I need to call the resetCamRot() method, and traspass the local rotation from the camera object to the parent so that the situation meets the the FPS movement requirements (no local Y axis rotation).
Without calling the resetCamRot() method, when the FPS movement starts on right mouse button click, the camera abruptly changes to the direction it was facing before "forcing" it with goToPivot that sets the position and the rotation.(Just commentinf the resetCamRot method out)
Although resetCamRot() does the work it feels a bit hacky, so is there another way to set the camera to a forced rotation maintaining the local rotation of the child object (where the camera is) to 0?
I thought of decomposing the next step rotation given by Quaternion.Lerp(transform.rotation, pivot.rotation, 0.05f); in the goToPivot() method in each of their respective axis and gameObjects as its done when the rotation is set from the input, to have a clean local Y rot in he camera gameobject each step. Seems to be the over-complicated thing in this case, but was not able to figure that out.
I you wish to try the script out for the challenge just need to add a parent gameobject to the camera and the attach the target in the editor.
This will make the camera look in the direction, the parent transform look in the direction, only flattened, and finally update the internal state (xRot) in accordance with the difference between the two:
void LookTowards(Vector3 direction) {
Vector3 flattened = direction;
flattened.y = 0f;
parentGo.rotation = Quaternion.LookRotation(flattened);
transform.rotation = Quaternion.LookRotation(direction);
xRot = Vector3.SignedAngle(flattened, direction, parentGo.right);
}
I'm trying to make shooting with a shotgun, I have already made shooting with one bullet. Code:
Vector2 shootingDirection = new Vector2(joystick.Horizontal, joystick.Vertical);
shootingDirection.Normalize();
if (shootingDirection != new Vector2(0, 0))
{
if(isShotGun) ShotGunShoot(shootingDirection);
GameObject bullet = Instantiate(bulletPrefab, crossHair.transform.position, Quaternion.identity);
bullet.transform.Rotate(0.0f, 0.0f, Mathf.Atan2(shootingDirection.y, shootingDirection.x) * Mathf.Rad2Deg);
bullet.GetComponent<Rigidbody2D>().AddForce(shootingDirection * 10f, ForceMode2D.Impulse);
}
}
But I'm just trying to create two other bullets with a slight deviation from the main one, so that it looks like a fraction, but it does not work correctly. Code:
private void ShotGunShoot(Vector2 dir)
{
GameObject shotGun = Instantiate(bulletPrefab, crossHair.transform.position, Quaternion.identity);
shotGun.transform.Rotate(0.0f, 0.0f, Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 30f);
shotGun.GetComponent<Rigidbody2D>().AddForce((dir + new Vector2(-.3f, 0f)) * 10f, ForceMode2D.Impulse);
shotGun = Instantiate(bulletPrefab, crossHair.transform.position, Quaternion.identity);
shotGun.transform.Rotate(0.0f, 0.0f, Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg + 30f);
shotGun.GetComponent<Rigidbody2D>().AddForce((dir+ new Vector2(.3f, 0f)) * 10f, ForceMode2D.Impulse);
}
As it should be
Here it is now
Thanks for help!
For the rotation. You can simply set the direction (from your image I can see that your bullet has to fly towards its right vector) like e.g.
shotgun.transform.right = dir;
shotgun.transform.Rotate(0, 0, 30);
For the add force: This uses world space directions.
You always pass in the direction and add the additional offset in world space. So that additional offset goes always in X axis direction regardless in which direction you shoot.
Rather take the direction into account by using the local force Rigidbody.AddRelativeForce
shotGun.GetComponent<Rigidbody2D>().AddForceRelative((shotgun.transform.right + new Vector2(0f, 0.3f)).normalized * 10f, ForceMode2D.Impulse);
This now uses the bullets right direction and additionally uses an offset of 0.3 along its local Y axis.
Btw: If you give your prefab the correct type
public Rigidbody bulletPrefab;
you can skip the GetComponent<Rigidbody> calls.
I am working on controls for a bipedal tank, that has a boost/dash feature.
When the boost/dash mode is activated by holding a button the tank changes from a traditional WASD strafing movement to something like a jet fighter but on ground.
Now when the player tries to turn while boosting the camera needs to tilt with the turning direction to make it feel smoother.
Here is a video clip showing my problem
This is the script added to the main camera
public class PlayerCameraTilt : MonoBehaviour
{
private Camera viewCam;
private CharacterController characterController;
public float tiltAmount = 10f;
private void Start()
{
viewCam = GetComponent<Camera>();
characterController = GetComponentInParent<CharacterController>();
}
private void Update()
{
if (characterController.GetComponent<PlayerController>().movementState == MovementModes.boost)
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 euler = transform.localEulerAngles;
euler.z = Mathf.Lerp(euler.z, -inputValue, 5f * Time.deltaTime);
transform.localEulerAngles = euler;
}
else
{
Vector3 euler = transform.localEulerAngles;
euler.z = Mathf.Lerp(euler.z, 0f, 5f * Time.deltaTime);
transform.localEulerAngles = euler;
}
}
}
It kind of works, BUT only in one rotation direction, namely the positive one. If i turn the other way the angle becomes negative and does a whole 360 degree rotation until it ends up at 0 degrees.
I tried around with the built in Quaternion methods like Quaternion.Rotate() or Quaternion.AngleAxis()
but they didn't work because Quaternion.Rotate() doesn't tilt the Camera but completely rotates it. Quaternion.AngleAxis() works with the whole tilt angle limit but also does something to the other axis which i don't want to modify.
Is there a way to prevent the camera from doing a complete 360° rotation when the axis input becomes negative and just tilt in a slight angle?
Wraparound issues aside, the z component is "applied" first among the euler components, so I wouldn't modify it directly like that in this application.
Instead, I would convert the input to an angle to lean, rotate the direction of the local up before localRotation is applied (Quaternion.Inverse(transform.localRotation) * transform.up) by that angle, then use Quaternion.LookRotation to find a rotation with the current forward and that up, then use Quaternion.Slerp to slerp toward that rotation:
private void Update()
{
if (characterController.GetComponent<PlayerController>().movementState == MovementModes.boost)
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 upOfParent = Quaternion.Inverse(transform.localRotation) * transform.up;
Vector3 upDir = Quaternion.AngleAxis(-inputValue, transform.forward) * upOfParent;
Quaternion goalRot = Quaternion.LookRotation(transform.forward, upDir);
transform.rotation = Quaternion.Slerp(transform.rotation, goalRot, 5f * Time.deltaTime);
}
else
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 upOfParent = Quaternion.Inverse(transform.localRotation) * transform.up;
Quaternion goalRot = Quaternion.LookRotation(transform.forward, upOfParent);
transform.rotation = Quaternion.Slerp(transform.rotation, goalRot, 5f * Time.deltaTime);
}
}
Just keep in mind that using t = 5f * Time.deltaTime for lerp/slerp operations does not always guarantee that the output will ever equal the to parameter.
I want to rotate my 3d model based on player touch on x and y direction.
So that I am detecting horizontal and vertical touch.
But in this I want to restrict z direction rotation. For this I tried multiple codes and ask suggestions in other forums too. At present no suggestion is working for me.
Basically, I don't want z direction rotation. Following image give you more idea, where things going wrong. Model rotated completely into z direction. I want to stop this.
Here is my multiple tries to achieve same thing.
void Update ()
{
// If there are two touches on the device...
if (Input.touchCount == 1 && GameManager.Instance.IsGameStart) {
// Store currnet touch.
Touch touch = Input.GetTouch (0);
// transform.RotateAround (transform.position, Vector3.up, - touch.deltaPosition.x Time.deltaTime 15f);
// transform.RotateAround (transform.position, Vector3.right, touch.deltaPosition.y Time.deltaTime 15f);
// transform.RotateAround (transform.position, Vector3.forward, 0f);
// transform.Rotate (Vector3.up, -touch.deltaPosition.x Time.deltaTime 10f, Space.World);
// transform.Rotate (Vector3.right, touch.deltaPosition.y Time.deltaTime 5f, Space.World);
// transform.Rotate (Vector3.forward, 0f, Space.World);
myRigidbody.MoveRotation (myRigidbody.rotation Quaternion.Euler (Vector3.right touch.deltaPosition.y Time.deltaTime 5f));
myRigidbody.MoveRotation (myRigidbody.rotation Quaternion.Euler (Vector3.up -touch.deltaPosition.x Time.deltaTime 10f));
}
}
In above each block represent unique effort to restrict z direction.
Now please give me some suggestion to achieve same thing.
As well my discussion running at Unity forum
Touch based rotation of 3d model
EDIT: I have tried with restricting rigidbody in z rotation. So my inspector look something like this.
EDIT : After discussion on game development chat room. I have following kind of code :
float prevZ = transform.eulerAngles.z;
transform.Rotate (Vector3.up, -touch.deltaPosition.x Time.deltaTime 10f, Space.World);
transform.Rotate (Vector3.right, touch.deltaPosition.y Time.deltaTime 5f, Space.World);
Vector3 modelVec = transform.eulerAngles;
modelVec.z = prevZ;
transform.eulerAngles = modelVec;
I am just near to solution but now my golf globe model can't able to move more that 180 degree from top or bottom side drag. I just reach around 180 degree and it gets just rotated towards any other direction.
Ok after your comments, it sounds like you may need to start fresh.
Based on what I understand, try this out:
Vector3 rotation = new Vector3();
rotation.y = -touch.deltaPosition.x * Time.deltaTime * yRotSpeed;
rotation.x = touch.deltaPosition.y * Time.deltaTime * xRotSpeed;
rotation.z = 0;
transform.Rotate(rotation);
and then I'd suggest adding:
public float yRotSpeed;
public float xRotSpeed;
as fields of your script so that you can adjust the rotating speed within the unity engine in the future.
Just do like this.
// private variables
private Vector3 inputRotation; // difference of input mouse pos and screen mid point
private Vector3 mouseinput;
// Update is called once per frame
void Update() {
FindPlayerInput();
}
void FindPlayerInput()
{
mouseinput = Input.mousePosition;
mouseinput.z = 0; // for no rotation in z direction
inputRotation = mouseinput - new Vector3(Screen.width * 0.5f, Screen.height * 0.5f,0);
ProcessMovement();
}
void ProcessMovement(){
transform.rotation = Quaternion.LookRotation(inputRotation);
}
I'm still newbie to Unity... I'm trying to develop simple maze game. I want to roll my ball through maze, but I have to rotate camera left or right, otherwise the player can't see what's behind while rolling the ball on the left or on the right.
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate()
{
transform.position = player.transform.position + offset;
}
I'm using low pass filter for accelerometer values:
Vector3 lowpass()
{
float LowPassFilterFactor = AccelerometerUpdateInterval / LowPassKernelWidthInSeconds;
lowPassValue = Vector3.Lerp(lowPassValue, Input.acceleration, LowPassFilterFactor);
return lowPassValue;
}
Accelerometer values are from -1 to 1 for each coordinate. Because of that I check my lowPassValue.x value and limit it. If it's positive ( >0.3 ), then the camera should turn right and if it's negative ( <-0.3 ) then camera should turn left.
Quaternion rotation = Quaternion.AngleAxis(45, Vector3.up* Time.deltaTime) ; // right
transform.rotation = rotation;
Quaternion rotation = Quaternion.AngleAxis(-45, Vector3.up * Time.deltaTime) ; // left
transform.rotation = rotation;
But then my offset doesn't work anymore, I can't see ball anymore. And camera rotation doesn't work as it should.
Is there any better solution for this or I'm using the wrong function?
Any help will be very appreciated!
You have a problem with your AngleAxis() where you are multiplying the Axis to rotate on, by Time.deltaTime. this means that essentially you are changing the axis of rotation, and it is unpredictable. Most likely you wont get your "Right" or "Left" rotation. Multiply deltaTime by the angle itself instead.
Also, Quaternions are to be multiplied if you want to apply an angle with them:
Quaternion rotation = Quaternion.AngleAxis(45 * Time.deltaTime, Vector3.up) ; // right
transform.rotation *= rotation;
Quaternion rotation = Quaternion.AngleAxis(-45 * Time.deltaTime, Vector3.up) ; // left
transform.rotation *= rotation;
or this could just be achieved as:
transform.Rotate(45 * Vector3.right * Time.deltaTime); // right
transform.Rotate(45 * -Vector3.right * Time.deltaTime); // left