How to rotate an object along all 3 axes with finger swipe? - c#

I'm working on a simple AR Vuforia application. How can I implement the rotation of an object along all three axes with one finger swipe?
The code I'm currently using has one bug: the rotation of the object depends on its local axes. For example, if I look at the object from the front, everything works as it should, but if I look at the object from the back side, the finger swipe upwards makes it rotate downwards and vice versa.
Here is this script:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X")*rotSpeed*Mathf.Deg2Rad;
float rotY = Input.GetAxis("Mouse Y")*rotSpeed*Mathf.Deg2Rad;
transform.Rotate(Vector3.up, -rotX);
transform.Rotate(Vector3.right, -rotY);
}
This is not what I need, how can I rotate the object according to the finger swipe direction regardless of the angle from which I look at it?
Update
A simple non-AR example, which may help you understand what I need is an iOS game "Space Frontier 2". After a successful launch of the rocket, it lands on the planet and you can rotate the planet with your finger swipe.
Here is the video demo: https://youtu.be/OiNPP1WNIAI

This works nice regardless of your object's rotation, and regardless of your camera position relative to the object:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed;
Camera camera = Camera.main;
Vector3 right = Vector3.Cross(camera.transform.up, transform.position - camera.transform.position);
Vector3 up = Vector3.Cross(transform.position - camera.transform.position, right);
transform.rotation = Quaternion.AngleAxis(-rotX, up) * transform.rotation;
transform.rotation = Quaternion.AngleAxis(rotY, right) * transform.rotation;
}
Make sure your camera has the "MainCamera" tag, or assign the camera externally if necessary.

I do not have the exact code with me right now.
But if you did not update your point of view coordinates, this should be the expected result.
Consider a real ball with 2 colors, blue and red, separated vertically.
When you are in front of it, seeing only the blue side, stroking it up will make the blue side go up and the red side appear from the bottom.
Now move behind it, seeing only the red side, and stroke it up again.
The blue face will go down and appear from the bottom.
Unity applies physics to virtual objects the same way we interact with real objects.
So you need to consider your camera position with the object orientation when you apply movements to it.
You need to apply a transformation matrix to your movement based on your camera location related to the object origin orientation.
I hope this is clear enough to put you on tracks to fix it.

I think you have to somehow clamp the rotation to have the desired behaviour. I wrote a script recently to do just that. I did a little modification though.
public float rotSpeed = 30f;
float ClampAngle(float _angle, float _min, float _max)
{
if (_angle < 0f) _angle = 360 + _angle;
if (_angle > 180f) Mathf.Max(_angle, 360 + _min);
return Mathf.Min(_angle, _max);
}
USAGE:
void RotateGameObject()
{
float h = Input.GetTouch(0).deltaPosition.x * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
float v = Input.GetTouch(0).deltaPosition.y * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
Vector3 rot = transform.rotation.eulerAngles + new Vector3(-v, h, 0f);
//Change the y & z values to match your expected behaviour.
rot.x = ClampAngle(rot.x, -5f, 20f);
//Clamp rotation on the y-axis
rot.y = ClampAngle(rot.y, -20f, 20f);
transform.eulerAngles = rot;
}
See if that works and of course, try to play with the values.

Related

Unity - Rotate around object by mouse

