Unity 2D: Rigidbody2D.velocity doesn't move character - c#

I was making a 2D player controller and it worked until the day after I made a follow camera script, and now my character can't move but the animation still works. I tried using AddForce() instead of changing Rigidbody2D.velocity but that didn't work either, and after 2 or 3 days I still couldn't find a solution. Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
Rigidbody2D rb2d;
Animator animator;
SpriteRenderer spriteRenderer;
float direction;
public float speed;
// Start is called before the first frame update
void Start()
{
direction = Input.GetAxisRaw("Horizontal");
animator = GetComponent<Animator>();
rb2d=GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
}
void Update()
{
transform.position = new Vector3(Mathf.Clamp(transform.position.x, -199, 197),
transform.position.y, transform.position.z);
if ((Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) && ((Input.GetKey("right") || Input.GetKey("d")) || Input.GetKey("left") || Input.GetKey("a")))
{
speed = 20f;
run();
}
else if (!(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) && (Input.GetKey("right") || Input.GetKey("d")))
{
speed = 10f;
walk();
}
else if (!(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) && (Input.GetKey("left") || Input.GetKey("a")))
{
speed = 10f;
walk();
}
else
{
speed = 0f;
animator.Play("Player_idle");
}
}
void walk()
{
if (speed > 0) {
animator.Play("Player_walk_right");
}
else if (speed < 0)
{
animator.Play("Player_walk_left");
}
//rb2d.AddForce(new Vector2(speed * direction * Time.deltaTime, 0));
rb2d.velocity = new Vector2(speed * direction * Time.deltaTime, rb2d.velocity.y);
Debug.Log(rb2d.velocity);
}
void run()
{
if (speed > 0)
{
animator.Play("Player_run_right");
}
else if (speed < 0)
{
animator.Play("Player_run_left");
}
//rb2d.AddForce(new Vector2(speed * direction * Time.deltaTime, 0));
rb2d.velocity = new Vector2(speed * direction * Time.deltaTime, rb2d.velocity.y);
Debug.Log(rb2d.velocity);
}
}
Here is an image of the inspector
If someone could help that would be appreciated.

If we look at your code, the problematic statement should be here:
rb2d.velocity = new Vector2(speed * direction * Time.deltaTime, rb2d.velocity.y);
One of these three variables must be zero to cause your problem.
Potential Problem 1: direction
You seem to only be setting direction once, in Start():
direction = Input.GetAxisRaw("Horizontal");
You are probably not pressing any keys/moving any joysticks the frame that the scene starts up. That means direction ends up being 0 and is never changed again.
Either change your line to
rb2d.velocity = new Vector2(speed * Time.deltaTime, rb2d.velocity.y);
(excluding direction) or move the direction assignment statement to your Update() method.
Potential Problem 2: Time.deltaTime
As said by #Daniel in the comments, the Time.deltaTime statement might be problematic.
Check your project settings/other scripts to make sure Time.timeScale is not equal to zero.
You could remove Time.deltaTime if #1 doesn't work, but I agree with you that the statement should be in there to keep the game consistent across framerates. Try changing Update() to FixedUpdate(); if you do this you will need to use Time.fixedDeltaTime instead.
How to debug in the future
To debug this problem in the future, try inserting a breakpoint at the problematic line and attaching your IDE to Unity. If you hover over each of the variables, you should be able to see which variable is equal to zero.

Related

Unable to patrol enemies

