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);
}
}
}
}
}