I'm hoping someone can clear this up for me, I've literally spent days on this.
I have a need to focus the camera on the front of an object and then allow the player to orbit the object while holding the mouse button. I've managed to get the camera to focus on the front of the object using this:
if (!arrived)
{
//Centre on our object
var newPos = target.transform.position + currentRotation * (distance * target.transform.forward);
transform.position = Vector3.Lerp(transform.position, newPos, 0.25f);
transform.LookAt(target.position);
return;
}
But then I'm looking for the mouse button being held and attempting to rotate around the target object, keeping a consistent distance from it.
I've tried so many different ways but all of them have issues.
I tried:
transform.RotateAround(target.position, Vector3.down, (movementForce * 100000) * Time.deltaTime);
But which works fine horizontally but the same using Vector.left doesn't seem to work vertically.
I've tried:
transform.LookAt(target.position);
Vector3 rotation = new Vector3(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"), 0);
transform.Translate(rotation * Time.deltaTime * 10);
But that moves the camera further away from the target over time.
And finally I'm not trying this:
//Horizontal
Vector3 relativePos = target.position - transform.position; // Vector from camera to player
Vector3 relativePosRight = Vector3.Cross(relativePos, Vector3.left);
transform.RotateAround(target.position, relativePosRight, 100 * Time.deltaTime * Input.GetAxisRaw("Mouse X"));
//Vertical
Vector3 relativePos = target.position - transform.position; // Vector from camera to player
Vector3 relativePosRight = Vector3.Cross(relativePos,Vector3.up);
transform.RotateAround(target.position, relativePosRight, 100 * Time.deltaTime * Input.GetAxisRaw("Mouse Y"));
Which vertically works fine, but when moving the mouse horizontally, that seems to affect it vertically as well and orbits at a weird angle.
Please forgive any obvious mistakes in the above, I've literally resorted to copying and pasting every solution I find online to get the right thing.
Thanks in advance!
What does your scene hierarchy look like? Are you able to make the camera a child of the object you want to orbit, have the camera always looking at the object and then rotate the object with the mouse?
Similar to this answer.
So something like this:
// Move the camera to the correct position/distance from the target.
Camera.main.transform.position = target.position + new Vector3(0,1,0); // 1m above the target.
Camera.main.transform.LookAt(target.position);
Camera.main.transform.SetParent(target);
// Rotate the target with the mouse input.
Vector3 rotation = new Vector3(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"), 0);
target.Translate(rotation * Time.deltaTime * 10);
It might not be exactly what you might want but it visually looks like it is orbiting the object.
Hope that helps!

Rotating field of view with player

So I have trying to create a system that looks for a ledge to climb. I have a vertical field of view that looks for these ledges and I have, so far, got it to rotate with the analogue stick's direction, so I can find a ledge and move to it where my analogue is pointing. (Look up, find ledge, move up, etc). My problem is, while the the field of view moves where I need it to move, it stays fixed on one axis and does not rotate with the player.
In the picture the cone is facing where it should be, and rotates around the player as I want it to, but as you can see, the cone faces the X-Axis and does not move from there. I want it to rotate with the player.
In the below code, the returned Vector's y value makes the cone point upwards. I have tried all manner of functions in the x and z values, but nothing is sticking.
public Vector3 DirFromAngle(float angleInDegrees, bool angleIsGlobal)
{
if(!angleIsGlobal)
{
angleInDegrees += (viewDir + 90);
}
Vector3 newValue = new Vector3(0, Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), Mathf.Cos(angleInDegrees * Mathf.Deg2Rad));
return newValue;
}
The viewDir value makes the cone rotate with my analogue stick, to make the cone rotate with my player, I assume that something needs to be done with either the x or z values, or both, but for the life of me, I can't figure it out.
Thank you for any help on this issue. Apologies if my explanation isn't very good.
void OnSceneGUI()
{
LedgePointSearch lps = (LedgePointSearch)target;
Handles.color = Color.white;
Handles.DrawWireArc(lps.transform.position, lps.transform.forward * 90, Vector3.up, 360, lps.viewRadius);
Vector3 viewAngleA = lps.DirFromAngle(-lps.viewAngle / 2, false);
Vector3 viewAngleB = lps.DirFromAngle(lps.viewAngle / 2, false);
Handles.DrawLine(lps.transform.position, lps.transform.position + viewAngleA * lps.viewRadius);
Handles.DrawLine(lps.transform.position, lps.transform.position + viewAngleB * lps.viewRadius);
}
This is the editor script that displays the field of view.
The circle simply represents the radius of the field of view, how far it goes out.
https://www.dropbox.com/s/k9siha2aog9vj8o/fov.mp4?dl=0
In the video, the circle rotates with the player, and the cone rotates with my left analogue movements. I want the cone to be like the circle, with it rotating as my player does, but still matching my analogue movements.
One way to approach this is to find the Y rotation of the player and apply it to newValue before returning it.
public Vector3 DirFromAngle(float angleInDegrees, bool angleIsGlobal)
{
if(!angleIsGlobal)
{
angleInDegrees += (viewDir + 90);
}
Vector3 newValue = new Vector3(0, Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), Mathf.Cos(angleInDegrees * Mathf.Deg2Rad));
// get Y rotation of player
yRotationAngle = player.transform.rotation.eulerAngles.y;
// convert to Quaternion using only the Y rotation
Quaternion yRotation = Quaternion.Euler(0f, yRotationAngle + 90f, 0f);
// Apply yRotation
newValue = yRotation * newValue;
return newValue;
}

Unity2D Enemy Patrol, weird sprite rotation

