Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Line Rider game, and Flash.

March 31st update: part 5 released
March 4th update: part 4 released

In the 3rd part I am going to make the ball bounce.

Read lessons 1 and 2 if you haven’t done it already.

Trigonomerty Basics

Let’s introduce trigonometry basics and how flash manages trigonometry. I suggest you to give a look at wikipedia, where I found some information I am reporting here.

The shape of a right triangle is completely determined, up to similarity, by the value of either of the other two angles. This means that once one of the other angles is known, the ratios of the various sides are always the same regardless of the size of the triangle. These ratios are traditionally described by the following trigonometric functions of the known angle:

The sine function (sin), defined as the ratio of the leg opposite the angle to the hypotenuse.
The cosine function (cos), defined as the ratio of the adjacent leg to the hypotenuse.
The tangent function (tan), defined as the ratio of the opposite leg to the adjacent leg.
The adjacent leg is the side of the angle that is not the hypotenuse. The hypotenuse is the side opposite to the 90 degree angle in a right triangle; it is the longest side of the triangle.

The reciprocals of these functions are named the cosecant (csc), secant (sec) and cotangent (cot), respectively. The inverse functions are called the arcsine, arccosine, and arctangent, respectively

Trigonomerty

That’s all you need to know about trigonometry…

Trigonometry and Flash

Flash determines angles in radians, but we need degrees… so we need to know how to convert degrees to randians and radians to degrees.

angle_degrees = angle_radians * 180/Math.PI;
angle_radians = angle_degrees * Math.PI/180;

These are the formulas to convert between degrees and randias. The Math.PI is a constant with the value of pi (3.14…)

Direction theory

The first thing we need to know is the direction of the ball of whatever other thing.
To introduce these concepts, I am showing you a movie where there is a flat ground and an arrow that points from the mouse position to the center of the ground.

Move the mouse over the movie, and you’ll see the arrow to rotate keeping the direction from the mouse pointer to the center.

How can we do that? Using trigonometry previously explained.

_root.attachMovie("arrow", "arrow", 10001);
arrow._x = 150;
arrow._y = 150;
arrow.onEnterFrame = function() {
	mousex = _xmouse-150;
	mousey = (_ymouse-150)*-1;
	angle = Math.atan(mousey/mousex)/(Math.PI/180);
	if (mousex<0) {
		angle += 180;
	}
	if (mousex>=0 && mousey<0) {
		angle += 360;
	}
	_root.angletext.text = "Angle: "+angle;
	this._rotation = angle*-1;
};

Lines 1-3: the "arrow" movie is attached to the stage and placed at 150,150 (the absolute center of the stage).

Lines 5-6: determining the position of the mouse pointer relatively to the center of the stage.

Now, it's obvious that mousex and mousey values represent respectively the adjacent and the opposite values. We need to determine the angle.

Line 7 Applies a formula based on trigonometry explained above and converts the radians to degrees.

Lines 8-13 Transform angle value from flash angle system to "our" angle system. When I say "our" angle system I mean that 0 degrees is where the clock says "3", 90 degrees where the clock says "12", 180 degrees where the clock says "9" and 270 degrees where the clock says "6".

With this actionscript we determined the angle where the ball comes from.

Now, let's make it bounce.

Bouncing theory

In a real world, bounce is determined from various variables, such as terrain hardness, ball hardness, friction and so on. At the moment, we only need to know that the bouncing ball acts like a ray of light casted on a mirror. The ground is the mirror, and the incoming ball is the ray of light.

Look at this movie: you move the blue arrow (ball) with the mouse while the red arrow is the bouncing direction

The actionscript is very similar to the previous one:

_root.attachMovie("arrow", "arrow", 10001);
_root.attachMovie("bounce", "bounce", 1000);
arrow._x = 150;
arrow._y = 150;
bounce._x = 150;
bounce._y = 150;
arrow.onEnterFrame = function() {
	mousex = _xmouse-150;
	mousey = (_ymouse-150)*-1;
	angle = Math.atan(mousey/mousex)/(Math.PI/180);
	if (mousex<0) {
		angle += 180;
	}
	if (mousex>=0 && mousey<0) {
		angle += 360;
	}
	bounce_angle = 180-angle;
	if (bounce_angle<0) {
		bounce_angle += 360;
	}
	_root.angletext.text = "Angle: "+angle;
	_root.bouncetext.text = "Angle: "+bounce_angle;
	this._rotation = angle*-1;
	bounce._rotation = -bounce_angle;
};

The only important lines here are lines 17-20 where I get the bounce angle starting from the incoming angle and convert the value to the "clock" values explained before.

Now we know almost all about bouncing... I say "almost" because we assumed the ground to be plain. What if the ground itself should have an angle?

Bouncing on angled ground

In next example, you move the ball angle with the mouse and the ground with left and right arrow keys

Look: even if the ground has its angle, the bounce still works.

