Create a Flash game like Deflection - part 2

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:

ACTIONSCRIPT:
  1. // create game object
  2. game = {gravity:0, dragging:false, clip:_root.game_mc, stageW:500, stageH:400, maxV:20};
  3. // create object
  4. // point p0 is its starting point in the coordinates x/y
  5. _root.attachMovie("ball", "ball", 1);
  6. game.myOb = {clip:ball, airf:1, b:1, f:1, r:20, lastTime:getTimer()};
  7. game.myOb.p0 = {x:150, y:80};
  8. // vectors x/y components
  9. game.myOb.vx = 8;
  10. game.myOb.vy = 12;
  11. // create first vector
  12. // point p0 is its starting point in the coordinates x/y
  13. // point p1 is its end point in the coordinates x/y
  14. game.v = new Array();
  15. game.v[0] = {p0:{x:50, y:40}, p1:{x:450, y:40}, b:1, f:1};
  16. game.v[1] = {p0:{x:50, y:40}, p1:{x:50, y:360}, b:1, f:1};
  17. game.v[2] = {p0:{x:50, y:360}, p1:{x:450, y:360}, b:1, f:1};
  18. game.v[3] = {p0:{x:100, y:80}, p1:{x:400, y:320}, b:1, f:1};
  19. _root.createEmptyMovieClip("lines", 2);
  20. lines.lineStyle(1, 0xff0000);
  21. // draw and calculate all parameters for the wall vectors
  22. for (x=0; x<game.v.length; x++) {
  23.     lines.moveTo(game.v[x].p0.x, game.v[x].p0.y);
  24.     lines.lineTo(game.v[x].p1.x, game.v[x].p1.y);
  25.     updateVector(game.v[x], true);
  26. }
  27. _root.onEnterFrame = function() {
  28.     _root.runMe();
  29. };
  30. // function to draw the points, lines and show text
  31. function drawAll(v) {
  32.     // place ob mc
  33.     v.clip._x = v.p1.x;
  34.     v.clip._y = v.p1.y;
  35. }
  36. // main function
  37. function runMe() {
  38.     // start to calculate movement
  39.     var ob = game.myOb;
  40.     // add air resistance
  41.     ob.vx *= ob.airf;
  42.     ob.vy *= ob.airf;
  43.     // dont let it go over max speed
  44.     if (ob.vx>game.maxV) {
  45.         ob.vx = game.maxV;
  46.     } else if (ob.vx<-game.maxV) {
  47.         ob.vx = -game.maxV;
  48.     }
  49.     if (ob.vy>game.maxV) {
  50.         ob.vy = game.maxV;
  51.     } else if (ob.vy<-game.maxV) {
  52.         ob.vy = -game.maxV;
  53.     }
  54.     // update the vector parameters
  55.     updateObject(ob);
  56.     // check the walls for collisions
  57.     for (x=0; x<game.v.length; x++) {
  58.         var w = game.v[x];
  59.         var v = findIntersection(ob, w);
  60.         v = updateVector(v, false);
  61.         var pen = ob.r-v.len;
  62.         // if we have hit the wall
  63.         if (pen>=0) {
  64.             // move object away from the wall
  65.             ob.p1.x += v.dx*pen;
  66.             ob.p1.y += v.dy*pen;
  67.             // change movement, bounce off from the normal of v
  68.             var vbounce = {dx:v.lx, dy:v.ly, lx:v.dx, ly:v.dy, b:1, f:1};
  69.             var vb = bounce(ob, vbounce);
  70.             ob.vx = vb.vx;
  71.             ob.vy = vb.vy;
  72.         }
  73.     }
  74.     /********************************************************************/
  75.     // CODE ADDED BY SRDJAN SUSNIC
  76.     // check the lines created by mouse for collisions
  77.     x = 0;
  78.     while (x<game.mouseV.length) {
  79.         var w = game.mouseV[x];
  80.         var v = findIntersection(ob, w);
  81.         v = updateVector(v, false);
  82.         var pen = ob.r-v.len;
  83.         // if we have hit the wall
  84.         if (pen>=0) {
  85.             // move object away from the wall
  86.             ob.p1.x += v.dx*pen;
  87.             ob.p1.y += v.dy*pen;
  88.             // change movement, bounce off from the normal of v
  89.             var vbounce = {dx:v.lx, dy:v.ly, lx:v.dx, ly:v.dy, b:1, f:1};
  90.             var vb = bounce(ob, vbounce);
  91.             ob.vx = vb.vx;
  92.             ob.vy = vb.vy;
  93.             // remove the clip and vector array of the collided line
  94.             game.mouseV[x].lineClip.removeMovieClip();
  95.             game.mouseV.splice(x, 1);
  96.         } else {
  97.             x++;
  98.         }
  99.     }
  100.     // END OF CODE ADDED BY SRDJAN SUSNIC   
  101.     /********************************************************************/
  102.     // reset object to other side if gone out of stage
  103.     if (ob.p1.x>game.stageW+ob.r) {
  104.         ob.p1.x = -ob.r;
  105.     } else if (ob.p1.x<-ob.r) {
  106.         ob.p1.x = game.stageW+ob.r;
  107.     }
  108.     if (ob.p1.y>game.stageH+ob.r) {
  109.         ob.p1.y = -ob.r;
  110.     } else if (ob.p1.y<-ob.r) {
  111.         ob.p1.y = game.stageH+ob.r;
  112.     }
  113.     // draw it
  114.     drawAll(ob);
  115.     // make end point equal to starting point for next cycle
  116.     ob.p0 = ob.p1;
  117.     // save the movement without time
  118.     ob.vx = ob.vx/ob.timeFrame;
  119.     ob.vy = ob.vy/ob.timeFrame;
  120. }
  121. // function to find all parameters for the vector
  122. function updateVector(v, frompoints) {
  123.     // x and y components
  124.     if (frompoints) {
  125.         v.vx = v.p1.x-v.p0.x;
  126.         v.vy = v.p1.y-v.p0.y;
  127.     } else {
  128.         v.p1.x = v.p0.x+v.vx;
  129.         v.p1.y = v.p0.y+v.vy;
  130.     }
  131.     // length of vector
  132.     v.len = Math.sqrt(v.vx*v.vx+v.vy*v.vy);
  133.     // normalized unti-sized components
  134.     if (v.len>0) {
  135.         v.dx = v.vx/v.len;
  136.         v.dy = v.vy/v.len;
  137.     } else {
  138.         v.dx = 0;
  139.         v.dy = 0;
  140.     }
  141.     // right hand normal
  142.     v.rx = -v.dy;
  143.     v.ry = v.dx;
  144.     // left hand normal
  145.     v.lx = v.dy;
  146.     v.ly = -v.dx;
  147.     return v;
  148. }
  149. function updateObject(v) {
  150.     // find time passed from last update
  151.     var thisTime = getTimer();
  152.     var time = (thisTime-v.lastTime)/100;
  153.     // we use time, not frames to move so multiply movement vector with time passed
  154.     v.vx *= time;
  155.     v.vy *= time;
  156.     // add gravity, also based on time
  157.     v.vy = v.vy+time*game.gravity;
  158.     v.p1 = {};
  159.     // find end point coordinates
  160.     v.p1.x = v.p0.x+v.vx;
  161.     v.p1.y = v.p0.y+v.vy;
  162.     // length of vector
  163.     v.len = Math.sqrt(v.vx*v.vx+v.vy*v.vy);
  164.     // normalized unti-sized components
  165.     v.dx = v.vx/v.len;
  166.     v.dy = v.vy/v.len;
  167.     // right hand normal
  168.     v.rx = -v.vy;
  169.     v.ry = v.vx;
  170.     // left hand normal
  171.     v.lx = v.vy;
  172.     v.ly = -v.vx;
  173.     // save the current time
  174.     v.lastTime = thisTime;
  175.     // save time passed
  176.     v.timeFrame = time;
  177. }
  178. // find intersection point of 2 vectors
  179. function findIntersection(v1, v2) {
  180.     // vector between center of ball and starting point of wall
  181.     var v3 = {};
  182.     v3.vx = v1.p1.x-v2.p0.x;
  183.     v3.vy = v1.p1.y-v2.p0.y;
  184.     // check if we have hit starting point
  185.     var dp = v3.vx*v2.dx+v3.vy*v2.dy;
  186.     if (dp<0) {
  187.         // hits starting point
  188.         var v = v3;
  189.     } else {
  190.         var v4 = {};
  191.         v4.vx = v1.p1.x-v2.p1.x;
  192.         v4.vy = v1.p1.y-v2.p1.y;
  193.         // check if we have hit side or endpoint
  194.         var dp = v4.vx*v2.dx+v4.vy*v2.dy;
  195.         if (dp>0) {
  196.             // hits ending point
  197.             var v = v4;
  198.         } else {
  199.             // it hits the wall
  200.             // project this vector on the normal of the wall
  201.             var v = projectVector(v3, v2.lx, v2.ly);
  202.         }
  203.     }
  204.     return v;
  205. }
  206. // find new vector bouncing from v2
  207. function bounce(v1, v2) {
  208.     // projection of v1 on v2
  209.     var proj1 = projectVector(v1, v2.dx, v2.dy);
  210.     // projection of v1 on v2 normal
  211.     var proj2 = projectVector(v1, v2.lx, v2.ly);
  212.     var proj = {};
  213.     // reverse projection on v2 normal
  214.     proj2.len = Math.sqrt(proj2.vx*proj2.vx+proj2.vy*proj2.vy);
  215.     proj2.vx = v2.lx*proj2.len;
  216.     proj2.vy = v2.ly*proj2.len;
  217.     // add the projections
  218.     proj.vx = v1.f*v2.f*proj1.vx+v1.b*v2.b*proj2.vx;
  219.     proj.vy = v1.f*v2.f*proj1.vy+v1.b*v2.b*proj2.vy;
  220.     return proj;
  221. }
  222. // project vector v1 on unit-sized vector dx/dy
  223. function projectVector(v1, dx, dy) {
  224.     // find dot product
  225.     var dp = v1.vx*dx+v1.vy*dy;
  226.     var proj = {};
  227.     // projection components
  228.     proj.vx = dp*dx;
  229.     proj.vy = dp*dy;
  230.     return proj;
  231. }
  232. /********************************************************************/
  233. // CODE ADDED BY SRDJAN SUSNIC
  234. // declare starting point of the current drawing line
  235. var lineX1, lineY1;
  236. // declare ending point of the current drawing line
  237. var lineX2, lineY2;
  238. // flag that states if we can draw line or not
  239. can_draw = false;
  240. // flag that states if the player drew a line
  241. player_drew = false;
  242. // next movie depth for the current drawing line
  243. nextLineDepth = 0;
  244. // create array for vectors of lines drawn by mouse
  245. game.mouseV = new Array();
  246. // create a movie which represents a line drawn by mouse
  247. _root.createEmptyMovieClip("mouseLine", 3);
  248. // when we click...
  249. onMouseDown = function () {
  250.     // get starting point of line according to current mouse position
  251.     lineX1 = _root._xmouse;
  252.     lineY1 = _root._ymouse;
  253.     // set drawing flag so we can draw a line when mouse is moved
  254.     can_draw = true;
  255. };
  256. // when we move mouse...
  257. onMouseMove = function () {
  258.     if (can_draw) {
  259.         // the player is drawing!
  260.         player_drew = true;
  261.         // get ending point of line according to current mouse position
  262.         lineX2 = _root._xmouse;
  263.         lineY2 = _root._ymouse;
  264.         // clear the previous line drawn by mouse
  265.         mouseLine.clear();
  266.         // set the drawing style
  267.         mouseLine.lineStyle(2, 0x00dd00);
  268.         // move the pen to the starting position
  269.         mouseLine.moveTo(lineX1, lineY1);
  270.         // draw the line to the ending position
  271.         mouseLine.lineTo(lineX2, lineY2);
  272.     }
  273. };
  274. // when we release...
  275. onMouseUp = function () {
  276.     if (player_drew) {
  277.         // clear the line drawn by mouse
  278.         mouseLine.clear();
  279.         // create a new movie clip which contains the line previously drawn by mouse
  280.         var tmp = createEmptyMovieClip("newLine", 10+nextLineDepth);
  281.         tmp.lineStyle(5, 0x0000ff);
  282.         tmp.moveTo(lineX1, lineY1);
  283.         tmp.lineTo(lineX2, lineY2);
  284.         // increase movie depth for the next line
  285.         nextLineDepth++;
  286.         // add the parameters of previously created line to the end of line vectors array
  287.         // lineClip parameter is used to store previously created line movie clip
  288.         // so we can remove it when ball bounces from it
  289.         index = game.mouseV.length;
  290.         game.mouseV[index] = {p0:{x:lineX1, y:lineY1}, p1:{x:lineX2, y:lineY2}, b:1, f:1, lineClip:tmp};
  291.         // calculate all parameters for the created line vector
  292.         updateVector(game.mouseV[index], true);
  293.         // set drawing flag so we can't draw a line when mouse is moved
  294.         player_drew = false;
  295.     }
  296.     can_draw = false;
  297. };
  298. // END OF CODE ADDED BY SRDJAN SUSNIC   
  299. /********************************************************************/

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

