Install Circle Chain on your iPhone for free and get the source code!! 645 downloads to go - last updated: April 21, 2012

Worms-like destructible terrain in Flash – Part 2

After having some troubles with the email, I am finally able to post Jordi Sanglas Molist‘s second step of Worms-like destructible terrain in Flash.

Now the character can jump and move. I’ve also solved a bug: in the last script I checked a collision using the feet, so if the terrain was between both feet the character would fall.

Now, instead of using a hitTest between a BitmapData and a point I use a hitTest between a BitmapData and a Rectangle.

We have to check more collisions, so I used four rectangles:

* The rectangle below the character is used to check if the character must fall

* The rectangle above the character is used to check if the character hit the ground (while he was jumping)

* The rectangles at the sides are used to check if the character can move.

These rectangles aren’t as long as the character, they’re 17 pixels height instead of 20. That’s because, if the character wants to move left and the obstacle isn’t high enough (high enough to reach the rectangle), the character will be able to move. A similar strategy is used in “Create a flash draw game like line rider or others – part 5“, where a point (the knee point) is used to check if the character can move.

I renamed the function “fall”: now it’s “move_character”. I only commented the new lines. Now I’m working on part 3, but I still don’t know how to calculate the explosion impulse. I looked for some information, but now I’m thinking about maths (an explosion is a growing circle).

This is the script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package {
	import flash.display.Sprite;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.geom.Matrix;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.KeyboardEvent;
 
	public class worms extends Sprite {
 
		public var terrain_bmpd:BitmapData=new BitmapData(550,200,true,0xFF00FF00);
		public var terrain_bmp:Bitmap=new Bitmap(terrain_bmpd);
		public var character:Sprite=new Sprite  ;
		public var character_speed:Number=0;//That number is the y speed that the character has
		public var hole:Sprite=new Sprite  ;
		public var hole_matrix:Matrix;
		public var left_key:Boolean;
		public var right_key:Boolean;
		public var space_key:Boolean;
		public var jumping:Boolean=true;//When that variable is true, the character is in the air
		public var i:int;//We will use this variable to make a loop
 
		public function worms() {
			draw_objects();
 
			stage.addEventListener(Event.ENTER_FRAME,move_character);
			stage.addEventListener(MouseEvent.MOUSE_UP,mouse_up);
			stage.addEventListener(KeyboardEvent.KEY_DOWN,key_down);
			stage.addEventListener(KeyboardEvent.KEY_UP,key_up);
		}
 
		public function move_character(e:Event) {
			//If left key is pressed, we'll move the character to the left
			if (left_key) {
				for (i=0; i<3; i++) {//Do you remember when we made the character fall? We had to move the character pixel by pixel
					if (! terrain_bmpd.hitTest(new Point(terrain_bmp.x,terrain_bmp.y),0x01,new Rectangle(character.x-6,character.y-10,1,17))) {
						character.x--;	/*If the character doesn't hit the ground, we can move left. However,
										the character may be sunk under the ground. We have to lift it*/
						while (terrain_bmpd.hitTest(new Point(terrain_bmp.x,terrain_bmp.y),0x01,new Rectangle(character.x-5,character.y+9,10,1))) {
							character.y--;
						}
					}
				}
			}
			if (right_key) {//Well, that's the same for the right key
				for (i=0; i<3; i++) {
					if (! terrain_bmpd.hitTest(new Point(terrain_bmp.x,terrain_bmp.y),0x01,new Rectangle(character.x+5,character.y-10,1,17))) {
						character.x++;
						while (terrain_bmpd.hitTest(new Point(terrain_bmp.x,terrain_bmp.y),0x01,new Rectangle(character.x-5,character.y+9,10,1))) {
							character.y--;
						}
					}
				}
			}
			if (space_key&&! jumping) {//That's easy: if he isn't jumping and you press space, his speed will be negative and he'll jump
				character_speed=-10;
				jumping=true;//Now the character can't jump again
			}
 
			character_speed++;//Every frame we will increase character's speed
			if (character_speed>0) {
				//If the speed is positive, we will check a collision between the terrain and the rectangle below the character
				for (i=0; i<character_speed; i++) {//We check the collision pixel by pixel...
					if (! terrain_bmpd.hitTest(new Point(terrain_bmp.x,terrain_bmp.y),0x01,new Rectangle(character.x-5,character.y+9,10,1))) {
						character.y++;//If there isn't a collision, the character will fall
					} else {
						jumping=false;//If there's a collision with the ground, the character isn't jumping
						character_speed=0;//The speed is 0, because the character hit the ground
					}
				}
			} else {
				for (i=0; i<Math.abs(character_speed); i++) {//If the speed is negative, the for loop won't work. We have to use Math.abs().
				//Now we will check the collision between the terrain and the rectangle above the character
					if (! terrain_bmpd.hitTest(new Point(terrain_bmp.x,terrain_bmp.y),0x01,new Rectangle(character.x-5,character.y-10,10,1))) {
						character.y--;
					} else {
						character_speed=0;//Well, that's the same: the character hit the ground
					}
				}
			}
		}
 
		public function mouse_up(e:MouseEvent) {
			hole_matrix=new Matrix  ;
			hole_matrix.translate(e.stageX-terrain_bmp.x,e.stageY-terrain_bmp.y);
			terrain_bmpd.draw(hole,hole_matrix,null,BlendMode.ERASE);
 
		}
 
		public function key_down(e:KeyboardEvent) {
			if (e.keyCode==37) {
				left_key=true;
			}
			if (e.keyCode==39) {
				right_key=true;
			}
			if (e.keyCode==32) {
				space_key=true;
			}
		}
		public function key_up(e:KeyboardEvent) {
			if (e.keyCode==37) {
				left_key=false;
			}
			if (e.keyCode==39) {
				right_key=false;
			}
			if (e.keyCode==32) {
				space_key=false;
			}
		}
 
		public function draw_objects() {
			terrain_bmp.y=200;
			stage.addChild(terrain_bmp);
 
			character.graphics.beginFill(0x0000FF);
			character.graphics.drawRect(-5,-10,10,20);
			character.x=250;
			stage.addChild(character);
 
			hole.graphics.beginFill(0x000000);
			hole.graphics.drawCircle(0,0,30);
		}
	}
}

