Fighting Game Tutorial Sprites Backgrounds Keys to Attack Engine

advertisement
Fighting Game Tutorial




Sprites
Backgrounds
Keys to Attack Engine
A little Physics
Sprites
You gotta get out there, and collect your sprites. Or...! if you're an avid game maker like me, you
could make your very own! I like having everything original, in case I ever made it big
and sold my games for millions of dollars. I'm living the dream baby. Get your MK vs
SF sprites for those epic showdowns. Or how about taking pictures of yourselves and
putting you and your friends in the game? (that's a personal side project I'm currently
working on).
I went online and grabbed this off the internet. Please only use these sprites as a base
for your characters. You cannot distribute a game for anything by personal use using
these sprites as they are copyrighted by Capcom.
In any case, for this tutorial and Jamjam's perosnal advice is to use a template sprite,
which you will later remove. Spriting and animation in by itself is a fulltime job, and as
the professional programmer you are, you outsource that job!
So how do we use this? Real quick, we'll go through how to implement these in your
game.







Go to your sprites folder, right click and create new sprite.
Edit Sprite
Create from strip
Find the where you saved the image above
Image width/Image Height 96x96
Hover over sprite you want (it's okay if other sprites are in the same box)
OK
This is what you should see so far. Now to add the other sprites




File
Add from strip
Select same file
Select next image to the right
After your satisfied with the number of frames, you need to go in and delete the extra stuff you
grabbed by accident. It shouldn't take longer than 30 seconds. Crop and you're good to go.
Now after your done all that, name it something you will remember. I like to name it according to the
file type so "spr" then the name of the character "ryu" then the description of the sprite "stand". i.e.
"spr_ryu_stand"
Now to be detail oriented, open up the sprite properties, and set the origin to right below the sprites
feet. I chose (22 x 82) but it might be different for your sprite.
Background
Now that spriting is done, we need to add a room, and it's background. Go to backgrounds and right
click -> create background. Load background, and pick a background you'd like. You can use the one
I'm using below.
At first the background is not animated, but we can fix that in the part 3 of this 2D fighter tutorial.
Go to rooms and create a room with a size of 768x224 (size of background). Name the room
something like "rm_testroom". Then go to the backgrounds tab, and click on "<no background>" and
select the one you like. Now if you go run your game, you should see a room with your background in
it, with no players. What an awesome 2D fighter we have so far! Not really. Okay next.
Keys to Attack
Time to throw in the players!
Creating the players






Go to objects folder
Right click, insert object
Click on sprite (under the name) select your "stand" sprite
Name it "obj_player1"
OK
Do this twice, for obj_player2
Putting it into the room





Open up your room again,
Go to objects
Place obj_player1 on one side
Place obj_player2 on other side
Run the game
Amazed yet? no? we can't do anything with the players you say? What ungrateful game makers you
are. Fine! lets get to coding these guys to attack.
Attacking
Ah, the heart of the 2D fighter. Attacking. of course! how could we forget about attacking. First a few
admin stuff.




Open obj_player1/obj_player2 properties (do for both)
add event, create
control tab on the right drag and drop (execute code)
type these two variables in
o action = false
o walking = false
Go to your "scripts" folder and create a script. Name it "scr_drawplayer". Type this in the script:
draw_sprite_ext(sprite_index, image_index, x,y, image_xscale, image_yscale, image_angle,
image_blend, image_alpha)




Open up player1/2
Add event draw
Control tab / Drag-Drop Execute Script
Box should pop up, click on the script category and select scr_drawplayer
But why should we create a script for drawing the player, game maker already does it??? Well, since
we've gone beyond the realm of drag & drop, and actually going to be inserting code into the draw
event. Game maker scraps its own draw event for yours! So if we didn't put this code in, game maker
would explode and all life as we know it would cease to exist.
create a script, name it "scr_drawattack".
insert this in the script:
var key, spr_base, spr_atk;
key = argument0
spr_base = argument1
spr_atk = argument2
This is your first taste of creating an engine. You do this to save you time when your creating new
characters and new attacks!
Insert this in 'scr_drawattack' after the 3 arguments:
//if currently not attacking, and a key has been pressed
//change sprite to attack sprite
if keyboard_check_pressed(key) and !action
{if sprite_index != spr_atk
{image_index = 0; //set to beginning of animation
sprite_index = spr_atk;
action = true}
}
//this code looks to see if attack animation has completed
//if so, return back to base sprite
if sprite_index == spr_atk//if currently attacking
{if image_index == image_number - 1//check if animation finished
{sprite_index = spr_base; //if animation finished return to base
action = false}
}
We're almost there! Ahh the finale! Okay open up your player1 again







Add a step event and drop a script in.
Double click the script you just dropped in
Set the script to scr_drawattack
argument0 to ord('A')
argument1 to spr_ryu_stand
argument2 to spr_ryu_jab
OK
See how these arguments coincide with your the arguments in your script? argument0 is the key,
argument1 is the BASE sprite, and argument2 is the ATTACK sprite.

RUN GAME
Press 'A' to jab.
Go back to your obj_player1 properties and add in as many scr_drawattack into step event as you
want.




Open it your second scr_drawattack
change up the "key" and the "attack" sprite.
I changed argument0 to "S"
and argument2 to "spr_ryu_highkick".
Now my player does a kick when I press "S".
For player 2, you'd have to change the keys. So do not use the same keys for player 1 as player 2.
Obviously.
Sprites! we learned how to add sprites from a strip, and create an animated character
Backgrounds! we learned how to add a background
Rooms! we learned how to create rooms and add backgrounds
Engine! This is the crux of the tutorial. The engine is the core of your game, and will be the theme of
these tutorials from now on. You learned how to script, use arguments, and create an engine for your
attacks!
1. Animated Backgrounds
I've looked around online for how to animate backgrounds on game maker, and none of them are
quite as elegantly done as this one ! You can take the one below or you can follow these steps to
make your own!
First, take your gif (animated background) and insert it into your sprite resources. Click edit, then save
it as a .png file. This should create a strip like the one I have above. Is that it? Yes that's it!
The file that you just saved should be named "xxxx_strip4.png" where xxxx is the name of the sprite,
and 4 means there are 4 images in the sprite. Replace the old background you had with this new one
you just made.
Go to your room editor and set the horizontal room speed to 768 (or whatever the width of each frame
is)
This is much simpler, does not lag, and is easy to implement.
2.a Physics
A little background on why we should implement physics into the game. Physics really adds an
amount of professionalism that new game makers seem to oversee when they are making their
games. When you are walking or running, you don't go from 0 - fullspeed instantaneously, it takes
maybe half a second to get there.
And when we stop, we do not stop instantaneously; it takes time for friction to take its toll on our
movement. This is what we are planning to implement in the game!
Start by:



Insert new script
name it scr_move
put in scr_move, the code below
var right, up, left, down, spdinc, maxhspd;
right = argument0;
up = argument1;
left = argument2;
spdinc = 5;
maxhspd = 10;
{if hspeed < -maxhspd{hspeed = -maxhspd}
if hspeed >= maxhspd{hspeed = maxhspd}}//limit max speed
if action{hspeed = 0}
if abs(hspeed) < maxhspd// if going slower than max speed
{if keyboard_check(left)
{motion_add(180, spdinc)}
if keyboard_check(right)
{motion_add(0, spdinc)}
}
if abs(hspeed) >= maxhspd// if going faster than max speed
{if hspeed > 0{//if going right
if keyboard_check(left)
{motion_add(180, spdinc)}}
if hspeed < 0{//if going left
if keyboard_check(right)
{motion_add(0, spdinc)}}
}
After you've put in the code, time to put it in the players!
Open up your obj_player1 / 2, then place
in the step event script: scr_move. Now, make sure your arguments here coincide with the arguments
in the script. If you check the script "scr_move", you will see, "right" is argument0, "up" is argument1,
and "left" is argument2.
This means, if you put ord('D') as argument0 here, the keyboardkey D would move the player right, if
you put ord('Y') as argument0, the keyboardkey Y would move the player right. Choose whatever
keys you would like, I personally like to use vk_right/vk_up/vk_left respectively.
RUN!
Try using your left and right keys. You player should move! But he's not stopping. Why? Well what
stops an object in motion from moving? Friction!
Now we have to add in a little friction into the game.
Start by:



Inserting a new script
name it scr_friction
put in scr_friction, the code below
var fric;
fric = 1
if hspeed > 0
{if hspeed -fric > 0 {hspeed -=fric} else {hspeed = 0}}
if hspeed < 0
{if hspeed +fric < 0 {hspeed +=fric} else {hspeed = 0}}
Put this in the player step event
RUN!
Move the player around ! ah! the power of friction stops Ryu in his tracks! This would really come in
handy when your throwing the other player around the screen. Really, this little headache you just
experienced is totally worth it considering the hundreds of variables you would of implemented had
you not done this now!
2.b Move Animation
Now to make his movement a bit more believable, we need to change his sprite from standing, to
walking. So we go back to our sprite sheet and find where Ryu looks like he is walking. Create a
sprite using his walking animation, and name it "spr_ryu_walk".
Next, we have to make a modification to our script "scr_move". So open that up, and put in this code:
if abs(hspeed) > 0 and !action {walking = true}
else {walking = false}
right at the beginning of your code, after you initiate your variables, after "maxhspeed = 10;".
This code is saying, if he is not doing an action, and he's moving, then walking should be true. Now
we have to change the sprite when he's moving.



insert script
name it "scr_change_sprite"
put in 'scr_change_sprite' the code below
if walking and !action
{sprite_index = spr_ryu_walk}
if !walking and !action
{sprite_index = spr_ryu_stand}
put this in the step event of the players.
3. onHit Animations
What do I mean by onHit animations? Well, simply put, you'll be able to attack the other player now!
And the other player will react to your hits.
3.a Hitboxes
How do we make them? It's very easy, duplicate one of your
attacking sprites; "ryu_spr_jab" for example. Now delete
everything except his fist in this duplicated file. Save as "ryu_spr_jab_hitbox". Now do the same for
all his other attacks. Make sure in the sprite properties menu, that "separate collision masks" is
selected. That's all there is to it!
3.b Collision script
We need to elicit some help from our fellow programmers. This script will allow you to find exactly
where two sprites meet. The script is found in the example game at the top of the tutorial, but if you'd
like to give him some love, leave a comment on his forum.
I specifically took the script "CollisionPointIDs". It's really all we need, because we need to know
when and where exactly our fist meets his face, or body, or balls (we might implement some ball
shots in this game).
After you inserted CollisionPointIDs into your game your done! Onto the next step
3.c onHit Script
Now this is a bit trickier than the other two parts so pay close attention. Insert a script and call it
"col_attackbox". Then put in the code below into this script.
if other.owner == self.id
{exit}
if CollisionPointIDs(self.id, other.id)
{damaged = true}
with (other.id) {instance_destroy()}
Lets check our exhaustive list for how
to do onHit animations.
Awesome! we have everything we
need to implement onHit animations.
Oh! I almost forgot, add this this to your
sprite resources and name it:
"spr_ryu_hit".
Open up a script we've made before called "scr_change_sprite" and add this piece of code in after
your last line of code:
if damaged and sprite_index != spr_ryu_hit
{sprite_index = spr_ryu_hit;
action = true
image_index = 0}
This means, if we are damaged and he does not look like he's being hit, change sprite to being hit.
Player is performing action.
We are introducing a new variable "damaged" into our player in the above script. So add this in the
create event for obj_player1/2:
damaged = false
Now to put it all together, we need an object. Create an object and name it "obj_attackbox". Then
open up "scr_drawattack".You may just copy and paste this script, but I recommend understanding
what I changed. I highlighted the changes in red.
var key, spr_base, spr_atk;
key = argument0
spr_base = argument1
spr_atk = argument2
spr_atk_hitbox = argument3//new argument introduced
//This section was switched to the top.
//this code looks to see if attack animation has completed
//if so, return back to base sprite
if sprite_index == spr_atk//if currently attacking
{if image_index == image_number - 1//check if animation finished
{sprite_index = spr_base; //if animation finished return to base
action = false}}
//this entire section is new
if action{exit}
if keyboard_check_pressed(key)
{var atkbox;
atkbox = instance_create(x, y, obj_attackbox)
atkbox.owner = self.id
atkbox.sprite_index = spr_atk_hitbox
atkbox.image_index = 0
}
//This section switched to bottom.
//if currently not attacking, and a key has been pressed
//change sprite to attack sprite
if keyboard_check_pressed(key) //and !action
{if sprite_index != spr_atk
{image_index = 0; //set to
beginning of animation
sprite_index = spr_atk;
action = true}
}
So a few minor changes, and an entire
section was added.
Now open up obj_attackbox, and
deselect the "visible" option. Then add a step and draw event. In the step event, insert this code:
x = owner.x
image_index = owner.image_index
if image_index == image_number-1
{instance_destroy()}
In the draw event of obj_attackbox, insert previously written script: scr_drawplayer.
Open up obj_player1 / 2 and add event
"collision" with "obj_attackbox". And insert the script "col_attackbox" in the event. Make sure player2
has a step event, and has scr_change_sprite in its step event.
Now you can run up to player2 and attack him. But notice how he's stuck on that animation! Lets fix
that animation up and we're done for this tutorial. PHEW!
Open up scr_change_sprite and put this script in:
if sprite_index == spr_ryu_hit{
{if image_index >= image_number -1
{action = false; damaged = false}}}
Tutorials shall now be limited to 3 sections only! So what will we cover in only 3 sections today?
1. Gravity
2. Special Effects
3. Healthbar
1. Gravity
Ah, Gravity. It wasn't long ago when you were just a mystery to us. That is, until you forced an apple
upon Newton's head - as if to say "over here dummy!". Gravity is indeed a wonder in the real world,
so how are we possibly going to implement this in our game? Well, first we have to understand a bit
about how gravity works on objects. Lets say we throw a ball down from a tall building, what's going
to happen? The ball is going to constantly speed up until it falls splat on the ground. So lets put this in
the game!

create 2 variables in obj_player1 / 2
o onground = false;
o
ground = 208;

Open 'scr_move'
o type this in at the bottom of the script
if onground
{if keyboard_check_pressed(up)
{motion_add(90, 10)}}


create script called 'scr_gravity'
put the code below in the script
var gforce;
gforce = 0.5
if y >= ground
{vspeed = 0; y = ground; onground = true}
if y < ground
{motion_add(270, gforce); onground = false}
3. Place 'scr_gravity' in End Step event of obj_player1 /2
Try it out! Player can hop, skip, jump and land safely. With this new gravity engine it's really easy to
implement anything! For example if we wanted our player to start flying, we just set the ground to
above 208; maybe 100?
But it doesn't really look like the player is jumping does it? We need something to make it a bit more
convincing. We need to change the sprite when he's in the air! This should be easy, just go to your
script 'scr_change_sprite' and add in the script below.
if !onground
{if sprite_index == spr_ryu_walk
or sprite_index == spr_ryu_stand
{image_index = 0
sprite_index = spr_ryu_jump}
}
if sprite_index == spr_ryu_jump
{if image_index > image_number -1
{image_index = image_number -1}
}
Within the same script (scr_change_sprite) look for line 1 and line 3, we need to add what's
highlighted in red below:
if !walking and !action and onground.
if walking and !action and onground
That's it! Lets try it out!
RUN!
Nice! He actually looks like he's jumping!
2. Special Effects
What do I mean by special effects? Well, take a look on the image below. Special effects really
visually enhance the punch! Street fighter games have different sized onHit sfx for different intensities
of damage. The more damage it is, the bigger the effect!
You can play around with different effects, so you don't have to stick with what I have. Maybe if you
wanted to do more of a Mortal Kombat feel, you may want to add in blood splatter instead of just a
"pow" special effect! Here's the one I use for my games below. These are property of Capcom, and I,
nor you should use these sprites for commercial purposes.
Throw these into your sprite resources, and center the sprite origin. Delete the black background by
clicking 'edit', 'images', 'erase background' choose black, select 'apply to all images in sprite', and
you're good.
Rename the sprites 'spr_lowhit' and 'spr_lrghit'.
Now we need an object to display these special effects:






Create object
Name it obj_specialeffect
Add Event
o Other -> Animation End
Actions: Destroy the Instance
OK
OK
Open script 'col_attackbox', then within the if statement CollisionPointIDs add the below in RED.
if CollisionPointIDs(self.id, other.id)
{damaged = true;
var sfx;
sfx = instance_create(__x, __y, obj_specialeffect);
sfx.sprite_index = spr_lowhit;
}
3. Health bars Part A
I'm going to make health bars a two part series. There's a lot more to health bars than just a green
bar at the top of the screen! But for now, that's exactly what we're going to do. Later on, I'll show you
guys how to add damage indicators, and making your health bars look just a bit prettier.
Start by going creating two variables in
create event of obj_player1/2. Call
these two variables:
curhp = 100
maxhp = 100
I created a script called 'ini_player'
where I place all my starting variables
for obj_player1/2. You should do the
same. This way you don't have to do
things twice! I will be referring to this
script from now on whenever I initialize
variables!
creating a script called 'scr_healthbar'
and insert this script in below:
//player 1
with(obj_player1){
draw_healthbar(16, 16, 316, 32, curhp/maxhp * 100,
c_black, c_green, c_green, 180, true, true)}
//player 2
with(obj_player2){
draw_healthbar(room_width - 16, 16, room_width - 316,
32, curhp/maxhp * 100, c_black, c_green,
c_green, 0, true, true)}
Then create an object called 'obj_hud' and insert 'scr_healthbar' in its draw event. Place 'obj_hud'
anywhere in the room editor.


go into scr_col_attackbox
within the if statement 'CollisionPointIDs', type this in:
o curhp -= 5
What did we learn today? Gravity! Not even Einstein figured this out yet. We learned about special
effects and how awesome it makes your game looks. And Lastly, healthbars, we learned how to
implement them into our game.
1. Healthbars Part B.
So what could we possibly do better than the health bars we've already had in place? Well! if you take
a look at some games out there now like: League of Legends for example. They have "damage"
indicators, usually in red, telling you exactly how much damage your character has taken.
Create a sprite 1x16px
Apply a dark green to light green gradient on it
Name it 'spr_healthbar'
Create a sprite 1x16px
Apply a dark red to light red gradient on it
Name it 'spr_dmgbar'
This will be used to draw
the healthbars from now on! The gradient adds a touch of lighting to the bar that wasn't there before.
The flat green that the HP bar had before made it seem bland and uninteresting.
I tend to use the 3rd gradient from the left, but it's your choice. However, when you do choose one, be
consistent! The green and red bars should have the same gradient applied to them.
You may even want to just copy and paste the green bar, and change the hue to red.
Insert a new script with the following details:
Name:
draw_spritebar
Code:
draw_sprite_ext(argument0, 1, argument1, argument2, argument3, argument4, image_angle, image_blend, image_alpha)
This code is used to draw the healthbar
as a sprite. How we used to draw a
healthbar is indicating:
(x1, y1, x2, y2). This code is very
similar, x1, y1, x2, y2
is argument1, argument2, argument3,
and argument4 respectively.
Initialize 2 variables in script 'ini_player':
last_damage = 0
last_damage_timer = 0
These variables will be used to indicate the damage the player has taken. In order to do this, we have
to store the last damage the player has taken in a variable. The timer is just a small touch of
professionalism. It sets a small delay between seeing the full amount of damage, and reducing the
length of the damage bar.
Insert a new script with the following details:
Name:
scr_healthbar
Code:
var height;
height = 0.5;
//player1
with(obj_player1)
{draw_rectangle(15, 15, 317, 16 + (16 * height), false)
draw_spritebar(spr_dmgbar, 16, 16, 300 * ((curhp + last_damage) / maxhp), height)
draw_spritebar(spr_healthbar, 16, 16, 300 * (curhp / maxhp), height)
if last_damage_timer > 1
{last_damage_timer -=1}
else{if last_damage > 0 {last_damage -=1}}
}
//player2
with(obj_player2)
{draw_rectangle(room_width - 317, 15, room_width - 16, 16 + (16 * height), false)
draw_spritebar(spr_dmgbar, room_width - 316, 16, 300 * ((curhp + last_damage) / maxhp), height)
draw_spritebar(spr_healthbar, room_width - 316, 16, 300 * (curhp / maxhp), height)
if last_damage_timer > 1
{last_damage_timer -=1}
else{if last_damage > 0 {last_damage -=1}}
}
Code Explanation:
Now this is the core of the new health bar! I'll explain this line by line:


draw_rectangle
o The border and background underneath the health bar
draw_spritebar(spr_dmgbar,...
o this is the damage bar that is drawn underneath, this is the same value as your current
health + the damage you just took. The red bar jutting out, is that extra bit you are
adding.


draw_spritebar(spr_healthbar,...
o this is the green healthbar draw on top the damagebar.
damage timer:
o This is saying; if there is a delay, subtract 1 until delay is over. When delay is over,
check if there the player is indicating any damage. If so, subtract the amount shown by
1 until none is shown.
Add these lines of code within script 'coll_attackbox', within if statement:
'if CollisionPointIDs'(self.id,other.id):
last_damage +=5
last_damage_timer +=5
This is done when the player is hit. We need to update the last damage he took, in this case it would
be 5hp of damage was taken. So +5. Then we set the delay on the damage indicator. I chose 5
arbitrarily, you may choose whatever you think looks best!
2. Juggling
What is juggling? Juggling in games is when you are able to string together combos so that your
opponent is always in the air and is left helpless to your relentless attacks! How do we program this
into our game? Well, we have basically have to force the enemy into the air whenever he's been
attacked by a certain move.
Must Read*
How you want to implement juggling is up to you. There are many different ways games implement
combos. Some games have pre-set combos like Killer Instinct. Some other games require you to
string together your own combos. Your goal as a programmer is to have a vision in mind as to how
you would like this to be done. I personally like to give the players the opportunity to be creative.
Say goodbye to dragging and dropping! the number of arguments that scripts allow in a drag and
drop scenario is too limited for what we have to do here. So we need to relocate our scripts.
Remember to delete the four drag and drop scripts: scr_drawattack from the players step event, and
replace it this one script: scr_attack.
Insert new Script:
scr_attack
Code:
//Key, basesprite, attacksprite, hitbox, damage, type
if object_index == obj_player1{
scr_drawattack(ord('A'), spr_ryu_stand, spr_ryu_jab, spr_ryu_jab_hitbox, 5, 'normal')
scr_drawattack(ord('S'), spr_ryu_stand, spr_ryu_cross, spr_ryu_cross_hitbox, 5, 'normal')
scr_drawattack(ord('Z'), spr_ryu_stand, spr_ryu_lowkick, spr_ryu_lowkick_hitbox, 5, 'normal')
scr_drawattack(ord('X'), spr_ryu_stand, spr_ryu_highkick, spr_ryu_highkick_hitbox, 5, 'juggle')}
else{
scr_drawattack(ord('G'), spr_ryu_stand, spr_ryu_jab, spr_ryu_jab_hitbox, 5, 'normal')
scr_drawattack(ord('Y'), spr_ryu_stand, spr_ryu_cross, spr_ryu_cross_hitbox, 5, 'normal')
scr_drawattack(ord('U'), spr_ryu_stand, spr_ryu_lowkick, spr_ryu_lowkick_hitbox, 5, 'normal')
scr_drawattack(ord('H'), spr_ryu_stand, spr_ryu_highkick, spr_ryu_highkick_hitbox, 5, 'juggle')
}
So instead of using the drag and drop, where each icon represents scr_drawattack, we just put them
all in one script. We also added two new variables, "damage" and "type" at the end of the script. This
will indicate how much damage we are doing to the opponent and how it hits the opponent.
Edit Script: scr_drawattack
Edits are indicated in RED. You may just copy and paste the whole script.
Code:
var key, spr_base, spr_atk, spr_atk_hitbox, damage, type;
key = argument0;
spr_base = argument1;
spr_atk = argument2;
spr_atk_hitbox = argument3;
damage = argument4;
type = argument5;
//this code looks to see if attack animation has completed
//if so, return back to base sprite
if sprite_index == spr_atk//if currently attacking
{if image_index == image_number - 1;//check if animation finished
{sprite_index = spr_base;
action = false}
}//if animation finished return to base
if action{exit}
if keyboard_check_pressed(key)
{var atkbox;
atkbox = instance_create(x, y, obj_attackbox)
atkbox.owner = self.id;
atkbox.sprite_index = spr_atk_hitbox;
atkbox.image_index = 0;
atkbox.damage = damage;
atkbox.type = type;
}
//if currently not attacking, and a key has been pressed
//change sprite to attack sprite
if keyboard_check_pressed(key)
{if sprite_index != spr_atk;
{image_index = 0;
sprite_index = spr_atk;
action = true}
}
There are a few edits here in red that you might want to understand. After I retrieved the arguments
from scr_attack, I have to relay this message to the other player, IF the player gets hit. So we give it
to attackbox. We need to indicate how much damage this attack does, and whether the player should
be hit into the air.
Edit Script: col_attackbox
Edits are indicated in Red
if other.owner == self.id
{exit}
if CollisionPointIDs(self.id, other.id)
{damaged = true;
var sfx;
sfx = instance_create(__x, __y, obj_specialeffect);
sfx.sprite_index = spr_lowhit;
curhp -= other.damage;
last_damage += other.damage;
last_damage_timer +=5;
if other.type == 'juggle'
{motion_set(90, 8)}
}
with (other.id){instance_destroy()}
Since the hitbox is given the variables "damage" and "type". We can indicate that the player colliding
with the hitbox should be 1) damaged by 5, and 2) hit into the air.
Edit script: ini_player
Add these two lines to the script:
last_damage = 0;
last_damage_timer = 0;
Edit script: scr_gravity
Edits are indicated in RED.
var gforce;
gforce = 0.5;
if y >= ground
{if vspeed > 0{vspeed = 0}; y = ground; onground = true}
if y < ground
{motion_add(270, gforce); onground = false}
RUN!
Try high kicking! The guy pops into the air ! Man this is looking to be one hell of a 2D Fighter ! How
much more could we do? What else do can we implement into this game?? Much, much more guys.
But it really is up to you how far you want to take this!
Juggling No Attacking
So I was playing around with juggling the last game and I quickly discovered a problem that I wanted
to solve. While juggling the opponent, I found that the other player could still attack while in the air! I
didn't like that. If I hit someone into the air, there should be a refractory period in which the other
player is left helpless.
So how are we going to implement this "refractory period"? Simply, we need a timer in the player. A
'juggle' timer.
edit script: ini_player
add code:
juggle_timer = 0;
edit script: col_attackbox
look for line: "if other.type == 'juggle'{"
and within that if statement, type in:
juggle_timer = 10;
Okay, so now we have something called a juggle_timer, but the player does not know what it does,
and it doesn't count down yet. We can easily fix that by making a new script.
Insert new script: scr_timer
Code:
if juggle_timer > 0
{juggle_timer -= 1}
Place scr_timer into the step event of player1/2.
Lastly, we need to tell the player how to behave when the juggle timer is on. That is, we don't want
the player to attack.
Insert new script: scr_preventattack
Code:
if action or juggle_timer > 0
{return true}
else
{return false}
Edit script: scr_drawattack
Look for the line "if action{exit}"
then replace it with:
if scr_preventattack(){exit}
Alternatively, we could have just put "if juggle_timer > 0{exit}" below "if action{exit}" statement.
However this method is much cleaner. Say for example, we have more timers we wanted to
implement that inhibited the player from attacking. We would simply edit one script:
scr_preventattack. It's a much cleaner method, and this small amount of work you are putting in now,
will save you a lot of time in the long run!
Kick the other guy in the air, and try attacking with that player. It's impossible ! Exactly what we
wanted ! You'll learn that it's the little things like this that will take up the most time when your
programming. It doesn't work exactly the way you intended and you have to make patches upon
patches.
Screen Shaking
First we need to set up a few things about the room. We need to make sure:





Views enabled
Visible when room starts checked
View: Width x Height || 768 x 224
Port: Width x Height || 768 x 224
No object is followed
Now we need to get to coding the screen shake!
Create new object: obj_camera
Create Event: Execute Code:
shake = false; //Whether to be shaking or not
maxshake = 0; //The shake intensity (maximum-pixel-shake-per-side)
curshake = 0; //Current Intensity.
shake_length = 100
goright = false
Step Event: Execute Code:
//this script shakes the screen from side to side
if shake
{//change direction
if curshake >= maxshake
{goright = false}
if curshake <= -maxshake
{goright = true}
if goright
{curshake += maxshake}
else
{curshake -= maxshake}
//this function below makes sure there is no zero shake value
if curshake == 0
{if goright
{curshake += maxshake}
else{curshake -= maxshake}}
//change x (shake)
view_xview[0] = curshake
shake_length -= 1
//quake reset
if shake_length <= 0
{view_xview[0] = 0
curshake = 0}
}
I'll give you a quick explanation as to what's going on here. It checks if shake is on, if it is, the screen
either moves left or right accordingly. Shaking is on a timer, and when time is up, we need to reset
the view to the default value.
Now we need a script that we call to turn shake on!
Insert new script: quake
Code:
obj_camera.shake = true
obj_camera.maxshake = argument0
obj_camera.shake_length = argument1
So! if we wanted to call this function, all we have to do is: quake(5, 10)
This means, the shake value is 5, and the timer is set to 10 steps. Lets say we have a really hard
punch, and we want to emphasize this, all we'd have to do is put quake(5,5) in the col_attackbox
script! I'll let you figure out where! If you have trouble, remember you can always refer to my file!
Special Effects
We've really come a long way haven't we? Here, I wanted to throw in a few special effects to really
emphasize things that are going on in the game. We already have one in there, the punch special
effect! how 'bout some more? I'll get you started, and you can figure out more if you wanted to! It's all
up to you.





Jumping
Falling
Special Attacks (hadukens)
Supers
Running
I'll show you how I implement some of these effects in the game, and you may throw in some more if
you'd like!
The above sprites are the ones I used for jumping and running respectively. They are of course,
copyrighted images from Capcoms Street Fighter 3. So do not use these sprites in your game if you
intend to sell it!
Add the above sprites into your sprite resources, and name then spr_jump and spr_run
respectively. We need a script to play the special effects!
Insert new script: create_sfx
Code:
var sfx;
sfx = instance_create(argument0, argument1, obj_specialeffect)
sfx.sprite_index = argument2
Edit Scipt: scr_move
Code: At the bottom of the script, you should see:
if onground
{if keyboard_check_pressed(up){motion_add(90, 10)}}
replace it with:
if onground
{if keyboard_check_pressed(up)
{motion_add(90, 10)
create_sfx(x, y, spr_jump)
}
}
Well, there's just a few more things I would like to cover before this tutorial ends!



Event Notices
Combo Count
Your Choice!
Okay, so what happens up to part 6 when we beat the ever-living snot out of the other player?
Nothing, he still stands tall like the giant prick he is. We're going to fix that here, and now! First we'
have initiate a variable called "dead".
edit script: ini_player
add code: dead = false
now we need a trigger event that tells us when to tell the player he's dead. we do that in the
col_attackbox script.
edit script: col_attackbox
add this code below "last_damage_timer +=5":
if curhp <= 0
{dead = true}
Perfect, now the player knows when he's dead ! that is, when his hp falls below 0, or is at 0.
However we're still not done! we still need to change the animation to the dying animation. so
open up our "scr_change_sprite"
edit script: scr_change_sprite
add code:
if dead
{if sprite_index != spr_ryu_dead
{sprite_index = spr_ryu_dead;
image_index = 0; motion_set(90, 5)}
else
{if image_index = image_number -1 {image_speed = 0}}
exit}
Okay so let me explain what's happening here. First few lines say, if it's he's dead, and the animation
doesn't show he's dead, change his animation, starting from 0. Also, jump into the air slightly when
dying. Then it says, if the animation IS showing he's dead, then stop at the last frame. "exit" just
means that the script should no longer run beyond line 8. And why should it? He's dead! No other
animation should be shown.
Some minor details I changed to fix bugs and such, open up scr_preventattack
edit script: scr_preventattack
add code: "or dead" at the end of line 1
I actually didn't like how other player was still able to move when he was dead, so I edited the move
script.
edit script: scr_move
add code: if dead {exit} @ line 18
And that's it for the death animation! Now after you beat the shit out of the other player he'll actually
FAINT! and he'll do a small jump into the air while he's at it too, just to make things a bit overly
dramatic. But we're not done yet! The winning player needs a winning pose!
Winning animation
The winning animation is quite simple! Actually to make things even easier for us in the future I'd like
to add a new variable to obj_player1 and obj_player2.
edit script: ini_player
add code:
if self.id = obj_player1.id
{other_player = obj_player2.id}
else
{other_player = obj_player1.id}
What I am doing here, is storing the variable "other_player" so that I can have easy access later.
edit script: scr_change_sprite
add code to end of script:
if other_player.dead and sprite_index != spr_ryu_win
{sprite_index = spr_ryu_win}
RUN!
That's it! Now after you win, and he falls dead to the ground, you'll taunt him with your infinitely
looping shoryukens.
Download