Hiya all. I’m relatively new to Unity and C#. I have made some progress using add force to get basic movement. I dont know how to incorporate a max speed or a deceleration speed. Here is the code I have so far. does anyone have any suggestions on how I can achieve these functions? Any help would be appreciated
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rb;
[SerializeField] private float moveSpeed = 7;
[SerializeField] private float accel = 1;
[SerializeField] private float decel = 1;
private float dirX = 0f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
//Put non physics based movement in here
void Update()
{
dirX = Input.GetAxis("Horizontal");
}
//Put physics based movement in here
private void FixedUpdate()
{
if(dirX > 0f)
{
rb.AddForce(new Vector2(moveSpeed * accel, 0));
}
else if(dirX < -0f)
{
rb.AddForce(new Vector2(-moveSpeed * accel, 0));
}
else
{
rb.AddForce(new Vector2(0, 0));
}
}
}
If you move by adding force then you need to compute a drag that limits you, or else tone down the force as you reach the desired speed.
A better way is to set the velocity of the Rigidbody directly.
You can set it immediately, eg, no acceleration, or you can tween the velocity up from a current value to the desired value based on input. This is a handy and extremely-common pattern in gamedev:
Smoothing movement between any two particular values:
You have currentQuantity and desiredQuantity.
only set desiredQuantity
the code always moves currentQuantity towards desiredQuantity
read currentQuantity for the smoothed value
Works for floats, Vectors, Colors, Quaternions, anything continuous or lerp-able.
So where you have things like “desiredQuanity” and currentQuanity", are those values I would set for my moveSpeed and accel? (or should I be setting a maxMoveSpeed?) I’m just trying to work out how to implement it. Also, when it comes to adding drag, would I apply that in the deceleration phase? or does it need to be constantly added?
But now I’m getting an error and I don’t really understand what it means or how to solve it:
Assets\PlayerMovement.cs(41,65): error CS1503: Argument 2: cannot convert from ‘float’ to ‘UnityEngine.Vector2’
Any ideas whats causing it? I Know its complaining about a problem on this line:
currentVelocity = Vector2.MoveTowards( currentVelocity, maxMoveSpeed, accel * Time.deltaTime);
but not sure what
I’ve decided to go back to the AddForce method I was using previously for the movement. I was able to apply drag in a way that seems to be working very close to how I want it to work, and just needs a few tweaks. I seem to be having trouble with Jumping now.
Here is what I have so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[Header ("Components")]
private Rigidbody2D rb;
private CapsuleCollider2D capColl;
[Header ("Layer masks")]
[SerializeField] private LayerMask groundLayer;
[SerializeField] private LayerMask wallLayer;
[SerializeField] private LayerMask cornerCorrectLayer;
[Header ("Movement Variables")]
[SerializeField] private float moveSpeed = 7f;
[SerializeField] private float maxMoveSpeed = 10f;
[SerializeField] private float movementAcceleration = 1f;
[SerializeField] private float groundLinearDrag = 5f;
private float dirX = 0f;
private float dirY = 0f;
private bool changeDirection => (rb.velocity.x > 0f && dirX < 0f) || (rb.velocity.x < 0f && dirX > 0f);
[Header ("Jump Variables")]
[SerializeField] private float jumpForce = 10f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
capColl = GetComponent<CapsuleCollider2D>();
}
// Update is called once per frame
//Put non physics based movement here
void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
dirY = Input.GetAxisRaw("Vertical");
}
//Put physics based movement in here
private void FixedUpdate()
{
//Directional movement
if(dirX > 0f)
{
rb.AddForce(new Vector2(moveSpeed * movementAcceleration, 0));
}
else if(dirX < -0f)
{
rb.AddForce(new Vector2(-moveSpeed * movementAcceleration, 0));
}
else
{
rb.AddForce(new Vector2(0, 0));
}
if(Input.GetButtonDown("Jump"))
{
Jump();
}
}
private void ApplyGroundLinearDrag()
{
if (Mathf.Abs(dirX) < 0.4f || changeDirection)
{
rb.drag = groundLinearDrag;
}
else
{
rb.drag = 0f;
}
}
//Jump logic
private void Jump()
{
if (isGrounded())
{
rb.AddForce(new Vector2(rb.velocity.x, jumpForce));
}
}
private bool isGrounded()
{
RaycastHit2D raycastHit = Physics2D.BoxCast(capColl.bounds.center, capColl.bounds.size, 0, Vector2.down, 0.1f, groundLayer);
return raycastHit.collider != null;
}
}
Am I doing something wrong with how I’m getting the jump to work? because when I press jump in-game, it doesn’t seem to be doing anything
I take that back. It looks like groundLinearDrag isn’t actually doing anything and its th linear drag of th rigidbody thats doing the work. Is there a way I can get the ground linear drag to work properly?
In your case you have made desiredVelocity a float and then tried to use that to MoveTowards with a Vector2
This is just apples and oranges and will not work, which is what all of the links above point out.
Let’s review where #7 above stands.
You made desiredVelocity a float variable in your class and set it to 10. Do you perhaps mean to call that PlayerWalkSpeed or something else? That’s what it feels like.
You made dirX be the input from the player. That’s fine.
Now on this problematic line:
(which will not work because desiredVelocity is a float, NOT a Vector2)
Instead, to fix your code in #7 above:
use dirX (player input) and what you call desiredVelocity (probably better called PlayerWalkSpeed since it appears to be preset to 10), and create a new Vector2 to use for your MoveTowards:
Vector2 tempVector = new Vector2( dirX * desiredVelocity, 0);
// and now use this tempVector for our computations
currentVelocity = Vector2.MoveTowards(
currentVelocity, tempVector, acceleration * Time.deltaTime);
As I pointed out multiple times above, you don’t just try combinations. You reason about the data, the error, what you are trying to achieve, and you engineer a solution.
First, I’m sorry for talking back to you earlier, I’m just frustrated because it feels like nothing I do works.
I am genuinely more confused. I think I might need a fresh start on this project.
If I’m using dirx as an input for directional movement on the x axis, that’s ok. I think some of the confusion is coming from what terminology we are using.
Is my “moveSpeed” supposed to be what you are calling “currentVelocity”?
Is my “maxMoveSpeed” what you are referring to as “desiredVelocity”?
I know you’re saying to not get hung up on terminology, But that’s what makes sense in my head. Is there something wrong with the terminology I’m using and how C# reads what terms I’m using?
I think I need to start from a new script.
This is what I now have: