As: Terrain Based Platformer

2,452 Views | 16 Replies
New Topic Respond to this Topic

As: Terrain Based Platformer 2006-07-30 06:55:56



There seem to be a lot of tutorials on platformer engines here at the moment, but hopefully I can add something and give an insight into creative ways of solving problems which may have not previously occured.

This engine is designed so that the user doesn't have to worry about maming a load of floors and walls. It works by testing points of the character against a single layer of terrain, as well as against platforms and hazards.

NB: This can be prone to bugging up in certain conditions so it's advisable that you don't have too many sharp surfaces on your terrain, or have them covered with a invisible boxes which the character will hitTest against.

What you will learn:

Assuming you read the comments and don't just try to coppy and paste this like an idiot, this will give you a decent idea on how to use:

- Movement on non-flat surfaces
- Practical uses for functions you define
- Variables (obv.)
- A quick and easy way to make the 'Camera' follow the character (no camera necessary)
- Binary, or the cool person's way of making shit happen
- Probably some other stuff

What you won't learn:

- AI - this is purely the base for a platformer; you'll have to work out stuff like enemies for yourself
- Animation - again, slot your own method of getting the character's animation to respond to circumstances because it won't be here
- A fully working engine - this is intended primarily for teaching purposes, so don't try to steal it >.<

What you will already have:

A movie clip for the character on the main timeline in which you will have the code
A movie clip with the instance name 'platform' in which you will have:
- a movie clip with all your terrain in it with instance 'scape'
- a movie clip with platforms which do not act as walls or ceilings with the instance 'floatform'
- you may also wish to have backgrounds which move with the character
- you may have static hazards such as 'water' (explained in code)

Due to the legnth of the code with comments it will be posted in two parts. Please refrain from posting in between.

BBS Signature

Response to As: Terrain Based Platformer 2006-07-30 07:00:51

The script:

//Let's get started!

The script between this and its terminal curly bracket will execute once when the clip is first loaded

var pa_dx:Number = 0;
var pa_dy:Number = 0;
var pa_dir:Number = 0;
var pa_runspeed:Number = 6;
var pa_jumpheight:Number = 16;
var pa_gravity:Number = 1.2;
var pa_fallspeed:Number = 0;
var pa_jumped:Boolean = false;
var pa_falling:Boolean = true;
var pa_death:Boolean = false;
var pa_fallcheck:Boolean = false;
var pa_damage:Boolean = false;
var pa_invuncount:Number = 0;

// This is where all variables are defined. Defining their types strictly is a good practice to get into.