Improve the blog rating this post
Tell me what do you think about this post. I'll write better and better entries.
1 Star2 Stars3 Stars4 Stars5 Stars (16 votes, average: 4.44 out of 5)
Loading ... Loading ...

» Flash Templates provided by Template Monster are pre-made web design products developed using Flash technology.
They can be easily customized to meet the unique requirements of your project.

7 Responses to “Create a Flash game like Deflection - part 2”

  1. souled on July 12th, 2008 2:18 pm

    Wow, nice!

  2. Questo on July 12th, 2008 10:21 pm

    Amazing
    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.

  3. David on July 13th, 2008 1:28 am

    I just got a very nice idea! I’ll email you the game when I’m done!

  4. FrozenHaddock on July 13th, 2008 1:35 am

    This is pretty awesome, definitely looking at making something with this! (even if it’s just the line drawing and removal part of it, I have a few ideas…)

  5. ssusnic on July 14th, 2008 8:27 am

    Thanks for fixing bug! Nice to see that people like this implementation of player interaction.

  6. Create a Flash game like Deflection - part 3 : Emanuele Feronato - italian geek and PROgrammer on July 25th, 2008 6:47 pm

    [...] tutorial: available parts 1, 2, [...]

  7. Create a Flash game like Deflection : Emanuele Feronato - italian geek and PROgrammer on July 25th, 2008 6:49 pm

    [...] tutorial: available parts 1, 2, [...]

Leave a Reply