Restrict Direction of rotation in Realtime - unity3d

have a hand of clock which the player once starts rotating (Dragging) CCW until he completes one full rotation. ( Without lifting drag )
I am trying to lock the rotation to only CCW direction while/once the player starts rotating. I got help from the following links : [Detect Direction][1] by #BobBobson108
Here is gif of what is actually happening: Demo
void OnMouseDrag()
{
//rotation
Vector3 mousePos = Input.mousePosition;
mousePos.z = 5.23f;
Vector3 objectPos = Camera.main.WorldToScreenPoint(transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle - 90f));
hand_vector = transform.up;
cross_product = Vector3.Cross(ref_vector, hand_vector);
dot_product = Vector3.Dot(cross_product, transform.forward*-1);
//Debug.Log("Hand Vector: " + hand_vector);
//Debug.Log("Ref Vector: " + ref_vector);
Debug.Log(cross_product);
Debug.Log(dot_product);
}
I tried to debug the values of the cross product, but the direction of resultant vector seems to be same even when when the player starts backward rotation.
Also the cross product vector changes direction only when the player starts rotation in CW direction from the default position i.e. 12 'o clock.
I have very less experience of working with Quaternions and rotations. Any help will be highly helpful. Thanks !!!
Desired

Use http://docs.unity3d.com/ScriptReference/Vector3.Angle.html function to get the value of the angle. You should get a positive/negative value depending on the direction.
You could then lock the rotation if the sign is not the correct direction you want.

I managed to figure out a solution to above question. Here I am posting my solution in case anyone stumbles across a similar situation in future.
void OnMouseDrag()
{
transform.Rotate(new Vector3(0,0, Mathf.Sqrt(Input.GetAxis("Mouse X") * Input.GetAxis("Mouse X") + Input.GetAxis("Mouse Y") * Input.GetAxis("Mouse Y"))));
/*
Vector3 mousePos = Input.mousePosition;
mousePos.z = 5.23f;
Vector3 objectPos = Camera.main.WorldToScreenPoint(transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
print("Angle is :");
print(Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90f);
if (counter_clockwise)
{
if (Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90f > 0)
{
angle = Mathf.Max(angle, Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90);
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
if (Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90f < 0)
{
angle = Mathf.Max(angle, 360 + (Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90));
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
}
*/
glow_color.a = 1f;
child_yellowglow.color = glow_color;
}
I am setting the direction bools from using this :
void OnMouseDown()
{
Vector3 mouseDragStartPos = Input.mousePosition;
print("Mouse pos: " + mouseDragStartPos);
print(" ref_vector" + ref_vector);
if (mouseDragStartPos.x < ref_vector.x)
{
clockwise = false;
counter_clockwise = true;
print("Left !!!");
}
if (mouseDragStartPos.x >= ref_vector.x)
{
clockwise = true;
counter_clockwise = false;
print("Right !!!");
}
}
Hope this helps !!!

Related

Problem rotating an object on its local orientation

