using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
public float movementSpeed;
public Rigidbody2D Rigidbody;
private Vector2 moveDirection;
public Transform Player;
void Start()
{
}
void Update()
{
ProcessInputs();
} void FixedUpdate()
{
move();
}
void ProcessInputs()
{
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");
moveDirection = new Vector2(moveX, moveY).normalized;
}
void move()
{
Rigidbody.velocity = new Vector2(moveDirection.x * movementSpeed, moveDirection.y * movementSpeed);
}
}
So i needed some tips so i thoght id ask here, i wanted to implement dashing in my Top-Down-Shooter but i didnt find any code on Youtube that would properly work with my code i have also tried moveing the players position +2 to the wanted direction but i couldnt work it out.
id be happy if yall could help me.
Nice that you are using FixedUpdate() for physics - many beginners use that wrong.
However do not set velocity manually. Use AddForce.
It will effectively set the velocity but automatically takes the objects mass into account and allows to speed up instead of instantly being at speed.
That is the more logical approach since you move in a direction by applying forces to your body.
For Dashing, you could add a significantly higher force for a small number of Physics frames (aka small number of FixedUpdate calls). You can use a countdown which you set to a number when the chaarcter hsould start dashing.
In the FixedUpdate you decrement the counter and as long as it is >0 you apply the dashing force.
Related
I'm trying to use rb.velocity in unity to make my 2D character jump. I have used Debug.Log() to check if unity registers the input, and it does. But it does not affect my character in game when pressing the button. Here's the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed = 5f;
public float jumpForce = 7f;
public Rigidbody2D rb;
Vector2 movement;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Space was pressed");
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
}
}
I have tried replacing the values with all sorts of things in the Vector2, but to no avail.
If your rigidbody is using gravity then in this case a small vertical velocity of 7f would be negated by gravity very quickly (less than a second). You can check this in the physics settings of your project or with Rigidbody.useGravity.
If you intend to use gravity then it is recommended to use Rigidbody.AddForce to add an upward force to the object and let gravity bring it back down - example SO answer here.
If you want to turn off gravity and not use AddForce then it would be best to either use Rigidbody.MovePosition or set Rigidbody.velocity, but not both.
For example:
void Update() {
movement = new Vector2(Input.GetAxisRaw("Horizontal") * moveSpeed, movement.y);
}
void FixedUpdate() {
if (Input.GetKeyDown(KeyCode.Space)) {
movement.y = jumpForce;
}
rb.velocity = movement;
}
But in that case you would have to manually figure out when the jump is complete and set a downwards velocity to bring it back to the ground yourself. If you want the easiest and most natural solution, then leveraging Unity's built-in physics with gravity and forces would be best.
Honestly, your code looks fine. I would move the Input.GetKeyDown check into Update instead of FixedUpdate. But other than that it looks good.
Instead, make sure your jumpForce is not 0. Just because you set the initial value in your script
public float jumpForce = 7f;
Doesn't mean that it is 7f. Check the script in the inspector and make sure it's not 0. Setting values on scripts like you did only sets the initial value. If you created the jump force variable before assigning 7 to it, it will still be 0. You have to set the variables in the inspector.
And if that doesn't work use:
rb.AddForce(jumpForce * Vector3.up, ForceMode.Impulse);
Instead of trying to manually set the velocity.
My movement is working fine without Time.deltaTime but when I add it to my player movement I can move left to right fine but I fall slowly and I cant jump
using Newtonsoft.Json.Bson;
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerMovement : MonoBehaviour
{
[SerializeField] private float horSpeed;
[SerializeField] private float vertSpeed;
private Rigidbody2D rb;
private Boolean isJumping;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
// we store the initial velocity, which is a struct.
var v = rb.velocity * Time.deltaTime;
if (Input.GetKey(KeyCode.Space) && !isJumping)
{
vf.y = vertSpeed;
isJumping = true;
}
if (Input.GetKey(KeyCode.A))
{
vf.x = -horSpeed;
}
if (Input.GetKey(KeyCode.D))
{
vf.x = horSpeed;
}
if (Input.GetKey(KeyCode.S))
{
vf.y = -vertSpeed;
}
rb.velocity = vf;
if(Input.GetKey(KeyCode.Escape))
SceneManager.LoadScene(0);
}
private void OnCollisionEnter2D(Collision2D collision)
{
isJumping = false;
}
}
I've added it to my enemy script and it works fine so im not sure whats different with player movement to using transform.position
Why would you multiply the velocity by Time.deltaTime?
This is used to convert a value from a "certain unit per frame" into a value "certain unit per second".
A velocity already IS a value in units per second.
Linear velocity of the Rigidbody in units per second.
=> It makes no sense to apply Time.deltaTime here at all.
For your X axis movement it doesn't make much difference since you anyway apply that velocity continuously every frame. Here you just would probably want to handle the case where neither left nor right is pressed and set vf.x = 0.
For the Y axis however you apply the jump only once, just to divide it by about 60 (or whatever your frame rate is) right in the next frame => you never give it the chance to fall or jump.
In general you should modify the Rigidbody in FixedUpdate. In your specific case it is fine to do this in Update, it is just redundant work ;)
Yes I know this question was asked before by SuperSonyk! That post is here:
Set rigidbody.velocity to direction of mouse in Unity2d
However- the link referenced in the answer to that post is now legacy material, and I can't bring myself to understand it in Unity's current version.
My Problem: In short, I want to make my player accelerate in the direction of my cursor. My game is currently a TOP-DOWN Space Shooter in 2D. My player already looks at my mouse correctly, using cam.ScreenToWorldPoint. But relentlessly trying to add force seems futile for me, since I am fairly new to coding.
If I have any other issues in my code, It would be great if anyone could point them out!
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
//================= MOVEMENT =====================
private float thrust = 0.5f;
private float maxSpeed = 10f;
public Rigidbody2D rb;
//================= AIMING =======================
public Camera cam;
Vector2 mousePos;
// Update is called once per frame: Good for INPUTS
void Update()
{
//aiming
mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
}
// Called Set amount of times. Good for PHYSICS CALCULATIONS
void FixedUpdate()
{
Move();
speedLimiter();
//aim
Vector2 lookDirection = mousePos - rb.position;
float angle = Mathf.Atan2(lookDirection.y, lookDirection.x) * Mathf.Rad2Deg - 90f;
rb.rotation = angle;
}
//======= MY MOVE FUNCTION DOES NOT WORK. HELP? ======
void Move()
{
if (Input.GetButtonDown("Accelerate"))
{
rb.velocity = new Vector3(0, thrust, 0) * Time.deltaTime;
}
}
void speedLimiter()
{
if (rb.velocity.magnitude > maxSpeed)
{
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
}
}
}
Please summarize the edits clearly, thank you!
In general since this is a 2D rigidbody also the velocity is a Vector2 and you should probably rather use Vector2.ClampMagnitude
and then in
rb.velocity = new Vector3(0, thrust, 0) * Time.deltaTime;
do you only want to move in global Y direction? Also a velocity is already a "per second" value -> it makes no sense to multiply by Time.deltaTime if you reassign a new velocity. Since it says thrust I guess you rather wanted to add to the existing velocity.
What you would rather do is save your mouse direction you already have and do
public class PlayerController : MonoBehaviour
{
...
void FixedUpdate()
{
// I would update the aim BEFORE moving
// Use a NORMALIZED direction! Makes things easier later
Vector2 moveDirection = (mousePos - rb.position).normalized;
float angle = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg - 90f;
rb.rotation = angle;
// OPTIONAL: Redirect the existing velocity into the new up direction
// without this after rotating you would still continue to move into the same global direction
rb.velocity = rb.velocity.magnitude * moveDirection;
Move(moveDirection);
speedLimiter();
}
void Move(Vector2 moveDirection)
{
if (Input.GetButtonDown("Accelerate"))
{
// Instead of re-assigning you would probably add to the existing velocity
// otherwise remove the "+" again
rb.velocity += moveDirection * thrust * Time.deltaTime;
}
}
void speedLimiter()
{
if (rb.velocity.magnitude > maxSpeed)
{
// You are working with Vector2 so use the correct method right away
rb.velocity = Vector2.ClampMagnitude(rb.velocity, maxSpeed);
}
}
}
You already have half of the work by having your player looking at the mouse. We will be using the vector lookDirection as the direction of the movement for the player, normalize it so its length is 1 and multiply it by thrust. This way, we have a vector in the direction of the mouse and of length thrust as intended.
void Move()
{
if (Input.GetButtonDown("Accelerate"))
{
Vector2 lookDirection = (mousePos - rb.position);
rb.AddForce(lookDirection.normalized * thrust);
}
}
Note that we work here with Vector2 since you are using a Rigidbody2D.
Also, I don't think that using Time.DeltaTime is relevant here. When you apply force to a physic object, you don't need to use it, by definition, the function FixedUpdate() has a fixed frequency. If you look at one of Unity's tutorial, you can see that they don't multiply it by Time.DeltaTime
Last tip: you may want to be playing around with the drag property of your Rigidbody2D to have your player slow down over time when not accelerating, otherwise, it will be sliding out of control and the player won't be able to stop it.
Don't hesitate to tell me if my answer is not clear for you or does not entirely satisfy you, it's my first answer here!
EDIT: I forgot to tell you but as derHugo mentioned, since you are using Rigidbody2D, you must use Vector2.ClampMagnitude to limit your speed in your speedLimiter function. Also, I don't think that you need your if since the function Vector2.ClampMagnitude will only change the value of the velocity if it exceeds the maximum.
Thanks to everyone who responded!
With the help of Brackeys community, I managed to solve this by using this method:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
//================= MOVEMENT =====================
private float thrust = 10f;
private float maxSpeed = 100f;
public Rigidbody2D rb;
//================= AIMING =======================
public Camera cam;
Vector2 mousePos;
// Update is called once per frame: Good for INPUTS
void Update()
{
//aiming
mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
}
// Called Set amount of times. Good for PHYSICS CALCULATIONS
void FixedUpdate()
{
Move();
speedLimiter();
//aim
Vector2 lookDirection = mousePos - rb.position;
float angle = Mathf.Atan2(lookDirection.y, lookDirection.x) * Mathf.Rad2Deg - 90f;
rb.rotation = angle;
}
void Move()
{
if (Input.GetKey("up"))
{
rb.AddRelativeForce(Vector2.up*thrust);
}
}
void speedLimiter()
{
if (rb.velocity.magnitude > maxSpeed)
{
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
}
}
//rb.AddForce(new Vector3(0, thrust, 0));
}
I've been trying to get this working using pretty much every method I can find (even using the dreaded transform.translate) but I just can't seem to get it working. This is just a draft of the code and if there are any other ways to go about it I'm down to change some stuff.
Currently, he barely moves (it looks like he's getting stuck on the floor somehow.) I'm fairly new to moving objects using rigid bodies so I'm pretty much in the dark on how to solve this issue.
Here's the script from my latest crack at it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerTest : MonoBehaviour
{
public float speed = 10.0f;
public Rigidbody rb;
public Vector3 movement;
// Start is called before the first frame update
void Start()
{
rb.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("w"))
{
movement = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
}
}
void FixedUpdate()
{
moveCharacter(movement);
}
void moveCharacter(Vector3 direction)
{
rb.MovePosition(transform.position + (transform.forward * speed * Time.deltaTime));
}
}
In your code you have your moveCharacter function inside your Update function, enclosed is the fixed one, which should work now. Before your FixedUpdate was not getting called, therefore your moveCharacter function was not as well and your GameObject was not moving.
EDIT 1: You shoud also multiply with your movement direction as well, updated the script to fit that
EDIT 2: I misplaced the curly brackets, fixed that now
EDIT 3: You should also update your movement Vector3 every frame, not if W is pressed, fixed the script again.
EDIT 4: Fixed the movement bug (copy and paste entire script, since i changed more lines)
This is the updated script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerTest : MonoBehaviour
{
public float speed = 10.0f;
public Rigidbody rb;
public Vector3 movement;
// Start is called before the first frame update
void Start()
{
rb.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
movement = new Vector3(Input.GetAxis("Horizontal"), 1f, Input.GetAxis("Vertical"));
}
void FixedUpdate()
{
moveCharacter(movement);
}
void moveCharacter(Vector3 direction)
{
Vector3 offset = new Vector3(movement.x * transform.position.x, movement.y * transform.position.y, movement.z * transform.position.z);
rb.MovePosition(transform.position + (offset * speed * Time.deltaTime));
}
}
References: Rigidbody.MovePosition
I have the following code
public Rigidbody2D rb;
public float speed = 5f;
void FixedUpdate()
{
if (Input.GetKeyDown("w"))
{
Fire();
}
}
void Fire()
{
rb.MovePosition(rb.position + Vector2.down * speed * Time.deltaTime);
}
but every time I play the game, the ball does not move according to the fire function, it only goes down by 1 on the y-axis.
How can I edit my code, so that the Rigidbody moves according to the Fire() function?
There could be a couple things going wrong here. The first thing that stands out to me is that you're using Input.GetKeyDown instead of Input.GetKey-- GetKeyDown only returns true on the first frame that the key is pressed (so it's useful for things like shooting once per keypress), whereas GetKey returns true for the entire time that the key is down (so it's useful for things like movement). Changing that should give you the behavior that you're expecting.
Another issue is that you're doing input checking in FixedUpdate. It runs on a separate game loop from Update, and you can find more details about that here: Is it really wrong to use Input.GetKey() on FixedUpdate?
I would use Input and GetKey to store the input state in a Vector2 in the Update loop, and then use that data in FixedUpdate to do the actual movement:
public Rigidbody2D rb;
public float speed = 5f;
private Vector2 velocity = Vector2.zero;
void Update()
{
if (Input.GetKey("w"))
{
velocity = Vector2.down * speed;
}
else {
velocity = Vector2.zero;
}
}
void FixedUpdate()
{
MoveBall();
}
void MoveBall()
{
rb.MovePosition(rb.position * velocity * Time.deltaTime);
}
This way, you also have a stronger separation between the input code and movement code, and it will be easier to handle once you start trying to implement more complexity. Good luck!