This past week, I've been working a lot on collision detection in project "Breaking the Seal". Here was how I got to where I am now:
Research different methods
Try Bounding Box
Tweak my Ball class
Vary the angle for more control and hitting obstacles/blocks
The Process
To keep things simple in this game, since there is no rotation, I decided to go with a bounding box algorithm to detect collisions. Using Monogame (Open Source version of XNA), I can detect when two rectangles are intresecting. Inside the Rectangle class their is a build in Bounds property, but I could not figure out how to update it. For some reason it only set the Bounds on object creation. I already had all of the coordinates that I needed to make my own bounding box, so that's what I did.
There are two main object types that I have in my game, and their is a top-level class for each one. I have Obstacles (what they player is trying to hit) and I have Moving Objects (the ball and the paddle). All of them had to have a bounding box that I created. I got the bounds from calculations made on the different image files that I have loaded into the game. Any time a moving object moves, it updates the bounding box as well. I handle the walls differently by setting constants for the boundaries, but the way the ball reacts is pretty much identical to the way it reacts from colliding with the actual objects.
After I had bounding boxes created, I had to have ways of detecting the direction the ball is moving. This may be inefficient, but it has worked out great so far for me. I have two boolean variables for the ball object that check which direction the ball is moving (one is vertical and the other is horizontal). The ball object also has two functions that control the switching of directions (once again one for vertical and the other for horizontal). When I want to change direction I just call these functions and it flips the "flag" so the ball will go in the opposite direction.
I created two speed variables for the ball object as well (SpeedX and SpeedY). By changing the values of the individual speeds (essentially I'm using vectors) I can vary the angle that the ball is moving. It's basic rise/run stuff. Originally, SpeedX and SpeedY were always identical, so everything was always moving at the same angle. I needed a way to vary that angle.
That's when I came to the next idea. I'm already detecting a collision, so now when the ball hits the paddle I will have to detect where on the paddle it is connecting. I drew this one up on a piece of paper before starting. It probably saved me a lot of time and energy doing things that way. Truth be told, I actually figured out my algorithm in the car on the way to work. I wrote it down at lunch and implemented it at night.
I divided the paddle into separate parts (mathematically), and based off of what half of the paddle it was on determined it's rebound direction. I further divided the paddle (it ended up being into 7ths) to give me a variation in angles:
1 2 3 4 5 6 7
| ---- ---- ---- ---- ---- ---- ---- |
If the ball hit on the outside of these sections, it just changed it's horizontal direction. If it hits in section 1 or 7, the SpeedX is slightly increased and SpeedY slightly decreased (more horizontal than vertical). If it hit in sections 2 or 7, SpeedX and SpeedY are identical (a 45 degree angle). If it hit in section 3 or 5, the SpeedX slightly decreased and SpeedY slightly increased (more vertical than horizontal). Lastly, if it hit in section 4, SpeedX was zero and SpeedY was slightly increased (just vertical movement). This also may not be the most efficient, but it works for my purposes, and the calculations are very simple, and I'm just using a bunch of conditionals to check where it hits. The angle of the ball only changes when it hits the paddle. Otherwise, it will deflect at the same angle that it hit the object (obstacles and walls).
My Opinion on the Experience
For me, I thoroughly enjoyed working this out. While I may be doing the same thing as everyone else approaching this problem, it was still all figured out on pencil and paper by me. I feel like this is a very simple solution to the problem. I didn't need to deal with trigonometry this time around. When I get to more involved things that are using rotation and such, yes, I will need to use it.
Largely, this project is meant to help me see what's involved in making a game. The focus this time around for me is more on the process, and not so much the content. In that regard, I think it is going great. Once I understand the process, I can then move on to producing better content.
I find myself wishing that I had retained more math from high school (trig in particular). I never would've thought I would've enjoyed the math and the algorithms so much. With using all of this stuff, I've come to a greater appreciation of math. It's unfortunate that most schools make math feel like a boring and uncreative process. Math is very creative, but it is a different level of creativity than what we normally view as creative in the world. Math can make beautiful things. Look at fractals, they are beautiful works of art that occur naturally in our world.That's only one of many examples. Math is beautiful, and it is really unfortunate that it is sold to kids as a boring and linear thing. I look forward to re-learning more and making beautiful works of math in my programs.
What's next?
My game works as a game now. It's just missing some things you normally have in a game. There is only one state to the game. I need to work on making more game states to make it a game that can actually be released. I will post more on it in a future post. Right now, there is only playing the game. There needs to be a start screen, play screen, pause screen, game over screen, etc... Those are all examples of game states.
Once game states are figured out, I can then move on to adding some more flare.
Let me know if you have any thoughts if you stop by for a read by either responding on this or maybe tweeting it. My twitter handle is @boris_zhp.