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.