I wrote a simple player movement script which moves my player like this:
private void MovePlayer()
{
// Initialize Directions For Player Movement
movement = transform.right * horizontal * playerSpeed + transform.forward * vertical * playerSpeed;
// Move Player
rb.AddForce(movement, ForceMode.Acceleration);
}
and I am trying to rotate my player towards the axes, for example if the player is pressing a the horizontal will be -1 and I want to rotate my player left horizontal * 90f, now when I try this, my horizontal axis is acting like my vertical, if I press A it will bring my player backwards, if I press D it will do the same thing, this is how I rotate the player:
// buggy code:
private void RotatePLayerTowardsAxis()
{
// Rotate PLayer Horizontaly
transform.rotation = Quaternion.Euler(0f, horizontal * 90, 0f);
}
is there a way I can do this?
Edit:
The vertical is still pushing me up and down.
First, it is important to check if you are looking at the scene in Local or Global view. Check your axes in Local mode:
If your character model faces towards the blue axis, then everything should be okay.
If you want to rotate your character only by 90 degrees all the time, then it can be done somehow like this:
transform.rotation = Quaternion.Euler(0, 90, 0);
You can use the following as well, but this might not fit your needs:
transform.Rotate(transform.up, 90);
This will make your character rotate by 90 degrees AROUND the up axis. If you want it to rotate always around the world up axis:
transform.Rotate(Vector3.up, 90);
However, transform.rotation = Quaternion.Euler(0, 90, 0); might be better for you, as it always "resets" the rotation when you overwrite it. This will make the character fixed to a direction. So if you press left, the charater will always look into the left by 90 degree. And if you press right after the left turn, your character will do a 180° turn instead of looking forward. I hope you get what I'm trying to say. This means, that your character will be bound to the world axis instead of its own. To modify this (if you want to), write something like this:
transform.rotation += Quaternion.Euler(0, 90, 0);
Hope I could help!
Related
I need to make a 3d top down character controller and animate it.
To begin with, I made a code for the character's movement relative to the camera. And this code works, the character walks and turns well.
Vector3 inputDirection = new Vector3(_input.GetAxis.x, 0, _input.GetAxis.y);
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + _camera.rotation.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transformPlayer.eulerAngles.y, targetAngle, ref _turnVelocity, TurnSmoothTime);
transformPlayer.rotation = Quaternion.Euler(0f, angle, 0f);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
moveDirectionNormalized = moveDirection.normalized;
_characterPlayer.Move(moveDirectionNormalized * SpeedMultiplier * Time.deltaTime);
The character model is a child object of _characterPlayer.
And if, when the character moves, an enemy gets into his radius, then the player's model will turn towards the enemy, and the character himself will go further along the moveDirectionNormalized.
For turns, I wrote the following code:
if (NearestEnemyAtAttackRadius != null)
{
Quaternion rotation = Quaternion.LookRotation(NearestEnemyAtAttackRadius.transform.position - MeshCharacter.position);
MeshCharacter.rotation = Quaternion.RotateTowards(MeshCharacter.rotation, rotation, 800f * Time.deltaTime);
}
else
{
MeshCharacter.localRotation = Quaternion.RotateTowards(MeshCharacter.localRotation, Quaternion.Euler(Vector3.zero), 800f * Time.deltaTime);
}
Now if there is an enemy nearby, my character swings towards the enemy, and if there is no enemy or the enemy has left the radius, then the initial state is returned.
And here my problem begins. I wanted to add an animation of the movement. The character has 4 animations: movement with a tilt to the right, left, forward and backward.
In the Animator, I made a Blend Tree (2d simple direction) with 4 animations. Added 2 Float values MoveDirectionX, MoveDirectionY correctly configured for all motion pos x and pos y.
And if I am in MoveDirectionX, MoveDirectionY will feed the vector moveDirectionNormalized, then it does not work correctly. The values of moveDirectionNormalized do not depend on the repetition of my model in any way, and if my character moves away from the enemy, he looks at the enemy but in fact goes backwards, the animation should turn on as he leans back. But now moveDirectionNormalized does not depend on the repetition of my model, and the character tilt animations randomly switch depending on moveDirectionNormalized. As I understand it, it is necessary to create a new vector that will take into account the rotation of my model, but I do not understand how to do this.
As a result, I want to get a vector where x - shows where the character is moving to the left or right (from -1 to 1) and y - shows the movement forward, backward (also from -1 to 1), and this vector should take into account the rotation of the player. At the moment, in the character model, only y changes in rotation. moveDirectionNormalized returns a value that indicates where the movement is directed relative to world space. And I need to make a vector that will return directions relative to the player's rotation. That is, if the character's gaze is directed at the enemy, and the character himself retreats from him, I would like to receive a vector (0, -1). And if the player's gaze is directed at the enemy and he goes to the right (I remind you that the player is constantly looking towards the enemy, that is, you can walk around the enemy and the character will constantly turn in his direction), then I would like to get a vector (1,0)
I am not 100% sure I understand, but if I do, this should help:
You can use Quaternion.Inverse() on the rotation of your player, and multiply that by the vector.
Vector3 yourVector;
Quaternion inverse = Quaternion.Inverse([player rotation]);
return inverse * yourVector;
Multiplying a quaternion by a vector rotates it with the quaternion, so if you invert it it will cancel out the rotation of the player.
First off: I am very new to Unity, as in VERY new.
I want to do the following: I want to rotate a cube around a stationary point (in my case a camera) with a radius that is adjustable in the inspector. The cube should always have its Z-axis oriented towards the camera's position. While the cube is orbiting around the camera, it should additionally follow a sine function to move up and down with a magnitude of 2.
I have some working code, the only problem is an increase in distance over time. The longer the runtime, the higher the distance between the cube and the camera.
Here is what I currently have:
void Awake()
{
cameraPosition = GameObject.FindGameObjectWithTag("MainCamera").transform;
transform.position = new Vector3(x: transform.position.x,
y: transform.position.y,
z: cameraPosition.position.z + radius);
movement = transform.position;
}
I instantiate some variables in the Awake()-method and set the cube's position to where it should be (do you instantiate in Awake()?). I'll use the Vector3 movement later in my code for the "swinging" of the cube.
void Update()
{
transform.LookAt(cameraPosition);
transform.RotateAround(cameraPosition.position, cameraPosition.transform.up, 30 * Time.deltaTime * rotationSpeed);
MoveAndRotate();
}
Here I set the orientation of the cube's z-axis and rotate it around the camera. 30 is just a constant i am using for tests.
void MoveAndRotate()
{
movement += transform.right * Time.deltaTime * movementSpeed;
transform.position = movement + Vector3.up * Mathf.Sin(Time.time * frequency) * magnitude;
}
To be quite frank, I do not understand this bit of code completely. I do however understand that this includes a rotation as it moves the cube along it's x-axis as well as along the world's y-axis. I have yet to get into Vector and matrices, so if you could share your knowledge on that topic as well I'd be grateful for that.
It seems like I have found the solution for my problem, and it is an easy one at that.
First of all we need the initial position of our cube because we need to have access to its original y-coordinate to account for offsets.
So in Awake(), instead of
movement = transform.position;
We simply change it to
initialPosition = transform.position;
To have more readable code.
Next, we change our MoveAndRotate()-method to only be a single line long.
void MoveAndRotate()
{
transform.position = new Vector3(transform.position.x,
Mathf.Sin(Time.time * frequency) * magnitude + initialPosition.y,
transform.position.z);
}
What exactly does that line then? It sets the position of our cube to a new Vector3. This Vector consists of
its current x-value
our newly calculated y-value (our height, if you want to say so) + the offset from our original position
its current z value
With this, the cube will only bop up and down with distancing itself from the camera.
I have also found the reason for the increase in distance: My method of movement does not describe a sphere (which would keep the distance the same no matter how you rotate the cube) but rather a plane. Of course, moving the cube along a plane will automatically increase the distance for some points of the movement.
For instantiating variables in Awake it should be fine, but you could also do it in the Start(){} Method that Unity provides if you wanted to.
For the main problem itself I'm guessing that calling this function every frame is the Problem, because you add on to the position.
movement += transform.right * Time.deltaTime * movementSpeed;
Would be nice if you could try to replace it with this code and see if it helped.
movement = transform.right * Time.deltaTime * movementSpeed;
I've been trying for some time now with different tutorials to get a nice firstperson (cockpit view) spaceship controll system. I tried using mouse only, keyboard only and combinations but I keep encountering the same problem with all tutorials. even this simple line of code does it:
transform.position += transform.forward * Time.deltaTime * 90f;
transform.Rotate( Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
The problem I keep getting is that if I pitch its ok. it I yaw its ok. But If I do both (so I go diagonaly) it also rotates my ship on the Z axis and messes up my orientation. I tried locking the z rotation in the rigidbody but that does'nt help either. I tried making code myself alternating with apply torque and simply rotating, followed some tutorials including this one: Tutorial but keep getting the rotation problem.
What I want to make is a game that controlls like the old game Helbender
Does anyone of you know of a way that I can get spaceship controlls to work?
----EDIT-----
Got a bit further now. It doenst turn on my z axis anymore becouse I keep setting it to 0. Only problem now is that if I try to make a looping the ship flips around instead of nicely looping.
if (Input.GetKey("up"))
{
transform.Rotate(transform.right * -ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("down"))
{
transform.Rotate(transform.right * ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("left"))
{
transform.Rotate(transform.up * -ShipPanSpeed * Time.deltaTime,Space.World);
}
if (Input.GetKey("right"))
{
transform.Rotate(transform.up * ShipPanSpeed * Time.deltaTime,Space.World);
}
float z = transform.eulerAngles.z;
transform.Rotate(0, 0, -z);
You could always try to make one parent object for the Controls and then a child object (the spaceshit) that you can rotate for the pivot but not attach any movement beside rotation.
What i mean is that you can rotate the parent on the Y axis to make it rotate and move the transform forward or backward at the same time. If you want to pivot up or down you can transform forward at the sametime you transform up/down multiplied with the axis you want to pivot with
Example:
private void Update(){
//PARENT--------------------------------------------
// MOVING FORWARD AND BACKWARD
transform.position += transform.forward * Input.GetAxis("Vertical") * speed * Time.deltaTime();
// MOVING RIGHT AND LEFT
transform.position += transform.right * Input.GetAxis("Horizontal") * speed * Time.deltaTime();
//PIVOT UP AND DOWN
transform.position += transform.up * -Input.GetAxis("Mouse Y") * speed * Time.deltaTime();
//ROTATE AROUND THE Y AXIS
tranform.Rotate(0f, Input.GetAxis("Horizontal") * rotationspeed, 0f);
}
For the spaceship (child) for the pivot i would recommend you to make a emptyobject and set the chip to lookAt that object based on the input axis you use to move up/down and forward/backward.
Hope this helped or at least gave you a idea of how to make it :)
I am making a third person mobile game with the help of joysticks. I have it set up where joystick.vertical moves the character forward or backwards depending on where he is looking and joystick.horizontal turns the character. Since the camera is parented to the character the camera always stays behind the character.
Swiping across the screen rotates the camera around the player with a touch panel using Camera.main.transform.RotateAround() function and the transform.LookAt() ensures I am looking at my character always.
My issue: I would like when the swipe is let go the camera to return to its original position behind the character but in a smooth motion or at a set speed moving around the player.
My Solution 1: To make an empty gameObject parented to the character and place it in the position where I want the camera to revert back to and call this position when the mouse is let go.
float spanCamera = -Joystick.Horizontal;
Camera.main.transform.LookAt(rb.transform.position);
if (spanCamera != 0)
Camera.main.transform.RotateAround(rb.position, Vector3.up, spanCamera * Time.fixedDeltaTime * spanSpeed);
else if (Input.touchCount <= 1)
{
float var6 = var5 * Time.deltaTime;
Camera.main.transform.position = camPos.transform.position;
Camera.main.transform.LookAt(camLookAt.transform.position);
}
This piece of code moves the camera back to the start position immediately without smoothing.
Solution 2: use a Vector3.MoveTowards() instead
// Camera.main.transform.position = camPos.transform.position;
Camera.main.transform.position = Vector3.MoveTowards(Camera.main.transform.position, camPos.transform.position, var6);
This code allows me to smoothly move to the start position in a straight line. I want it to go around the player.
So I tried a different method where I assign a float value 1 if the camera turns right and check if the rotate button is let go and if the value is 1 within an if block.
public float axisDir;
...
else if (spanCamera == 0 && axisDir == 1)
{
Camera.main.transform.RotateAround(rb.position, Vector3.up, -1 * Time.fixedDeltaTime * spanSpeed);
}
But this results in an infinite spin because I do not know how to check if the desired position has been reached.
I hope someone can help. This is quite a long post. :(
You could have an dummy gameObject as a child of the player, and the camera as a child of the dummy.
That way, the camera is looking at the centre of the gameObject: where the player is. The camera would also rotate with the player, so it would always be behind the player.
Now, you know that when Mathf.Approximately(dummy.transform.localEulerAngles.y, 0.0f), the camera is behind the player. [1][2]
Knowing that, you can check when the player stopped swiping and start slowly rotating it back.
// If the player let go and camera is not behind the player
if (!playerIsSwiping && !Mathf.Approximately(dummy.transform.localEulerAngles.y, 0.0f))
{
// Slowly rotate until the camera is behind the player
dummy.transform.RotateAround(Vector3.zero, Vector3.up, rotationSpeed * Time.deltaTime);
}
try this buddy :
// Maximum turn rate in degrees per second.
public float turningRate = 30f;
// Rotation we should blend towards.
private Quaternion _targetRotation = Quaternion.identity;
// Call this when you want to turn the object smoothly.
public void SetBlendedEulerAngles(Vector3 angles)
{
_targetRotation = Quaternion.Euler(angles);
}
private void Update()
{
// Turn towards our target rotation.
transform.rotation = Quaternion.RotateTowards(transform.rotation, _targetRotation, turningRate * Time.deltaTime);
}
i found it here
from my own experience using LERP works quite well, you lookin for a smooth transition, or between two points, known as interpolation, in this case linear interpolation.
I am trying to create a 3d game like ketchapp ball race, in which the cube slides along a road, and the left right movement is controlled using touch
The problem I am facing is that the touch senstivity seems to react different on different devices, due to which I am not able to calculate the left-right displacement for all devices.
This is how I am calculating the left-right displacement of the cube:
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition ;
transform.Translate(touchDeltaPosition.x * .1f * Time.deltaTime, 0, 0);
However this is not working properly all device . Any help will be highly appreciated
See this answer: https://stackoverflow.com/a/25740565/10063126
Basically, ScreenToWorldPoint was used.
World position is computed; not screen touch position.
But you have to manually solve for delta position.
Example:
Vector3 currPos = Input.mousePosition;
Vector3 startPos = Camera.main.ScreenToWorldPoint(currPos);
Vector3 endPos = Camera.main.ScreenToWorldPoint(prevPos);
Vector3 deltaPos = endPos - startPos;
transform.Translate(deltaPos.x * sensitivity * Time.deltaTime, 0, 0);
prevPos = currPos;
How about using 2 buttons on your screen one for left control and one for right control and then when the left button is pressed you can give a value to go left and same for right button. This way your ball's movement will be independent from the touched position's X value.