I'm creating a movement function for my character(which I've done many times but this time it's not working correctly) and here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(Animator))]
public class Movement : MonoBehaviour {
public CharacterController controller;
public float moveSpeed;
public float jumpForce;
public float gravityScale;
public Animator animator;
private bool shiftPressed = false;
private void Update()
{
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
shiftPressed = true;
else
shiftPressed = false;
if(shiftPressed)
{
moveSpeed = 20f;
} else
{
moveSpeed = 10f;
}
Vector3 moveDirection = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, 0.0f, Input.GetAxis("Vertical") * moveSpeed);
if(Input.GetKey(KeyCode.Space) && controller.isGrounded)
{
moveDirection.y = jumpForce;
}
if (moveDirection != Vector3.zero)
animator.SetFloat("Speed", moveSpeed);
else if (moveDirection == Vector3.zero)
animator.SetFloat("Speed", 0f);
else if (moveDirection != Vector3.zero)
animator.SetFloat("Speed", moveSpeed);
if(moveDirection != Vector3.zero)
transform.rotation = Quaternion.LookRotation(moveDirection);
moveDirection = Camera.main.transform.TransformDirection(moveDirection);
moveDirection.y = moveDirection.y + (Physics.gravity.y * Time.deltaTime * gravityScale);
controller.Move(moveDirection * Time.deltaTime);
}
}
As you can see that there is no function to go up in the y axis except the jump function. Mysteriously, when I press the 'S' key or 'downArrow' the player moves -z as he should but ironically he moves in +y axis as well. To ensure there is no y axis function I tried making jump function a comment but did the same way still. I thought it might be some character specific problem so I tried adding the code to a cube(thinking it to be my animation mistake) but it didn't helped at any point. I ensured the character controller is set nicely(collider and stuff); I've attached screenshots.
Please help!
Thanks in advance.
The problem has already been stated by several here, but it seems you still do not understand the issue, concluding from your reactions.
This line will always make your character move up.
moveDirection.y = moveDirection.y + (Physics.gravity.y * Time.deltaTime * gravityScale);
You are trying to use gravity (which is a force) in conjunction with manipulating transform. In Unity, you either do one of the two, not both. This will lead to undesired and hard to fix results.
If you want to use forces in your code, then i suggest the follow:
Add a RigidBody to your character. Check the "use gravity" checkbox.
Get the RigidBody in your controller script by calling and add force to it to move it.
var rb = getComponent<RigidBody>();
rb.AddForce(10f);
Do note that if you add force, you can add it continuosly in the Update method, or just once by passing a second paramater "forcemode".
rb.AddForce(10, ForceMode.Impulse); // add instant force, using mass
// Or
rb.AddForce(10, ForceMode.VelocityChange); // add instant force, ignoring mass
// Or
rb.AddForce(10, ForceMode.Force); // add continuous force, using mass
// Or
rb.AddForce(10, ForceMode.Acceleration); // add continous force, ignoring mass
Let me guess.. your character keeps moving up by about the current downwards slope of the camera?
As your code stands, as an example, if your Camera's is Vector3(10,0,0) and if you're trying to move Vector3(5, 0, 5), you've asked the movement vector to be transformed to world space, based off of the camera transform. So, your new movement vector will be something like Vector3(5,1,5). This should do the trick:
var worldDirection = Camera.main.transform.TransformDirection(moveDirection);
moveDirection = new Vector3(
worldDirection.x,
moveDirection.y + (Physics.gravity.y * Time.deltaTime * gravityScale),
worldDirection.z );
moveDirection.y = moveDirection.y + (Physics.gravity.y * Time.deltaTime * gravityScale);
This line always sets "y", and is modified/set as the last function prior to the ultimate statement. It is here, you should validate and verify all factors that has influence the final calculation of "y".
You must validate that each of the variables are calculated to your expected values:
moveDirection.y
Physics.gravity.y
Time.deltaTime
gravityScale
Each will influence the final value of moveDirection.y. Once you have verified each individual value, the final y value will make sense to you. If any of these values are not what you expect, you have a bug in the calculation of that variable.
Happy hunting!
Related
I was attempting to put simple movement into a project and for some reason this has caused the object its applied to to fall extremely slow. I am using the newer input system and I haven't really been using it previously so I'm unsure if it's an error regarding that.
The movement is working as intended so far. Gravity is at default in settings.
public class Movement : MonoBehaviour
{
public Rigidbody2D rb;
public float moveSpeed = 4f;
public InputAction playerControl;
Vector2 moveDirection = Vector2.zero;
private void OnEnable()
{
playerControl.Enable();
}
private void OnDisable()
{
playerControl.Disable();
}
// Update is called once per frame
void Update()
{
moveDirection = playerControl.ReadValue<Vector2>();
}
private void FixedUpdate()
{
rb.velocity = new Vector2(moveDirection.x * moveSpeed, moveDirection.y * moveSpeed);
}
}
This is what I have applied to the player object so far. When actually moving there is no issue, but falling doesn't work as intended
In FixedUpdate, you set the velocity of the RigidBody, including the y component. This does not interact well with gravity.
Gravity decreases the vertical speed of the RigidBody2D to make the object fall. Meanwhile, your code erases these changes each frame, which means that it cannot accelerate downwards, leading to it falling very slowly and at a constant speed (rather than accelerating downwards as expected).
If you have complete control over your vertical movement, how would gravity work? If the player is not meant to be able to control their vertical movement, change the line to:
rb.velocity = new Vector2(moveDirection.x * moveSpeed, rb.velocity.y);
This will fix the issue but will remove your vertical control. Is this what you want?
If you want to keep vertical movement but not overwrite gravity, you have to make some kind of compromise. If you want gravity to act whenever you are not controlling your character's vertical movement, you can do something like this:
if (moveDirection.y > 0.001)
{
rb.velocity = new Vector2(moveDirection.x * moveSpeed, moveDirection.y * moveSpeed);
}
else
{
rb.velocity = new Vector2(moveDirection.x * moveSpeed, rb.velocity.y);
}
You can also add the vertical movement to your vertical speed. This will mean that the player does not have complete control over their vertical speed like their horizontal speed, but rather being able to apply a force against it.
rb.velocity = new Vector2(moveDirection.x * moveSpeed, rb.y + moveDirection.y * verticalMoveSpeed);
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
public Rigidbody rb;
public float MouseSensitivity;
public float MoveSpeed;
public float jumpForce;
void Start ()
{
}
void Update()
{
//Look around
rb.MoveRotation(rb.rotation * Quaternion.Euler(new Vector3(0, Input.GetAxis("Mouse X") * MouseSensitivity, 0)));
//Move
rb.MovePosition(transform.position + (transform.forward * Input.GetAxis("Vertical") * MoveSpeed) + (transform.right * Input.GetAxis("Horizontal") * MoveSpeed));
//Jump
if (Input.GetKeyDown("space"))
{
print("clicked");
rb.AddForce(Vector3.up * jumpForce);
}
}
}
this is my code and a picture of the player object when I'm trying to jump it doesn't work but it does print clicked I tried to do many things but nothing worked so if you know how to solve the issue please tell me
RigidBody.AddForce has a second parameter of type ForceMode that defaults to ForceMode.Force. That particular ForceMode is only good for continual application of force (like a rocket's thruster). For a feature like jumping, you'll either want to use ForceMode.Impulse or ForceMode.VelocityChange.
// Pick one or the other
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
rb.AddForce(Vector3.up * jumpForce, ForceMode.VelocityChange);
Also, make sure your jumpForce value isn't tiny or it'll be an unnoticeably small "jump."
Firstly, physics calculations should generally be calculated inside of FixedUpdate(). This is described in the unity documentation here.
Edit: To make it more clear for the comment on my post. Input should be located inside of the Update() method whilst physics calculations should generally be calculated inside of the FixedUpdate() method.
If it is decided that you want to register input inside of Update() and physics calculations, based on that input, inside of FixedUpdate() then you would use a boolean switch.
Looking at your code I would say that either:
The mass of your Rigidbody is high and your jumpForce variable is too low, trying increasing the value of the jumpForce variable to see if the GameObject moves.
Your Rigidbody has the Is Kinematic checkbox selected.
AddForce is defaulting the ForceMode to ForceMode.Force, try using a different force mode like ForceMode.Impulse to deliver a quick force to the GameObject. In your case this would look like rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
Hope this helps.
I should say that I have very very little C# and Unity experience. I got most of this code from a Brackeys tutorial.
So, this code originally just made the player move at a set speed. So, I added a new public float set to a higher speed and set an if statement to change the value of the float that controls the speed (the float is literally named speed). I added a Debug.Log to display if the if statement is triggered/what the value of the speed float is. This log entry always displays once the Lshift key is pressed (default control axes have Fire3 set to Lshift inside of the unity project settings). I think my issue is that my speed is somehow decreasing before the player even moves. Additionally, this is probably the worst way to implement a sprint function, so if anyone has any better ideas, please let me know!
Clarification: The player can move. My intended effect is for the sprint key (Lshift) to be held down to achieve the sprinting effect. I did intend for the speed to reset every frame, so that as soon as the Lshift key is let go, the speed of the player will drop down to the normal state (12f). Currently I have a Debug.Log in place that displays the value of the "speed" float whenever the Lshift key is pressed. This always returns 18 in the console, which is the intended effect. However, even though this number is displayed in the console, there is no actual movement speed change in the player.
public CharacterController controller;
public float speed = 16f;
public float gravity = -9.81f;
public float jumpHeight = 3f;
public float sprintspeed = 18f;
public Transform groundCheck; //this is where the groundcheck empty object goes
public float groundDistance = 0.4f;
public LayerMask groundMask; //make sure to add a layer into the unity project called "ground"
Vector3 velocity;
bool isGrounded;
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask); //this just creates a sphere and checks it's collision state with any other objects
if(isGrounded && velocity.y < 0)
{
velocity.y = -2f; //sets velocity to a low static number.
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
speed = 12f;
if(Input.GetButtonDown("Fire3")) //theoretically increases the speed float only when left control is pressed down
{
speed = sprintspeed;
Debug.Log(speed);
}
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
if(Input.GetButtonDown("Jump") && isGrounded)//jump function below
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
Thanks in advance!
I would look to see what values are in the inspector since both speed and sprintspeed are public. There is a chance that sprintspeed might be set to 12f and therefore not change the speed. Also, keep in mind that with your implementation you can't change the speed variable from the inspector since you're updating it back to 12f every frame.
If that doesn't help with anything, perhaps some clarification is needed. Is your player moving at all? Is it just the sprinting that isn't working? What value does your Debug.Log give you? What are the values in the inspector?
I've been programming like an hour or so, then i realice that in unity 5 the charactercontroller.isGrounded doesn't work. Could anyone give me a answer?
This is the code i had
public float playerSpeed = 3f;
public float realSpeed = 3f;
public float jumpSpeed= 7f;
public float sprintSpeed= 5f;
public float gravity = 20f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
CharacterController CC = GetComponent<CharacterController>();
if(Input.GetKey(KeyCode.W)){
transform.Translate(Vector3.forward * playerSpeed* Time.deltaTime);
}
if(Input.GetKey(KeyCode.S)){
transform.Translate(Vector3.back * playerSpeed* Time.deltaTime);
}
if(Input.GetKey(KeyCode.D)){
transform.Translate(Vector3.right * playerSpeed* Time.deltaTime);
}
if(Input.GetKey(KeyCode.A)){
transform.Translate(Vector3.left * playerSpeed* Time.deltaTime);
}
if(Input.GetKey(KeyCode.Space) && CC.isGrounded){
transform.Translate(Vector3.up * jumpSpeed* Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftShift)) {
playerSpeed = sprintSpeed;
} else {
playerSpeed = realSpeed;
}
}
}`
So you're trying to make your character jump but only when it's on the ground?
I had this problem before a well. My solution was to make an empty gameobject and place it as a child of your character and a little bit and then put a collider as a trigger on your empty object.
Then you can have collision detection on your empty object to detect whether it is ontriggerstay on just the bottom side. It also compensates for little bumps and stuff.
According to your code you are not using any character controller. You are just changing the position of Object by using translate which will never collide with your ground. Where as to use character controller you have to provide a move direction with gravity to character controller so that its will use character controller to move your player. Gravity vector will pull your character downward and collide with ground then isGrounded will be true. Check Character Controller implementation in this unity script reference for detail.
Does anyone have a good jumping script for 2d games in unity? The code I have works but still is far from jumping, it looks like it is flying.
using UnityEngine;
using System.Collections;
public class movingplayer : MonoBehaviour {
public Vector2 speed = new Vector2(10,10);
private Vector2 movement = new Vector2(1,1);
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
float inputX = Input.GetAxis ("Horizontal");
float inputY = Input.GetAxis ("Vertical");
movement = new Vector2(
speed.x * inputX,
speed.y * inputY);
if (Input.GetKeyDown ("space")){
transform.Translate(Vector3.up * 260 * Time.deltaTime, Space.World);
}
}
void FixedUpdate()
{
// 5 - Move the game object
rigidbody2D.velocity = movement;
//rigidbody2D.AddForce(movement);
}
}
Usually for jumping people use Rigidbody2D.AddForce with Forcemode.Impulse. It may seem like your object is pushed once in Y axis and it will fall down automatically due to gravity.
Example:
rigidbody2D.AddForce(new Vector2(0, 10), ForceMode2D.Impulse);
The answer above is now obsolete with Unity 5 or newer. Use this instead!
GetComponent<Rigidbody2D>().AddForce(new Vector2(0,10), ForceMode2D.Impulse);
I also want to add that this leaves the jump height super private and only editable in the script, so this is what I did...
public float playerSpeed; //allows us to be able to change speed in Unity
public Vector2 jumpHeight;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
transform.Translate(playerSpeed * Time.deltaTime, 0f, 0f); //makes player run
if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space)) //makes player jump
{
GetComponent<Rigidbody2D>().AddForce(jumpHeight, ForceMode2D.Impulse);
This makes it to where you can edit the jump height in Unity itself without having to go back to the script.
Side note - I wanted to comment on the answer above, but I can't because I'm new here. :)
Use Addforce() method of a rigidbody compenent, make sure rigidbody is attached to the object and gravity is enabled,
something like this
gameObj.rigidbody2D.AddForce(Vector3.up * 10 * Time.deltaTime); or
gameObj.rigidbody2D.AddForce(Vector3.up * 1000);
See which combination and what values matches your requirement and use accordingly.
Hope it helps