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!
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 ;)
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.
I just start making a game with Unity and Visual Studio, i have a bit confuse that why my Speed value always at zero even i set it equal to another variable.
public class Ballista : MonoBehaviour
{
public Transform firePoint;
public GameObject arrowPrefab;
public float speed = 10f;
public float startTimeHold;
public float holdDownTime;
public float arrowSpeed = 100f;
public float finalSpeed;
private void Update()
{
if (Input.GetKeyDown(KeyCode.M))
{
startTimeHold = Time.time;
}
if (Input.GetKeyUp(KeyCode.M))
{
holdDownTime = Time.time - startTimeHold;
Shoot();
finalSpeed = holdDownTime * arrowSpeed;
}
Debug.Log("holddowntimeis: " + holdDownTime);
Debug.Log("final speed is: " + finalSpeed);
}
public void Shoot()
{
GameObject arrowGO = (GameObject)Instantiate(arrowPrefab, firePoint.position, firePoint.rotation);
}
}
and this is the script that my speed value always zero
{
Rigidbody2D rgBody2D;
public GameObject ballista;
private float speed;
private void Awake()
{
rgBody2D = GetComponent<Rigidbody2D>();
}
private void Start()
{
\\ i though the code below will set my speed equal to my finalSpeed but it still 0
speed = ballista.GetComponent<Ballista>().finalSpeed;
Vector2 mousePos = Input.mousePosition;
Debug.Log("speed: " + speed);
rgBody2D.AddForce(mousePos * speed * Time.deltaTime);
}
void Update()
{
}
}
Different to what others said here you actually do NOT want to do it in Update.
Your goal here is to once give your newly spawned arrow a start velocity, not a continuous force.
The issue here is of other nature I think:
You are always spawning a new instance of your second script from a given prefab. This prefab seems to hold a reference to a Ballista prefab instance. At least you are never assigning a new value to the ballista! It might simply be a wrong reference where the finalSpeed is never updated.
Your are first doing the Shoot and after it set the finalSpeed -> even if it would be the correct reference you always get the wrong finalSpeed value!
I would actually change your two scripts in order toake your arrow instance being controlled by the Ballista instead of letting each spawned arrow poll the speed itself:
public class Ballista : MonoBehaviour
{
public Transform firePoint;
// By giving it the correct type here you don't need GetComponent later
public Rigidbody2D arrowPrefab;
public float startTimeHold;
public float arrowSpeed = 100f;
// I personally would add aax value and clamp since to fast RigidBodies can break collision detection eventually
public float maxArrowSpeed = 300;
private void Update()
{
if (Input.GetKeyDown(KeyCode.M))
{
startTimeHold = Time.time;
}
if (Input.GetKeyUp(KeyCode.M))
{
var holdDownTime = Time.time - startTimeHold;
// get the speed before you shoot
// Here personally I would clamp to be sure the arrow is never faster than maxArrowSpeed
// regardless of how long the user held the button pressed
var finalSpeed = Mathf.Min(holdDownTime * arrowSpeed, maxArrowSpeed);
Debug.Log("holddowntimeis: " + holdDownTime);
Debug.Log("final speed is: " + finalSpeed);
// pass in your speed
Shoot(finalSpeed);
}
}
private void Shoot(float speed)
{
// Instantiate anyway returns the type of the given prefab
// which now is a Rigidbody2D
var arrow = Instantiate(arrowPrefab, firePoint.position, firePoint.rotation);
// Directly set the speed from here
// -> your arrow doesn't even need an extra component
// Since you already spawned it with the correct rotation you maybe don't even need the mouse position thing
// AddForceRelative adds a force in the local space of the arrow so if the rotation is correctly
// this simply adds the force in its forward direction
// Note that also using Time.deltaTime actually only makes sense if you set something continuously
// For a one-time force you wouldn't need it, rather adjust your arrowSpeed field
arrow.AddForceRelative(Vector2.forward * speed);
}
}
Instead of using AddForce or AddForceRelative you could actually also simply set the target velocity:
arrow.velocity = Vector2.forward * speed;
Since you are not updateding it continuously this is totally fine and a lot easier to foresee the actual target speed since when adding a force you have to take the mass and frictions into account. You would than ofcourse have to adjust the arrowSpeed (and evtl maxArrowSpeed) accordingly to not anymore represent a force but an actual velocity in Units/second.
I hope I made my points clear enough, don't hesitate to ask if something stayed unclear ;)
speed = ballista.GetComponent().finalSpeed;
should Come in
void Update(){
}
block and not in
void Start() {
}
as void start is only run once and at that point in time the speed is zero
Hope it helped :)
Start happens only once.
Start is called on the frame when a script is enabled just before any
of the Update methods are called the first time.
Disregarding everything else, i am guessing you want it to update the speed every frame in Update
Update is called every frame, if the MonoBehaviour is enabled.
private void Update()
{
\\ i though the code below will set my speed equal to my finalSpeed but it still 0
speed = ballista.GetComponent<Ballista>().finalSpeed;
Vector2 mousePos = Input.mousePosition;
Debug.Log("speed: " + speed);
rgBody2D.AddForce(mousePos * speed * Time.deltaTime);
}
hi i was wondering if someone could help me fix practice code (i make practice codes before i make the real thing because its just how i roll) it is basically an object that requires the user to click on the screen in order for it to not touch the ground much like flappy bird however although i have applied gravity correctly to the sprite i cannot fix the velocity section (i coded is to every time the user clicks with his mouse or taps the space key the object will move up like flappy bird)
using UnityEngine;
using System.Collections;
public class BirdMovment : MonoBehaviour {
Vector3 Velocity = Vector3.zero;
public Vector3 gravity;
public Vector3 flapVelocity;
public float maxSpeed = 5f;
bool didFlap = false;
// Use this for initialization
void Start () {
}
void update (){
if (Input.GetKeyDown (KeyCode.Mouse0))
{
didFlap = true;
}
}
// Update is called once per frame
void FixedUpdate () {
Velocity += gravity* Time.deltaTime;
if (didFlap) {
didFlap = false;
Velocity += flapVelocity;
}
Velocity = Vector3.ClampMagnitude (Velocity, maxSpeed);
transform.position += Velocity * Time.deltaTime;
}
}
can you please fix the error as every time i set the velocity in unity for the sprite ad run the program the sprite just keeps on falling and no matter how much i click or tap the space key the sprite does not stop falling even if i increase the velocity
First of all, the correct Update function is with a capital U, so Update() instead of update(). Then, since you're not doing anything with physics, you can do everything in Update and not use FixedUpdate at all. So you can remove the didFlap variable and add to Velocity directly inside the if (Input.GetKeyDown ...) block. Furthermore, regarding gravity, you're multiplying it twice with Time.deltaTimethere, so remove the first one. That should get you started.