I want to rotate a cube in Unity3D.When I push arrow left button on keyboard the cube have to rotate left.If I push up, the cube have to rotate up.But with my script the cube rotate left and then the left-side rotate up.
This is the current status:
That's what I want:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotate : MonoBehaviour
{
public float smooth = 1f;
private Quaternion targetRotation;
// Start is called before the first frame update
void Start()
{
targetRotation = transform.rotation;
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.UpArrow)){
targetRotation *= Quaternion.AngleAxis(90, Vector3.right);
}
if(Input.GetKeyDown(KeyCode.DownArrow)){
targetRotation *= Quaternion.AngleAxis(90, Vector3.left);
}
if(Input.GetKeyDown(KeyCode.LeftArrow)){
targetRotation *= Quaternion.AngleAxis(90, Vector3.up);
}
if(Input.GetKeyDown(KeyCode.RightArrow)){
targetRotation *= Quaternion.AngleAxis(90, Vector3.down);
}
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, 10* smooth * Time.deltaTime);
}
}
You need to swap the order of your quaternion multiplication.
The way you have it now, the rotations are applied to the axes as they would be after the original rotation because you are effectively doing targetRotation = targetRotation * ...;.
However, you want to rotate the rotation around the world axes. You can do this by doing targetRotation = ... * targetRotation;:
void Update()
{
if(Input.GetKeyDown(KeyCode.UpArrow)){
targetRotation = Quaternion.AngleAxis(90, Vector3.right) * targetRotation;
}
if(Input.GetKeyDown(KeyCode.DownArrow)){
targetRotation = Quaternion.AngleAxis(90, Vector3.left) * targetRotation;
}
if(Input.GetKeyDown(KeyCode.LeftArrow)){
targetRotation = Quaternion.AngleAxis(90, Vector3.up) * targetRotation;
}
if(Input.GetKeyDown(KeyCode.RightArrow)){
targetRotation = Quaternion.AngleAxis(90, Vector3.down) * targetRotation;
}
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, 10* smooth * Time.deltaTime);
}
See How do I rotate a Quaternion with 2nd Quaternion on its local or world axes without using transform.Rotate? for more information.
Related
I'm trying to cast a ray on Vector2.right and another ray on either side of it by 20 degrees.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PathFinding : MonoBehaviour
{
public float speed = 5f;
// Update is called once per frame
private void Update()
{
//replace target.position with Camera.main.ScreenToWorldPoint(Input.mousePosition) to follow mouse pointer
Vector2 direction = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, speed * Time.deltaTime);
if (Input.GetKey(KeyCode.Space))
{
Debug.DrawRay(transform.position, transform.TransformDirection(Vector2.right) * 10f, Color.green);
RaycastHit2D front = Physics2D.Raycast(transform.position, transform.TransformDirection(Vector2.right), 10f);
if (front)
{
Debug.Log("Hit Something : " + front.collider.name);
//hit.transform.GetComponent<SpriteRenderer>().color = Color.red;
Debug.DrawRay(transform.position, transform.TransformDirection(Vector2.right) * 10f, Color.red);
}
RaycastHit2D left1 = Physics2D.Raycast(transform.position, transform.Rotate_Direction(Vector2.right), 10f);
}
}
}
It's just in the last line of code that I'm having a hard time. I want to add a slight rotation to the transform.Rotate_direction(Vector2.right) bit.
I'm pretty new to programming and especially to this here so if you could explain what you do and maybe show me how to implement it that would be greatly appreciated.
Thanks in advance.
By multiplying the Quaternion behind the vector you can change its direction. In your question, you need to use Quaternion.AngleAxis.
Quaternion.AngleAxis(20f, Vector3.forward) * Vector2.right
I'm trying to make a game using planet gravity physics. I'm stuck in rotating player.
private void FixedUpdate()
{
ProcessInput();
Vector3 gravityUp = (transform.position - gravityTarget.position).normalized;
Vector3 bodyUp = transform.up;
rb.AddForce(gravityUp * gravity);
Quaternion targetRotation = Quaternion.FromToRotation(bodyUp , gravityUp) * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation , 50 * Time.fixedDeltaTime);
transform.rotation =targetRotation;
Quaternion desRot = Quaternion.LookRotation(moveDir);
desRot = Quaternion.RotateTowards(transform.rotation, desRot , 360 * Time.deltaTime);
transform.rotation = desRot;
}
private void Update()
{
rb.MovePosition(rb.position + transform.TransformDirection(moveDir) * 15f * Time.deltaTime);
}
private void ProcessInput()
{
moveDir = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;
}
Lets say I pressed Left Arrow and wanted to player to go left and turn left at the same time. The problem is transform.TransformDirection(moveDir). When I make the player turn to the left, player starts the move its left side instead of the world position. If I only use moveDir for positioning, it goes out of the world. How can I make this work?
You can see the video here!
Thanks for helping!
I was making a game where there is a plane which I control using the wasd keys, it rotates and translates. Up-to that its fine, but I would like the plane to re-align to its original rotation when I lift the key. The code I made up is this but it doesn't work. The plane realigns for only one frame and then "misaligned" again . This is the code -**
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class planemovement : MonoBehaviour
{
public int fspeed = 10;
float horizontal; float zrot;
float vertical; float yrot;
public float sense; public int lim = 0;
void Start()
{
}
// Update is called once per frame
void Update()
{
float rotz = Input.GetAxis("Vertical"); float roty = Input.GetAxis("Horizontal");
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
transform.Translate(Vector3.forward * fspeed * Time.deltaTime);
transform.Translate(Vector3.right * sense * Time.deltaTime * horizontal*20f);
transform.Translate(Vector3.up * sense * Time.deltaTime * vertical);
zrot -= rotz;
yrot -= roty;
zrot = Mathf.Clamp(zrot, -lim, lim);
yrot = Mathf.Clamp(yrot, -lim, lim);
transform.localRotation = Quaternion.Euler(zrot, 0f, yrot);
}
}
Rotation in Unity C# is usually quite wonky, the only time it is exact is when you use Quaternions properly.
public Quaternion startQuaternion;
void Start() {
startQuaternion = transform.rotation;
}
//when you want to reset to original
transform.rotation = startQuaternion;
https://docs.unity3d.com/ScriptReference/Quaternion.html
I don't quite understand, but if you using a rigidbody, you can try using "Quaternion.Lerp" and MoveRotation.
Quaternion.Lerp has three parameters and creates a rotation from point A to B, with a speed ugual to T (T goes from 0 to 1).
var currentRot = transform.rotation
var desired Rot = rotation on which the plane must be aligned
Quaternion RotPlane = Quaternion.Lerp (currentRot, desiredRot, 0.5)
MoveRotation(RotPlane)
You can use an if (Input.GetKeyUp) and put the script underneath it, so every time you release the buttons the plane returns to the desired rotation.
I'm using a controller script from the official Unity website to move my character around. I'm also using a script to turn the camera using the mouse. Everything works fine until the character looks around and faces a different direction. Then the WASD controls move them according to the original orientation. For example, if I turn 180 degrees W moves me backward and S moves me forward.
I've tried to figure this out using transform.forward but I don't really know what I'm doing.
The movement script:
CharacterController characterController;
public float speed = 6.0f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
private Vector3 moveDirection = Vector3.zero;
void Start()
{
characterController = GetComponent<CharacterController>();
}
void Update()
{
if (characterController.isGrounded)
{
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
moveDirection *= speed;
if (Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
}
// Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below
// when the moveDirection is multiplied by deltaTime). This is because gravity should be applied
// as an acceleration (ms^-2)
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
characterController.Move(moveDirection * Time.deltaTime);
}
Thank you for any help :)
You can use Transform.TransformDirection to convert from local direction to world direction. Call that with the local direction you want to move and it will return the corresponding world direction which you can give to CharacterController.Move:
void Update()
{
if (characterController.isGrounded)
{
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection = moveDirection * speed;
if (Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
}
// Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below
// when the moveDirection is multiplied by deltaTime). This is because gravity should be applied
// as an acceleration (ms^-2)
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
characterController.Move(worldMoveDirection * Time.deltaTime);
}
In fact, the old documentation for CharacterController.Move used this very method!
void Update()
{
if (controller.isGrounded)
{
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection = moveDirection * speed;
if (Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
}
// Apply gravity
moveDirection.y = moveDirection.y - (gravity * Time.deltaTime);
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}
I's because Move uses world space coordinates but you generating local.
Try change
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
to
moveDirection = transform.right * Input.GetAxis("Horizontal") + transform.forward * Input.GetAxis("Vertical");
I'm using the InControl input manager for my project. I'm using input from the right stick to rotate my player object, but I want the player to be rotated smoothly rather than instantaneously.
Here's my current code:
void FixedUpdate()
{
var device = InputManager.ActiveDevice;
MoveThePlayer(device.LeftStick.X, device.LeftStick.Y);
RotateThePlayer(device.RightStick.X, device.RightStick.Y);
}
void MoveThePlayer(float movex, float movey)
{
body.velocity = new Vector2(movex * speed, movey * speed);
}
void RotateThePlayer(float movex, float movey)
{
float heading = Mathf.Atan2(movey, movex);
transform.rotation = Quaternion.Euler(0f, 0f, heading * Mathf.Rad2Deg);
}
Lerps are your friend.
transform.Rotate() your player towards the angle you want by using Time.deltaTime
Example:
transform.Rotate(0, 0, (angleIWantToBeAt - transform.eulerAngles.z) * Time.deltaTime * speedMultiplier)