The game includes all of the arenas which are selected at random along with their music but currently the only playable characters are Ryu and Zangief. All of the music, sound files and arena images that the game uses do make for quite a lengthy loading time but I really wanted to make it an authentic experience and not remove anything. Besides I like to think it’s worth the wait! You can check it out here or you can keep reading to get a bit of insight into the techniques I used to achieve the end result.
I created a base player class which contains all the fundamentals for the functioning of a player – movement, collision detection, receiving damage when hit, etc. and every character is derived from this player class. The character-specific classes contain things like animations sequences, special moves, and all the things that will differ from character to character. So basically what that means is it’s pretty easy to add more characters which I would like to slowly do if I can find the time.
While ImpactJS does have hit detection out the box the hit detection for a game like this exceeded the limitations of that. The default hit detection of ImpactJS basically checks if the bounding boxes of 2 entities intersect and if they do it’s a hit which is quite adequate for a platformer like Super Mario but when you’re dealing with sprites that have limbs the hit detection needs to be a lot more accurate. So I created 2 entities to achieve this – a Hit Detector and a Hit Receptor.
Hit Receptors are spawned by each frame of every animation sequence and Hit Detectors are spawned by every attack animation. When a Hit Detector entity intersects with a Hit Receptor entity it’s a hit. So for example if a player is performing a punch a couple of Hit Detector entities will be spawned along the area of his punching arm registering a “hit” with any Hit Receptor they connect with. Of course they are invisible to the user unless the debug variable is set to true. The reason I kept the Hit Detectors small (22 x 25 pixels) is that it allows for greater accuracy when calculating the point of contact which is required when generating the little “hit burst” animations that Street Fighter 2 has.
Hit Receptors also contain information about whether they represent a “high” or “low” hit area so that it is known whether to play the face or stomach hit animation when a player is struck. They also contain information that indicates whether they are for a takedown attack in which case instead of triggering the affected player’s pain animation it will trigger their takedown sequence. An example of this is the leg sweep.
In order to create an authentic Street Fighter 2 experience I HAD to include the special moves. Street Fighter just isn’t Street Fighter without them. So to achieve this every key that is pressed by the user is added to an array. This array is checked every 0.6 seconds and if it’s contents matches any of the predefined special move key sequences then that special move is initialised and the array is emptied but if no special moves are matched then the array is just emptied.
The code for the characters special moves resides in the specific character entity and can range from being fairly simple like Ryu’s Fireball to being pretty damn complex like Ryu’s Hurricane Kick which was a bitch and a half to get right.
In some instances it was necessary to chain players animations so in order to achieve this I added the functionality to specify a callback function for an animation which is run when the animation sequence is finished. This callback function can do basically anything. In some instances it’s used to trigger a follow on animation for the player and in some instances it’s just used to unset certain flags or variables that were changed during the completed animation sequence. The possibilities for what it can be used for are basically endless.
Animation Frame Binding
In some instances I needed to be able to trigger some code to execute on a specific frame of an animation. For example the sound that plays when a player is knocked off their feet. When I had the sound playing at the same time that the animation began it looked silly because you’d hear the sound before the player actually touched the ground. So in order to make this more authentic I had to trigger the sound to play only when the animation had reached the frame where the player hits the floor. Which of course is not always the same frame for every player so I created the functionality to bind a function to a specific frame of animation which in turn can be used to trigger a sound to play.
Something else I added to the game was the ability to bind to certain in-game events. Some examples of these events are onroundstart, onbeforetouchingperimeter and onbeforehitfloor. I also created an event for every player’s generic attack – onpunch, onkick, etc. The reason this was imperative was in the case that I wanted to include a bit of custom functionality for a player for one of those generic attacks I couldn’t do it because the code resides in the common player entity that all players are derived from which means it’s shared amongst all players, so in order to be able to “inject” this code into that generic function I added the functionality to bind a function to an event that is triggered from within that generic function.
The AI is really nothing special so fortunately there’s very little chance of it ever becoming self-aware and destroying humanity. Basically when a player is set to AI mode all user input for it is disabled and it selects from a list of possible moves which it executes at a set interval. The moves are divided into long range and short range attacks which are selected at random depending on the distance of the player to the opponent. Like I said, really nothing special but in the future I would like to expand on it and have the frequency with which it executes special moves tied into a difficulty setting of some kind.
The game also uses a few awesome ImpactJS plugins made by other people:
And that’s just a little bit of insight into the techniques I used to create the game. So check it out and let me know what you think.