Making a Beat-Em-Up Fighting Game in Flash: Part FOUR Many have written to me asking for me to post swf files. Save them some time, that kind of thing. Well, if you're thinking of doing the same, don't bother. I'm doing your a favour by forcing you to code this puppy bit by bit. You will thank me after. Learn by doing. And when it's all done, when you've finished all these tutorials and absorbed everything you'll have built your knowledge base enough to go your own way and start creating your own little Flash beauties without relying on others. And then we won't have any crappy Pong remakes on the net anymore, but a ton of sweet, sweet Streets of Rage/Vigilante/Streetfighter clones. Less Pong, more top-notch hard action games. Ok, on with the show.
When making a sprite/movie clip jump, we need to consider two
important forces, gravity and upward velocity.
Now, if you jumped off the moon, which has no gravity (I think) you would go up
and up until Superman came to get you. On Earth, the force
you use to launch yourself into the air when you jump, is quickly
countered by the powerful force called gravity, and your ass is smacked
back down to the ground.
Now, there is more than one way to skin a, um...jumping routine. You need to decide upon which best fits your game. Let's take a look at some examples.
Velocity-Based Take StreetFighter 2 for example. On every scene (exception-bonus stage) you have only a one level ground. There's no platforms, no cliffs to fall off. If your character jumps, you only have to check whether or not his sprite/mc/feet have touched the ground again, and then the jump is complete. So you could say "IF THIS MC'S _Y VALUE IS THE SAME AS WHEN HE JUMPED, STOP THE JUMP". Even if you get punched in mid-air, the only thing you would have to do would be to add a little extra value to the u_velocity value, so that the mc floats for a bit longer. The same routine would still work.
Time-Based Even simpler. The pseudocode would look like. timer=0;
IF UP PRESSED
{
jump=true;
if(timer < WHATEVER TIME YOU SET TO LAND AGAIN)
{
Do jump animation();
Check for jump_kicks_etc();
timer++:
}
else
{
jump=false;
timer=0;
}
}
Probably works for games like Yi Ar Kung Fu (Okay now you know how old I am)
Most games however, require more complex code that takes into consideration platforms you can fall from or bump into, or ceilings and things. Depending on the speed and height of his fall, you may even have to sweep ahead of his projectory and check the collision before he's even anywhere near the ground, otherwise risking getting a sprite stuck halfway into the floor. However, within these sets of tutorials, we're not aiming to rewrite Super Mario, just a little fighting game, so let's keep things simple. Besides, you could Google up a dozen Flash tutorials for jumping in a second. No. What I'm going to show you is not much more complicated than the velocity-based idea, and deals with simply checking if a movie_clip under the characters feet is has a higher _y value then stop him falling. This isn't suitable for a Sonic game or any platformers in general. It wouldn't work even for the real SplatterHouse game. I simply want to recreate the physics behind a jump, nothing advanced. Let's begin by organising our code a little better before it turns into illegible spaghetti. We're going to start putting our routines into functions. They're reusable and you can't live without them. So scrap all of the previous code- literally delete all of your AS code- but leave the movieclips where they are in the library. If you're with me up until now , I'm assuming that you've created a jump animation within the main Rick movie clip alongside all the other moves. Make sure to name the frame it is on 'jump'. I also hope you know what a function is. Actually, you've been using one all along- onEnterFrame- a function that runs what ever code is within it at the speed of the game framerate.
function Initialize()
{
rick_mc.step=15;
rick_mc.attack = false;
rick_mc.stance= 1;
rick_mc.crouch=false;
keydown=false;
//Add a few new variables:
rick_mc.uvel=40;
rick_mc.gravity=6;
rick_mc.jump=false;
}
In the world of
game-programming, having an Initialise function is handy for everytime
you move onto a new level. or restart the game entirely.
Next up, let's wrap the movement code up in one. Directly below stick this one in there; function Movement()
{
if (Key.isDown (Key.RIGHT) )
{
rick_mc.stance=1;
rick_mc._x+=rick_mc.step;
rick_mc.gotoAndStop("walk");
}
else if (Key.isDown (Key.LEFT) )
{
rick_mc.stance=0;
rick_mc._x-=rick_mc.step;
rick_mc.gotoAndStop("walk");
}
else if (Key.isDown (Key.DOWN) )
{
rick_mc.gotoAndStop("crouch");
rick_mc.crouch=true;
}
else if (!Key.isDown () )
{
rick_mc.gotoAndStop("stance");
rick_mc.crouch=false;
}
//Jump check needs to be out of the else..if loop or character
//will not jump while walking.
if (Key.isDown (Key.UP))
{
rick_mc.gotoAndStop("jump");
rick_mc.jump=true;
}
if (Key.isDown (Key.CONTROL) && keydown==false)
{
rick_mc.attack=true;
}
};
All making sense so far?
As you can see, this new functions also checks for jumping, and sets a flag if UP is pressed. 1.Tap CTRL+F8 to make a new symbol. function Jump()
{
if (Key.isDown (Key.LEFT) )
{
rick_mc.stance=0;
rick_mc._x-=rick_mc.step;
}
else if (Key.isDown (Key.RIGHT) )
{
rick_mc.stance=1;
rick_mc._x+=rick_mc.step;
}
if(!rick_mc.attack)
{
if (Key.isDown (Key.DOWN))
{
rick_mc.gotoAndStop("crouch");
rick_mc.crouch=true;
}
else if (!Key.isDown () )
{
rick_mc.gotoAndStop("jump");
rick_mc.crouch=false;
}
}
if (Key.isDown (Key.CONTROL) && keydown==false)
{
rick_mc.attack=true;
}
rick_mc._y-=rick_mc.uvel;
rick_mc.uvel-=rick_mc.gravity;
if(rick_mc._y+20 > ground_mc._y+65)
{
rick_mc.jump=false;
rick_mc._y=ground_mc._y+65;
rick_mc.uvel=40;
}
}
All
we simply do is check that rick_mc (plus a height offset) is above the
ground_mc (plus an offset of its own) or else the jump stops. By the
way, you
might be thinking "What's the point in retyping all the key.isDown
checks?" and you wouldn't be an idiot for pointing that out. In fact,
this isn't
anybodies coding practice but my own. I simply find it a lot easier to
organise and control that way. Do what works for you. If you give every
character a function
for each state he's in, you'll have far fewer headaches with debugging once your program gains in size and complexity.But by all means, do whatever way works for you. Finally, let's just throw in our slighty modified Attack function, and the main code loop.
function Attack()
{
if(rick_mc.jump)
{
rick_mc.gotoAndStop("crouchkick");
}
else
{
if (Key.isDown (Key.DOWN))
{
rick_mc.gotoAndStop("crouchkick");
}
else
{
rick_mc.gotoAndStop("punch");
}
}
};
Initialize();
onEnterFrame = function()
{
if(!rick_mc.attack && !rick_mc.jump)
{
Movement();
}
if(rick_mc.jump)
Jump();
if(rick_mc.attack)
{
Attack();
}
if (Key.isDown (Key.CONTROL))
{
keydown=true;
}
else keydown=false;
if(rick_mc.stance==0)
rick_mc._xscale = -100;
else
rick_mc._xscale = 100;
}
As you may have noticed, we can activate the functions by adding the parenthesis, ( (); those things). Initialise is kept outside of the main onEnterFrame function. Why? Because we want it to run only once and once only when the frame loads. Right, you can run the fla now, and Rick will do a cute little bounce for you. Admittedly, it's not spot on like the SplatterHouse one. Firstly, in the arcade game the jump is time-sensitive - I mean - the longer you hold down the jump the higher he goes. Secondly, he does a kind of unique punch kick combo depending on the height of the jump. But so what? Moving on.
Next tutorial we'll start on getting a couple of baddies in there. Creating multiple enemies and at the same time learning about using complex data types to hold their state/variable structures. Might even chuck in some code to make sound-effects if you're lucky. Questions/advice/tutorial errors: email to youngdude77@hotmail.com | |