I'm still newbie to Unity... I'm trying to develop simple maze game. I want to roll my ball through maze, but I have to rotate camera left or right, otherwise the player can't see what's behind while rolling the ball on the left or on the right.
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate()
{
transform.position = player.transform.position + offset;
}
I'm using low pass filter for accelerometer values:
Vector3 lowpass()
{
float LowPassFilterFactor = AccelerometerUpdateInterval / LowPassKernelWidthInSeconds;
lowPassValue = Vector3.Lerp(lowPassValue, Input.acceleration, LowPassFilterFactor);
return lowPassValue;
}
Accelerometer values are from -1 to 1 for each coordinate. Because of that I check my lowPassValue.x value and limit it. If it's positive ( >0.3 ), then the camera should turn right and if it's negative ( <-0.3 ) then camera should turn left.
Quaternion rotation = Quaternion.AngleAxis(45, Vector3.up* Time.deltaTime) ; // right
transform.rotation = rotation;
Quaternion rotation = Quaternion.AngleAxis(-45, Vector3.up * Time.deltaTime) ; // left
transform.rotation = rotation;
But then my offset doesn't work anymore, I can't see ball anymore. And camera rotation doesn't work as it should.
Is there any better solution for this or I'm using the wrong function?
Any help will be very appreciated!
You have a problem with your AngleAxis() where you are multiplying the Axis to rotate on, by Time.deltaTime. this means that essentially you are changing the axis of rotation, and it is unpredictable. Most likely you wont get your "Right" or "Left" rotation. Multiply deltaTime by the angle itself instead.
Also, Quaternions are to be multiplied if you want to apply an angle with them:
Quaternion rotation = Quaternion.AngleAxis(45 * Time.deltaTime, Vector3.up) ; // right
transform.rotation *= rotation;
Quaternion rotation = Quaternion.AngleAxis(-45 * Time.deltaTime, Vector3.up) ; // left
transform.rotation *= rotation;
or this could just be achieved as:
transform.Rotate(45 * Vector3.right * Time.deltaTime); // right
transform.Rotate(45 * -Vector3.right * Time.deltaTime); // left
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 am working on controls for a bipedal tank, that has a boost/dash feature.
When the boost/dash mode is activated by holding a button the tank changes from a traditional WASD strafing movement to something like a jet fighter but on ground.
Now when the player tries to turn while boosting the camera needs to tilt with the turning direction to make it feel smoother.
Here is a video clip showing my problem
This is the script added to the main camera
public class PlayerCameraTilt : MonoBehaviour
{
private Camera viewCam;
private CharacterController characterController;
public float tiltAmount = 10f;
private void Start()
{
viewCam = GetComponent<Camera>();
characterController = GetComponentInParent<CharacterController>();
}
private void Update()
{
if (characterController.GetComponent<PlayerController>().movementState == MovementModes.boost)
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 euler = transform.localEulerAngles;
euler.z = Mathf.Lerp(euler.z, -inputValue, 5f * Time.deltaTime);
transform.localEulerAngles = euler;
}
else
{
Vector3 euler = transform.localEulerAngles;
euler.z = Mathf.Lerp(euler.z, 0f, 5f * Time.deltaTime);
transform.localEulerAngles = euler;
}
}
}
It kind of works, BUT only in one rotation direction, namely the positive one. If i turn the other way the angle becomes negative and does a whole 360 degree rotation until it ends up at 0 degrees.
I tried around with the built in Quaternion methods like Quaternion.Rotate() or Quaternion.AngleAxis()
but they didn't work because Quaternion.Rotate() doesn't tilt the Camera but completely rotates it. Quaternion.AngleAxis() works with the whole tilt angle limit but also does something to the other axis which i don't want to modify.
Is there a way to prevent the camera from doing a complete 360° rotation when the axis input becomes negative and just tilt in a slight angle?
Wraparound issues aside, the z component is "applied" first among the euler components, so I wouldn't modify it directly like that in this application.
Instead, I would convert the input to an angle to lean, rotate the direction of the local up before localRotation is applied (Quaternion.Inverse(transform.localRotation) * transform.up) by that angle, then use Quaternion.LookRotation to find a rotation with the current forward and that up, then use Quaternion.Slerp to slerp toward that rotation:
private void Update()
{
if (characterController.GetComponent<PlayerController>().movementState == MovementModes.boost)
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 upOfParent = Quaternion.Inverse(transform.localRotation) * transform.up;
Vector3 upDir = Quaternion.AngleAxis(-inputValue, transform.forward) * upOfParent;
Quaternion goalRot = Quaternion.LookRotation(transform.forward, upDir);
transform.rotation = Quaternion.Slerp(transform.rotation, goalRot, 5f * Time.deltaTime);
}
else
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 upOfParent = Quaternion.Inverse(transform.localRotation) * transform.up;
Quaternion goalRot = Quaternion.LookRotation(transform.forward, upOfParent);
transform.rotation = Quaternion.Slerp(transform.rotation, goalRot, 5f * Time.deltaTime);
}
}
Just keep in mind that using t = 5f * Time.deltaTime for lerp/slerp operations does not always guarantee that the output will ever equal the to parameter.
I'm trying to create a character controller that allows the movement speed to be affected by how far the player is pressing the left stick. When I can get that much to work, the other issue I encounter is the players speed decreasing while moving diagonally.
Most of the information I've found online deal with the opposite issue where diagonal movement is faster (movement vector goes above 1). The solution there would be to clamp the magnitude so pressing the stick into a corner doesn't go above 1. I've tried clamping to see if that would work, however, I don't believe that's the solution to my problem.
The code here allows the player to move in relation to the camera and the speed is influenced by input vector.
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 inputDir = input.normalized;
void Move(Vector3 inputDir, Vector3 input)
{
running = Input.GetKey(KeyCode.Joystick1Button1); // B button on xbox one controller
// Rotation stuff
if (inputDir != Vector3.zero) {
float targetRotation = Mathf.Atan2(inputDir.x, inputDir.z) * Mathf.Rad2Deg + cameraTransform.eulerAngles.y;
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref turnSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
}
// Pretty sure this is where things are breaking
float targetSpeed = ((running) ? runSpeed : walkSpeed) * inputDir.magnitude;
currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
currentSpeed *= input.magnitude;
vel = transform.forward * currentSpeed + Vector3.up * velocityY;
currentSpeed = new Vector3(_controller.velocity.x, 0, _controller.velocity.z).magnitude;
}
void ExecuteMovement()
{
_controller.Move(vel * Time.deltaTime);
}
Currently I have the following two issues:
The first issue being that when I reset my camera position I have to also reset my camera rotation. This is due to the fact that my camera
offset is set to a position slightly off of my player on the z and y
axis and obviously those values should change depending on my cameras
rotation although I am unsure how to figure out what those values
should be.
My second issue is that my rotation uses a raycast to find the middle of
the screen and determine its rotation origin although it seems to be
slightly off the middle of the screen as when it rotates the rotation
origin moves as well, if it is indeed in the middle of the screen
shouldn't it be completely still? Also is there a better and less
expensive way of achieving my desired rotation?
Relevant piece of code:
void RotateCamera()
{
//Find midle of screen
Ray ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0));
RaycastHit hitInfo;
//Checks if ray hit something
if (Physics.Raycast(ray, out hitInfo))
{
//Rotate left and right
if (Input.GetKey(KeyCode.RightArrow))
{
transform.RotateAround(hitInfo.point, -Vector3.up, rotationSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftArrow))
{
transform.RotateAround(hitInfo.point, Vector3.up, rotationSpeed * Time.deltaTime);
}
}
//Draws Raycast
Debug.DrawRay(ray.origin, ray.direction * 100, Color.yellow);
}
void ResetCameraPosition()
{
//Reset and lock camera position
transform.rotation = Quaternion.identity;
transform.position = player.transform.position + cameraOffset;
}
Image displaying what I mean
Use Camera.ScreenToWorldPoint to create a 'target' in the middle of the screen around which to pivot. Remove all the raycasting stuff as you don't need it and replace the relevant bits with:
float rotationSpeed = 45; // or whatever speed
float distance = 5f; // or whatever radius for the orbit
Vector3 target = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width / 2, Screen.height / 2, distance));
if (Input.GetKey(KeyCode.RightArrow))
{
transform.RotateAround(target , -Vector3.up, rotationSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftArrow))
{
transform.RotateAround(target , Vector3.up, rotationSpeed * Time.deltaTime);
}
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;