2D Fighting Game - Programming Techniques

PuppyHelmet
Unregistered
 
Post: #1
Howdy,

I'm interested in how a Capcom-style 2D fighter is coded. Aside from graphics and such, I'd like to learn how you handle the input of combo sequences, the best methods of collision detection, AI models, etc. I've done many a Google search and come up empty on tutorials for coding a fighter.

Could anyone refer me to such a tutorial, or maybe share a few pointers on programming techniques? I'm not so much interested in how to implement the game in a certain language*, rather how the program would work in the abstract.

(* That said, I'm open to suggestions of an environment to use. I've been working with RB for a while now, but I'm starting to push the edge of its graphics capabilities; I'm considering using a scriptable 3D engine like dim3 to take advantage of OpenGL acceleration.)

I'm thinking about developing a 2D fighter as a uDevGame entry for this year, and eventually I'd like to release an editor to let people build their own characters and moves - an option I wish more fighting games had.

Thanks,
- Chris Doucette
Quote this message in a reply
Moderator
Posts: 916
Joined: 2002.10
Post: #2
Quote:I'd like to learn how you handle the input of combo sequences
store the last 10 or so characters in a queue and check for sequences. This kind of stuff is taught in Data Structures (college class which is without a doubt the only class I have received true knowledge from as far as programming)

Quote:the best methods of collision detection
for 2D fighter? I suggest using double mask. Along with a simple 1bit mask for the entire character, also mask for fighting positions that contain "critical areas" such as hands or feets, that you can use for collision detection. But basically, mask to mask comparison would be fastest and most accurate (which matters a lot) in a 2D fighter

Quote:AI models
I can suggest 2 things for this: easy and hard. Easy would be a simple finite state machine (although in a fighting game it would be a tad bit large). Pretty much set states (make punch if this, defend if this) with a tad bit of randomness to throw off predictability. Hard would be fuzzy logic and adaptive learning based off of the player's past behavior.

Quote:That said, I'm open to suggestions of an environment to use. I've been working with RB for a while now, but I'm starting to push the edge of its graphics capabilities; I'm considering using a scriptable 3D engine like dim3 to take advantage of OpenGL acceleration.)
Cocoa and OpenGL are my tools of the trade (and all my games are 2D).

Quote:I'm thinking about developing a 2D fighter as a uDevGame entry for this year, and eventually I'd like to release an editor to let people build their own characters and moves - an option I wish more fighting games had.
think smaller before you think bigger. but good luck with whatever you choose to do
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #3
This is a subject I have much interest in, and have thought about at length, so I can give a few answers (hopefully).

First thing to do is familiarize yourself with the combat engine you're trying to emulate. That means reading all the articles at Shoryuken.com, GuardImpact.com, etc. Second, check out M.U.G.E.N.. It's a 2D fighting engine for the PC that lets you plug in your own fighters. You can't download the source, but it can give you a good idea of how to accomplish a few things.

Now as for coding things... Input is handled using a big buffer of moves. Every time you move the joystick or push a button it gets added to the buffer. The game traverses the buffer in a FIFO (first-in, first-out) manner, and compares the commands to that character's move list. Each move has things like priority, frame gap, damage, etc. I guess the best way to explain this is an example.

Take Ivy's Summon Suffering command throw in Soul Calibur and Soul Calibur 2 (yea, a 3D game, but the same techniques apply). To perform Summon Suffering you have to perform the following moves: down+forward, up+back, forward, down, down+forward, down+back, A+B. SS has a 50 frame gap, which means that each command needs to be inputted within 50 frames (game animation frames) of the next command. Now obviously as you move the joystick around to hit every position you're going to be inputting additional commands as well, but those don't manner. The game engine will just throw them away. However, note that down+back, A+B also performs Ivy's Razor Bite move. Why doesn't Ivy perform that move instead? Because Summon Suffering has a higher priority. So when the game discovers that you've inputted the commands for two different moves, it performs the one with the highest priority.

Another example. Akuma's Shun Goku Satsu (Raging Demon super combo) is performed with these commands: light punch, light punch, forward, light kick, heavy punch. This demonstrates move cancelling. As you hit buttons like light punch, the game will perform those moves, but as soon as you hit heavy punch to finish off the command list, the game *cancels* and current move and immediately begins performing the Shun Goku Satsu. If you want to be able to cancel one move into another, you have to keep track of past commands inputted into the buffer (ie, don't remove them the second they are read).

