Why is my player movement inverted when I turn around? - c#

I used rigidbodies a lot and recently started using character controllers. I have basic movement code for my character controller here:
public void Update()
{
isGrounded = controller.isGrounded;
if (isGrounded)
{
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
}
Vector3 move = Vector3.forward * z + Vector3.right * x;
controller.Move(move * speed * Time.deltaTime);
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
if (!isGrounded)
{
}
velocity.y += gravity * Time.deltaTime; // Gravity for jumps
controller.Move(velocity * Time.deltaTime);
}
The reason I am using this code is because I'm trying to make sure that when my player jumps, the jump does not follow my camera around. This code does that, however if I rotate 180 degrees on the y axis, my WASD keys all become inverted. I've tried adding * (1) but that just makes it worse. If I replace Vector3.forward & Vector3.right to transform.forward & transform.right, the keys are no longer inverted but then my jump is controlled by my mouse movement, so I'm really trying to get the first line of code to work.

Vector3.forward is always (1, 0, 0). If you want the movement to be based on the camera's rotation you need to use Transform.forward and Transform.right(Assuming your character only has rotation around the y axis)
If you don't want the jump to be controllable mid-air, you have to logic to create momentum and prevent the player from changing their momentum if they are in the air. The first line is never going to work.

Related

Unity Can't Do Ground Check with Objected Generated at Start Time

