- Home /
How to accelerate the ball in a pong clone
Hi all. I'm trying to accelerate the ball in a pong clone but I can't figure out how. I have no idea what I'm doing :(
public class Ball : MonoBehaviour {
public float initialVelocity = 2.0f;
public float maxVelocity = 100.0f;
public float accelerationRate = 2.0f;
void Start ()
{
rigidbody2D.velocity = (Vector2.one.normalized * initialVelocity);
}
void FixedUpdate()
{
while (rigidbody2D.velocity < maxVelocity) {??
}
initialVelocity = rigidbody2D.velocity * accelerationRate;
}
}
pong ? you mean on a hit ? is your game 2d ? do you know whats a bouncy physic ?
I just want the ball to accelerate slowly over time to make it more difficult for players as time goes on.
Answer by Tetheta · Jan 01, 2015 at 01:44 AM
Okay, a few things to think about here.
First off, the Start function is called once, when the Game Object is first created. At that point, you're setting the velocity to whatever initialVelocity is multiplied by your normalized vector. This means the ball will start out at a velocity of 2.
Now, FixedUpdate is called a set number of times per second, but your code in it is a bit odd. First off, you have a while loop. A while loop will keep doing whatever is in it until the condition of the loop returns true. In this case it would repeat what's in the loop until rigidbody2d.velocity is >= maxVelocity -- probably what you want.
Secondly, you don't actually have anything in the while loop. The braces (one of which you have commented) enclose whatever you want in that loop. Those lines of code there serve no purpose whatsoever.
Third, while you're setting initialVelocity to something new, you never assign your rigidbody2D.velocity to initialVelocity, so nothing happens.
To fix this:
First off, fixedUpdate is already called a bunch of times a second, so there is no reason to use a while loop in it. An if statement would work fine.
Secondly, you want to set rigidBody2D.velocity, not initialVelocity.
Third, you probably want to add 2, not multiply by 2 (otherwise your acceleration will be insanely fast).
So I was in a rush and didn't test the code, turns out I'm a dummy and was assuming 1-D motion for some odd reason. In order to get 2-D motion working, you need to multiply the rigidbody2D.velocity.normalized by the desired speed. An example of how this would be done is below (and more explanation in the comments). I actually tested this code and it seemed to work well in a basic new unity scene.
using UnityEngine;
using System.Collections;
public class Ball : MonoBehaviour
{
//I'm calling these speed, since technically velocity is a vector, speed is a scalar, and the difference is important here
public float initialSpeed = 0.2f;
private float curSpeed;
public float maxSpeed = 10f;
public float accelerationRate = .1f;
void Start()
{
curSpeed = initialSpeed; //Update curVelocity
rigidbody2D.velocity = (Vector2.one.normalized * curSpeed); //Set our starting velocity
//Vector2.one.normalized should start it going up and to the right at a 45 degree angle.
}
void FixedUpdate()
{
if (curSpeed < maxSpeed)
{
curSpeed += accelerationRate;
}
rigidbody2D.velocity = rigidbody2D.velocity.normalized * curSpeed; //Takes the velocity direction and multiplies it by our speed.
}
}
Thanks very much for your patient and detailed response Tetheta. I feel like I understand what's going on a bit more now. However, the game now won't start and I'm getting two errors in the console: 'Assets/Ball.cs(40,33): error CS0019: Operator <' cannot be applied to operands of type
UnityEngine.Vector2' and `float'
and then another error message that is the same except for the '+=' operator. I edited my code with your corrections, then to make sure I didn't type anything wrong I commented it out and copy and pasted yours in and it still didn't work. Any further help would be appreciated!
@Evil Tak @Elayekay $$anonymous$$y apologies, I ended up having to run as I was writing this so I posted it quickly without checking.
I was thinking for some reason that you were only accelerating in one direction, since this obviously isn't the case things are a bit more complex. A similar issue was talked about here for limiting the speed: http://answers.unity3d.com/questions/749319/question-regarding-ridigbody2dvelocitymagnitude.html
The issue comes in when you want to accelerate in (I'm assu$$anonymous$$g) the direction the ball is already going. To do this, you need to get the normalized velocity (which basically returns how much in each direction the ball is going, with a total velocity of one) and then multiply that by your desired speed.
If you want to be fast (which you usually do), calling sqr$$anonymous$$agnitude and comparing that to the square of your maximum is actually best practice, but you can use the direct .magnitude call if that makes more sense to you. However I didn't end up actually using that in my code.
In order to do all this in what you have, you should create a new value to store the current speed, and multiply by that in FixedUpdate ins$$anonymous$$d of directly assigning to your velocity. You'll also increase (+= should work with this one) that value every time until the maximum. The code would look like the following:
using UnityEngine;
using System.Collections;
public class Ball : $$anonymous$$onoBehaviour
{
//I'm calling these speed, since technically velocity is a vector, speed is a scalar, and the difference is important here
public float initialSpeed = 0.2f;
private float curSpeed;
public float maxSpeed = 10f;
public float accelerationRate = .1f;
void Start()
{
curSpeed = initialSpeed; //Update curVelocity
rigidbody2D.velocity = (Vector2.one.normalized * curSpeed); //Set our starting velocity
//Vector2.one.normalized should start it going up and to the right at a 45 degree angle.
}
void FixedUpdate()
{
if (curSpeed < maxSpeed)
{
curSpeed += accelerationRate;
}
rigidbody2D.velocity = rigidbody2D.velocity.normalized * curSpeed; //Takes the velocity direction and multiplies it by our speed.
}
}
I tested that code on a simple sprite with a rigidbody2D and it worked for me (hence the adjusted initial/etc values, change those back to whatever you want). I'll update my answer to reflect these changes.
Sorry about the earlier failure, I'm apparently pretty incapable without an editor yelling at me about basic things haha.
Answer by tanz94 · Jan 01, 2015 at 07:50 AM
In the above code rigidbody2D.velocity cannot be compared to maxvelocity since maxvelocity is scalar and the other is vector quantity.`Use this
if (rigidbody2D.velocity.magnitude < maxVelocity)
Thanks Tanz. That seemed to deal with the '<' error message, but not the '+=' one. I tried adding magnitude inside the if statement : rigidbody2D.velocity.magnitude += accelerationRate;
but then I got this error message: Assets/Ball.cs(18,46): error CS0200: Property or indexer `UnityEngine.Vector2.magnitude' cannot be assigned to (it is read only)
Answer by EvilTak · Jan 01, 2015 at 02:38 PM
To accelerate the ball, use rigidbody.AddForce. Look at the following implementation of your script:
public class Ball : MonoBehaviour {
public float initialVelocity = 2.0f;
public float maxVelocity = 100.0f;
public float accelerationRate = 2.0f;
void Start ()
{
rigidbody2D.velocity = (Vector2.one.normalized * initialVelocity);
}
void FixedUpdate()
{
Vector2 normalizedVel = rigidbody2D.velocity.normalized;
rigidbody2D.AddForce(normalizedVel * accelerationRate);
if(rigidbody2D.velocity.sqrMagnitude > maxVelocity * maxVelocity)
rigidbody2D.velocity = normalizedVel * maxVelocity; //This limits the velocity once it goes over maxVelocity
}
AddForce is much better than modifying the velocity directly.
Thanks Tak. I tried that and the ball went crazy fast. There appeared to be three of them! Tried changing the speed values but it didn't help. I think it might not be a good idea to up the speed every frame (I assume this is happening when you try to accelerate the ball in FixedUpdate). I've been trying out Time.deltaTime like so: public class Ball : $$anonymous$$onoBehaviour {
public float initialVelocity = 2.0f;
public float maxVelocity = 100.0f;
void Start ()
{
rigidbody2D.velocity = (Vector2.one.normalized * initialVelocity);
}
void FixedUpdate()
{
if (rigidbody2D.velocity.magnitude < maxVelocity)
{
initialVelocity += 2.0f * Time.deltaTime;
}
}
but it's not working. When I start the game the ball stays at the same speed, even though the value of the Initial Velocity goes up in the inspector!
Ins$$anonymous$$d, try using this in my code: rigidbody2D.AddForce(normalizedVel * accelerationRate * Time.fixedDeltaTime);
and decrease the value of accelerationRate in the inspector. That should work fine. In your other code, there isn't any way you can set the value of initialVelocity equal to the rigidbody's velocity. Your code is completely wrong.
Thanks. No luck again. The ball doesn't speed up over time whatever values I enter, and even when acceleration is at 1 it's still much faster than the initial velocity '2'