ball isn't spawning where desired

Started by
5 comments, last by ethancodes 5 years, 9 months ago

Ooohhhh boy. I'm back with more questions. I am having a horrible time with this pick up I'm working on. I've got multiple issues but I'm trying to make a list and work through them one by one. If you haven't already seen one of my other posts, I'm working on an arkanoid clone type game, with a pickup that when active, the ball will come back and hit the paddle, and as it leave the paddle, 6 additional balls should be spawned, with a short delay between each one, and then they all follow the first ball in a straight line away from the paddle until they all hit whatever is in front of them. Each ball is destroyed on impact except for the last ball in the line. So, onto my problem: Currently, the original ball hits the paddle and bounces away fine, and another ball is spawned. However, this ball is not spawned over the paddle like it should be. Some times it spawns right next to the paddle, sometimes it spawns half way across the screen. Left or right of the paddle, either way. Can't seem to find any rhyme or reason to it's spawn location. I have added code directly to this ball so that right after it is spawned, it's location should be initialized in a location over the paddle. I used the same code that I use on the original ball at the beginning of the game. Also, when this ball spawns, it falls. I thought I had it set so that the vector of the original ball would be assigned to this new ball and it would just move in the same direction as it, but apparently I'm missing something there. I'll post all my code for this pick up and also for the Ball class and maybe someone can explain what I'm doing wrong. This pickup is really making me lose my mind!

 

AssaultRiflePickUp class:


public class AssaultRiflePickUp : BasePickUp, ISpecialShotPickUp
{
	private int AmmoRemaining = 35;
	private float timer = 0.3f;
	private Vector3 mainBallVector;

	public GameObject newBall;

	void Start ()
	{	
		//assign paddle to variable
		paddle = GameObject.FindObjectOfType<Paddle> ();

		//find the ball and assign it to this variable
		foreach (Ball ball in GameManager.pickUpManager.allBalls) 
		{
			if (ball.mainBall) 
			{
				mainBall = ball;
			}
		}
	}

	public override void ActivatePickUp (MonoBehaviour coroutineHost)
	{
		Debug.Log("ActivatePickUp");
		//subscribe to events
		mainBall.onBallHitPaddle += AssaultRifleShot;
		mainBall.onBallCollided += DestroyExtraBalls;
	}

	public void SpecialShot ()	//spawn a new ball. add it to the list of balls. set it's spawn location, set it's velocity to match the original ball
	{
		Debug.Log("SpecialShot");

		Instantiate(newBall);
		newBall.GetComponent<Ball>().hasStarted = true;
		GameManager.pickUpManager.allBalls.Add(newBall.GetComponent<Ball>());
		newBall.GetComponent<Ball>().paddleToBallVector = newBall.transform.position - paddle.transform.position;
		newBall.transform.position = paddle.transform.position + newBall.GetComponent<Ball>().paddleToBallVector;  //use the original ball's vector3 to follow it directly
		newBall.GetComponent<Rigidbody2D>().velocity = mainBallVector;
	}

	public void DestroyExtraBalls (GameObject ball)
	{
		if (GameManager.pickUpManager.allBalls.Count > 1) 
		{
		}

		//TODO: Implement observer pattern to watch for balls colliding with something. If they do and they are not the main ball, destroy them.
	}

	public void DestroyPickUp ()
	{
			Debug.Log("DestroyPickUp");
			Destroy (GameManager.pickUpManager.pickUpQueue [0]);
			GameManager.pickUpManager.pickUpQueue.RemoveAt (0);
			GameManager.pickUpManager.pickUpActive = false;
	}

	//a timer used for timed pick ups
	public IEnumerator PowerUpTimer (float delay)
	{	
		Debug.Log("PowerUpTimer");
		yield return new WaitForSeconds (delay);
		SpecialShot();
	}

	//The coroutine is used to start a short timer so that the balls don't spawn on top of each other all at the same time.
	public void StartCoroutine (float delay, MonoBehaviour coroutineHost)
	{
		coroutineHost.StartCoroutine(PowerUpTimer(delay));
	}