I just can’t figure out how to make random points for patrolling, I went through 100 manuals, but I can’t do it.
No need to write about NavMeshAgent. Not used.
using System.Collections;
using UnityEngine;
public sealed class Manikin : MonoBehaviour {
private Vector3 StartManikin = Vector3.zero,
NewPosition = Vector3.zero;
private readonly float Speed = 2.0f;
void Start() {
StartManikin = transform.position;
}
void Update() {
if (Vector3.zero == NewPosition) {
NewPosition = StartManikin + Random.onUnitSphere * 2;
}
if (Vector3.Distance(transform.position, NewPosition) < 0.1f) {
StartManikin = transform.position;
NewPosition = Vector3.zero;
} else {
transform.LookAt(new Vector3(NewPosition.x, StartManikin.y, NewPosition.z));
transform.position = Vector3.MoveTowards(transform.position, NewPosition, Speed * Time.deltaTime);
}
}
}
The problem is that there may be obstacles in the form of a fence, a tree, houses, cars, etc.
I need that when the enemy appears, random points are generated in his radius so that he does not leave further.
Help me out, I can’t figure out what needs to be done to make everything work ...
It turns out that I just did not see that the Pivot of the model is not clear where, it flies in another dimension, the problem is solved, it is necessary to reset all transformations and the world point of the model's coordinates.
I didn’t see it right away, all the options turned out to be working ...
And also, it was necessary to fix the problem with the take-off along the y-axis, so that this does not happen, you need to look at the bottom point of the object from which we will spawn the coordinate for it.
if (Vector3.zero == NewPosition) {
NewPosition = StartManikin + (Random.onUnitSphere * 5);
NewPosition.y = transform.GetComponent<CapsuleCollider>().bounds.min.y;
}
if (Vector3.Distance(transform.position, NewPosition) < 0.1f) {
StartManikin = transform.position;
NewPosition = Vector3.zero;
} else {
transform.LookAt(new Vector3(NewPosition.x, transform.position.y, NewPosition.z));
transform.position = Vector3.MoveTowards(transform.position, NewPosition, Speed * Time.deltaTime);
}

Why is my character's horizontal velocity lost when jumping?

GOAL
I'm relatively new to Unity and I want my character to be able to run and jump at the same time causing the character to go up diagonally.
PROBLEM
However after making some adjustments to give the character some acceleration, the jump seems to clear all existing velocity, meaning the character goes up and then to the side instead of both at the same time:
(I apologise if its a bit hard to see)
CODE
This is my character movement script:
Rigidbody2D rb;
BoxCollider2D bc;
[Header("Run")]
float xInput = 0f;
public float maxRunSpeed;
public float acceleration;
[Space]
[Header("Jump")]
public float jumpHeight;
public float lowJumpHeight;
public float fallSpeed;
public float airControl;
[Space]
public LayerMask groundLayer;
public bool onGround;
[Space]
public Vector2 bottomOffset;
public Vector2 boxSize;
public float coyoteTime;
void Start() {
// Gets a reference to the components attatched to the player
rb = GetComponent<Rigidbody2D>();
bc = GetComponent<BoxCollider2D>();
}
void Update() {
Jump();
// Takes input for running and returns a value from 1 (right) to -1 (left)
xInput = Math.Sign(Input.GetAxisRaw("Horizontal"));
}
// Applies a velocity scaled by runSpeed to the player depending on the direction of the input
// Increaces the velocity by accerleration until the max velocity is reached
void FixedUpdate() {
rb.velocity = Math.Abs(rb.velocity.x) < Math.Abs(xInput) * maxRunSpeed ? rb.velocity + new Vector2(acceleration * xInput, rb.velocity.y) * Time.deltaTime : new Vector2(xInput * maxRunSpeed, rb.velocity.y);
}
void Jump() {
// Checks whether the player is on the ground and if it is, replenishes coyote time, but if not, it starts to tick it down
coyoteTime = onGround ? 0.1f : coyoteTime - Time.deltaTime;
// Draws a box to check whether the player is touching objects on the ground layer
onGround = Physics2D.OverlapBox((Vector2)transform.position + bottomOffset, boxSize, 0f, groundLayer);
// Adds an upwards velocity to player when there is still valid coyote time and the jump button is pressed
if (Input.GetButtonDown("Jump") && coyoteTime > 0) {
rb.velocity = Vector2.up * jumpHeight;
}
// Increases gravity of player when falling down or when the jump button is let go mid-jump
if (rb.velocity.y < 0 ) {
rb.velocity += Vector2.up * Physics2D.gravity.y * (fallSpeed - 1) * Time.deltaTime;
} else if (rb.velocity.y > 0 && !Input.GetButton("Jump")) {
rb.velocity += Vector2.up * Physics2D.gravity.y * (lowJumpHeight - 1) * Time.deltaTime;
}
}
Sorry for there being a lot of unecessary code, it's just im not sure what's causing the issue so i don't want to remove anything. Hopefully my comments make some sense?
This is happening because you're setting the velocity of your rigidbody directly with rb.velocity = Vector2.up * jumpHeight. So that will wipe all existing velocity.
If you want to just add a force to the velocity rather than replacing it entirely, you can do that with methods like Rigidbody2D.AddForce.
While in all other cases you keep your velocity values and only slightly modify them you are hard overwriting the absolute velocity in
rb.velocity = Vector2.up * jumpHeight;
erasing any velocity on X.
You could simply keep whatever you have on the other axis and only overwrite Y like
var velocity = rb.velocity;
velocity.y = jumpHeight;
rb.velocity = velocity;
or
rb.velocity = new Vector2(rb.velocity.x, jumpHeight);
basically the same way you do it also in FixedUpdate for the horizontal direction.

