New tile based platform engine – part 11 – slopes part b

As said in New tile based platform engine – part 11 – slopes part a, the game needed a fix for the jump from/on slope bug.

In part b the bug becomes a glitch… now you can jump from/on the slope but sometimes there is a “rebounce” glitch.

It’s very easy to determine why it’s happening and fix it… I am just leaving the explication for next time because I just got my computer repaired and need to do a lot of things.

I just wanted to answer a question about senseless slopes and N game mechanics.

There is a lot of difference between my tile based engine and a raycasting one.

Maybe I’ll cover it in next future.

Meanwhile, you are invited to take a look at the source code and fix the glitch at line 338

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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
walkable_tiles = Array(0, 5, 6, 7, 10, 11);
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;
jumping = false;
on_slope = 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, 2, 2, 1, 0, 4, 4, 8, 3, 3, 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, 5, 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, 10, 1, 11, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 1];
level[8] = [1, 1, 1, 1, 0, 9, 0, 0, 10, 1, 1, 1, 11, 0, 7, 0, 0, 6, 0, 0, 0, 0, 7, 0, 1];
level[9] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 4, 4, 1, 8, 1, 8, 1];
player = [10, 6];
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();
			}
		default :
			over = "ground";
			speed = ground_acceleration;
			friction = ground_friction;
			break;
	}
}
function check_collisions() {
	get_edges();
	is_on_slope();
	y_pos += yspeed;
	get_edges();
	// collision to the bottom 
	if (yspeed>0 and !on_slope) {
		if ((bottom_right != 0 and bottom_right != 6 and bottom_right != 10 and bottom_right != 11) or (bottom_left != 0 and bottom_left != 6 and bottom_left != 10 and bottom_left != 11)) {
			// 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;
	if (!on_slope) {
		for (x=0; x<walkable_tiles.length; x++) {
			if (tile == walkable_tiles[x]) {
				walkable = true;
				break;
			}
		}
	} else {
		walkable = true;
	}
	return (walkable);
}
function is_on_slope() {
	on_slope = false;
	x_slope_detector = Math.floor(x_pos/tile_size);
	y_slope_detector = Math.floor(y_pos/tile_size);
	if (jumping or falling) {
		if (level[y_slope_detector][x_slope_detector] == 10 or level[y_slope_detector][x_slope_detector] == 11) {
			if (level[y_slope_detector][x_slope_detector] == 10) {
				x_offset = tile_size-x_pos%tile_size;
			}
			// could be an "else"...               
			if (level[y_slope_detector][x_slope_detector] == 11) {
				x_offset = x_pos%tile_size;
			}
			if (y_pos>Math.floor(y_pos/tile_size)*tile_size-9+x_offset) {
				// rebounce fix here
			}
		}
	}
	// could NOT be an else  
	if (!jumping and !falling) {
		if (level[y_slope_detector+1][x_slope_detector] == 10 or level[y_slope_detector+1][x_slope_detector] == 11) {
			y_pos = (y_slope_detector+1)*tile_size+tile_size/2+1;
			y_slope_detector += 1;
		}
		if (level[y_slope_detector][x_slope_detector] == 10 or level[y_slope_detector][x_slope_detector] == 11) {
			if (level[y_slope_detector][x_slope_detector] == 10) {
				x_offset = tile_size-x_pos%tile_size;
			}
			// could be an "else"...               
			if (level[y_slope_detector][x_slope_detector] == 11) {
				x_offset = x_pos%tile_size;
			}
			y_pos = Math.floor(y_pos/tile_size)*tile_size-9+x_offset;
			on_slope = true;
		}
	}
	if (!jumping and !falling and !on_slope and over != "ladder") {
		y_pos = (y_slope_detector)*tile_size+tile_size/2+1;
	}
}

Enjoy the result

Download the source code and have fun

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (27 votes, average: 4.78 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 27 comments

  1. Pedro

    on October 24, 2008 at 2:28 pm

    I’ve found a small glitch about treadmills. When hero is on a last right treadmill, it’s totally moved to next tile, but, when it’s on a last left treadmill, only a pixel of the clip finishes above the next tile.

    Your platform engine it’s great, thanks!!

  2. Dude

    on October 24, 2008 at 2:38 pm

    Well done…looks like the glitch only apears when landing in the middle of the slope an not on the cornerns…
    Anyways I was wondering if you could enhance the enemies in the next part so they kill you and you can kill them (maybe by jumping on them)?

  3. Joel Parkey

    on October 24, 2008 at 7:03 pm

    Thats pretty darned aweome.

  4. Jeremi

    on October 25, 2008 at 3:37 am

    Nice work, dude you really help making flash games easy, thanks for helping all of us. I like all of your tutorials they are very helpful.

  5. AS3 Gamer

    on October 25, 2008 at 6:10 am

    Are you seriously coding in AS2 in 2008?

  6. miff

    on October 25, 2008 at 1:20 pm

    This is a good slope now
    Next part – scrolling level maybe?

  7. EagleVision

    on October 25, 2008 at 4:28 pm

    @AS3 Gamer
    Yes, and along with thousands of people who still don’t have enough money to buy CS3/CS4, unlike you rich guy.

    Just don’t assume things, and make a firm statement. Think. ^^

    Anyways, enough flaming. :P Nice tutorial, I won’t download it yet, since I like to see how it goes first, and if I work on the first the next version comes out with something I don’t want to work on…And that just gets very messy.

    Good job, keep going.
    Samuel

  8. jacko123

    on October 25, 2008 at 4:52 pm

    Hey…
    nice tutorial!
    By The Way: Your feed is broken!

  9. Josh of Cubicle Ninjas

    on October 25, 2008 at 8:25 pm

    I love guys like AS3 Gamer.

    They still haven’t figured out the difference between tools and content. You just hand built a clean and efficient platforming engine and he is worried that it isn’t “new” enough. Does it work any worse? Nope. And yet he bitches on.

    The good news is that people like him are so busy chasing technology they never make anything useful. Give me Flash 5, Photoshop 3, and some free time and I will blow your mind…

    As always amazing work Emanuele!

    (BTW anyone else find the RSS on this site broken? I rarely get new updates through the feed.)

  10. Anonymous

    on October 26, 2008 at 8:18 pm

    I once jumped on the first red block, and fell through and didn’t see the character again.

  11. Anonymous

    on October 26, 2008 at 8:20 pm

    im trying to make a platformer/rpg game and i want to make a slope without code being in the frame, i want it to be on a mc. Do you know how?

  12. woody harris

    on October 26, 2008 at 8:59 pm

    how did you learn as2/3 so well? i understand most of the code youve done like in that ball revamped clone but when you start to have to use math, tiles, shooting, etc i dont really know what to do and therefore cant make so many genres of games because of these limitations. my expertise is in java and though the language is nearly identical i cant grasp the game programmers mentality. any recommendations.

  13. Quarky Quantum

    on October 26, 2008 at 9:05 pm

    Great work on the tutorials,
    by the way I too have noticed your broken rss feed.

  14. Jon W

    on October 28, 2008 at 11:30 am

    I’m a long fan of yours and have seen this platformer engine. Its brilliant! And I’ve seen a lot of people asking for a level editor, so, I made one! Download it here:
    http://www.uploading.com/files/BGQFI3EC/editor.zip.html
    Hope you like it and happy building!
    Jon

  15. askovitch

    on November 3, 2008 at 11:57 am

    hi whens the next part coming out?? could you make exits and more levels prehaps?

  16. Goodbye AS2… : Emanuele Feronato

    on November 26, 2008 at 1:02 pm

    [...] you noticed, my last post about AS2 coding is New tile based platform engine – part 11 – slopes part b, almost a month [...]

  17. caboose

    on November 28, 2008 at 6:18 am

    what program are you using to make the scripts and tower deffence games?

  18. Chris

    on December 12, 2008 at 3:43 am

    for killing your guy on contact with enemy just paste this code under the enemy stuff (after: “else{ this.speed *= -1; }”:

    if (this.hitTest(level_container.hero._x, level_container.hero._y, true)) {
    place_player();
    }

  19. Chris

    on December 12, 2008 at 9:20 am

    For Scrolling use this code:
    if (Key.isDown(Key.LEFT)) {
    //scrolls screen
    _x += -xspeed*.6;
    xspeed -= speed;
    walking = true;

    }
    if (Key.isDown(Key.RIGHT)) {
    //scrolls screen
    _x -= xspeed*.6;
    xspeed += speed;
    walking = true;
    }

  20. Chris

    on December 12, 2008 at 9:52 pm

    Also you shoud add “_x = 0” under the place player

  21. Agadoijo

    on December 31, 2008 at 5:21 pm

    Great work on the tutorial!
    Do you plan to load levels from files? That would be great!
    Thanks for your help.

  22. Gravyerd

    on March 23, 2009 at 2:56 am

    please, next you need say:
    Lava + Scroll + Enemy Killer
    i find how to create coins :D and a number of coins xp

  23. Gravyerd

    on March 23, 2009 at 3:08 am

    and a question…
    how to use teleport?

    onClipEvent (enterFrame) {
    if (this.hitTest(_root.level_container.hero)) {
    // if this hits the char (_root.char)
    level_container.hero._y += 20;
    // _root.score goes up 1
    unloadMovie(this);
    // this movie clip is unloaded
    }
    }

    this is my try script (but don’t work)
    i put it in a mc already created… why don’t work?
    i make the code to coins and work

    onClipEvent (enterFrame) {
    if (this.hitTest(_root.level_container.hero)) {
    // This is the hit, and it work
    _root.score.text++;
    // to work
    unloadMovie(this);
    // anything work, but the teleport not work…
    }
    }

    but teleport not… please help me

  24. Gravyerd

    on March 25, 2009 at 2:38 am

    Only 1 problem why your game:
    You can’t put a preloader or anything before, is the code in first frame or is the code in first frame, if not in frame 1, do not work
    need a preloader, in the start the game start LOOOOOOW and stoping every 2 seconds… slow download, need download the game + images in the same time that the player are playing… please, need free the frame number, i can make 10 level, but is 1 over other and other, please fix this

  25. FatJoe

    on June 5, 2009 at 4:09 pm

    Gravyerd – put the preloader in a new scene, make sure the preloader scene is moved above the game scene ( shift + F2 ) should work..

  26. michael

    on September 22, 2009 at 4:41 am

    if i want to refer to the tiles or enemies at a different point in the code, say, a hittest, how would i do that?

    something like _root.blah.tile

  27. Luis

    on December 9, 2010 at 2:23 am

    Does anyone knows how to make the enemies fall from where they are? I mean if the moving enemies detect a 0 in the array they fall until they touch ground? any helP?