	//Controls the pick up's cycle
	public void AssaultRifleShot (GameObject mainBall)
	{
		Debug.Log("AssaultRifleShot called");
		mainBallVector = mainBall.GetComponent<Rigidbody2D>().velocity; //grab mainBall's direction and speed before making it a destroyable ball
		mainBall.GetComponent<Ball>().mainBall = false;	//deactivate the original ball as the mainBall so that it may be destroyed on impact

		if (AmmoRemaining > 0) 
		{ 
			Debug.Log("AssaultRifleShot - Inside If Statement");
			//if there is ammo remaining, set the main ball to just a normal ball so it can be destroyed on impact and then start coroutine
			mainBall.GetComponent<Ball> ().mainBall = false;
			Debug.Log("AssaultRifleShot - 1");
			mainBall.GetComponent<Ball> ().onBallHitPaddle -= AssaultRifleShot; //unsubscribe to event when mainBall is set to false.
			Debug.Log("AssaultRifleShot - 2");
			StartCoroutine(timer, GameManager.monoBehaviour);
			Debug.Log("AssaultRifleShot - 3");
			AmmoRemaining -= 1;
			Debug.Log("AssaultRifleShot - 4");
		} 
		else 
		{
			DestroyPickUp();	
		}
	}
}

Side note: There is some base class code for the pick up, if it is decided that that is needed as well I can post it. But I don't think it's relevant.

 

Ball class:


public class Ball : MonoBehaviour
{
	private Paddle paddle;

	public Vector3 paddleToBallVector;
	public bool mainBall = false;
	public float Speed { get; set; }
	public float MaxSpeed = 10.198f;
	public bool hasStarted = false;

	public delegate void DestroyBalls(GameObject ball);
	public event DestroyBalls onBallCollided;

	public delegate void BallHitPaddle(GameObject ball);
	public event BallHitPaddle onBallHitPaddle;

	void Start ()
	{
		//find the paddle and assign it to variable
		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);
			}

		} 

	}

	void OnCollisionEnter2D (Collision2D collider)
	{
		//use this vector2 to adjust the velocity so the ball does not get stuck in a vertical bouncing loop
		if (hasStarted) {	//apply sound when the ball hits something
			AudioSource audio = this.gameObject.GetComponent<AudioSource> ();
			audio.Play ();
			Vector2 tweak = new Vector2 (UnityEngine.Random.Range (0f, 0.2f), UnityEngine.Random.Range (0f, 0.2f));
			//the following lines set the speed and direction of the ball based on built in physics, and the current speed of the ball. Speed can be changed based on pick ups
			this.gameObject.GetComponent<Rigidbody2D> ().velocity = this.gameObject.GetComponent<Rigidbody2D> ().velocity.normalized;
			this.gameObject.GetComponent<Rigidbody2D> ().velocity *= Speed * MaxSpeed;

			this.gameObject.GetComponent<Rigidbody2D> ().velocity += tweak;

			if (collider.gameObject.name == "Paddle" && this.mainBall) 
			{
				if (onBallHitPaddle != null) {
					onBallHitPaddle (this.gameObject);
				}
			}
		}
	}
}

 

Advertisement
3 hours ago, ethancodes said:

Can't seem to find any rhyme or reason to it's spawn location.

Isn't it because of this:


newBall.transform.position = paddle.transform.position + newBall.GetComponent<Ball>().paddleToBallVector;  //use the original ball's vector3 to follow it directly

 

When the original ball hits the power up, you could save that point for a time. Then as the ball moves away you can spawn a new one at that point.

So if I take that line of code out, it seems to help, but of course the player is still moving the paddle, so it seems to spawn where the paddle was, but not where it is now. From what I can tell, it's kind of hard to say for sure though. I don't want to save the original ball's location when it hit the paddle because if the paddle moves, it's going to spawn where the ball was and not where the paddle is. That line of code should be spawning it right above the paddle I thought, unless I have a mistake somewhere there.

Aint you should subtract paddle pos from ball pos to have ball local coordinates and instead of using 


newBall.GetComponent<Ball>().paddleToBallVector;

Of which you didnt provide the code for

Use that result instead?

On 7/20/2018 at 4:44 AM, ethancodes said:

newBall.GetComponent<Ball>().paddleToBallVector = newBall.transform.position - paddle.transform.position;

It seems to me that you use newBall.transform.position without initialising it, in your SpecialShot() function?

.:vinterberg:.

@vinterberg I have "Instantiate(newBall);" The new ball is definitely there, I can see it and interact with it. 

 

As for what @KKTHXBYE , I'm not sure what you are trying to say. What code did I not show? I'm actually not sure if I need the paddleToBallVector because that set up is originally used to make the ball stay with the paddle while the paddle is moved around. I don't actually want that. I just want it to spawn at the paddle and then launch immediately. So maybe I don't need the paddleToBallVector?

This topic is closed to new replies.

Advertisement