[HELP] 'Tweak' solution insufficient... how to make paddle velocity affect ball vector?

Like several others here, I’ve noticed that the ‘tweak’ solution, while it helps prevent perfectly vertical “boring loops” doesn’t stop boring loops altogether. In my experience, I’ve found that I’m getting even more of them. For instance, say the right half of the blocks are cleared, and the ball is bouncing up and down in the empty right half. What happens is that, because there is a random force applied to change the ball vector, the ball will typically stay within a horizontal range, bouncing a bit left (randomly) then a bit right (randomly), and it can take a very long time to get a sufficient number of random vectors in the same direction to push the ball out of this horizontal range (if it can escape at all).

The best solution would be to make this even more Arkanoid-like, and use the paddle position and ‘x’ (horizontal) velocity to impact the ball vector. As a beginner, I don’t know how to make this work. If there are any more experienced beginners (or instructors) who have some ideas on how to do this, I’d be really happy to hear them. Thanks!

I’m not sure of the answer but since the paddle is kinematic I’m not sure it will have a velocity property since it only moved when instructed by the script.

1 Like

I think what needs to be done is to calculate the difference between the paddle’s current ‘x’ position and its ‘x’ position some number of milliseconds earlier. Based on that, the script could determine which direction the paddle was moving and how quickly. And based on that value, a new vector could be calculated for the ball at collision. But don’t ask me how to script that or rig it in Unity yet, as I have no clue!

What if in Update (or would it be FixedUpdate?), there were two floats? xPosOld and xPosNew (for the old x paddle position and the current x paddle position). I don’t know how to create a time offset to compare these two vars, but I’m guessing there would need to be some way to assign xPosOld at a set time interval, like every 100ms. Assuming that’s possible, then comparing the average difference between xPosNew and xPosOld over that time interval would yield a useful value for determining the paddle’s direction and velocity.

The question may be outdated already but anyway:
If I recall right, Arkanoid did not use the velocity of the paddle to influence the ball.
Instead it compared the distance from the center of the paddle to the ball on impact to tweak the ball’s direction.
(Or maybe both, I may recall wrong :wink: )

I did it something like this:
(tried to delete all unneeded stuff, I hope I didn’t break it)

using UnityEngine;

public class Ball : MonoBehaviour
{
    private Paddle paddle;

    void Start()
    {
        {
            paddle = GameObject.FindObjectOfType<Paddle>();
        }
        void OnCollisionExit2D(Collision2D collision)
        {

            if (collision.gameObject.tag != "Paddle")
            {
                // Do brickstuff
            }
            else
            {
                tweak = new Vector2((this.GetComponent<Rigidbody2D>().position.x - paddle.GetComponent<Rigidbody2D>().position.x) * 7f, 0f);
            }
            // tweaking the tweak.x if needed
            this.GetComponent<Rigidbody2D>().velocity += tweak;

        }

    }
}

However, since I am a coding scrub like most of us here, it may be not the right solution :smiley:
It seems to work at least:

3 Likes

I’ll give it a try, thanks!

1 Like

Hi,

I have two solutions or rather hacks to the OP’s problem. Both of them seemed to work for the entire duration of my game (5 levels) when playing myself or when enabling auto-play (with a bit of trial and error while tweaking the add on velocities).

Hack 1:

I think the solution offered by @Hagyto is very good (Thanks for Sharing :slight_smile: ) and I also had thought among the same lines and had come up with this piece of code:

if (gamestart && col.gameObject.GetComponent<Paddle>())
		{
			if(this.transform.position.x <= pddl.transform.position.x -1f)
			{
				this.rigidbody2D.velocity += new Vector2 (Random.Range(-0.2f,0f),Random.Range(-0.2f,0f));
			}
			if(this.transform.position.x > pddl.transform.position.x - 1f && this.transform.position.x < pddl.transform.position.x + 1f)
			{
				this.rigidbody2D.velocity += new Vector2 (0f,Random.Range(0f,0.2f));
			}
			if(this.transform.position.x >= pddl.transform.position.x + 1f && this.transform.position.x < pddl.transform.position.x + 8f)
			{
				this.rigidbody2D.velocity += new Vector2 (Random.Range(0.2f,0),Random.Range(-0.2f,0f));
			}	
		}

(I had set my paddle width to the width of my playspace to test this code i.e. 16f)
Basically what I did here was add the tweaked velocity according to where the ball hit the paddle i.e if the ball hit the left side (0f to 7f) , I added only negative x velocity; when it hit center (7f to 9f) , no x velocity was added; and similarly when the ball hit the right side of the paddle (9f to 16f) , I added positive x velocity (I have kept this project on the back burner for a while and I foolishly forgot to write down the optimum tweak velocity I came up with. Hence, if you apply this, you might have to do a bit of trial and error. Sorry for that… :sweat_smile: ).

Anyway, this hack worked but offered somewhat (not perfect) of the smooth game-play you see in Arkanoid kind of games. I think Hagyto’s solution is a more effective and simplified version of this hack but I still thought this was worth mentioning and it might help someone out. :smiley:

Hack 2:

Here is the code:

if(rigidbody2D.velocity.x >= -0.5f && rigidbody2D.velocity.x <= 0.5f)
		{ 
			if(pddl.transform.position.x <= 8f)
			{
				Vector2 tweak = new Vector2(2f, Random.Range(-0.2f,0.2f));
			}
			if(pddl.transform.position.x > 8f)
			{
				Vector2 tweak = new Vector2(-2f, Random.Range(-0.2f,0.2f));
			}
		}
		else if(rigidbody2D.velocity.y >= -0.5f && rigidbody2D.velocity.y <= 0.5f)
		{ 
			if (this.transform.position.y <= 9f)
			{
				Vector2 tweak = new Vector2(Random.Range(-0.2f,0.2f), 2f);
			}
			if (this.transform.position.y > 9f)
			{
				Vector2 tweak = new Vector2(Random.Range(-0.2f,0.2f), -2f);
			}
		}
		else
		{
			Vector2 tweak = new Vector2(Random.Range(-0.2f,0.2f), Random.Range(-0.2f,0.2f));
		}

In this code, I checked the velocity of the ball. If it came anywhere near a horizontal or vertical boring loop (-0.5f to 0.5f) , I added 10 times the velocity that I was adding initially for the next collision hence taking it out of the boring loop before it even enters it.
The direction the tweak was added depended on the position of the ball as it collided with the paddle (vertical boring loop) or the walls (horizontal boring loop).
Due to this, the behavior of the ball may seem a bit odd at the point the fix is applied , but it was certainly effective.
This particular fix can be rid of that odd behavior if we apply the tweak according to the direction the ball was moving when it hit the collider (paddle or wall), but I haven’t yet done that (on my TODO list).

I certainly hope this helps and maybe leads to an optimum solution. If there is any way to simplify my code or logic, please let me know.

Thanks & Cheers,
YA

3 Likes

Privacy & Terms