And this is the result:

Move the player with left – right arrow keys and click on the terrain to create an explosion.

Download the source code. Now Jordi is trying to manage explosion impulse but he’s having some problems. Any blog-bomber reader willing to read?

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (10 votes, average: 4.70 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.
Be my fan on Facebook and follow me on Twitter! Exclusive content for my Facebook fans and Twitter followers

This post has 24 comments

  1. jose

    on August 6, 2010 at 1:41 am

    i’m the first to comment and i think this is a great idea. This original and the weapons made Worms the famous game we now today. I had always asked myself how to now i only thank Jordi Snaglas.

  2. Kaustav

    on August 6, 2010 at 6:29 am

    Hey, great tut and code!

    What exactly do you mean by ‘explosion impulse’? I may be able to help =)

  3. Jordi Sanglas Molist

    on August 6, 2010 at 7:35 am

    When there’s an explosion near a worm, that one will move away from the centre. But how is this related to the distance?

    I first thought that: the distance from the explosion centre to the worm is inversely proportional to the impulse. But that doesn’t work: the explosion at 1cm from the worm wouldn’t move it at twice the speed that the explosion at 2cm.

    Sorry if there are mistakes, I haven’t revised the text.

  4. MC

    on August 6, 2010 at 10:52 am

    @Jordi: you should use an explosion radio… if the enemy is between this radio it will explode… then, you should calculate “how close” is inside the radio (50% distance = half damage… 25% near= 75% damage, and so on… ) there are many ways, this is just one idea

  5. Jordi Sanglas Molist

    on August 6, 2010 at 12:23 pm

    Well, the problem was the impulse speed; however, your idea can also be applied: if the worm is 25% near, the speed will be 75%…

    Thanks, MC! Part 3 is coming.

  6. Jordi Sanglas Molist

    on August 6, 2010 at 12:36 pm

    I forgot some parentheses!

    new Sprite ; –> new Sprite();
    new Matrix ; –> new Matrix();

    I don’t know why it works without them.

  7. Jesús

    on August 6, 2010 at 5:17 pm

    I think that 2d character behaivor would be more easy to implement using box2d for example, what do you think about this?

  8. Kaustav

    on August 6, 2010 at 8:01 pm

    Oh that?? That’s simple. You just use the intensity formula:

    Force = constant/(Distance^2);

    (The constant is the power of the explosion)

    Now, the force is turned into acceleration through:

    Acc = Force/mass

    (mass is weight of character)

    So you just add the acc to the character_speed variable of your character on that frame.

  9. Jodi Houareau

    on August 7, 2010 at 10:50 am

    nice code Jordi,

    I am trying to do the same thing with movieclips/vectors and am a bit stuck with getting the hittest from a new rectangle

    this is part of my move player function so far…

    if (!ground.hitTestPoint(player.x-6, player.y-30, true)) {

    but it needs to look more like this i think…

    if (!ground.hitTestPoint(0×01,new Rectangle(player.x-6,player.y-10,1,17))) {

    I’ve imported flash.geom.Rectangle. keep getting errors, any help would be appreciated!

  10. yura_never_sleeps

    on August 7, 2010 at 12:26 pm

    nice tutorial man!
    i know there it is just draft of the game but i m gonna say that there is a little bug:
    when u fall u can press space and the character will make a jump from air.
    i hope u understood my english :D

  11. Jordi Sanglas Molist

    on August 8, 2010 at 9:15 am

    I think you’re right, but if I wanted to get good results I would have to use that formula every frame (the explosion lasts some miliseconds). Otherwise, it will happen that:

    Explosion 1 pixel away from the character: speed=x;
    Explosion 2 pixels away from the character: speed=x/4;
    And the difference is only one pixel.

    However, I think I’ll use MC’s formula (less real, but enough for a game).

    Thank you, Kaustav. Sometimes I need help. Keep commenting!

  12. Jordi Sanglas Molist

    on August 8, 2010 at 9:53 am

    I think that using movieclips you can’t do that kind of hitTest.

    MovieClip can use two hit tests:

    - hitTestPoint: to check a collision between a point and a MovieClip.
    - hitTestObject: to check a collision between two MovieClips (well, between the bounding boxes).

    If you want, you can use a for loop and the hitTestPoint method to check one by one the rectangle points, but maybe it will be much CPU consuming (I don’t know, I haven’t tried it).

  13. Jordi Sanglas Molist

    on August 9, 2010 at 9:24 pm

    Thank you (I didn’t notice)! I’ll try to solve it in part 3.

  14. Jordi Sanglas Molist

    on August 9, 2010 at 9:32 pm

    Sorry I pressed ENTER before I finished my comment (and I copied part of my e-mail address to “website”). As I said, I’ll try to solve it in part 3. I think it may be easy: we won’t check if the character is jumping, but we will check if it’s in the air.

    I’ll also add the forgotten parentheses.

  15. Jordi Sanglas Molist

    on August 9, 2010 at 9:51 pm

    If you use Box2d, you’ll be able to do more things. However, as I don’t want to create dynamic boxes (or something similar), I think that “custom physics” are simpler and less CPU consuming.

    But you can use Box2d, if you find it easier (or if you want to add special objects); although I don’t know how to “make holes” in Box2d boxes. Well, I don’t use Box2d.

    I wrote this text really quickly, so forgive me if there are mistakes.

  16. Worms-like destructible terrain in Flash â?? Part 2 – Emanuele Feronato « Worms

    on August 11, 2010 at 2:30 am

    [...] KeyboardEvent; public class worms extends Sprite { public var terrain_bmpd:BitmapData=new BitmapData(550,200,true,0xFF00FF00); public var terrain_bmp:Bitmap=new Bitmap(terrain_bmpd); public var character:Sprite=new Sprite ; public var …Read full article [...]

  17. Someone

    on August 11, 2010 at 4:21 pm

    How would you make platforms (i.e, two levels) of ground, or at least custom shapes? I tried, but it filled in the blank space with a white bitmap…

  18. Games Up

    on August 11, 2010 at 4:56 pm

    Brilliant. I always wanted to make a worms type game. This will be very useful to me. Now just need to sit and pull it apart. Thanks again.

  19. Jordi Sanglas Molist

    on August 11, 2010 at 8:01 pm

    You could create a transparent bitmap and use the same function: BitmapData.draw(). Instead of ERASE, the BlendMode would be NORMAL. For example, you can try this code in a *.fla document:

    //Create the bitmap. It must be transparent.
    var terrain_bmpd:BitmapData=new BitmapData(500,500,true,0×00000000);
    var terrain_bmp:Bitmap=new Bitmap(terrain_bmpd);
    stage.addChild(terrain_bmp);

    //The terrain will be a circle
    var circle:Sprite=new Sprite();
    circle.graphics.beginFill(0x00FF00);
    circle.graphics.drawCircle(0,0,30);

    var circle_matrix:Matrix=new Matrix();
    circle_matrix.translate(50,50);

    terrain_bmpd.draw(circle,circle_matrix,null,BlendMode.NORMAL);

    If you want platforms, you can use rectangles instead of circles.
    You can also use setPixel32() to set individual pixels.

  20. simranzenov

    on May 31, 2011 at 2:05 pm

    Your collision rectangle should not have a gap. I tested it and got myself stuck on a piece of land. Just thought I would let you know.

  21. simranzenov

    on May 31, 2011 at 3:11 pm

    Strange I cant seem to duplicate it again. Maybe it was just my browser freezing up. :S

  22. lionel

    on July 19, 2011 at 5:02 pm

    hey im working with the same thing on flashpunk but am using tilemaps instead of bitmap data, would i beable to get the same kind of detection with tile maps?

  23. Tony

    on August 20, 2011 at 10:06 am

    I love you Emanuele!! Thank you so much for posting all of these tutorials. It’s like a one stop learn-gasm for all of my action script programming needs. Keep up the good work!

  24. Cloudy Pixel Games » Tutorial #1:Pixel Perfect Collision with Flixel Part 1

    on January 29, 2012 at 3:47 am

    [...] The two tutorials that had the code is here and here. [...]