Hello Guest

Author Topic: Kinematic Physics, Breakout, and the death of my sanity  (Read 3432 times)

ricke

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 10
    • View Profile
Kinematic Physics, Breakout, and the death of my sanity
« on: June 07, 2016, 06:55:59 pm »
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. :o  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.

Code: [Select]
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));
    }
}

ricke

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Kinematic Physics, Breakout, and the death of my sanity
« Reply #1 on: June 10, 2016, 03:19:58 pm »
While I'd still be very interested in knowing why this scenario doesn't work properly (as it would be educational for understanding kinematic scenarios), I've changed my direction on the game structure and have embraced the non-kinematic physics approach with 2D physics materials.  This solved all the collision issues I was having and with minimum effort... easily enough that I was frustrated to have spent so much time trying to get the kinematic approach working.  Oh well, I've learned some things in the process that I otherwise wouldn't have learned without the effort.  :)