OK so this has been an issue for a week now i cant seem to figure it out i am trying to flip my submarine on its y axis once its goes upside-down. it rotates on my mouse position i will show you my code.
//This code rotates my submarine on mouse position which is perfect.
Vector3 RayPos = cam.WorldToScreenPoint(transform.position);
Vector3 dir = Input.mousePosition - RayPos;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation,
rotateSpeed * Time.deltaTime);
//now this code is my problem once my sub goes upside down it flips (y) but
it only does it once but then when i go back the correct way it wont flip
on (y) anymore.
Debug.Log(Mathf.Abs(Vector3.Dot(transform.up, Vector3.up)));
if (Mathf.Abs(Vector3.Dot(transform.up, Vector3.down)) < 0.125f)
{
if (Mathf.Abs(Vector3.Dot(transform.right, Vector3.down)) > 0.825f)
{
SubTrans.localScale = new Vector3(transform.localScale.x, -1,
transform.localScale.z);
}
else
{
SubTrans.localScale = new Vector3(transform.localScale.x, 1,
transform.localScale.z);
}
}
Related
My player is the cube and the target is sphere
`void Update()
{
Vector3 direction = target.position - player.transform.position;
Quaternion rotation = Quaternion.LookRotation(direction);
if (Input.GetMouseButton(0))
{
player.transform.rotation = Quaternion.RotateTowards(player.transform.rotation, Quaternion.Euler(player.transform.rotation.x, player.transform.rotation.y, rotation.z), rotationSpeed * Time.deltaTime);
}
else
{
player.transform.Rotate(-Vector3.forward * 1f);
}
}
`
Player is rotating infinitely like a spherically movement with transform rotate. When I click I want to rotate my player to target position. I'm trying with rotate towards but its rotating to 0. How can I fix this problem or should I do with something else.
So first of all: The x, y, z of a Quaternion are not what you expect them to be! They have nothing to do with Euler angles and move in normalized ranges between -1 and 1.
Then assuming you rotate the player only ever on the Z axis then you could simply use e.g.
void Update()
{
// use Vector2 to eliminate any delta on the Z axis
// -> vector is only in XY space
Vector2 direction = target.position - player.transform.position;
// -> rotation is only on Z axis
Quaternion rotation = Quaternion.LookRotation(direction);
if (Input.GetMouseButton(0))
{
player.transform.rotation = Quaternion.RotateTowards(player.transform.rotation, rotation), rotationSpeed * Time.deltaTime);
}
else
{
player.transform.Rotate(-Vector3.forward * Time.deltaTime);
}
}
I do not understand how this code works and I am seeking an explanation. This code is inside an update function, updating the Objects location constantly.
By "facing the mouse direction" I mean that the object is like the earth orbiting around the sun for example, but you choose where it is currently located on it's rotation line around the sun.
public GameObject player;
private Vector3 v3Pos;
private float angle;
private readonly float distance = 0.16f;
private void Update()
{
v3Pos = Input.mousePosition;
v3Pos.z = (player.transform.position.z -
Camera.main.transform.position.z);
v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
v3Pos -= player.transform.position;
angle = Mathf.Atan2(v3Pos.y, v3Pos.x) * Mathf.Rad2Deg;
if (angle < 0.0f) { angle += 360.0f; }
transform.localEulerAngles = new Vector3(0, 0, angle);
float xPos = Mathf.Cos(Mathf.Deg2Rad * angle) * distance;
float yPos = Mathf.Sin(Mathf.Deg2Rad * angle) * distance;
transform.localPosition = new Vector3(player.transform.position.x +
xPos * 4, player.transform.position.y + yPos * 4, 0);
}
I found this code in a video which makes an object (like a gun) rotate around the player and follow the mouse simultaneously but I don't understand how it works. How does it work? Also, I don't know where the video is at any more but I will find it if necessary.
It warps the attached gameobject so many units in the direction of the mouse cursor from the player (locally for some reason), and also turns to face its right side in that direction (locally for some reason).
Individual sections explained in the comments below:
public GameObject player;
private Vector3 v3Pos;
private float angle;
private readonly float distance = 0.16f;
private void Update()
{
// mouse position in screen space
// current value = (mouse x, mouse y, 0) )
Vector3 v3Pos = Input.mousePosition;
// sets the z coordinate to be the difference from the camera to the player
// along the forward world axis.
// current value = (mouse x, mouse y, camera->player distance along forward)
v3Pos.z = (player.transform.position.z - Camera.main.transform.position.z);
// v3Pos now means the position of the cursor, projected onto plane the player
// is on parallel to camera plane
// This means it's a world space positioning of the mouse
v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
// v3Pos now means the direction from the player to the mouse position
// in world space.
// Despite the name, now a direction, not a position!
v3Pos -= player.transform.position;
// finds the signed angle from right to the direction v3Pos represents.
// in the range (-180, 180]. positive = counterclockwise
angle = Mathf.Atan2(v3Pos.y, v3Pos.x) * Mathf.Rad2Deg;
// converts negative angle into an equivalent positive angle.
if (angle < 0.0f) { angle += 360.0f; }
// sets the forward axis angle of the transform this
// MonoBehaviour is attached to as the same angle.
// Since we measured from the right to the direction of the mouse,
// this turns the right side to face the mouse.
// This is done in local space for some reason, can't tell from code.
transform.localEulerAngles = new Vector3(0, 0, angle);
// finds x and y coordinates of a point in the same direction as
// v3Pos the mouse from the player but at distance
// Could use v3Pos but with a z=0, normalized then * distance but
// recalculating with trig works too.
// basic trig refresher
// cos of angle from right gives unit circle x coordinate
// sin of angle from right gives unit circle y coordinate
float xPos = Mathf.Cos(Mathf.Deg2Rad * angle) * distance;
float yPos = Mathf.Sin(Mathf.Deg2Rad * angle) * distance;
// sets the player's local position to be the position of the player
// adjusted by the direction and distance of the point.
// Also done in local space, can't tell why from code.
// Weird to use something else's world position as the local position
// for something else.
transform.localPosition = new Vector3(player.transform.position.x
+ xPos * 4, player.transform.position.y + yPos * 4, 0);
}
The alternate calculation mentioned above could be done like this:
Vector3 v3Pos = Input.mousePosition;
v3Pos.z = (player.transform.position.z - Camera.main.transform.position.z);
v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
v3Pos -= player.transform.position;
angle = Mathf.Atan2(v3Pos.y, v3Pos.x) * Mathf.Rad2Deg;
if (angle < 0.0f) { angle += 360.0f; }
transform.eulerAngles = new Vector3(0, 0, angle);
Vector3 v3DirFlat = v3Pos;
v3DirFlat.z = 0f;
// keeping both * distance and * 4
v3DirFlat = v3DirFlat.normalized * distance * 4;
transform.position = player.transform.position + v3DirFlat;
The steps are
// Get the mouse position on the screen
v3Pos = Input.mousePosition;
// Bring that point down until it is level with the player
v3Pos.z = (player.transform.position.z - Camera.main.transform.position.z);
// Find that point in world space coordinates
v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
// Find the vector from the player to that point
v3Pos -= player.transform.position;
// Calculate the angle between that vector and the X axis
angle = Mathf.Atan2(v3Pos.y, v3Pos.x) * Mathf.Rad2Deg;
// ensure the values are between 0 and 360
if (angle < 0.0f) { angle += 360.0f; }
// Set the item's rotation to that angle, so it faces the right direction
transform.localEulerAngles = new Vector3(0, 0, angle);
// Find the new position of the item on the orbit circle
float xPos = Mathf.Cos(Mathf.Deg2Rad * angle) * distance;
float yPos = Mathf.Sin(Mathf.Deg2Rad * angle) * distance;
// Set the item to it's new position
transform.localPosition = new Vector3(player.transform.position.x + xPos * 4, player.transform.position.y + yPos * 4, 0);
I'm not sure why the coordinates in that last step are multiplied by 4, they should already be positioned on a circle with radius distance
after a good amount of searching I haven't been able to find out how to change the rotation of my overlap boxes set up and the gizmo used to visualize them.
//draw a hitbox in front of the character to see which objects it collides with
Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight)
+ Vector3.right * lastAttack.collDistance;
Vector3 boxSize = new Vector3 (lastAttack.CollSize/2, lastAttack.CollSize/2, hitZRange/2);
Collider[] hitColliders = Physics.OverlapBox(boxPosition, boxSize, Quaternion.identity,
HitLayerMask);
I'm using it for damage calculation. I want the OverlapBox to take the same rotation of the player and always be in front of the player.
void OnDrawGizmos(){
if (lastAttack != null && (Time.time - lastAttackTime) < lastAttack.duration) {
Gizmos.color = Color.red;
Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight)
+ Vector3.right * ((int)lastAttackDirection * lastAttack.collDistance);
Vector3 boxSize = new Vector3 (lastAttack.CollSize, lastAttack.CollSize, hitZRange);
Gizmos.DrawWireCube (boxPosition, boxSize);
}
}
Draw the Box Overlap as a gizmo to show where it currently is testing
To have the overlap box inherit the transform's rotation, you can use transform.rotation instead of Quaternion.identity for the overlap box's rotation.
For the gizmo, it's a little more complex. One way to fix this is to change the Gizmo matrix to be the local transform matrix with Gizmos.matrix = transform.localToWorldMatrix, which will make the gizmo inherit the player's rotation. But, it will also make the gizmo's position be relative to the player's local position. So, you'll need to convert the world position boxPosition to local position before you draw the gizmo. You can use transform.InverseTransformPoint to do this.
You may want to restore the gizmo settings to what they were previously or it could result in unexpected behaviour in other places where Gizmos is used.
Altogether:
//draw a hitbox in front of the character to see which objects it collides with
Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight)
+ Vector3.right * lastAttack.collDistance;
Vector3 boxSize = new Vector3 (lastAttack.CollSize/2, lastAttack.CollSize/2, hitZRange/2);
Collider[] hitColliders = Physics.OverlapBox(boxPosition, boxSize,
transform.rotation, HitLayerMask);
...
void OnDrawGizmos(){
if (lastAttack != null && (Time.time - lastAttackTime) < lastAttack.duration) {
// cache previous Gizmos settings
Color prevColor = Gizmos.color;
Matrix4x4 prevMatrix = Gismos.matrix;
Gizmos.color = Color.red;
Gizmos.matrix = transform.localToWorldMatrix;
Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight)
+ Vector3.right * ((int)lastAttackDirection * lastAttack.collDistance);
// convert from world position to local position
boxPosition = transform.InverseTransformPoint(boxPosition);
Vector3 boxSize = new Vector3 (lastAttack.CollSize, lastAttack.CollSize, hitZRange);
Gizmos.DrawWireCube (boxPosition, boxSize);
// restore previous Gizmos settings
Gizmos.color = prevColor;
Gizmos.matrix = prevMatrix;
}
}
Using Unity, I'm trying to move my turrets rotation using first person camera by using touch, I grab from side of screen to center from the direction i want to go to like in google maps, the touch grab will move my camera there smoothly.
Problem is the camera being very jerky, not smooth in position.
In Global
private float smoothTouchFactor = 5;
This is the code I am using in Update()
Quaternion rotation;
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
Touch touch = Input.GetTouch(0);
x += touch.deltaPosition.x * xSpeed * 0.02f;
y -= touch.deltaPosition.y * ySpeed * 0.02f;
rotation = Quaternion.Euler(y, x, 0f);
turretHeadToMove.rotation = Quaternion.Slerp(turretHeadToMove.rotation, rotation, Time.deltaTime * smoothTouchFactor);
}
}
rotation = Quaternion.Euler(y, x, 0f);
turretHeadToMove.rotation = Quaternion.Slerp(turretHeadToMove.rotation, rotation, Time.deltaTime * smoothTouchFactor);
If I dont add the last 2 lines after the if(touchCount) then the camera goes back to initial position after i lift my finger off the screen.
Here is the mouse axis Mouse X/Y code that works and moves the turret with no jerky motion, smoothly.
private float xSpeed = 40.0f;
private float ySpeed = 40.0f;
in Update()
x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
Quaternion rotation = Quaternion.Euler(y, x, 0f);
turretHeadToMove.rotation = rotation;
From your description of needing those "two lines" at the end, it sounds like you have code elsewhere that's constantly trying to reset their rotation. So, we add a variable to keep rotation consistent with the Quaternion set the last time the touch control was done, and just be sure to assign it to turretHeadToMove.rotation before handling the touch controls.
Then, you can use Euler to create a Quaternion of how much you want to rotate this frame. And then multiply the current rotation by that amount in order to get the new rotation
Altogether this might look like:
As a field:
private Quaternion savedRotation = Quaternion.identity;
In Update:
// Add it before the block so that modifications to `localRotation` are consistent with memory
turretHeadToMove.rotation = savedRotation;
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
Touch touch = Input.GetTouch(0);
Quaternion previousRotation = turretHeadToMove.rotation;
Quaternion rotationThisFrame = Quaternion.Euler(
touch.deltaPosition.y * ySpeed,
touch.deltaPosition.x * xSpeed, 0f);
turretHeadToMove.rotation = previousRotation * rotationThisFrame;
savedRotation = turretHeadToMove.rotation;
}
}
So I've been trying to get this to work but no luck so far, hopefully you can help. The thing is I have a camera in my project that the user can freely move with mouse and buttons.
Currently like so:
move = new Vector3(0, 0, -1) * moveSpeed;
move = new Vector3(0, 0, 1) * moveSpeed;
...
And then I just add move vector to cameraPos vector: cameraPos += move
Then problem is if I rotate the camera and then try to move, for example down, it will not move straight down but in a certain angle. I am assuming this is due to moving on local axis. But what I want to do is to move on a world axis. Is something like that possible, or do I have to somehow calculate the angle and then move on more than one axis?
Best regards!
EDIT:
I am rotating the camera where cameraPos is the current position of the camera and rotation is the current rotation of the camera. And this is the code to rotate the camera:
void Update()
{
...
if(pressed)
{
int newY = currentY - oldY;
pitch -= rotSpeed * newY;
}
Rotate();
}
void Rotate()
{
rotation = Matrix.CreateRotationX(pitch);
Vector3 transformedReference = Vector3.Transform(cameraPos, rotation);
Vector3 lookAt = cameraPos + transformedReference;
view = Matrix.CreateLookAt(cameraPos, lookAt, Vector3.Up);
oldY = currentY;
}
Ihope this is more readable.
I was able to solve this problem by using:
Vector3 v;
if (state.IsKeyDown(Keys.Up))
v = new Vector3(0, 0, 1) * moveSpeed;
... //Other code for moving down,left,right
if (state.IsKeyDown(Keys.V))
view *= Matrix.CreateRotationX(MathHelper.ToRadians(-5f) * rotSpeed); //Multiplying view Matrix to create rotation
view *= Matrix.CreateTranslation(v); //Multiplying view Matrix to create movement by Vector3 v
I suppose you're already saving the direction you're looking at in a Vector3. Replace your method with this:
direction.Normalize();
var move = direction * moveSpeed;
cameraPos += move;