Talking about Line Rider game, and Flash.
March 31st update: part 5 released
March 4th update: part 4 released
February 17th update: part 3 released
In this part I’ll explore how to detect collision between a ball and the line.
Please read part 1 if you didn’t already.
You may say: “hey, I don’t want a ball, I want a car!!”. There’s no problem, you will learn everyting, I will explain, during next tutorials, how to insert complex objects, but the basics are the same for every collision.
The easy way
Ok, let’s imagine you have the purple line in the movie, and the blue ball you see.
The actionscript in the blue ball is:
onClipEvent (load) {
yspeed = 0;
xspeed = 0;
gravity = 0.2;
}
onClipEvent (enterFrame) {
if (_root.go == true) {
yspeed = yspeed+gravity;
if (_root.terrain.hitTest(_x, _y, true)) {
yspeed = 0;
}
_y = _y+yspeed;
_x = _x+xspeed;
}
}
Lines 1-5: These instructions are execute only once, when the ball firstly appears on the stage. If you followed my flash game creation tutorial you are familiar with those instructions. I am defining ball x and y speed (set to 0, the ball does not move) and the gravity.
Lines 6-15: These are the instructions execute every time the ball is on the stage… every 1/50 seconds in our case.
On line 7 you may see that the whole cycle is executed only when a variable called “go” is true. Don’t worry about it, I put this control to let the ball fall only when you click on the stage.
Line 8: gravity value is added to yspeed. You should easily understand these instructions, if not check flash game creation tutorial part 1 and all will be clear
Lines 9-11: The core of this script: I check the collision between the ball and the terrain, and if positive, I stop the ball. Stopping the ball is the first thing to do before bouncing.
Well, let’s test the script now! It should work!
Hmmm… it didn’t work as I expected… I want the ball to stop when it collides with the ground… but in this case the ball passed the ground as it crashed it.
What’s wrong then? Let’s see this instruction: _root.terrain.hitTest(_x, _y, true)
… you can see the collision is checked on _x and _y ball values… the center of the ball. If you look at the movie, you may see the ball stopped once its center was in collision with the ground.
The hardest way
The solution now is: don’t worry about the center and let’s check the collision between the ground and the ball circumference
Let’s try this actionscript, then
onClipEvent (load) {
yspeed = 0;
xspeed = 0;
gravity = 0.2;
radius = 25;
precision = 90;
}
onClipEvent (enterFrame) {
if (_root.go == true) {
yspeed = yspeed+gravity;
for (x=1; x
Line 5: A new variable is initialized, the radius variable. It contains the value of the radius of our ball, in pixels
Line 6: Another new variable, called precision. We'll see how the higher the precision, the more accurate the collision checking, the more CPU expensive the game. It's up to you finding the right compromise between accuracy and CPU.
Line 11: A cicle executed precision
times
Lines 12-13: spot_x
and spot_y
are the coordinates of points at ball's circumference taken every 360/precision
degrees. And on line 14 you can see I am checking the collision between these points (the circumference) and the terrain.
Let's see if does it work.
It works!! The ball stops on the ground without passing it!!
Two things:
1) Since this operation could be CPU expensive, remember to find a compromise between precision and performances. In most cases, the smaller the ball, the less precision needed.
2) Always try so set precision as a number that perfectly divides 360. I mean values like 36,45,72,90,180. I found 90 is a good value in most cases.
Yeah, I solved the problem, congratulations and so on...
Getting harder and harder... how many collisions?
It's not as easy as it seems...
Look at this actionscript
onClipEvent (load) {
yspeed = 0;
xspeed = 0;
gravity = 0.2;
radius = 25;
precision = 90;
}
onClipEvent (enterFrame) {
if (_root.go == true) {
collisions = 0;
yspeed = yspeed+gravity;
for (x=1; x
Basically it's the same script with three more instructions:
Line 10: A collisions
variable is set to zero.
Line 17: Everytime a collision is checked, the collisions
variable is incremented
Line 20: I show the collision
value. You may thing this value will be 1...
Test the script...
I got an "8"... meaning that what seems a single collision, in reality is made of eight collisions. If you raise the precision to 360, you should get something around 27. I mean twentiseven different collisions, and only one to choose.
What can I do?
Collisions - the final word
Check this last (at the moment) actionscript
onClipEvent (load) {
yspeed = 0;
xspeed = 0;
gravity = 0.2;
radius = 25;
precision = 360;
}
onClipEvent (enterFrame) {
if (_root.go == true) {
collisions = 0;
sum_x = 0;
sum_y = 0;
yspeed = yspeed+gravity;
for (x=1; x0) {
spot_x = sum_x/collisions;
spot_y = sum_y/collisions;
createEmptyMovieClip("lines", 100000);
lines.lineStyle(3, 0x000000, 100);
lines.moveTo(0, 0);
lines.lineTo(spot_x-_x, spot_y-_y);
}
_y = _y+yspeed;
_x = _x+xspeed;
}
}
Lines 11 and 12: I declare two new variables, sum_x
and sum_y
and set them to zero.
Lines 20 and 21: If a collision is checked, I add to sum_x the value of spot_x (the x value of circumference collision) and to sum_y the value of spot_y (same thing for the y value).
Line 24: Check if collisions
is greater than zero, in this case...
Lines 25-26: the new spot_x, the (almost) real point where the ball collided with the ground, is determined dividing the sum_x
variable by the number of collisions. In other words, I am finding the average point of all collisions occurred. Same thing with the spot_y
Lines 27-30: I am just showing a movieclip with a line that goes from the center of the ball to the spot with the average collisions detected
Look at the movie.
This time it works for real.
That's all at the moment, download the full sources of all examples and give me feedback, in next lesson I will explain how to make the ball bounce.
Have fun.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.