Change speed of object

Started by
14 comments, last by Scouting Ninja 5 years, 11 months ago

I've got a ball object and I want to be able to manipulate the ball's speed (both speed up and slow down) based on different pickups dropped in the game. I'm not sure how best to do this. Here is my code for the Ball class:


public class Ball : MonoBehaviour 
{

	private Paddle paddle;
	private bool hasStarted = false;
	private Vector3 paddleToBallVector;

	// Use this for initialization
	void Start () 
	{
		paddle = GameObject.FindObjectOfType<Paddle>();
		paddleToBallVector = this.transform.position - paddle.transform.position;
	}
	
	// Update is called once per frame
	void Update ()
	{
		if (!hasStarted) 
		{
			//Lock the ball relative to the paddle.
			this.transform.position = paddle.transform.position + paddleToBallVector;
			//Wait for a mouse press to launch.
			if (Input.GetMouseButtonDown (0)) 
			{
				hasStarted = true;
				this.GetComponent<Rigidbody2D> ().velocity = new Vector2 (2f, 10f);
			}
		} 

	}

	void OnCollisionEnter2D (Collision2D collider)
	{
		//use this vector2 to adjust the velocity so the ball does not get stuck in a vertical bouncing loop
		Vector2 tweak = new Vector2 (Random.Range(0f, 0.2f),Random.Range(0f, 0.2f));
		if (hasStarted)
		{
			AudioSource audio = this.gameObject.GetComponent<AudioSource>();
			audio.Play();
			this.gameObject.GetComponent<Rigidbody2D>().velocity += tweak;
		}

	}
}

I just need to know how to manipulate the speed for this class. I'm not sure if how I have it set up now is the best way to manage movement of the ball object or if I should modify it to accommodate for speed manipulation.  

Advertisement

Good to see you are making progress. Now you enter the realm of vector math.

There is some things I must double check you know. A vector has both magnitude and direction. We can think of any vector as a line, that points in a direction and has a length.

attachment.php?id=41587

This image shows the vector (2,2) and how it starts from (0,0) to make an arrow pointing at 45 degrees or NE. All the vectors you work with act like this, even the 3D ones.

 

Next you need to know what a scalar is. A scalar is any single value like 1 or 48 or 9.2 etc. It is a number. The reason it is called a scalar is because it scales the vector. Like this:

(2,2) * 2 = (4,4) //See it is double the size now, it has scaled:

Scaler.jpg.6c615e22ad275ead6c2023d107363f9d.jpg

If your ball's velocity is (2,2) and you multiply it by 2, it would double in speed.

Lets say your speed boosts makes the ball only a little bit faster each time; it would look like this:


//To make things shorter lets add a pointer to the rigidbody
Rigidbody2D BallBody;

//Rigid bodies have to be assigned at start
void Start(){
  BallBody = this.gameObject.GetComponent<Rigidbody2D>().velocity;
}

//Now the code for speed up
void MakeBallFaster(){
  //we will add 0.2 of the balls speed to the object
  BallBody.velocity = BallBody.velocity* 1.2f;//You can also make it a variable
}

//Similar code to slow it down
void HalfBallSpeed(){
  BallBody.velocity = BallBody.velocity* 0.5f;
}


Most programmers like having a speed variable, that constantly scales the velocity and can be used to limit speed. Advanced:

Spoiler

 



//Make the speed varaible publick to easy edit it
public Speed = 0f;
private SpeedMax = 100f;//This is the limit

//To make things shorter lets add a pointer to the rigidbody
Rigidbody2D BallBody;

//Rigid bodies have to be assigned at start
void Start(){
  BallBody = this.gameObject.GetComponent<Rigidbody2D>().velocity;
}

//Now the code for speed up
public float SpeedUp(float SpeedAmount){
  Speed = Speed + SpeedAmount;
  //Speed can only be added upto the max
  if (Speed > SpeedMax)
  {
    Speed = SpeedMax; //mow it can't be more than 100
  }
  return Speed;
}

//Similar code to slow it down
public float SpeedDown(float SpeedAmount){
  Speed = Speed - SpeedAmount;
  //Speed can only be added upto the max
  if (Speed < -SpeedMax)
  {
    Speed = -SpeedMax; //mow it can't be smaller than -100
  }
  return Speed;
}