Hello i am new in the forum! I hope i am in the right section! Im trying to rotate a camera (that rapresent the player POV) using the mouse delta and im rotating the camera in local coordinates not world coordinates and i want avoid gimbal lock effect. I read somewhere on the internet that for that purpose i have to use quaternions, and i read how to do that. The problem is that axis rotations works well moving in local orientation but one of the axis is losing its local orientation and it rotate following the world coordinates orientation. I will post the code and i hope someone can help me and telling me where im doing things wrong. Thanks!
public class Player : MonoBehaviour {
[Header("Camera")]
[SerializeField] private Camera _camera;
[SerializeField] private Vector2 _xMinMaxRotation = new Vector2(-90, 90);
[SerializeField] private Vector2 _yMinMaxRotation = new Vector2(-90, 90);
[SerializeField] private float _mouseXSensistivity = 1;
[SerializeField] private float _mouseYSensistivity = 1;
[SerializeField] private float _mouseZSensistivity = 1;
[SerializeField] private float _xStartRotation = 0;
[SerializeField] private float _yStartRotation = 0;
private Vector2 _mouseDelta;
private float _rotY, _rotX, _rotZ;
//public GameObject head;
// Start is called before the first frame update
void Start() {
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update() {
_mouseDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
MoveCamera();
}
private void MoveCamera() {
_rotX += _mouseDelta.x * _mouseXSensistivity * Time.deltaTime * 100;
_rotX = Mathf.Clamp(_rotX, _xMinMaxRotation.x, _xMinMaxRotation.y);
_rotY += _mouseDelta.y * _mouseYSensistivity * Time.deltaTime * 100;
_rotY = Mathf.Clamp(_rotY, _yMinMaxRotation.x, _yMinMaxRotation.y);
//Calculation for RotZ
if (Input.GetKey(KeyCode.Q)) {
_rotZ += +_mouseZSensistivity * Time.deltaTime * 50;
if (_rotZ > 25) _rotZ = 25;
}
else {
if (_rotZ > 0) {
_rotZ -= 2 * _mouseZSensistivity * Time.deltaTime * 50;
if (_rotZ < 0) _rotZ = 0;
}
}
if (Input.GetKey(KeyCode.E)) {
_rotZ += -_mouseZSensistivity * Time.deltaTime * 50;
if (_rotZ < -25) _rotZ = -25;
}
else {
if (_rotZ < 0) {
_rotZ -= 2 * -_mouseZSensistivity * Time.deltaTime * 50;
if (_rotZ > 0) _rotZ = 0;
}
}
Quaternion currentRotation = Quaternion.identity;
currentRotation = currentRotation * Quaternion.AngleAxis(_rotX, transform.up);
currentRotation = currentRotation * Quaternion.AngleAxis(-_rotY, transform.right);
currentRotation = currentRotation * Quaternion.AngleAxis(_rotZ, transform.forward);
_camera.transform.localRotation = currentRotation;
//head.transform.position = _camera.transform.position;
//head.transform.rotation = _camera.transform.rotation;
}
The last part with quaternions is where im trying to calculate angles in order to properly rotate in local coordinates.
You don’t need to use quaternions at all.
You can use transform.EulerAngles instead of the transform.rotation or transform.localEulerAngles instead of transform.LocalRotation.
I messed up the capitalization I’m sure.
Say you wanted to rotate the camera 10 degrees along the local x axis. That would look something like
transform.localEulerAngles = transform.localEulerAngles.Add(10,0,0);
That’s it as far as I know. If you wanna read more about this,
transfrom.localEulerAngles
If your question was completely different, let me know and I can change or remove my answer.

How can I get this jumping and movement code to work together?

I'm trying to use the Character Controller component in Unity and I managed to make the movement code, however, I was unable to add jumping and gravity or at least have them work together so my temporary solution was to just break them into 2 different methods. This probably isn't ideal so how could I get this to work properly?
void Update()
{
GetInput();
JumpingCode();
MovementCode();
}
void JumpingCode()
{
// Jumping
if (jumpPressed && characterController.isGrounded)
velocityY = Mathf.Sqrt(jumpHeight * -2f * (gravity * gravityScale));
// Gravity
velocityY += gravity * gravityScale * Time.deltaTime;
Vector3 direction = new Vector3(horizontalInput, velocityY, verticalInput).normalized;
characterController.Move(direction * walkSpeed * Time.deltaTime);
}
void MovementCode()
{
Vector3 direction = new Vector3(horizontalInput, 0f, verticalInput).normalized;
if (direction.magnitude > 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + playerCamera.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
transform.rotation = Quaternion.Euler(0f, angle, 0f);
characterController.Move(moveDirection.normalized * walkSpeed * Time.deltaTime);
}
}
I can't understand how you're arriving at the values you're using there, but the solution would be to accumulate the outputs and then do the .Move() action once at the end, like:
void Update()
{
Vector3 motion;
GetInput();
motion += JumpingCode();
motion += MovementCode();
characterController.Move(motion*Time.deltaTime);
}
private Vector3 JumpingCode()
{
// stuff
return direction * walkSpeed;
}
private Vector3 MovementCode()
{
// stuff
return direction * walkSpeed;
}
Noteworthy there is that I dropped Time.deltaTime from your functions, but I don't know how you were using it in the code you provided.

Delay when calculating a players movement direction

I am trying to determine the direction of a transform. I originally tried to do this by tracking the rigidbody.velocity but that property seems unreliable so I am having to calculate the direction manually. The yellow line draws fine and it does point in the wrong direction however it appears to be delayed
I am calling the following method in my update method:
void DetermineMovementDirection()
{
currentLoc = (transform.position - prevLoc) / Time.deltaTime;
Vector3 t = (prevLoc + currentLoc).normalized;
Debug.DrawLine(transform.position, transform.position + t * 5, Color.yellow);
}
I would expect the yellow line to always point in the direction the player was moving rather than have a long delay. How can I fix this?
As requested the movement function:
void Update()
{
float inputZ = Input.GetAxis("Horizontal");
float inputX = Input.GetAxis("Vertical");
if (movementAllowed)
if (inputZ != 0 || inputX != 0)
{
transform.eulerAngles = new Vector3(0, Mathf.Atan2(inputZ, inputX) * 180 / Mathf.PI, 0);
transform.Translate(moveSpeed * inputZ * Time.deltaTime, 0f, moveSpeed * inputX * Time.deltaTime, Space.World);
}
}
And I am simply updating at the end of the update method:
prevLoc = transform.position;

Can We Create a Gizmos Like cone in unity with script

I want to create a cone Gizmo like the one in the picture below by using a script.
This is an example code:
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, range);
}
The red line is the Gizmo that I want.
Can anyone help out?
The code below is a modified version of Tetrad's answer to a similar question.
void OnDrawGizmosSelected()
{
float angle = 30.0f;
float rayRange = 10.0f;
float halfFOV = angle / 2.0f;
float coneDirection = 180;
Quaternion upRayRotation = Quaternion.AngleAxis(-halfFOV + coneDirection, Vector3.forward);
Quaternion downRayRotation = Quaternion.AngleAxis(halfFOV + coneDirection, Vector3.forward);
Vector3 upRayDirection = upRayRotation * transform.right * rayRange;
Vector3 downRayDirection = downRayRotation * transform.right * rayRange;
Gizmos.DrawRay(transform.position, upRayDirection);
Gizmos.DrawRay(transform.position, downRayDirection);
Gizmos.DrawLine(transform.position + downRayDirection, transform.position + upRayDirection);
}
Hope that helps!

