Talking about Deflection game, Actionscript 2, Flash, Game development and Users contributions.
Multipart tutorial: available parts 1, 2, 3
In the 1st part I showed you how to make a deflection engine starting from an old tutorial, now it’s time to let the player draw walls.
The idea comes from Srdjan Susnic, a reader who runs the blog Ask For Game Task.
The main task Srdjan accomplished was to add a mouse control so a player can draw lines from which the ball will bounce.
After collision between the ball and a line drawn by mouse, that line must be removed
The code is clear and well commented, but it seems to suffer a bug if the player just clicks the mouse without drawing.
It’s just a minor issue I fixed in a moment, and if you already read the original post, I just added the control if the player drew a line when he releases the mouse button with player_drew
variable.
Anyway, this is the actionscript:
// create game object
game = {gravity:0, dragging:false, clip:_root.game_mc, stageW:500, stageH:400, maxV:20};
// create object
// point p0 is its starting point in the coordinates x/y
_root.attachMovie("ball", "ball", 1);
game.myOb = {clip:ball, airf:1, b:1, f:1, r:20, lastTime:getTimer()};
game.myOb.p0 = {x:150, y:80};
// vectors x/y components
game.myOb.vx = 8;
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}, b:1, f:1};
game.v[1] = {p0:{x:50, y:40}, p1:{x:50, y:360}, b:1, f:1};
game.v[2] = {p0:{x:50, y:360}, p1:{x:450, y:360}, b:1, f:1};
game.v[3] = {p0:{x:100, y:80}, p1:{x:400, y:320}, b:1, f:1};
_root.createEmptyMovieClip("lines", 2);
lines.lineStyle(1, 0xff0000);
// 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;
// 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 array for vectors of lines drawn by mouse
game.mouseV = new Array();
// create a movie which represents a line drawn by mouse
_root.createEmptyMovieClip("mouseLine", 3);
// 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) {
// clear the line drawn by mouse
mouseLine.clear();
// create a new movie clip which contains the line previously drawn by mouse
var tmp = 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;
}
can_draw = false;
};
// END OF CODE ADDED BY SRDJAN SUSNIC
/********************************************************************/
And this is the result:
Now you can draw lines with the mouse and the only thing we need in order to have a complete game engine is handling the exit.
Any idea?
Download the source code and play.
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.