function pa_landing():Void{
pa_fallcheck = true;
pa_falling = false;
pa_fallspeed = 0;
pa_jumped = false;
pa_airspeed = 0;
pa_airset = false;
pa_invuncount = 80;
pa_damage = false;

/*A function to be called when the character lands on a surface. This block of code will be called more than once, so it can shorten your code dramatically if you put it in a function.

It resets variables to their values while on ground, as well as initiating the second stage of my damage process where the character experienes a brief period of invilnerability if he has been damaged.*/

function damaged(dmg:Number):Void{
pa_damage = true;
pa_jumped = false;
pa_fallspeed = -10;

//A function which can be called if the character is hit by an enemy. It features an input number if you wish to have the health drained more by certain enemies or attacks. If you wish to use this input, add a line saying _root.healthvariable -= dmg and add the input when you call the function (_root.char.damaged(#Number)). You will need to define a _root variable for health for this to work.


//The following will execute on every frame of your game.

//Movement and gravity

//If your guy is not dying

pa_dir = (Key.isDown(39) - Key.isDown(37));

//Here's a nice bit of binary. If either key is down the Key.isDown(#); is true, and returns this. The true can also be read as a one if used as a number, while false is a zero. So, if neither or both keys are down, the direction is 1 - 1 or 0 - 0 which is zero. If left or right are down the direction becomes -1 or 1 respectively.

_x += pa_runspeed * pa_dir * !pa_damage;

/* Increases the character's _x position by his speed multiplied by direction (-1, 1 or 0, remember?)

We have more binary here - instead of using an if(); statement the value is multiplied by the variable. If the damage variable is false, !pa_damage returns true (! = not), with a value of one, and Number * 1 = Number. If, however, it is true, !pa_damage returns false, so Number * 0 = 0, and the speed becomes 0. Result- you guy will not move. */


//Remember - !variable will return true if the variable is false and vice versa. This statement means thecode will execute if the falling variable is false.

pa_jumped = Key.isDown(38);

//Sets the value of jumped to the value of the jump key being down - true if it is down and false if it is not.

pa_fallspeed += pa_gravity * (pa_fallspeed - (pa_jumpheight * pa_jumped) < 20);

/*This is all to do with falling, so pay attention. Unlike many engines for platformers, with mine you are always falling and being pushed back up, a bit like real life physics.

Now, this bit of code increases the speed of falling by the gravity variable multiplied by whether the speed is below a certain point. As a result, if the speed exceeds a certain point then the part in brackets returns a value of false, or 0, and gravity * the comparison becomes 0, so the speed of falling no longer increased. Stuff like this can seem complicated at first, but the more you can get into it the simpler it becomes.

_y += pa_fallspeed - (pa_jumpheight * pa_jumped);

//This again utilises binary. It increases the character's _y position by the speed of falling (in Flash the _y axis is inverted), but the speed of falling minus the jumpheight multiplied by the value of jumping (true or false; 1 or 0). So, if the character is jumping, and since the speed of falling is reset to 0 on landing, immediately after you jump the fallspeed variable is a negative and so the character goes up instead of down. At least, untill gravity catches up.

_y += 5 * pa_fallcheck;
pa_fallcheck = false;

/*This is a line I always make a point of adding in these engines. The fallcheck variable is a failsafe which means that on the first frame away from the ground your _y position is reduced by 5 pixels.

This does make things closer to real life - when you're walking downhill or down stairs you don't just walk straight forward and let gravity do all the work. You step downwards and continue walking. The same is true in games.

If this value wasn't here then the character would go into falling mode over ridicolously short slopes, which would look particularly bad if you had his animation tied into whether he was falling or not. A side effect of this is that in the first frame of jumping he can rise slower than in the second, but this really isn't noticable particularly in higher framerates, and isn't really worth wotrking around.

if(pa_invuncount > 0){
_visible = ((pa_invuncount % 6) >= 3);
pa_invuncount --;

/*This is the second stage of what happens when you recieve damage. In the first you jump into the air, and upon landing move to the second. Here you experience a brief, in this case 80 frame burst of invulnerability avter you are damaged. There are games where you recieve damage as long as you are in contact with an enemy, and this is a way around this.

It also removes any unfairness involving repeatedly taking damage from the same enemy whenever you hit the ground. Try to include something like this in your game.

This code makes use of a flicker effect. For further information on this see my other tutorial in AS:Main.

_visible = true;

BBS Signature

Response to As: Terrain Based Platformer 2006-07-30 07:03:06

//Hit Testing
/* N.B:

In the following code shapeFlags are used to represent points on the character. Points such as _x + 40 and _y + 120 are intended for a specific guy. You will have to alter them for use with your character if you want to use them, so remember that.

To use points like this think of them as distance from your guy's reference (the cross thingy on his MC), because that's what they are. Also, don't forget the inversion of the _y axis.

if(_root.platform.scape.hitTest(_x, _y + 20, true)){
pa_jumped = false;
pa_fallspeed -= pa_jumpheight - pa_fallspeed;
_y += pa_fallspeed;
pa_falling = true;

//The above is supposed to represent what happens when your guy hits the ceiling. I made this engine a while ago and this bit isn't very well thought out (I cba going over it again), so try something of your own.

while(_root.platform.scape.hitTest(_x + 16, _y + 90, true) || _root.platform.scape.hitTest(_x + 16, _y + 40, true)){
_x --;

//This simply loops through checking whether your terrain (an MC instanced 'scape' in an MC instanced 'platform' on the _root) is touching two points on the right hand side of your character, one above the other, and moves him a bit to the left whenever this is true untill they are no longer touching. Make sure neither is at the base of your guy; they should be quite a bit above. You'll see why when we get to points at the base of your guy.

while(_root.platform.scape.hitTest(_x - 16, _y + 90, true) || _root.platform.scape.hitTest(_x - 16, _y + 40, true)){
_x ++;

//As above, but with the left instead of right.

if(_root.platform.scape.hitTest(_x + 8, _y + 108, true) || _root.platform.scape.hitTest(_x - 8, _y + 108, true)){

//If one of two points on the base of your character hits the ground, execute the landing function.

while(_root.platform.scape.hitTest(_x + 8, _y + 108, true) || _root.platform.scape.hitTest(_x - 8, _y + 108, true)){
_y -= 0.2;

/*This is the same type of loop as with the sides of your character, but with his base. Now, the two points here must be at the base of your character, but not at the same horizontal alignment as the points on his side. This is because the angles between them and the lowest points at his side determine how steep a slope your guy is able to walk up.

There's a diagram at the end of this post to help the more visual learners amoung you understand this.*/

if(pa_fallspeed - (pa_jumpheight * pa_jumped) >= 0){

//Now, the following code executes only if your guy is heading downwards. You ever play a 2D platformer where you can jump upwards through a platform and land on it when you come down? This is a simple way of doing it.

if(_root.background1.floatform.hitTest(_x + 8, _y + 108, true) || _root.background1.floatform.hitTest(_x - 8, _y + 108, true)){

//If your base hits the MC instanced 'floatform' in the same MC as all your platforms, you will go through the landing process.

_x + 8, _y + 108, true) || _root.background1.floatform.hitTest(_x - 8, _y + 108, true)){
_y -= 0.2;

//There's nothing more to be said about loops here :P

if(_root.platform.water.hitTest(_x + 8, _y + 108, true) || _root.platform.water.hitTest(_x - 8, _y + 108, true)){
pa_death = true;

//This is just to demonstrate that terrain and platforms aren't all you can put in your holder movie clip. You can make MCs of any range of hazards like water, lava and spikes and hitTest against those, too. Having them all in the same MC just makes them easier to move around.

pa_dx = Math.round((Stage.width / 2 - _x) / 8);
pa_dy = Math.round((Stage.height / 2 - _y) / 5);

/*Now, this is an easy, if not totally efficient, way of making the 'camera' follow your guy. Actually, it's everything following the stage, but w/ever.

The above code finds the x and y distance between your guy and the center of stage. There's no physical reason to divide them by anything, but it can look a lot smoother. If you want it to follow the guy with no easing, remove the dividing things.

The rounding is to eliminate any bugs or inaccuracies Flash seems to throw at times involving numbers with lots of digits.

_x += pa_dx;
_y += pa_dy;
_root.platform._x += pa_dx;
_root.platform._y += pa_dy;

This alters your guy's and the platform's _x and _y positions to move them towards the center of the stage. If you have any other instances you want to move at the same rate be sure to add those in here too.

_root.background1._x += pa_dx / 2;
_root.background1._y += pa_dy / 2;

This simply demonstrates how you can have backgrounds moving at slower speeds than the main screen (and also foregrounds moving faster if you so desire). It doesn't really require any further explaination - the rate of movement is halved in this case.


As: Terrain Based Platformer

BBS Signature

Response to As: Terrain Based Platformer 2006-07-30 07:05:50

Just quickly scanned over it and it seems you have expanded on the whole platformer thing. Good work. I'll be coming back to read more thoroughly later when I have more time. Well done.


BBS Signature

Response to As: Terrain Based Platformer 2006-07-30 07:16:33

Oh, btw, I dug up this old example using a slightly expanded version of the engine from my stash:

Part of a long dead collab, cast into the seas of obscurity...

BBS Signature

Response to As: Terrain Based Platformer 2006-07-30 07:36:24

At 7/30/06 07:16 AM, _Paranoia_ wrote: Part of a long dead collab, cast into the seas of obscurity...

I like it. Nice one. And the tutorial is quite good as well, nicely explained.

Response to As: Terrain Based Platformer 2006-07-30 08:44:59

At 7/30/06 07:16 AM, _Paranoia_ wrote: Oh, btw, I dug up this old example using a slightly expanded version of the engine from my stash:

Part of a long dead collab, cast into the seas of obscurity...

Cool, nice art, i'll give the script a go later, i'm pretty busy at the mo. Looks good, and well explained :)

BBS Signature

Response to As: Terrain Based Platformer 2006-07-30 08:57:20

dude you rock! I was looking for a tutorial just like this =D

This looks so well put together and explained.


Response to As: Terrain Based Platformer 2006-07-30 11:50:03

I think you switched instance names half way through. Some parts you said 'platform' and others you said 'background1'. Unless it was deliberate :)

Or you forgot to mention it in the movieclip thingy at the top. Just thought i'd metion it :)

BBS Signature

Response to As: Terrain Based Platformer 2006-07-31 14:30:23

Pyro111 already made a better tut...

BBS Signature

Response to As: Terrain Based Platformer 2006-07-31 15:51:13

yah, this type of platformer was already covered. But nice tut none the less.

BBS Signature

Response to As: Terrain Based Platformer 2006-07-31 16:00:38

put in all in one code or im not usin it

Response to As: Terrain Based Platformer 2006-07-31 16:35:29

At 7/31/06 02:30 PM, Hoeloe wrote: Pyro111 already made a better tut...

Pyro's didn't cover things such as sliding and checking multiple points on a character. His was just movement on slopes.

I think

Perpetually looking for time to return to the arts.

BBS Signature

Response to As: Terrain Based Platformer 2006-07-31 16:39:28

At 7/31/06 04:00 PM, Adobe_Flash_Player_9 wrote: put in all in one code or im not usin it

You're not meant to use it. You're meant to study it and make your own.

Like what I'll be doing with this thread if and when I want to make a platformer. +Bookmarked


BBS Signature

Response to As: Terrain Based Platformer 2006-11-03 12:08:32

Great tutorial, can you make a post that teaches how to make a character bounce off the ground instead of having the character just stick? I know somewhat how to do it, but theres probably a MUCH easier way of doing so than my method...


I cut things.

Response to As: Terrain Based Platformer 2008-11-02 04:06:55

this is the first coherent tutorial on the topic i have yet to find and it works flawlessly! You have given me the code i have been searching months on and have totally helped my flash! Thank you soooooooooooo much!