I have a game that generates a maze at the start of the game. The player is dropped into the maze from a height of about 10 feet or so. The problem is that if I click the player object and change the inspector from normal to debug, I see that the character is still continuously generating falling velocity. I have a sphere at the bottom of the character that is supposed to do a ground check but clearly that isn't working. This is the relevant code for one of the ground tiles and the ground check features of the character.
Ground Tile Code in GameManager.cs in Scripts folder.
var tile = Instantiate(_tilePrefab);
tile.transform.Rotate(90, 0, 0);
tile.transform.localPosition = new Vector3((x * tileWidth) + offsetTile, 0, (y * tileWidth) + offsetTile);
tile.gameObject.layer = LayerMask.NameToLayer("Ground");
tile.transform.parent = _mazePrefab;
PlayerMovement.cs in Scripts folder
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
public float speed = 15f;
public float gravity = -9.8f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y > 0)
{
velocity.y = 0f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
I have a ground layer created and everything and I have an empty that projects a sphere at the base of my character.
What am I doing wrong?
The problem must be that your gravity resetting isn’t working. I suppose you are using the tutorial from Brackeys — I have used his tutorial before, so I know it works. The problem must be that your gravity resetting. So, I go through your code. I notice there is an if statement meant to reset the velocity when the player is grounded. So, I check the isGrounded variable. The only thing that could set that incorrectly is that the maze doesn’t have the right layer. Your code does set the layer right, so I rule that one out. I then look back at the if statement. The only thing that could set it off is the second term in it:
if (... && velocity.y > 0)
Notice how later in your code the velocity rapidly decreases.
velocity.y += gravity * Time.deltaTime;
Notice how gravity is a negative variable.
float gravity = -9.8f;
And Time.deltaTime is positive. When multiplying positive and negative values, if the number of negative values in the equation is odd the result is negative, and if it is even the result is positive. Therefore, velocity decreases instead of increases.
In the if statement, you check if velocity.y > 0, in other words: if the velocity is greater than 0, do something. But according to the math, velocity is always decreasing, not increasing. But you are detecting if the velocity is above 0, not under it.
Change the if statement to:
if (isGrounded && velocity.y < 0)
Notice how I change the > to a < to detect if it is less than zero.
That would solve your problem and you could go off here, but there is something else that is less important. Notice how after your if statement, you decrease the velocity.
...
if (isGrounded && velocity.y > 0)// «— if statement.
{
velocity.y = 0f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;// «—- change velocity.
...
Since after you call the if statement you change it, you won’t need to detect if the velocity is less than 0. This is because the velocity will always be slightly less than 0 at the end of each frame.
There are two things you could do here.
You could remove the second part of the if statement.
You could add the velocity change to the else of the if statement.
For 1:
if (isGrounded)
{
velocity.y = 0f;
}
For 2:
Add:
if (isGrounded)
{
velocity.y = 0f;
}
else
{
velocity.y += gravity * Time.deltaTime;
}
And remove:
controller.Move(move * speed * Time.deltaTime);
//removed this line «—-
controller.Move(velocity * Time.deltaTime);

Allowing only x Position to change with Time using Kinect Body Joint Position in Unity

Guys I am making an endless runner game which will be controlled with body position.
I'm trying to move character left or right (x-axis) with my body position by using Kinect sensor. The character is free to move forward (z-axis) with Time.deltaTime. The character has CharacterController and script attached. The code is below for movement:
CharacterController controller;
KinectManager kinectManager;
float speed = 5.0f
Vector3 moveDir;
void Update()
{
moveDir = Vector3.zero;
moveDir.z = speed;
moveDir.x = kinectManager.instance.BodyPosition * speed;
//controller.Move(moveDir * Time.deltaTime);
controller.Move(new Vector3 (moveDir.x, 0, moveDir.z * Time.deltaTime));
}
This statement controller.Move(moveDir * Time.deltaTime); keeps moving character to the left or right because x position is being incremented with Time.deltaTime so I wanted to restrict that and I changed that to controller.Move(new Vector3 (moveDir.x, 0, moveDir.z * Time.deltaTime));.
Now whats happening is the character is stuck at the same position. I can move left or right with body position but cannot move forward. What am I missing here?
Please help.
Indentifying issues
First try to watch you axis carefully that where is your gameobject y axis because you are assigning 0 value to it . The below code will help you find the issue and resolve it .
Solution
void Update()
{
if (controller.isGrounded)
{
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection = moveDirection * speed;
if (Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
}
// Apply gravity
moveDirection.y = moveDirection.y - (gravity * Time.deltaTime);
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}

Unity, rotate an object in axis and back to starting point in the same direction

I want to rotate an object in the Y direction at constant speed. When stopped I want to rotate back to Quaternion.identity in the same direction.
public bool spin;
public float speed;
private void Update() {
if (spin) {
transform.Rotate (-Vector3.up, Time.deltaTime * speed, Space.World);
} else if (transform.rotaion != Quaternion.identity) {
transform.rotation = Quaternion.RotateTowards (transform.rotation, Quaternion.identity, Time.deltaTime * speed);
}
}
This works great but it spins back on opposite direction. How do you force it to keep spinning on original direction to Quaternion.identity?
This works great but it spins back on opposite direction.
RotateTowards will take the shortest path to its target - whichever direction that may be.
How do you force it to keep spinning on original direction to Quaternion.identity?
Reverse direction when rotation passes 180 degrees (or halfway):
var dir = transform.eulerAngles.y < 180f ? 1f : -1f;
Quaternion.RotateTowards(rotation, Quaternion.identity, Time.deltaTime * speed * dir);

Unity Player falling very slowly

I created controls for a 3D Platformer game. Somehow the player is falling down very very slowly.
My player object got 2 components, the default capsule collider and the default Rigidbody. I didnt change anything there.
So my code is this one here:
float movementSpeed = 8;
float currentMovementSpeed;
float speedSmoothTime = 0.1f;
float turnSmoothTime = 0.2f;
float jumpPower = 5;
float airControlPercentage = 0.2f;
float turnSmoothVelocity;
float speedSmoothVelocity;
bool isGrounded;
private void FixedUpdate()
{
isGrounded = GroundCheck(); // Is player grounded?
Vector2 inputDirection = (new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"))).normalized;
if (Input.GetButtonDown("Jump") && isGrounded) // Jump handling
Debug.Log("Player Jump");
if (inputDirection != Vector2.zero)
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, Mathf.Atan2(inputDirection.x, inputDirection.y) * Mathf.Rad2Deg + cameraTransform.eulerAngles.y, ref turnSmoothVelocity, GetModifiedSmoothTime(turnSmoothTime)); // Rotate
currentMovementSpeed = Mathf.SmoothDamp(currentMovementSpeed, movementSpeed * inputDirection.magnitude, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
playerRigid.velocity = transform.forward * currentMovementSpeed + Vector3.up * playerRigid.velocity.y * Time.deltaTime; // Move
currentMovementSpeed = (new Vector2(playerRigid.velocity.x, playerRigid.velocity.z)).magnitude;
}
private float GetModifiedSmoothTime(float smoothTime) // Limit the control while in air
{
if (isGrounded)
return smoothTime;
if (airControlPercentage == 0)
return float.MaxValue;
return smoothTime / airControlPercentage;
}
private bool GroundCheck() // Player is grounded?
{
if (true)
return true;
return false;
}
Does someone knows what to do here?
It probably has something to do with your current gravity. Check in edit -> project settings -> physics the value of your gravity. In my case is -9,81. Change it to a higher value and see what happens.
I finally got it. How to fix it:
In this line of code
playerRigid.velocity = transform.forward * currentMovementSpeed + Vector3.up * playerRigid.velocity.y * Time.deltaTime;
Take out
* Time.deltaTime
Now the player is falling correctly.
Actually , transform.forward effect the y component of the body thus effects the gravity acting on the body.
Use
rb.velocity = new Vector3(horizontal , -1 , vertical) * speed ; .
It will work, or simply use AddForce to drive the player.
when you want to use gravity calculations, changing the rigidbody in your code can do this.
//rb.velocity = moveInput * moveSpeed;
for example will screw with your movement, even when a button isn't being pressed.
using something like:
if(Input.GetButtonDown("Jump") && Mathf.Abs(rb.velocity.y) < 0.001f)
{
rb.AddForce(new Vector2(0, jumpForce), ForceMode2D.Impulse);
}
will simply add forces on top of the calculations, instead of changing them prior to
In my case, the slow descending of my game character was solved by eliminating unnecessary calls to the physics system in the FixedUpdate() function. For example, when a joystick's X-axis and/or Y-axis are in the zero position.
I call addForce, velocity, rb transforms, etc. only if the absolute joystick value (- and +) exceeds a minimum value, in my case 0.04. Without these tests, these physics calls are done every time FixedUpdate() is called. This seems to overload the physics system, because at the same time, physics is also processing gravity etc.
Note that merely setting the joystick's dead zones in the Unity Input System doesn't solve this problem.
void FixedUpdate()
{
if (Mathf.Abs(stick.x) > 0.04) // prevent unnecessary physics call.
{
rb.transform.eulerAngles = rb.transform.eulerAngles - new Vector3(0, stick.x * Time.deltaTime * RotationSpeed * -1, 0);
}
if (Mathf.Abs(stick.y) > 0.04) // prevent unnecessary physics call.
{
rb.velocity = transform.forward * stick.y * Speed * Time.deltaTime;
}
}

How can i move a cylinder right and left?

Between two points or only to the left nonestop or only to the right nonestop.
In this code i spin the cylinder but i can't move it to the sides:
using UnityEngine;
using System.Collections;
public class MakeTwoPoints3D : MonoBehaviour
{
public float speed = 10f;
public float delta = 15.5f; // Amount to move left and right from the start point
public float moveSpeed = 5.0f;
private Vector3 startPos;
void Start()
{
startPos = transform.position;
}
void Update()
{
transform.Rotate(Vector3.up, speed * Time.deltaTime);
transform.position += transform.right * Time.deltaTime * moveSpeed;
}
}
If i make transform.right it will move the cylinder in circle on place up and down in circle. If i make transform.up it will move it to me i mean like forward but to the camera but at least it will move it. And if i make transform.Forward again it will make circles and will remove the cylinder in circles up down.
I can't figure out how to move it to the sides.
You need use Vector3.right instead of transform.right.
void Update()
{
transform.Rotate(Vector3.up, speed * Time.deltaTime);
transform.position += Vector3.right * Time.deltaTime * moveSpeed;
}
When you use transform.right, the Vector3 will adopt the local rotations of that object's transform. Meaning, if the object was rotated 45 degrees around the Y axis, your transform.right vector would be on an angle. If you keep translating an object along it's local axis while you rotate it, it will travel in a circle.
On the other hand, Vector3.right is always in world space so it will always face "true" right.

Categories