New tile based platform engine – part 10 – optimization, doors n’ keys
Here we are with some optimization, as well as a feature some people requested: doors and keys.
Let’s start with the first optimization step.
Optimization
See how does the script at step 9 determine if a tile is walkable (player can pass through it):
if ((top_right != 0 and top_right != 5 and top_right != 6 and top_right != 7) or (bottom_right != 0 and bottom_right != 5 and bottom_right != 6 and bottom_right != 7)) {
I have to check if all values are different from 0, 5, 6 and 7 because 0 = empty, 5 = cloud, 6 = ladder and 7 = trampoline.
Nothing difficult at this point, but let’s imagine I am going to add another walkable tile… I should update the and formula by adding the new tile type.
The more walkable tiles I add, the more the probability of making errors or forgetting something.
So I created an array with all walkable tiles this way:
walkable_tiles = Array(0, 5, 6, 7);
Then the old code becomes
if (!is_walkable(top_right) or !is_walkable(bottom_right)) {
Where is_walkable is basically an in_array function (not included in AS2!!)
1 2 3 4 5 6 7 8 9 10 | function is_walkable(tile) {
walkable = false;
for (x=0; x<walkable_tiles.length; x++) {
if (tile == walkable_tiles[x]) {
walkable = true;
break;
}
}
return (walkable);
} |
Doors and keys
A door is a unwalkable tile that becomes a walkable one when the player takes its key.
Every key is an array made this way:
[key x pos, key y pos, door x pos, door y pos]
Meaning that the key is located at (key x pos, key y pos) and once collected opens the door at (door x pos, door y pos).
Let’s see the source:
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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | walkable_tiles = Array(0, 5, 6, 7);
tile_size = 20;
ground_acceleration = 1;
ground_friction = 0.8;
air_acceleration = 0.5;
air_friction = 0.7;
ice_acceleration = 0.15;
ice_friction = 0.95;
treadmill_speed = 2;
max_speed = 3;
xspeed = 0;
yspeed = 0;
falling = false;
gravity = 0.5;
jump_speed = 6;
climbing = false;
climb_speed = 0.8;
level = new Array();
enemy = new Array();
coin = new Array();
key = new Array();
level[0] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
level[1] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
level[2] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 1, 0, 0, 0, 0, 1];
level[3] = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 1];
level[4] = [1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 1];
level[5] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 1];
level[6] = [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 1, 0, 0, 0, 0, 0, 1];
level[7] = [1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 1];
level[8] = [1, 1, 1, 1, 0, 9, 0, 0, 0, 5, 5, 0, 0, 0, 7, 0, 0, 6, 0, 0, 0, 0, 7, 0, 1];
level[9] = [1, 1, 1, 1, 1, 1, 1, 2, 2, 8, 8, 8, 8, 1, 1, 3, 3, 1, 4, 4, 1, 8, 1, 8, 1];
player = [4, 8];
enemy[0] = [10, 3, -2];
enemy[1] = [3, 3, -2];
coin[0] = [2, 2];
coin[1] = [23, 4];
key[0] = [1, 5, 5, 8];
function create_level(l) {
_root.createEmptyMovieClip("level_container", 1);
level_height = l.length;
level_width = l[0].length;
for (y=0; y<level_height; y++) {
for (x=0; x<level_width; x++) {
if (l[y][x] != 0) {
t = level_container.attachMovie("tile", "t"+y+"_"+x, _root.level_container.getNextHighestDepth(), {_x:x*tile_size, _y:y*tile_size});
t.gotoAndStop(l[y][x]);
}
}
}
place_player();
for (x=0; x<coin.length; x++) {
coin_mc = level_container.attachMovie("coin", "coin_"+_root.level_container.getNextHighestDepth(), _root.level_container.getNextHighestDepth(), {_x:coin[x][0]*tile_size+tile_size/2, _y:coin[x][1]*tile_size+tile_size/2+1});
coin_mc.onEnterFrame = function() {
if (this.hitTest(level_container.hero._x, level_container.hero._y, true)) {
this.removeMovieClip();
}
};
}
for (x=0; x<key.length; x++) {
key_mc = level_container.attachMovie("key", "key"+_root.level_container.getNextHighestDepth(), _root.level_container.getNextHighestDepth(), {_x:key[x][0]*tile_size+tile_size/2, _y:key[x][1]*tile_size+tile_size/2+1});
key_mc.ind = x;
key_mc.onEnterFrame = function() {
if (this.hitTest(level_container.hero._x, level_container.hero._y, true)) {
open_x = [key[this.ind][2]];
open_y = [key[this.ind][3]];
level[open_y][open_x] = 0;
_root.level_container["t"+open_y+"_"+open_x].removeMovieClip();
this.removeMovieClip();
}
};
}
for (x=0; x<enemy.length; x++) {
foe = level_container.attachMovie("patrol", "patrol_"+_root.level_container.getNextHighestDepth(), _root.level_container.getNextHighestDepth(), {_x:enemy[x][0]*tile_size+tile_size/2, _y:enemy[x][1]*tile_size+tile_size/2+1});
foe.speed = enemy[x][2];
foe.onEnterFrame = function() {
this.x_pos = this._x;
this.y_pos = this._y;
this.x_pos += this.speed;
this.left_foot_x = Math.floor((this.x_pos-6)/tile_size);
this.right_foot_x = Math.floor((this.x_pos+5)/tile_size);
this.foot_y = Math.floor((this.y_pos+9)/tile_size);
this.bottom = Math.floor((this.y_pos+8)/tile_size);
this.left_foot = level[this.foot_y][this.left_foot_x];
this.right_foot = level[this.foot_y][this.right_foot_x];
this.left = level[this.bottom][this.left_foot_x];
this.right = level[this.bottom][this.right_foot_x];
if (this.left_foot != 0 and this.right_foot != 0 and this.left == 0 and this.right == 0) {
this._x = this.x_pos;
} else {
this.speed *= -1;
}
};
}
}
create_level(level);
_root.onEnterFrame = function() {
ground_under_feet();
walking = false;
climbing = false;
if (Key.isDown(Key.LEFT)) {
xspeed -= speed;
walking = true;
}
if (Key.isDown(Key.RIGHT)) {
xspeed += speed;
walking = true;
}
if (Key.isDown(Key.UP)) {
get_edges();
if (top_right == 6 or bottom_right == 6 or top_left == 6 or bottom_left == 6) {
jumping = false;
falling = false;
climbing = true;
climbdir = -1;
}
}
if (Key.isDown(Key.DOWN)) {
get_edges();
if ((over == "ladder") or (top_right == 6 or bottom_right == 6 or top_left == 6 or bottom_left == 6)) {
jumping = false;
falling = false;
climbing = true;
climbdir = 1;
}
}
if (Key.isDown(Key.SPACE)) {
get_edges();
if (!falling and !jumping) {
jumping = true;
yspeed = -jump_speed;
}
}
if (!walking) {
xspeed *= friction;
if (Math.abs(xspeed)<0.5) {
xspeed = 0;
}
}
if (xspeed>max_speed) {
xspeed = max_speed;
}
if (xspeed<max_speed*-1) {
xspeed = max_speed*-1;
}
if (falling or jumping) {
yspeed += gravity;
}
if (climbing) {
yspeed = climb_speed*climbdir;
}
if (!falling and !jumping and !climbing) {
yspeed = 0;
}
xspeed += bonus_speed;
check_collisions();
level_container.hero._x = x_pos;
level_container.hero._y = y_pos;
xspeed -= bonus_speed;
};
function ground_under_feet() {
bonus_speed = 0;
left_foot_x = Math.floor((x_pos-6)/tile_size);
right_foot_x = Math.floor((x_pos+5)/tile_size);
foot_y = Math.floor((y_pos+9)/tile_size);
left_foot = level[foot_y][left_foot_x];
right_foot = level[foot_y][right_foot_x];
if (left_foot != 0) {
current_tile = left_foot;
} else {
current_tile = right_foot;
}
switch (current_tile) {
case 0 :
over = "air";
speed = air_acceleration;
friction = air_friction;
falling = true;
break;
case 1 :
over = "ground";
speed = ground_acceleration;
friction = ground_friction;
break;
case 2 :
over = "ice";
speed = ice_acceleration;
friction = ice_friction;
break;
case 3 :
over = "treadmill";
speed = ground_acceleration;
friction = ground_friction;
bonus_speed = -treadmill_speed;
break;
case 4 :
over = "treadmill";
speed = ground_acceleration;
friction = ground_friction;
bonus_speed = treadmill_speed;
break;
case 5 :
over = "cloud";
speed = ground_acceleration;
friction = ground_friction;
break;
case 6 :
over = "ladder";
speed = ground_acceleration;
friction = ground_friction;
break;
case 7 :
over = "trampoline";
speed = ground_acceleration;
friction = ground_friction;
break;
case 8 :
over = "spikes";
if (left_foot == 8 and right_foot == 8) {
place_player();
}
}
}
function check_collisions() {
y_pos += yspeed;
get_edges();
// collision to the bottom
if (yspeed>0) {
if ((bottom_right != 0 and bottom_right != 6) or (bottom_left != 0 and bottom_left != 6)) {
// not a cloud...
if (bottom_right != 5 and bottom_left != 5) {
// a trampoline
if ((bottom_right == 7 or bottom_left == 7) and (Math.abs(yspeed)>1)) {
yspeed = yspeed*-1;
jumping = true;
falling = true;
} else {
y_pos = bottom*tile_size-9;
yspeed = 0;
falling = false;
jumping = false;
}
} else {
//cloud
if (prev_bottom<bottom) {
y_pos = bottom*tile_size-9;
yspeed = 0;
falling = false;
jumping = false;
}
}
}
}
// collision to the top
if (yspeed<0) {
if ((top_right != 0 and top_right != 5 and top_right != 6) or (top_left != 0 and top_left != 5 and top_left != 6)) {
y_pos = bottom*tile_size+1+8;
yspeed = 0;
falling = false;
jumping = false;
}
}
x_pos += xspeed;
get_edges();
// collision to the left
if (xspeed<0) {
if (!is_walkable(top_left) or !is_walkable(bottom_left)) {
x_pos = (left+1)*tile_size+6;
xspeed = 0;
}
}
// collision to the right
if (xspeed>0) {
if (!is_walkable(top_right) or !is_walkable(bottom_right)) {
x_pos = right*tile_size-6;
xspeed = 0;
}
}
prev_bottom = bottom;
}
function get_edges() {
// right edge
right = Math.floor((x_pos+5)/tile_size);
// left edge
left = Math.floor((x_pos-6)/tile_size);
// bottom edge
bottom = Math.floor((y_pos+8)/tile_size);
// top edge
top = Math.floor((y_pos-9)/tile_size);
// adjacent tiles
top_right = level[top][right];
top_left = level[top][left];
bottom_left = level[bottom][left];
bottom_right = level[bottom][right];
}
function place_player() {
level_container.hero.removeMovieClip();
x_pos = player[0]*tile_size+tile_size/2;
y_pos = player[1]*tile_size+tile_size/2+1;
level_container.attachMovie("hero", "hero", _root.level_container.getNextHighestDepth(), {_x:x_pos, _y:y_pos});
}
function is_walkable(tile) {
walkable = false;
for (x=0; x<walkable_tiles.length; x++) {
if (tile == walkable_tiles[x]) {
walkable = true;
break;
}
}
return (walkable);
} |
And this is the game:
Download the source code and give feedback.
They can be easily customized to meet the unique requirements of your project.
20 Responses to “New tile based platform engine – part 10 – optimization, doors n’ keys”
Leave a Reply
Trackbacks
-
New tile based platform engine - AS3 version updated to step 10 PLUS scrolling : Emanuele Feronato on
October 14th, 2008 1:25 pm
[...] you are looking for AS3 version of step 10, here it is… made by Robin vd Vleuten from the Netherlands with scrolling included! Hello [...]
-
labs.VETTIGHEID » Blog Archive » Platform Tile Game with Box2D: First Attempt! on
August 19th, 2009 2:07 pm
[...] in flash-games seems to be the next hype, so I couldn’t stay behind. A while ago, I found Emanuele Feronato’s tutorials on tile-based platform games in AS2 and decided to convert them to AS3. But the engine was still not what I wanted, it was fancier if [...]
- Create a dynamic content animated footer ad for your site in just 9 jQuery lines – 17 lines version
- Sell sitelocked version of your Flash games and even .fla sources to Free Online Games
- Protect your work from ActionScript code theft with SWF Protector
- Create a dynamic content animated footer ad for your site in just 9 jQuery lines
- Understanding Box2D’s one-way platforms, aka CLOUDS
- Triqui MochiAds Arcade plugin for WordPress upgraded to 1.2
- Box2D Flash game creation tutorial – part 2
- 11 Flash isometric engines you can use in your games
- Monetize your Flash games with GamesChart
- Box2D Flash game creation tutorial – part 1
- Create a Lightbox effect only with CSS - no javascript needed
- Flash game creation tutorial - part 1
- Create a Flash Racing Game Tutorial
- Flash game creation tutorial - part 2
- Make a Flash game like Flash Element Tower Defense - Part 2
- Flash game creation tutorial - part 3
- Make a Flash game like Flash Element Tower Defense - Part 1
- Create a flash draw game like Line Rider or others - part 1
- Triqui MochiAds Arcade plugin for WordPress official page
- Create a flash artillery game - step 1
- Flash game creation tutorial – part 5.2 (4.87/5)
- Create a flash artillery game – step 1 (4.79/5)
- Create a Flash Racing Game Tutorial (4.76/5)
- Create a flash artillery game – step 2 (4.74/5)
- Create a survival horror game in Flash tutorial – part 1 (4.73/5)
- Creation of a Flash arcade site using WordPress – step 2 (4.73/5)
- Flash game creation tutorial – part 2 (4.71/5)
- Flash game creation tutorial – part 1 (4.70/5)
- Create a flash draw game like Line Rider or others – part 1 (4.69/5)
- Creation of a platform game with Flash – step 2 (4.68/5)