Needed help here, I've been following this tutorial about Enemy Patrolling, https://www.youtube.com/watch?v=KKU3ejp0Alg
The tutorial tell us to set 2 Empty Game Objects and the coordinates so the sprite will walk from one direction to another, the walking does working, however the rotation of the sprite became really weird, the 'Worm' sprite is suppose to move left and right now it change into facing upward
Please look at this image,
When moving from left to right
When moving from right to left
public Transform[] patrolPoints;
public float speed;
Transform currentPatrolPoint;
int currentPatrolIndex;
// Use this for initialization
void Start()
{
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * speed);
if (Vector3.Distance(transform.position, currentPatrolPoint.position) < .1f) {
if (currentPatrolIndex + 1 < patrolPoints.Length)
currentPatrolIndex++;
else
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
Vector3 patrolPointDir = currentPatrolPoint.position - transform.position;
float angle = Mathf.Atan2(patrolPointDir.y, patrolPointDir.x) * Mathf.Rad2Deg - 90f;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 180f);
}
This is the code
Thank you
You can pass the optional parameter Space.World to your translation to move your object relative to world space instead of object space. That should prevent your object from rotating.
transform.Translate(Vector3.up * Time.deltaTime * speed, Space.World);
You can read more about it in the documentation.
You probably rotated the enemy sprite by 90 degrees. Try placing all your scripts into empty game object with no rotation, than place the enemy sprite as child of the empty game object and rotate as you need. This way your logic won't collide with your graphics.

Unity - Sprite Rotation + Get Angle

Im trying to get a sprite rotation by key input (arrow down or up).
The point is lifting the arrow (sprite) to choose the angle. Its like a system of a golf game, actually.
So far i tried:
void Update () {
if (Input.GetKey(KeyCode.UpArrow)){
transform.Rotate (Vector3.forward * -2); }
if (Input.GetKey(KeyCode.DownArrow)){
transform.Rotate (Vector3.forward * +2); }
}
I will need the angle, since it will be related to a "shot" part i will be doing next. My point is setting the right angle with the keys up and down.
I can move the "arrow" sprite with my code, but i cannot set the max angle (90), minimum (0) and get the angle to use in the shot ^^
Hard question to answer without just simply giving you the code. This code works by assuming your character's forward vector is actually it's right vector (common in 2d sprite games) in order to shoot in the other direction, rotate your objects y axis 180.
float minRotation = 0f;
float maxRotation = 90f;
float rotationSpeed = 40f; //degrees per second
//get current rotation, seeing as you're making a sprite game
// i'm assuming camera facing forward along positive z axis
Vector3 currentEuler = transform.rotation.eulerAngles;
float rotation = currentEuler.z;
//increment rotation via inputs
if (Input.GetKey(KeyCode.UpArrow)){
rotation += rotationSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.DownArrow)){
rotation -= rotationSpeed * Time.deltaTime;
}
//clamp rotation to your min/max
rotation = Mathf.Clamp(rotation, minRotation, maxRotation );
//set rotation back onto transform
transform.rotation = Quaternion.Euler( new Vector3(currentEuler.x, currentEuler.y, rotation));
If you were making a golf game, you'd set the ball's velocity to be transform.right * shotPower

Rotate GameObject on Z axis while moving forward

Currently I have the following code, and it works 100% for a 3D game, but I can't get it to work for a 2D game.
What it is supposed to do, is once the object gets to the waypoint, it is supposed to rotate towards the new waypoint. What is actually happening is that it is rotating around the x and y axis, and not the z axis. What can I do to make it only rotate on the z axis? The object is supposed to turn as it moves forward based on the turn speed. It shouldn't be an instant turn, unless the turnspeed is a high number. But anyways, again I ask how do I get this code to only roate on the z axis?
void Update () {
if(toWaypoint > -1){
Vector3 targetDir = wayPoints[toWaypoint].position - transform.position;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, turnSpeed * Time.deltaTime, 0.0f);
transform.rotation = Quaternion.LookRotation(newDir);
}
if(!usePhysics && toWaypoint != -1){
transform.Translate(Vector3.forward * Time.deltaTime * speed);
next();
}
}
Look rotation is not dependable for 2D games as the forward axis is different. One workaround is to parent the sprite to an empty GameObject with the z axis (blue arrow) pointed in the direction that the sprite will be rotating.
Looks like you're using Unity3D, which leaves me wondering why you're messing around with the Z-axis in the first place if you're making a game in 2D editing mode. The Z-axis does literally nothing in that mode, unless you set your two axes to include it somehow. My suggestion to you is to switch to 2D editing if you haven't already, then use Vector2s instead of Vector3s.
Also, try using one of the other axes as your axis of rotation (transform.right or .up instead of .forward).
I found what I was looking for:
void Update () {
if(toWaypoint > -1){
Vector3 vectorToTarget = wayPoints[toWaypoint].position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * turnSpeed);
}
if(!usePhysics && toWaypoint != -1){
transform.Translate(Vector3.right * Time.deltaTime * speed);
next();
}
}

Categories

Resources