//The above functions are just limits, lets use them
void Start(){
  //When the game starts we wan't the ball to move at the avrage speed
  //Lets say 0.1 blocks per tick is normal
  BallBody.velocity = Vector3.Up * SpeedUp(0.1f);
}

//When it hits it should speed up
void OnCollisionEnter2D(){
  BallBody.velocity = BallBody.velocity * SpeedUp(0.1f);
}

 

 

This is pretty close to what I ended up with last night. The major difference is that I was doing it in a different script titled SlowBall. Which brings me to a structure question. I'm going to have about 6 different power ups. Some of them simply change the ball's behavior, such as speed in this case. Others make multiple balls and do various different things with them, and one of them stops the ball on the paddle and gives the player an aiming control. Knowing all this, would it be best to have an individual script that handles everything to do with each one of these? Or should I do something like you have done here where I would add methods directly on the Ball script, and then just activate them when there is a collision with a specially tagged game object or something?

15 hours ago, ethancodes said:

would it be best to have an individual script that handles everything to do with each one of these?

How  you want. I did a test a while ago on how performance intense Unity scripts are and they are very light.

Maybe you would like to have them under inheritance, like you did with bricks. Programmers like this way because it is more flexible and keeps code easier to read. 

I've got this pretty close I think. One issue I'm still having that I'm a bit unsure about is that when I set the ball's speed to .5 to slow it down, it doesn't just slow the ball down to half speed. It continuously keeps slowing down and falling to the bottom of the screen, eventually just landing on the paddle. I'm assuming I need to change how the ball is moved because it seems that at it's decreased speed, it doesn't have enough force to keep it moving? I want it to continue moving and bouncing off of walls, bricks, and the paddle, but at a decreased speed.

3 hours ago, ethancodes said:

It continuously keeps slowing down and falling to the bottom

Do you keep slowing it down? Remember that you should only half the speed once.

Can I see the part of the code that calls the slowdown?

Here is the SlowBall powerup code:


public class SlowBall : MonoBehaviour {

	private int timer = 2;

	GameObject ball;

	// Use this for initialization
	void Start () {
		ball = GameObject.FindGameObjectWithTag("Ball");
	}

	void OnCollisionEnter2D (Collision2D collision)
	{
		if (collision.gameObject.tag == "Paddle" || collision.gameObject.tag == "Ball") 
		{
			 ball.GetComponent<Ball>().Speed = .5f; //reduce ball speed
			 ball.GetComponent<Ball>().PowerUpTimer(timer); //set time that power up is active
			 Destroy(gameObject); //destroy power up object
		}
	}

}

And then this is the ball's code. I believe this is actually where the problem is. I think it has to do with how I'm putting the speed variable in there. It seems like I have the same thing multiple times.


public class Ball : MonoBehaviour 
{

	private Paddle paddle;
	private bool hasStarted = false;
	private Vector3 paddleToBallVector;

	public float Speed { get; set; }

	// Use this for initialization
	void Start () 
	{
		paddle = GameObject.FindObjectOfType<Paddle>();
		paddleToBallVector = this.transform.position - paddle.transform.position;
		Speed = 1;
	}
	
	// Update is called once per frame
	void Update ()
	{
		if (!hasStarted) 
		{
			//Lock the ball relative to the paddle.
			this.transform.position = paddle.transform.position + paddleToBallVector;
			//Wait for a mouse press to launch.
			if (Input.GetMouseButtonDown (0)) 
			{
				hasStarted = true;
				this.GetComponent<Rigidbody2D> ().velocity = new Vector2 (2f, 10f) * Speed;
			}
		} 

	}

	void OnCollisionEnter2D (Collision2D collider)
	{
		//use this vector2 to adjust the velocity so the ball does not get stuck in a vertical bouncing loop
		Vector2 tweak = new Vector2 (Random.Range(0f, 0.2f),Random.Range(0f, 0.2f));
		if (hasStarted)
		{
			AudioSource audio = this.gameObject.GetComponent<AudioSource>();
			audio.Play();
			this.gameObject.GetComponent<Rigidbody2D>().velocity += tweak;
			this.gameObject.GetComponent<Rigidbody2D>().velocity *= Speed;
		}

	}

