Whenever I'm running against a wall, like if there is a wall to my left and I hold 'a' against the wall it kinda spazes out. It looks like the character is going in and out of the wall. Hopefully that made sense and you know what I'm talking about. So my question is how could I fix this so that when I am actively running into a wall it doesnt do that and instead the character is just there against the wall and appearing to move at all.
code for the movement:
void Update()
{
var movement = Input.GetAxis("Horizontal");
transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * MovementSpeed;
if (Input.GetButtonDown("Jump") && Mathf.Abs(_rigidbody.velocity.y) < .001f)
{
_rigidbody.AddForce(new Vector2(0, JumpForce), ForceMode2D.Impulse);
}
}
Setting the transform.position literally teleports the player, so it sometimes teleports them into the wall then they get pushed back.
To prevent that i suggest using the rigidbody's movePosition function. This takes into account physics while moving, so it interacts with the other objects that are there.
To change your current code to that it would be something like this:
void Update()
{
var movement = Input.GetAxis("Horizontal");
//This moves the GameObject to the currentPosition + The move direction. Which means to move it in the direction that you intended to move in.
_rigidbody.MovePosition(transform.position + new Vector3(movement, 0, 0) * Time.deltaTime * movementSpeed);
if (Input.GetButtonDown("Jump") && Mathf.Abs(_rigidbody.velocity.y) < .001f)
{
_rigidbody.AddForce(new Vector2(0, JumpForce), ForceMode2D.Impulse);
}
}
However i suggest splitting it into this:
float movement = 0f; //Setting a default value.
void Update()
{
movement = Input.GetAxis("Horizontal"); //Getting movement input from player
if (Input.GetButtonDown("Jump") && Mathf.Abs(_rigidbody.velocity.y) < .001f)
{
_rigidbody.AddForce(new Vector2(0, JumpForce), ForceMode2D.Impulse);
}
}
private void FixedUpdate()
{ //Moving in Physics update
_rigidbody.MovePosition(transform.position + new Vector3(movement, 0, 0) * Time.deltaTime * movementSpeed);
}
Because Update checks every frame, so its good for checking input, however you should apply physics in FixedUpdate(), because that is applied whenever there is a physics update (Or physics frame). (For even more smoothness!)
Related
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.
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.
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.
[EDIT] Changed title due to additional issues.
Whenever player moves, it draws arc to move. Whenever player jumps, camera controller zooms in first and then zoom out trying to fix its position. I want it to stay zoomed out while jumping (just realized how huge work this question could become...with "unless colliding or interfered its view with other objects"). I also want it to move, well, properly. (Just by movement without additional line of code related to camera script works perfect)
My player controller is default character controller script from Unity Documentation. My camera controller is based on youtube video. I know why it's causing trouble because I used different character controller than the tutorial used but that's because his character controller didn't work with mine. So I'm trying to fix while having default character controller.
[EDIT] After looking into the script for sometime I was able to narrow it down to one of possible culprits.
Vector3 camVel = Vector3.zero;
void MoveToTarget()
{
targetPos = target.position + position.targetPosOffset;
destination = Quaternion.Euler (orbit.xRotation, orbit.yRotation + target.eulerAngles.y, 0) * -Vector3.forward * position.distanceFromTarget;
destination += targetPos;
if (collision.colliding)
{
////from here
adjustedDestination = Quaternion.Euler (orbit.xRotation, orbit.yRotation + target.eulerAngles.y, 0) * Vector3.forward * position.adjustmentDistance;
adjustedDestination += targetPos;
if (position.smoothFollow)
{
//use smooth damp function
////to here makes weird behavior. Found out with debug.log line.
transform.position = Vector3.SmoothDamp(transform.position, adjustedDestination, ref camVel, position.smooth);
}
else
transform.position = adjustedDestination;
}
else
{
if (position.smoothFollow)
{
//use smooth damp function
transform.position = Vector3.SmoothDamp(transform.position, destination, ref camVel, position.smooth);
}
else
transform.position = destination;
}
}
target is getting reference from TPController, which is character controller below. Though I still don't understand why this is happening (It didn't happen in tutorial video). Unless...my character controller is somehow interfering with camera controller.
public Quaternion TargetRotation
{
get { return targetRotation; }
}
void Start() {
targetRotation = transform.rotation;
}
void Update() {
Movement ();
Turn ();
}
void Movement()
{
CharacterController controller = GetComponent<CharacterController>();
if (controller.isGrounded) {
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton("Jump"))
moveDirection.y = jumpSpeed;
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
void Turn()
{
if (Mathf.Abs (Input.GetAxis("Horizontal")) > inputDelay)
{
targetRotation *= Quaternion.AngleAxis (rotateVel * Input.GetAxis("Horizontal") * Time.deltaTime, Vector3.up);
}
transform.rotation = targetRotation;
}
disabling Turn() does allow character to move without drawing arc. But then camera doesn't turn around as character turns. ///this arc movement part is solved - leaving it here for future reference in case any one tries similar method: in the section of
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
put 0 instead of Input.GetAxis("Horizontal"). Should be able to move without drawing arc.
Thanks for help in advance.
I'm trying to add jumping to the controls of our control script but it just doesn't work yet and I'm getting kind of frustrated because I tried a lot to make it work. I don't use rigidbodies and rather want to use script based physics and - but later - raycasts (to detect ground). It's 3D but with a fixed perspective because the characters are sprites (we are thinking about trying a style similar to Don't Starve, Paper Mario etc.). And the thing I want to put in for now is to jump upwards when the character stands still and later on jumps that also let the character travel a bit of distance when the character moves. Well, you get the picture. For that I first need to get jumping working at all - and also gravity to put the character back down while also considering that the character could land on a ground that has a different height than the starting ground.
What happens now is that the character jumps just a tiny little bit, like not even a hop, and then falls down endlessly - or goes up endlessly when jump is pressed again. So, how do I fix that?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Controls3D : MonoBehaviour
{
public float player3DSpeed = 5f;
private bool IsGrounded = true;
private const float groundY = (float) 0.4;
private Vector3 Velocity = Vector3.zero;
public Vector3 gravity = new Vector3(0, -10, 0);
void Start()
{
}
void Update()
{
if (IsGrounded)
{
if (Input.GetButtonDown("Jump"))
{
IsGrounded = false;
Velocity = new Vector3(Input.GetAxis("Horizontal"), 20, Input.GetAxis("Vertical"));
}
Velocity.x = Input.GetAxis("Horizontal");
Velocity.z = Input.GetAxis("Vertical");
if (Velocity.sqrMagnitude > 1)
Velocity.Normalize();
transform.position += Velocity * player3DSpeed * Time.deltaTime;
}
else
{
Velocity += gravity * Time.deltaTime;
Vector3 position = transform.position + Velocity * Time.deltaTime;
if (position.y < groundY)
{
position.y = groundY;
IsGrounded = true;
}
transform.position = position;
}
}
}
If i were you, i think i wouldve changed the whole thing into a character controller, as this simplifies the process, a ####ton :P
If you figure out you do want to use the CC. This is the solution i usually use:
CharacterController controller = GetComponent<CharacterController>();
// is the controller on the ground?
if (controller.isGrounded)
{
//Feed moveDirection with input.
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
//Multiply it by speed.
moveDirection *= speed;
//Jumping
if (Input.GetButton("Jump"))
moveDirection.y = jumpSpeed;
}
//Applying gravity to the controller
moveDirection.y -= gravity * Time.deltaTime;
//Making the character move
controller.Move(moveDirection * Time.deltaTime);
moveDirection is a Vector3 Type variable, and speed and jumpSpeed are public float values used to modify the speed.
Please NOTE: Character Controllers, let you program your own Physics.