Coming along quite nicely as always. Keep it up!
Love it.
By the way, how’s the WordPress arcade plugin coming along?
Great work as always.
Really nice, this is getting better and better, a tile I just cant know how to do is slopes, may be you can help me with that. Thanks
Hello,
just found another great resource for tile based games.and this is as3 only:-)
http://www.tonypa.pri.ee/tbw/as3/start.html
I am having problems with aligning my character. when I have him to the dimensions said in the tutorials and have him centered on both the y axis and the x axis half of the hero’s body is sunk into the floors and around half of his body goes through walls. When I have him aligned in his mc so the hittests look correct the hittests with coins and other objects are off what am I doing wrong?
Awesomeness!!! Could you make it possible to open a door if you have a certain amount of keys? And if you die, maybe the coins would go back to their original places.
Great work as always!!
Great job!
One thing, there is a bug (or feature) – if you jump off the top of the ladder part and onto the bouncy block, and head back towards the latter, you’ll go right thorugh the ladder tile…
Hey, emanuele, why did you stop writing the “artillery” game toutorials?
im stuck!!!!!! i relly need them!!!!
(sorry for my english…)
tnx!
I made an AS3 port of your latest tutorial! I don’t know if you have any interest in posting it?
Hi Emanuele,
I guess there is a bug on the ladder tile. If you stand on the top of the ladder and press jump, the char will fall from the ladder. I don’t know if this is proposital but in my opinion the char should only step down if the down key is pressed.
Keep the awesome work!
I love where this is going, the game engine is brilliant! Especially with the translations into AS3 for future-proofing! Its performance is so efficient; their is not much horse-power needed to run it – a flash-lite potential for the mobile phone!
Since the roaming bots were introduced, what screamed in my head was their collision triggers. Plus elavators that transports the player up or across certain areas as well as its trampalines. (Oops, another challange ^-^).
Also whilst looking upon this and studying Tonypa’s tile-based study as well; scrolling the environment across the screen across with the player’s excess momentum can be a possibility. Also jumping from one arena to another…
I’d love to work on this engine and create as much gameplay mechanics too and cool imagery!
I am always looking for ways to optimize code. Thanks.
i hae a problem im trying to edit the level but after i have i try to run the game but it comes up with this error of a part of the code that i havent done anything with
line 160 Statement block must be terminated by ‘}’ function ground_under_feet() {
and
line 315 Syntax error. }
This is an amazing platform engine and heavily customizable. There are only a couple things I would still need:
1) Collision detection with patrols to trigger an event
2) Multiple levels via warp/door
I will start to get cracking on this stuff, great tutorial.
Great job. You have awsome tutorials.
I was wondering how to implement different levels.
I tried using a switch function but It didn’t turn out right. Maybe you should show how to implement an exit portal and different levels next. Keep up the good work.
Awsome tutorial, thanks a lot! I’d like to see moving plattforms and elevators…
im only 13 but im an intellegent 13 year old thank you for the action script and the tutuorial it helped alot