Hi there. I'm still new to Unity and 2D Toolkit and have been spending a lot of my time the past few weeks trying to learn all that I can. Partly as a learning exercise and partly because I thought it would be fun, I'm trying to roll over an old version of a breakout clone that I made several years ago. As ball mechanics are key in such a game, I have been focusing my beginning efforts on getting those nailed down tight. And despite my best efforts, Unity has been laughing at my pitiful attempts to make it work and feasting on my soul in the process.
So I thought I'd see if anyone here has some ideas on what I could be doing wrong. I'm not sure if this is a problem with 2D Toolkit, Unity, or me... but I thought I'd start here.
Just some background to begin on my project structure (I didn't list all components on my game objects, only the ones I thought pertinent to the issue):
- Using a Orthographic tk2dCamera object for viewing my game with a Preview / Native Resolution set at 1920 x 1080 and 1 Pixel Per Meter.
- Four boundary objects that surround my play area (top, bottom, left, right) with Box Collider 2D component set on each of them.
- Obligatory paddle object with Rigidbody 2D, Box Collider 2D, and PlayerController components. It is set as Kinematic on the Rigidbody.
- PointBrick Prefab with tk2dSprite and Box Collider 2D components. Sprite is 64 x 45, Upper Left anchor, and Box Trimmed collider in sprite collection.
- Ball Prefab with tk2dSprite, Rigidbody 2D, Circle Collider 2D, and BallController components. Sprite is 16 x 16, Middle Center anchor, and User Defined collider in sprite collection. It is set as Kinematic and Trigger on the Rigidbody.
- GameController object with GameController script that sets up random lines of bricks and manages ball lives / spawning.
- PlayerController script handles paddle movement in FixedUpdate method by modifying paddle transform from mouse movement.
- BallController script handles checking for collisions with boundaries and bricks. Currently, I don't destroy any bricks on collision as I'm testing, so they stick around for further collisions.
- I have two layers at play in my project - Default and Ball. My paddle and bricks live on the Default layer and any balls live on the Ball layer. I did this to avoid collisions between balls on the screen.
With that said, my problem lies in my collision checking in the BallController script. Observation of the game play at this point shows the collisions working, but inconsistently (and strangely so). My goal has been to do a simple reflection of the ball, whether on a boundary or a brick... in other words, I reverse the x / y axis of the ball appropriately based on what collided with the ball. The boundaries are straightforward in this regard, but the bricks are giving me fits.
I'm trying to use a RaycastHit2D to determine my collision point and reflect the ball properly, but for the life of me I can't get it operate consistently. The ball will perform several collisions flawlessly, even tightly packed collisions between bricks. Then boom... the ball just decides to continue right through a brick like nothing happened. My debugging seems to indicate the collision occurs but it doesn't change direction. Next time... it reflects off the same brick just fine, but will pass through a different brick later on. Rinse and repeat.
Here's my BallController code for reference. Perhaps another set of eyes will catch something I'm missing or perhaps something I'm doing wrong. Any help would be greatly appreciated.
using UnityEngine;
using System.Collections;
public class BallController : MonoBehaviour
{
private GameController _gameController;
private Rigidbody2D _rb;
private CircleCollider2D _collider;
private tk2dCamera _camera;
private bool _keepAlive;
// Use this for initialization
void Start()
{
// HACK: Keep the balls on the board for now
_keepAlive = true;
// Get a reference to the game controller script
_gameController = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameController>();
// Get a reference to the rigid body for the ball
_rb = GetComponent<Rigidbody2D>();
_collider = GetComponent<CircleCollider2D>();
//Get a reference to the camera
_camera = FindObjectOfType<tk2dCamera>();
Debug.Log(string.Format("Spinning up new ball -- Position: {0},{1} Velocity: {2},{3}", transform.position.x, transform.position.y, _rb.velocity.x, _rb.velocity.y));
}
void OnTriggerEnter2D(Collider2D other)
{
Debug.Log(string.Format("Before Collision: {0},{1}", _rb.velocity.x, _rb.velocity.y));
if (other.gameObject.CompareTag("PointBrick"))
{
RaycastHit2D hit = Physics2D.Raycast(new Vector2(transform.position.x, transform.position.y), _rb.velocity, 50.0f, LayerMask.GetMask("Default"));
if (hit.collider != null)
{
Debug.Log(string.Format("Hit -- Brick Transform: {0},{1} Ball Transform: {2},{3} Collision Point: {4},{5}", hit.transform.position.x, hit.transform.position.y, transform.position.x, transform.position.y, hit.point.x, hit.point.y));
Debug.Log(string.Format("Brick Bounds -- Min: {0},{1} Max: {2},{3} Center: {4},{5}",
hit.collider.bounds.min.x, hit.collider.bounds.min.y, hit.collider.bounds.max.x,
hit.collider.bounds.max.y, hit.collider.bounds.center.x, hit.collider.bounds.center.y));
if (hit.point.x <= hit.collider.bounds.min.x || hit.point.x >= hit.collider.bounds.max.x)
_rb.velocity = new Vector2(-_rb.velocity.x, _rb.velocity.y);
else if (hit.point.y <= hit.collider.bounds.min.y || hit.point.y >= hit.collider.bounds.max.y)
_rb.velocity = new Vector2(_rb.velocity.x, -_rb.velocity.y);
}
}
else if (other.gameObject.CompareTag("BoundaryLeft") || other.gameObject.CompareTag("BoundaryRight"))
_rb.velocity = new Vector2(-_rb.velocity.x, _rb.velocity.y);
else if (other.gameObject.CompareTag("BoundaryTop"))
_rb.velocity = new Vector2(_rb.velocity.x, -_rb.velocity.y);
else if (other.gameObject.CompareTag("BoundaryBottom") && _keepAlive)
_rb.velocity = new Vector2(_rb.velocity.x, -_rb.velocity.y);
else if (other.gameObject.CompareTag("Player"))
_rb.velocity = new Vector2(_rb.velocity.x, -_rb.velocity.y);
Debug.Log(string.Format("After Collision: {0},{1}", _rb.velocity.x, _rb.velocity.y));
}
}