	public IEnumerator PowerUpTimer (int delay)
	{
		yield return new WaitForSeconds(delay);
		Speed = 1;
		this.gameObject.GetComponent<Rigidbody2D>().velocity *= Speed;

	}
}

 

 


	void OnCollisionEnter2D (Collision2D collider)
	{
		//use this vector2 to adjust the velocity so the ball does not get stuck in a vertical bouncing loop
		Vector2 tweak = new Vector2 (Random.Range(0f, 0.2f),Random.Range(0f, 0.2f));
		if (hasStarted)
		{
			AudioSource audio = this.gameObject.GetComponent<AudioSource>();
			audio.Play();
			this.gameObject.GetComponent<Rigidbody2D>().velocity += tweak;
			this.gameObject.GetComponent<Rigidbody2D>().velocity *= Speed;
		}

	}

Here you keep effecting the speed.

To explain it starts as Vector2 (2f, 10f) then 1 bounce it = (2.2f,10.2f) * 0.5f = (1.1f, 5.1f) Then the next bounce it is (1.3f, 5.3f) *0.5f = (0.65f, 2.65f) etc.

The way you are trying to use the speed here is as if 1f = full speed and 0.5f = half speed. To do it like this you need some kind of MaxSpeed that can be effected by this.

 

So lets try this: Vector2 (2f, 10f) , this at the start so I assume it is what you want as the normal speed. To find speed we use you use the Pythagorean theorem: (2*2=4 , 10*10 =100) the root of 104 = 10.198f

At the top we now add this:


//Place This some where at the top
float MaxSpeed = 10.198f;
  
	void OnCollisionEnter2D (Collision2D collider)
	{
		//use this vector2 to adjust the velocity so the ball does not get stuck in a vertical bouncing loop
		Vector2 tweak = new Vector2 (Random.Range(0f, 0.2f),Random.Range(0f, 0.2f));
		if (hasStarted)
		{
			AudioSource audio = this.gameObject.GetComponent<AudioSource>();
			audio.Play();
			//So now we turn the velocity into a direction with the speed of 1 on collision
			this.gameObject.GetComponent<Rigidbody2D>().velocity = this.gameObject.GetComponent<Rigidbody2D>().velocity.normalized;
			//Next we take our max speed and set the velocity to current speed * MaxSpeed
			this.gameObject.GetComponent<Rigidbody2D>().velocity *= Speed*MaxSpeed;// 0.5f*10.198 = 5.099f
          
			//The tweek can be added now 
			this.gameObject.GetComponent<Rigidbody2D>().velocity += tweak;
		}

	}

To explain: if the ball starts with Vector2 (2f, 10f) it has a magnitude/ speed of 10.198f and normalized it is (0.196, 0.981). Normalized can be seen as the direction only; because it is a direction with speed of 1.

The length/ speed of a vector = Pythagorean theorem.

(0.196, 0.981) * 10.198 = (2f, 10f); So direction*speed = vector of speed and direction.

So here: this.gameObject.GetComponent<Rigidbody2D>().velocity.normalized; we take the velocity (2f, 10f) and divide it by it's own speed (10.198f) that is what normalized means. We get: (0.196, 0.981).

Here: this.gameObject.GetComponent<Rigidbody2D>().velocity *= Speed*MaxSpeed; our velocity is (0.196, 0.981) and now we take (10.198 *0.5 = 5.099); and use that as our new speed. (0.196, 0.981) * 5.099 = (1f ,5f) or 50% of (2f, 10f)

 

Normally speed isn't used like a percentage like here. Instead speed would have been a value.

Normalizing before multiplying with speed is always a good idea. Later you will also start using Delta time for frame-rate independent movement.

If you don't understand what I did above then try this: https://www.khanacademy.org/math/linear-algebra

That's what I was afraid of. I figured I was doing something wrong there, I just wasn't sure how to fix it. I get why you did all of this. I have a decent understanding of linear algebra, just a very poor understanding of when and how to apply it. But I think I'm starting to understand a little more as I continue to work on moving things around. Thanks again for the help!

9 hours ago, ethancodes said:

I have a decent understanding of linear algebra, just a very poor understanding of when and how to apply it.

That is one of the best things about making games, you actually get to see how this math you spend years learning in school actually works.

If you already understand linear algebra then Khan academy is often too boring to stick with. In that case Math Is Fun is a much lighter and more practical site:  https://www.mathsisfun.com/algebra/vectors.html

 

The important part of using vectors is knowing that the magnitude is speed when working with movement. So every vector already has a speed and a direction.

This topic is closed to new replies.

Advertisement