Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Deflection game, Actionscript 2, Flash and Game development.

Multipart tutorial: available parts 1, 2, 3

In this 3rd part we are going to create a complete game with exit and two levels.

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

I’ll also fix a bug reported by Questo:

I was playing around and if you right click while making a line it sotps the ball but the ball keeps moving when you put lines on it. it’s pretty cool.

It’s not a difficult task since the game engine is already working… I just created a makelevel function that handles level creation with a switch

// create game object
game = {gravity:0, dragging:false, clip:_root.game_mc, stageW:500, stageH:400, maxV:20};
// starting level 
level = 1;
// function that prepares the level
function makelevel(level) {
	// flag that states if we can draw line or not
	can_draw = false;
	// flag that states if the player drew a line
	player_drew = false;
	// next movie depth for the current drawing line
	nextLineDepth = 0;
	// create the exit
	_root.attachMovie("exit", "exit", 1);
	// create the movieclip that will contain maze lines
	_root.createEmptyMovieClip("lines", 2);
	lines.lineStyle(1, 0xff0000);
	// create a movie which represents a line drawn by mouse
	_root.createEmptyMovieClip("mouseLine", 3);
	// create array for vectors of lines drawn by mouse
	game.mouseV = new Array();
	// create the ball
	_root.attachMovie("ball", "ball", 4);
	game.myOb = {clip:ball, airf:1, b:1, f:1, r:10, lastTime:getTimer()};
	// drawing and placing assets according to level number
	switch (level) {
	case 1 :
		exit._x = 100;
		exit._y = 300;
		game.myOb.p0 = {x:20, y:80};
		// vectors x/y components
		game.myOb.vx = 0;
		game.myOb.vy = 12;
		// create first vector
		// point p0 is its starting point in the coordinates x/y
		// point p1 is its end point in the coordinates x/y
		game.v = new Array();
		game.v[0] = {p0:{x:50, y:40}, p1:{x:450, y:40}};
		game.v[1] = {p0:{x:50, y:40}, p1:{x:50, y:360}};
		game.v[2] = {p0:{x:50, y:360}, p1:{x:450, y:360}};
		game.v[3] = {p0:{x:100, y:80}, p1:{x:400, y:320}};
		break;
	case 2 :
		exit._x = 100;
		exit._y = 350;
		game.myOb.p0 = {x:250, y:250};
		// vectors x/y components
		game.myOb.vx = 12;
		game.myOb.vy = 0;
		// create first vector
		// point p0 is its starting point in the coordinates x/y
		// point p1 is its end point in the coordinates x/y
		game.v = new Array();
		game.v[0] = {p0:{x:200, y:0}, p1:{x:200, y:120}};
		game.v[1] = {p0:{x:200, y:150}, p1:{x:200, y:400}};
		game.v[2] = {p0:{x:300, y:0}, p1:{x:300, y:400}};
		game.v[3] = {p0:{x:0, y:300}, p1:{x:200, y:300}};
		game.v[4] = {p0:{x:200, y:150}, p1:{x:300, y:150}};
		break;
	}
	// draw and calculate all parameters for the wall vectors
	for (x=0; xgame.maxV) {
		ob.vx = game.maxV;
	} else if (ob.vx<-game.maxV) {
		ob.vx = -game.maxV;
	}
	if (ob.vy>game.maxV) {
		ob.vy = game.maxV;
	} else if (ob.vy<-game.maxV) {
		ob.vy = -game.maxV;
	}
	// update the vector parameters                 
	updateObject(ob);
	// check the walls for collisions
	for (x=0; x=0) {
			// move object away from the wall
			ob.p1.x += v.dx*pen;
			ob.p1.y += v.dy*pen;
			// change movement, bounce off from the normal of v
			var vbounce = {dx:v.lx, dy:v.ly, lx:v.dx, ly:v.dy, b:1, f:1};
			var vb = bounce(ob, vbounce);
			ob.vx = vb.vx;
			ob.vy = vb.vy;
		}
	}
	/********************************************************************/
	// CODE ADDED BY SRDJAN SUSNIC
	// check the lines created by mouse for collisions
	x = 0;
	while (x=0) {
			// move object away from the wall
			ob.p1.x += v.dx*pen;
			ob.p1.y += v.dy*pen;
			// change movement, bounce off from the normal of v
			var vbounce = {dx:v.lx, dy:v.ly, lx:v.dx, ly:v.dy, b:1, f:1};
			var vb = bounce(ob, vbounce);
			ob.vx = vb.vx;
			ob.vy = vb.vy;
			// remove the clip and vector array of the collided line
			game.mouseV[x].lineClip.removeMovieClip();
			game.mouseV.splice(x, 1);
		} else {
			x++;
		}
	}
	// END OF CODE ADDED BY SRDJAN SUSNIC	
	/********************************************************************/
	// reset object to other side if gone out of stage
	if (ob.p1.x>game.stageW+ob.r) {
		ob.p1.x = -ob.r;
	} else if (ob.p1.x<-ob.r) {
		ob.p1.x = game.stageW+ob.r;
	}
	if (ob.p1.y>game.stageH+ob.r) {
		ob.p1.y = -ob.r;
	} else if (ob.p1.y<-ob.r) {
		ob.p1.y = game.stageH+ob.r;
	}
	// draw it                 
	drawAll(ob);
	// make end point equal to starting point for next cycle
	ob.p0 = ob.p1;
	// save the movement without time
	ob.vx = ob.vx/ob.timeFrame;
	ob.vy = ob.vy/ob.timeFrame;
}
// function to find all parameters for the vector
function updateVector(v, frompoints) {
	// x and y components
	if (frompoints) {
		v.vx = v.p1.x-v.p0.x;
		v.vy = v.p1.y-v.p0.y;
	} else {
		v.p1.x = v.p0.x+v.vx;
		v.p1.y = v.p0.y+v.vy;
	}
	// length of vector
	v.len = Math.sqrt(v.vx*v.vx+v.vy*v.vy);
	// normalized unti-sized components
	if (v.len>0) {
		v.dx = v.vx/v.len;
		v.dy = v.vy/v.len;
	} else {
		v.dx = 0;
		v.dy = 0;
	}
	// right hand normal
	v.rx = -v.dy;
	v.ry = v.dx;
	// left hand normal
	v.lx = v.dy;
	v.ly = -v.dx;
	return v;
}
function updateObject(v) {
	// find time passed from last update
	var thisTime = getTimer();
	var time = (thisTime-v.lastTime)/100;
	// we use time, not frames to move so multiply movement vector with time passed
	v.vx *= time;
	v.vy *= time;
	// add gravity, also based on time
	v.vy = v.vy+time*game.gravity;
	v.p1 = {};
	// find end point coordinates
	v.p1.x = v.p0.x+v.vx;
	v.p1.y = v.p0.y+v.vy;
	// length of vector
	v.len = Math.sqrt(v.vx*v.vx+v.vy*v.vy);
	// normalized unti-sized components
	v.dx = v.vx/v.len;
	v.dy = v.vy/v.len;
	// right hand normal
	v.rx = -v.vy;
	v.ry = v.vx;
	// left hand normal
	v.lx = v.vy;
	v.ly = -v.vx;
	// save the current time
	v.lastTime = thisTime;
	// save time passed
	v.timeFrame = time;
}
// find intersection point of 2 vectors
function findIntersection(v1, v2) {
	// vector between center of ball and starting point of wall
	var v3 = {};
	v3.vx = v1.p1.x-v2.p0.x;
	v3.vy = v1.p1.y-v2.p0.y;
	// check if we have hit starting point
	var dp = v3.vx*v2.dx+v3.vy*v2.dy;
	if (dp<0) {
		// hits starting point
		var v = v3;
	} else {
		var v4 = {};
		v4.vx = v1.p1.x-v2.p1.x;
		v4.vy = v1.p1.y-v2.p1.y;
		// check if we have hit side or endpoint
		var dp = v4.vx*v2.dx+v4.vy*v2.dy;
		if (dp>0) {
			// hits ending point
			var v = v4;
		} else {
			// it hits the wall
			// project this vector on the normal of the wall
			var v = projectVector(v3, v2.lx, v2.ly);
		}
	}
	return v;
}
// find new vector bouncing from v2
function bounce(v1, v2) {
	// projection of v1 on v2
	var proj1 = projectVector(v1, v2.dx, v2.dy);
	// projection of v1 on v2 normal
	var proj2 = projectVector(v1, v2.lx, v2.ly);
	var proj = {};
	// reverse projection on v2 normal
	proj2.len = Math.sqrt(proj2.vx*proj2.vx+proj2.vy*proj2.vy);
	proj2.vx = v2.lx*proj2.len;
	proj2.vy = v2.ly*proj2.len;
	// add the projections
	proj.vx = v1.f*v2.f*proj1.vx+v1.b*v2.b*proj2.vx;
	proj.vy = v1.f*v2.f*proj1.vy+v1.b*v2.b*proj2.vy;
	return proj;
}
// project vector v1 on unit-sized vector dx/dy
function projectVector(v1, dx, dy) {
	// find dot product
	var dp = v1.vx*dx+v1.vy*dy;
	var proj = {};
	// projection components
	proj.vx = dp*dx;
	proj.vy = dp*dy;
	return proj;
}
/********************************************************************/
// CODE ADDED BY SRDJAN SUSNIC
// declare starting point of the current drawing line
var lineX1, lineY1;
// declare ending point of the current drawing line
var lineX2, lineY2;
// when we click...
onMouseDown = function () {
	// get starting point of line according to current mouse position
	lineX1 = _root._xmouse;
	lineY1 = _root._ymouse;
	// set drawing flag so we can draw a line when mouse is moved
	can_draw = true;
};
// when we move mouse...
onMouseMove = function () {
	if (can_draw) {
		// the player is drawing!
		player_drew = true;
		// get ending point of line according to current mouse position
		lineX2 = _root._xmouse;
		lineY2 = _root._ymouse;
		// clear the previous line drawn by mouse
		mouseLine.clear();
		// set the drawing style
		mouseLine.lineStyle(2, 0x00dd00);
		// move the pen to the starting position
		mouseLine.moveTo(lineX1, lineY1);
		// draw the line to the ending position
		mouseLine.lineTo(lineX2, lineY2);
	}
};
// when we release...
onMouseUp = function () {
	if (player_drew and !right_click) {
		// clear the line drawn by mouse
		mouseLine.clear();
		// create a new movie clip which contains the line previously drawn by mouse
		var tmp = mouseLine.createEmptyMovieClip("newLine", 10+nextLineDepth);
		tmp.lineStyle(5, 0x0000ff);
		tmp.moveTo(lineX1, lineY1);
		tmp.lineTo(lineX2, lineY2);
		// increase movie depth for the next line
		nextLineDepth++;
		// add the parameters of previously created line to the end of line vectors array
		// lineClip parameter is used to store previously created line movie clip
		// so we can remove it when ball bounces from it
		index = game.mouseV.length;
		game.mouseV[index] = {p0:{x:lineX1, y:lineY1}, p1:{x:lineX2, y:lineY2}, b:1, f:1, lineClip:tmp};
		// calculate all parameters for the created line vector
		updateVector(game.mouseV[index], true);
		// set drawing flag so we can't draw a line when mouse is moved
		player_drew = false;
	}
	// if the released button was after a right click, then don't draw the new line              
	if (right_click) {
		right_click = false;
		mouseLine.clear();
	}
	can_draw = false;
};
// END OF CODE ADDED BY SRDJAN SUSNIC	
/********************************************************************/

And now you can play this two levels game… take the blue ball to the green circle.

Now you have all the basics to create your own Deflection game… so I expect to see something interesting on NewGrounds in a few hours.

Download the full source code and show me what you did.

Multipart tutorial: available parts 1, 2, 3

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