_root.attachMovie("arrow", "arrow", 10001);
_root.attachMovie("bounce", "bounce", 1000);
arrow._x = 150;
arrow._y = 150;
bounce._x = 150;
bounce._y = 150;
arrow.onEnterFrame = function() {
	if (Key.isDown(Key.LEFT)) {
		ground._rotation--;
	}
	if (Key.isDown(Key.RIGHT)) {
		ground._rotation++;
	}
	mousex = _xmouse-150;
	mousey = (_ymouse-150)*-1;
	angle = Math.atan(mousey/mousex)/(Math.PI/180);
	if (mousex<0) {
		angle += 180;
	}
	if (mousex>=0 && mousey<0) {
		angle += 360;
	}
	bounce_angle = 180-angle-2*(ground._rotation);
	if (bounce_angle<0) {
		bounce_angle += 360;
	}
	_root.angletext.text = "Angle: "+angle;
	_root.bouncetext.text = "Angle: "+bounce_angle;
	_root.groundtext.text = "Angle: "+ground._rotation;
	this._rotation = angle*-1;
	bounce._rotation = -bounce_angle;
};

Lines 8-13 manage the routine to pan the ground according to left and right arrow keys

Line 23 determines the bounce angle almost the same way as before but I considered the ground rotation too. The 2* multiplier is there because in this examples ground rotation does not go from 0 to 359 but from -179 to 180.

Now we know how to determine the angle of impact, the ground rotation and the ball bounce... time to do something serious.

Putting all together

Time to pick the last example we left in part 2 and add all these little tricks

onClipEvent (load) {
	yspeed = 0;
	xspeed = 0;
	gravity = 0.2;
	radius = 25;
	friction = 0.90;
	precision = 360;
	bounces = 0;
}
onClipEvent (enterFrame) {
	if (_root.go == true) {
		collisions = 0;
		sum_x = 0;
		sum_y = 0;
		yspeed = yspeed+gravity;
		for (x=1; x0) {
			bounces++;
			_root.collisions.text = "Bounces: "+bounces;
			ball_dir = Math.atan(yspeed/(xspeed*-1))/(Math.PI/180);
			if ((xspeed*-1)<0) {
				ball_dir += 180;
			}
			if ((xspeed*-1)>=0 && yspeed<0) {
				ball_dir += 360;
			}
			spot_x = sum_x/collisions;
			spot_y = sum_y/collisions;
			x_cat = spot_x-_x;
			y_cat = spot_y-_y;
			ball_coll = Math.atan(y_cat/x_cat)/(Math.PI/180);
			if (x_cat<0) {
				ball_coll += 180;
			}
			if (x_cat>=0 && y_cat<0) {
				ball_coll += 360;
			}
			ground_rotation = ball_coll-90;
			if (ground_rotation<0) {
				ground_rotation += 180;
			}
			bounce_angle = 180-ball_dir-2*(ground_rotation);
			if (bounce_angle<0) {
				bounce_angle += 360;
			}
			speed = Math.sqrt((yspeed*yspeed)+(xspeed*xspeed));
			xspeed = speed*Math.cos(bounce_angle*Math.PI/180)*friction;
			yspeed = (speed*Math.sin(bounce_angle*Math.PI/180))*-1*friction;
		}
		_y = _y+yspeed;
		_x = _x+xspeed;
	}
}

Let's examine the lines not previously explained:

Line 6: introducing the friction... to know how to apply friction to a ball, refer to flash game creation tutorial part 1

Line 8: I set a bounce counter to zero. This will become useful later.

Line 26: If a collision is detected, then increase the bounce counter.

Lines 28-34: Determining ball direction angle starting from its xspeed and yspeed (opposite and adjacent). The xspeed is multiplied by -1 because, unlike previous examples, when xspeed is greater than zero means I am moving from left to right, and when xspeed is less than zero means I am moving from right to left.

Lines 37-38: Once I determined the average spot of collision as explained in step 2, now I calculate its x and y position relatively to the ball center. These are the opposite and adjacent needed to determine ball angle of impact.

Lines 39-45: Determining ball angle of collision

Lines 46-49: From the angle of collision, I am determining the ground angle

Lines 50-53: Now that I have ball direction and ground angle, with the same formula explained before I determine the bounce angle.

Line 54: With the Pythagorean theorem I calculate the ball speed starting from xspeed and yspeed

Lines 55-56: Now that I have the speed (hypotenuse) and the angle (A), with the trigonometry formulas I calculate new xspeed (adjacent) and yspeed (opposite)

Test the movie and you will see a pretty accurate bouncing, with only two issues:

1) Sometimes the ball seems to bounce "twice" as necessary

2) The ball never stops

We will fix these issues later on this tutorial, that is way to be finished, but you should be able to create your own raw draw game. If you create something playable sent it to me and I will publish it, meanwhile download the full sources of these examples and give me feedback.

Then, proceed to part 4

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.