Collision detection. Each frame of animation should have three things, the actual frame, the mask used to draw the frame, and a collision detection frame used for pixel-perfect collisions. The collision frame should be colored to represent different types of collisions. Ie, if you're punching, then the fist and arm could be blue, while the rest of the frame would be red. If your blue collision frame collides with the opponent's red collision frame, then you've hit your opponent, and vice-versa. If two blue collision frames hit then you've hit each other. If this makes no sense I'll post some example pics.

I have no clue on AI. Maybe David could help you out here because of his work on Lugaru on GLFighters.

Wow, this turned out to be longer than expected. Note that I've never actually programmed a fighter, this is just observations I've made over the years about how they (seem to) work. Any other questions just ask.

EDIT: Curse how long it took me to type this! Now it looks like I copied Sky.

Also, OpenGL is definitely the way to go for drawing the graphics. And you're definitely going to want to use a scripting language of some sort to define all the moves/characters/etc. You definitely don't want to be hardcoding anything when it comes to a fighter.
Quote this message in a reply
AJ Infinity
Unregistered
 
Post: #4
>I have no clue on AI.

Code:
if(fighter.x > cpu.x){
   cpu.walkLeft();
   cpu_comboqueue.addMove("walkLeft");
   if(cpu.x <= fighter.getBounds(xmax) && cpu.health >= 50 && fighter.isDucking == false){
       cpu.punch();
       cpu_comboqueue.addMove("punchLeft");
       if(cpu.x <= fighter.getBounds(xmax) && cpu.health >= 50 && fighter.isDucking == false){
           cpu.walkLeft();
           cpu_comboqueue.addMove("walkLeft");
           cpu.kickLeft();
           cpu_comboqueue.addMove("kickLeft");
    }
  }
  //I don't feel like typing anymore :). Actually, I'm kinda rushed at the moment.
}

/*Somewhere else*/
CPU::processCombos() {
    Combo_Meter combo;
    int length = cpu_comboqueue.getLength();
    for(i = 0; i < length; i++){
          char curMove = cpu_comboqueue.checkMove(i);
          switch(curMove){
                  case "moveLeft": combo.add(1); break;
                  case "moveRight": combo.add(2); break;
                  case "jumpLeft": combo.add(3); break;
                  case "jumpRight": combo.add(4); break;
                  case "punchLeft": combo.add(5); break;
                  case "punchRight": combo.add(6); break;
                  case "kickLeft": combo.add(7); break;
                  case "kickRight": combo.add(8); break;
          }         
   }
   MainClass.performCombo(combo.getName));
}
NOTE: Untested. I've made a fighting game before but it did not use the queue system of managing moves. I used simple if's and variables. eg if(keyDown[UP] && keyDown[align=right] && keyDown[KICK]){ kickLeft("up");};

A state machine would be even better also, where in the main loop you have a method call like ai.processStates(); and it determines the current state of the AI based on the players current position, the AI's health, the AI's postion, and more, then "fires" a move based on the current condition. have class methods like

Code:
void PLAYER::getCurrentPos(){...}; //Returns an array containing two variables for the x and y of the player
void PLAYER::getCurrentHealth(){...}; //Returns an integer containing the player's current health
void PLAYER::getCurrentAbilities(){...}; //Determines how good the AI should be based on how the player's been playing. IE: if they are just running and jumping around or if their just throwing moves anywhere but the AI

So on, so on
Quote this message in a reply
PuppyHelmet
Unregistered
 
Post: #5
Interesting. Is pixel-perfect c.d. really necessary, do you think? In a 3D context with real physics I can see how an approximation mechanism might lead to problems, but in 2D it seems like if you had a box or other polygon (in the case of irregularly shaped folks, multiple polygons) that represented the "hittable" part of the player, and checked for intersection with another polygon in the attack frame at the person's fist or foot or laser beam, that would be nearly indistinguishable from pixel-perfect, especially at high speed.

Of course, if pixel-perfect c.d. is done for you, why bother writing your own mechanism, but is it always preferable to a slightly more optimized approach?