Need advice about gameObject's rigidbody accesed by trigger

I'm trying to make jump pads for my platformer game in unity using c#.
I'm stumped, how do I add force to other gameObject using triggers?
tried using rb = gameobject.getcomponent<rigidbody> in void start, Didnt work.
this is my code closest of what I expect
public float force = 1500f;
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
other.GetComponent<Rigidbody>().AddForce(Vector3.up * force * Time.deltaTime);
Debug.Log("trigger!");
}
}
I expected if my player lands on the trigger it would launch him upwards, but it does not. I should also note that the console logs show "trigger!" so there is a mistake in and force.
No error messages.
Time.deltaTime is a very small number and you don't need it when the function is called once. You can also try other.GetComponent<Rigidbody>().AddForce(Vector3.up * force, ForceMode.VelocityChange);
You can read more about the AddForce method here: Rigidbody.AddForce
I know I am late, but you can try using your jump from the game. I mean you made the player jump if he presses space. You can reuse that.
That is my jump
private void Jump()
{
if (grounded && readyToJump)
{
readyToJump = false;
//Add jump forces
rb.AddForce(Vector2.up * jumpForce * 1.5f);
rb.AddForce(normalVector * jumpForce * 0.5f);
//If jumping while falling, reset y velocity.
Vector3 vel = rb.velocity;
if (rb.velocity.y < 0.5f)
rb.velocity = new Vector3(vel.x, 0, vel.z);
else if (rb.velocity.y > 0)
rb.velocity = new Vector3(vel.x, vel.y / 2, vel.z);
Invoke(nameof(ResetJump), jumpCooldown);
}
}
Now you can make something like this
private void OnCollisionEnter(Collision collision)
{
jumpPad JumpPad = collision.collider.GetComponent<jumpPad>();
if (JumpPad != null)
{
//Add jump forces
rb.AddForce(Vector2.up * jumpPadForce * 1.5f);
rb.AddForce(normalVector * jumpPadForce * 0.5f);
//If jumping while falling, reset y velocity.
Vector3 vel = rb.velocity;
if (rb.velocity.y < 0.5f)
rb.velocity = new Vector3(vel.x, 0, vel.z);
else if (rb.velocity.y > 0)
rb.velocity = new Vector3(vel.x, vel.y / 2, vel.z);
}
}
It is the simplest and quickest solution.
Just make a new jump force and called something like jump pad force.
That's it.

Unity: Diagonal movement not corresponding to correct key inputs