Unity 3rd person controller, rotation nightmare

I am trying to make a MMO character controller like the one of this Youtube video:https://www.youtube.com/watch?v=fOvf7gRO_aM
Basically, you use WASD to move around.
You can move the camera by mouse click and drag, and when moving, you character will now move in the new camera direction.
The thing is, i would like that when i press WASD, that the character (not the camera) would face the direction of the mouvement.
I tried to use this:
if (Input.GetAxis("Vertical") > 0 | Input.GetAxis("Vertical") < 0){
Quaternion turnAngle = Quaternion.Euler(0, centerPoint.eulerAngles.y, 0);
character.localRotation = Quaternion.Slerp(character.rotation, turnAngle, Time.deltaTime * rotationSpeed);
}
The character was not facing the right direction, so i tried this
if (Input.GetAxis("Vertical") > 0 | Input.GetAxis("Vertical") < 0){
Quaternion turnAngle = Quaternion.Euler(0, centerPoint.eulerAngles.y, 0);
character.rotation = Quaternion.LookRotation(movement);
}
but that does not seem to work. I am a noob after all :D
Here is the full code of the controller's move part:
private void Move()
{
moveFrontBack = Input.GetAxis("Vertical") * moveSpeed;
moveLeftRight = Input.GetAxis("Horizontal") * moveSpeed;
Vector3 movement = new Vector3(moveLeftRight, 0, moveFrontBack);
movement = character.rotation * movement;
characterController.Move(movement * Time.deltaTime);
//Animation on move
if (movement.magnitude != 0)
{
anim.SetBool("isWalking", true);
anim.SetBool("isIdle", false);
}
if (movement.magnitude == 0)
{
anim.SetBool("isWalking", false);
anim.SetBool("isIdle", true);
}
centerPoint.position = new Vector3(character.position.x, character.position.y + mouseYPosition, character.position.z);
//The place where things go south it seems
if (Input.GetAxis("Vertical") > 0 | Input.GetAxis("Vertical") < 0)
{
Quaternion turnAngle = Quaternion.Euler(0, centerPoint.eulerAngles.y, 0);
character.rotation = Quaternion.Slerp(character.rotation, turnAngle, Time.deltaTime * rotationSpeed);
}
I had a previous version on the controller, without the change of camera with mouse, but the right character's behaviour facing the direction of the input:
private void Move()
{
moveFrontBack = Input.GetAxis("Vertical") * moveSpeed;
moveLeftRight = Input.GetAxis("Horizontal") * moveSpeed;
Vector3 movement = new Vector3(moveLeftRight, 0, moveFrontBack);
characterController.Move(movement * Time.deltaTime);
if (movement != Vector3.zero) transform.rotation = Quaternion.LookRotation(movement);
if (movement.magnitude != 0)
{
anim.SetBool("isWalking", true);
anim.SetBool("isIdle", false);
}
if (movement.magnitude == 0)
{
anim.SetBool("isWalking", false);
anim.SetBool("isIdle", true);
}
playerCamera.position = new Vector3(character.position.x, character.position.y + yCamera, character.position.z + zCamera);
}
Also, here is the mousemoving part:
void MouseTurnAround()
{
zoom += Input.GetAxis("Mouse ScrollWheel") * zoomSpeed;
if (zoom > zoomMin)
zoom = zoomMin;
if (zoom < zoomMax)
zoom = zoomMax;
playerCamera.transform.localPosition = new Vector3(0, 0, zoom);
if (Input.GetMouseButton(0))
{
mouseX += Input.GetAxis("Mouse X");
mouseY -= Input.GetAxis("Mouse Y");
}
mouseY = Mathf.Clamp(mouseY, -60f, 60f);
playerCamera.LookAt(centerPoint);
centerPoint.localRotation = Quaternion.Euler(mouseY, mouseX, 0);
}
I don't really have more ideas, so maybe smart people can see what they can do ! Thanks in advance..
I managed some kind of a mix of my 2 solutions, and parented my character to an empty gameobject, which receives the new rotations. Then, i leave the character be oriented to the movement with look rotation.
private void Move()
{
moveFrontBack = Input.GetAxis("Vertical") * moveSpeed;
moveLeftRight = Input.GetAxis("Horizontal") * moveSpeed;
Vector3 movement = new Vector3(moveLeftRight, 0, moveFrontBack);
movement = character.rotation * movement;
characterController.Move(movement * Time.deltaTime);
//Animation on move
if (movement.magnitude != 0)
{
anim.SetBool("isWalking", true);
anim.SetBool("isIdle", false);
}
if (movement.magnitude == 0)
{
anim.SetBool("isWalking", false);
anim.SetBool("isIdle", true);
}
centerPoint.position = new Vector3(character.position.x, character.position.y + mouseYPosition, character.position.z);
//Rotates the character to move towards new direction
if (Input.GetAxis("Vertical") > 0 | Input.GetAxis("Vertical") < 0)
{
Quaternion turnAngle = Quaternion.Euler(0, centerPoint.eulerAngles.y, 0);
character.rotation = Quaternion.Slerp(character.rotation, turnAngle, Time.deltaTime * rotationSpeed);
}
if (movement != Vector3.zero) lkModel.rotation = Quaternion.LookRotation(movement);
}