- Chris
Quote this message in a reply
Moderator
Posts: 916
Joined: 2002.10
Post: #6
I never like box collisions (unless everything IS a box) because of how horribly bad it tends to look. The thing about 2D sprites is that is quite easy to get pixel perfect collision detection with a mask. If you don't want to do that, you could do multiple circles (I say about 6 circles for a human type shape). But you'll have to deal with inaccuracies. Believe me, nothing is more annoying than getting hit by something that didn't LOOK like it hit you
Quote this message in a reply
Moderator
Posts: 130
Joined: 2002.04
Post: #7
In a Capcom like 2D fighting game, there must be pixel perfect collisions, otherwise alot of players will get angry and frustrated.

"Gameplay Uber Alles. And if you can make it psychedelic too, great!" - Jeff Minter
Quote this message in a reply
AJ Infinity
Unregistered
 
Post: #8
Yeah, my collision is box based. For circle-to-circle body collisions, you'd use...
Code:
/*
File Circle2Circle.cpp
Originally from H2O_Cocoa_CollisionDefs.cpp
*/
#include<ClassDefs.h>
#include<H2O_Math.Defs.h>

int Circle2Circle_hitTest(CIRCLE circle_a, CIRCLE circle_b){
   int xDiff = circle_a.x - circle_b.x;
   int yDiff = circle_a.y - circle_b.y;
   int distance = h2o_sqrt(xDiff * xDiff + yDiff * yDiff);
   if(distance <= circle_a.radius + circle_b.radius){
      cout << "The circles hit each other!!";
   }
}
int main(){
   //The CIRCLE class contains methods for drawing a circle on the screen and getting/setting its x, y, z, width, heigt, radius, xvel, yvel

   CIRCLE circle1
   CIRCLE circle2
   circle1.setPos("x", 320);
   circle1.setVel("x", -2);
   circle1.setDimensions(64, 64);
   //The class automatically sets the radius to the width (diameter) of the circle divided by 2
   circle2.setPos("x", 0);
   circle2.setVel("x", 2);
   circle2.setDimensions(64, 64);
   Circle2Circle_hitTest(circle1, circle2);
}

Also try line segment collision detection.
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #9
Older 2D fighters (Street Fighter 2, King of Fighters, etc) used box collision, but all modern fighters (SF3, Capcom vs SNK, Guilty Gear XX) use pixel-perfect.

If I was you, I'd go with pixel-perfect. It's nearly as easy as comparing rects, and these days the speed hit is unnoticeable.
Quote this message in a reply
PuppyHelmet
Unregistered
 
Post: #10
OK, you've sold me.

Does Cocoa have a GL function that does mask-based c.d.? I have not a clue how you'd go about doing it from scratch. That would probably be a bad idea anyway.

I've got another uDevGame idea now, one that will be a little more inventive and less difficult to program, but I'll definitely want to start on the fighter in the not too distant future as well. Thanks for your help, yous guys.

- Chris
Quote this message in a reply
Member
Posts: 749
Joined: 2003.01
Post: #11
programming a cool fighting AI would be terribly challenging I guess. However, I tend to avoid writing complex code, cause it takes too much time. I like to write games that are fun despite having very simple and short code. I guess I' ll keep making shoot' em ups Wink
Quote this message in a reply
smartuser
Unregistered
 
Post: #12
Hi any progress on your game?
Can i view it somewhere?

For the collision it may be also posible to do a 1 bit color version symultaniously but off screen and in another resolution, for example when you have a 1024x768 on screen it is possible to do a collision test on a screen that is not visible and for example 320x200 so you have to check less pixels for a collisions i presume.

I've not yet tested this but i do think it is a nice solution.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Upcoming Multiplatform Game Programming Book for Beginners JazonYamamoto 3 923 Apr 14, 2014 05:55 PM
Last Post: JustinFic
  Game engines with object programming JonnyThunder 3 8,046 Aug 16, 2010 10:42 AM
Last Post: SethWillits
  ? Techniques for determining speed / efficiency Elphaba 9 4,736 Jul 19, 2009 03:42 AM
Last Post: DoG
  free mac game programming book jaked 4 6,594 Jun 8, 2009 12:48 AM
Last Post: SethWillits
  Game Programming Tutorial markvw 0 4,186 Jan 27, 2009 05:10 AM
Last Post: markvw