I've been trying to find a solution for this issue for a while now with no luck.
I want to be able to move in 8 directions but for some odd reason, my player only wants to move in 6 directions.
When I press:
W+D or W+A, it moves towards the top right.
S+D or S+A, it moves towards the bottom left.
The vertical and horizontal movements work perfectly fine. It's just two of the four diagonal movements which are being a pain.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControllerTest : MonoBehaviour
{
public float moveSpeed;
private Animator anim;
private Rigidbody2D playerRigidbody;
private bool playerMoving;
public Vector2 lastMove;
// Use this for initialization
void Start()
{
anim = GetComponent<Animator>();
playerRigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
playerMoving = false;
if (Input.GetAxisRaw("Horizontal") > 0.5f || Input.GetAxisRaw("Horizontal") < -0.5f)
{
playerRigidbody.velocity = new Vector2(Input.GetAxisRaw("Horizontal") * moveSpeed, playerRigidbody.velocity.y);
playerMoving = true;
lastMove = new Vector2(Input.GetAxisRaw("Horizontal"), 0f);
}
if (Input.GetAxisRaw("Vertical") > 0.5f || Input.GetAxisRaw("Vertical") < -0.5f)
{
playerRigidbody.velocity = new Vector2(playerRigidbody.velocity.y, Input.GetAxisRaw("Vertical") * moveSpeed);
playerMoving = true;
lastMove = new Vector2(0f, Input.GetAxisRaw("Vertical"));
}
if (Input.GetAxisRaw("Horizontal") < 0.5f && Input.GetAxisRaw("Horizontal") > -0.5f)
{
playerRigidbody.velocity = new Vector2(0f, playerRigidbody.velocity.y);
}
if (Input.GetAxisRaw("Vertical") < 0.5f && Input.GetAxisRaw("Vertical") > -0.5f)
{
playerRigidbody.velocity = new Vector2(playerRigidbody.velocity.x, 0f);
}
anim.SetFloat("MoveX", Input.GetAxisRaw("Horizontal"));
anim.SetFloat("MoveY", Input.GetAxisRaw("Vertical"));
anim.SetBool("PlayerMoving", playerMoving);
anim.SetFloat("LastMoveX", lastMove.x);
anim.SetFloat("LastMoveY", lastMove.y);
}
}
This is the basic code that I used for my character movement. If someone could help me fix this, it would be greatly appreciated.
Thanks,
Redza
The whole logic seems strange to me, I would make a single vector of movement
playerRigidbody.velocity = new Vector2(Input.GetAxisRaw("Horizontal") * moveSpeed, Input.GetAxisRaw("Vertical") * moveSpeed);
unless there are some other concerns.
It's possible that with so many conditions only last 2 of 4 are end being applied.
The mistake was with the code in the second "if" statement. I should have used playerRigidbody.velocity.x instead of playerRigidbody.velocity.y. Oopsies.

Make ball Jumping

I am trying to make a script where i can move a ball, horizontal and vertical. I managed to get that working.
But now I want to make my ball "jump". I ended with script below, but now my ball just get launched like a rocket xD
Can anyone help me out
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
public float speed;
public float jumpSpeed;
public GUIText countText;
public GUIText winText;
private int count;
void Start()
{
count = 0;
SetCountText();
winText.text = " ";
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0, moveVertical);
Vector3 jump = new Vector3 (0, jumpSpeed, 0);
GetComponent<Rigidbody>().AddForce (movement * speed * Time.deltaTime);
if (Input.GetButtonDown ("Jump"));
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "PickUp") {
other.gameObject.SetActive(false);
count = count +1;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if (count >= 10)
{
winText.text = "YOU WIN!";
}
}
}
Jumping does not work with adding a continuous force on an object. You will have to apply a single impulse to the object once when the jump button is first pressed. This impulse will also not include a time factor, because it is applied only once. So you would get something like this:
bool jumping;
if (Input.GetButtonDown ("Jump") && !this.jumping);
{
GetComponent<Rigidbody>().AddForce (jumpForce * new Vector3(0,1,0));
this.jumping = true;
}
Also note that in your example you are multiplying the upward unit vector by the jumpspeed twice. Once in the jump vector initialization and then once in the AddForce method.
Of course, you will also have to make sure that gravity applies to pull the object back down (and if the object hits the ground, reset the jump bool.
In general, depending on what kind of game you are making, it is easier to just set the velocity of the object yourself and don't work with the Unity physics engine to do some simple moving around.
There is an error in your code in the function FixedUpdate:
if (Input.GetButtonDown ("Jump"));
in that way you are applying a force on your object at every frame because the semicolon is excluding the row below from the condition. By removing the semicolon you will have a correct if implementation in case of a jump, as long as on your RigidBody component UseGravity is enabled.
if (Input.GetButtonDown ("Jump"))
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
Hope it helps.
Thanks everyone, it was a great help. I now have a jumping character. One who can only jump when grounded.
public bool IsGrounded;
void OnCollisionStay (Collision collisionInfo)
{
IsGrounded = true;
}
void OnCollisionExit (Collision collisionInfo)
{
IsGrounded = false;
}
if (Input.GetButtonDown ("Jump") && IsGrounded)
{
GetComponent<Rigidbody>().velocity = new Vector3(0, 10, 0);
}

Categories

Resources