Basic structure
|
These are the things you will be manipulating the most for your character to move around on the screen the way you want, like a real person walking and jumping and chillin' and groovin'.
- Animation : the animation currently displayed by the character. A number, corresponding to the action numbers defined in the AIR file, which in turn refers to the SFF file.
Mugen code example :
Anim = 200
- StateType / Type : one letter - S, A, C or L ; U can also be used, but it rarely is. This defines your current state : Standing, in the Air, Crouching, or Lying down. U means Unchanged, but if you don't want to change the statetype, you might as well omit the line.
Mugen code example :
StateType = S
- Movetype : one letter - I, A or H. This define the action you are in : Idle (just standing there / moving around), Attacking or getting Hit - a state with a Movetype of H is usually referred to as a gethit state. If the movetype is not A, you cannot hit the opponent, regardless of anything else in your code. The movetype H (getting hit) in gethit states is important for all sorts of behavior related to getting hit. For example, the ability to receive another hit, being juggled over the ground while falling, and grabs usually rely on knowing if the target is in gethit state.
Mugen code example :
MoveType = A
- Velocity : the movement speed, on the X (horizontal) and Y (vertical) axes, so the velocity is split in two numbers - one per axis. An X velocity of 1 means that (barring friction and obstacles) the character will move by one pixel forward on each tick (1/60th of a second), so in one second, it will have moved 60 pixels forward. By keeping in mind the size of the screen (320 pixels), you can calculate how fast you want the character to move around. One thing to watch out for is that the Y axis goes downward : a positive Y velocity will make your character move downward.
Mugen code example :
Vel = 2.65,0
- Position : the position on the X and Y axes of the screen. You will often want to influence your velocity and not your position, but directly influencing the position is possible. The Y position is defined as 0 when you are on the ground (a horizontal line defined in the stage), and, like velocity, if your Y position is a negative value, it means you are above the ground.
This is how landing is done : if your current statetype is A and your Y position is 0, Mugen will automatically send your character to the landing state (which is one of the common state defined in the common1.cns file). However, past this hardcoded landing, there's no magic : if your Y position is positive for whatever reason, you will have to put it back on track with your own code, and if you put your character in a state with the Statetype set as S even though his Y position is not that of the ground line, then you will be staring at your character floating above the ground.
- YAccel : this is a velocity that is constantly added to your Y velocity whenever your Statetype is A, to reproduce the effect of gravity. As defined in one of the constants at the top of your main CNS file, it is a positive value, and this is what makes it so that anytime you are in the air (with a Type/Statetype of A), you will fall down : because even if your Y velocity is 0, on every tick, your Y velocity will be increased by the value of YAccel.
When you jump, you set the Y velocity as a negative number, meaning a negative number is added to your position on the Y axis on each tick, meaning your position is moved upward ; then, on each tick, a positive value (rather small, usually between 0.3 and 0.5) is added to your Y velocity, which eventually reaches 0 (your Y position changes more slowly, until you stop going up) and then becomes positive (you start going down).
- Friction : the same as YAccel, except it effects the X velocity, and it happens when your Statetype is S or C. This is mainly useful when you get hit : the attack defines an X velocity that will be applied for you to be pushed back, then, if you are on the ground, your X velocity will start decreasing every tick by the value of your Friction. Unlike YAccel, though, friction stops being applied once your X velocity reaches 0 : you cannot start sliding forward after being pushed backward, unlike jumping where you do start falling down after you have stopped moving up. Other than that, also mind the friction when running or dashing - mind the triggers to set the velocity constantly or not.
YAccel and Friction are constants defined at the top of the file for the whole fight, so you do not actually change them during the round. Nevertheless, they are important elements that are always there and that will influence your code. Gravity issues are what result in a couple of extremely common problems on badly coded characters : they start floating in the air thinking they're standing on the ground, or they fall through the ground and never land, or they fly up and never come down. Just keep it in mind for your first time to avoid those silly (but not rare) problems, and then they will just be something obvious that doesn't need to be given much thought.
- Physics : one letter - S, C, A, U or N. Setting the Physics parameter allows you to override the default physics automatically applied depending on your Statetype. Setting Physics to S or C applies constant friction, and setting it to A applies constant YAccel (gravity) and will also put you into the landing state under the same conditions as with having a Statetype of A. N means neither friction nor gravity is applied, and U is unchanged - for when you want to change the statetype without changing the physics in any very specific case you may think of.
Pretty often, on moves like a jumping uppercut (Dragon Punch), the physics parameter is set to N to neutralize the gravity effect (the yaccel we saw just earlier), and the Y velocity is manually modified a little later into the "going up" part. This is partly because a Dragon Punch behavior might not be the same as the regular jumping behavior (which does use physics = A and yaccel), but don't forget it requires custom landing code.
Mugen code example :
Physics = N
- Ctrl (control) : one digit - 0 or 1. 0 if you don't currently have control, 1 if you do. Strictly speaking, it's just a flag that you change whenever you want. When you're standing still, you have control ; then, when you perform a light punch, you do not have control ; and when the punch is over, you gain control again. This flag is updated by your own code, in every state you go to, you have to determine if you have control or not. This is what will allow you to say that doing this command at that moment has any effect or not, depending on whether you have control or not at that instant.
Mugen code example :
Ctrl = 1
|
The actions of the character are defined by the state it is in. Those states are defined by your code in the CNS file. By default, when the character does nothing, he is in state 0 - this is the state of the stance.
Through various actions (command input, getting hit, any sort of trigger such as time-related detection or position detection), the character goes into another state. When you press the button for light punch, the character goes into the state you associated with that button press in which you defined what his light punch is ; when you get hit, you go into the state that defines the action of getting hit ; and so on. Every action corresponds to a state - attacking, moving, getting hit, dying, or just being there. The details of the action are defined by the code of the state : the animation, the way the character moves on the screen, the various graphic effects, the sound effects, and how it can interact with the opponent - or even with himself.
The character starts in the state of the stance, then is put into another state (one way or another), and when that action is finished, he eventually returns to the standing state. This cycle goes on through the entirety of the round : the character is always in one of the states in the CNS files, and goes from one state to another state. More specifically, the character is always in one and only one state, it can't be in two states at once ; if anything happens, it's because the code in your current state said it should happen, and something that is not coded in your current state cannot happen - unless another element (like the opponent) is interacting with the character.
This is a critical and very basic part of Mugen comprehension : if something is happening to your character, it is because the code says it should happen - either the code of your character, or the code of the opponent interacting with your character. Nothing on the screen happens by magic ; if you see something happening, there has to be some code controlling it. Furthermore, something coded in a state you are not in cannot happen, unless it is in a negative state (we'll talk about that in a later section) or it is something interacting with you.
|
The statedef, or just state, is the action you are currently performing - attacking, moving, standing... It is mostly one big section with many little blocks - the state controllers which we will see in a moment. The statedef starts with the line [statedef xxxx] and ends at the next similar line. Immediately after the first line, you define the most basic elements of the current state : the animation, some velocities, the statetype, movetype, physics... Then, you can have a series of state controllers - blocks of code that can be just a few lines short or need several lines, depending on the controller. Most of the time, the last controller is a ChangeState to either move to another state or to go back to statedef 0.
Mugen code example :
;---------------------------------------------------------------------------
; Taunt
; CNS difficulty: easy
[Statedef 195] ; the beginning of this state
type = S ; this is a standing state
ctrl = 0 ; you do not have control during this action
anim = 195 ; displays animation number 195
velset = 0,0 ; you stop moving at the start of this state
movetype = I ; this is an "idle" action : you are neither attacking nor getting hit
physics = S ; the physics applied are those of a standing state
sprpriority = 2 ; is displayed over any animation with priority 1 and under priority 3
[State 195, 1] ; a random state controller
type = CtrlSet
trigger1 = Time = 40
value = 1
[State 195, 2]
type = ChangeState
trigger1 = AnimTime = 0 ; once the animation is over...
value = 0 ; ...you go back to state 0, the standing state...
ctrl = 1 ; ... and you recover control
; the next line is another [statedef XXXX]
Note the semicolons : the text after one is a comment, and will not be read by Mugen. It is only here for the reader, not for Mugen. I will be using that in this overview.
|
The state controllers (shortened to sctrls) are the most critical elements of the code, the core that defines exactly what happens on the screen. One state controller does one thing, and if you want something to happen on the screen, you will look for a state controller that does that - or you will try to use the available controllers to reproduce an effect you want. This is the part that requires a bit of imagination.
There is a state controller that changes your position. There is a state controller that changes your velocity. There is one that changes your animation. One that displays a graphic effect, one that plays a sound. One that mimicks gravity by constantly applying the YAccel value regardless of your current statetype. Several that manipulate the opponent or the various effects you have created.
The sctrl is built with the "type = " line that tells what the controller does, a variable number of "triggerXXX = " lines that determine under what conditions the controller is activated, and then a variable number of parameters that are specific to the controller in question.
A complete list of the sctrls you can use and their parameters is given in the documentation that comes with Mugen.
A typical State Controller (SCTRL) :
[State 195, 1] ; starts a new SCTRL, the numbers are not mandatory, [State x, yadda] works
type = CtrlSet ; the type, to tell what to do
trigger1 = Time = 40 ; the trigger, to tell when you want the SCTRL to be activated
value = 1 ; the parameter of the SCTRL
|
Triggers, as it says on the tin, are what makes things happen - what decide that your state controllers are activated, when they are activated, and how they interact. The very first trigger you want to know about is whether you have control or not right now ; as we saw earlier, "ctrl" has either the value 0 or the value 1.
All triggers are a label, an expression, that holds a value, and can be used in a mathematical expression : you can check if your current position on the Y axis is 0, and that will tell you if you are on the ground ; you can check if your statetype is currently equal to S, to see if you are standing.
In addition to a number of specific triggers, you can use expressions and calculations. The objective of triggers is to obtain one final value, which will be equivalent to either "true" or "false" ; when the trigger you are using is evaluated to "true", then the state controller it is in will be triggered. The expression "ctrl = 1" is "true" when ctrl is, in fact, equal to 1 -and it is false otherwise- so a SCTRL using that expression as a trigger will be activated when you do have control.
For a given state controller, it is possible to set up various combinations of triggers ; you can decide that one particular trigger always has to be observed - for example, if you want to perform the standing light punch, you ALWAYS need to be on the ground before even thinking of going into the corresponding state ; this would be a "TriggerAll". You also ALWAYS needs to be pressing the corresponding button, and that would be a second "TriggerAll". Then, you can say that you need to have control, or maybe you can perform the light punch right before another light punch ends (which will result in you chaining one light punch into another). For that, you will use a "Trigger1" to consider the case where you do have control, and then a "Trigger2" will make it possible to also perform the move if you are in the state number of the same light punch (regardless of what you used for Trigger1). Then, you might also want a second "Trigger2" (there can be as many Trigger1s and Trigger2s as you need) to say that you need to be a few frames into the previous light punch before starting the second light punch, rather than allowing it before the first has even had a chance to hit.
In that example, the TriggerAll will always have to be observed (evaluated to "true") for the sctrl to be activated, and then it will also need either all Trigger1s to be observed, OR all the Trigger2s to be observed. In proper language, this means you always need to be on the ground AND press the button, AND then you can either have control OR be in the middle of a previous punch ; but just being on the ground alone is not enough, since you don't want the punch to interrupt another action that isn't supposed to be canceled by this punch.
Expanding on that, well organized triggers serve to decide in which situations you can activate a given sctrl : one same action can be used in several situations, one same effect can be activated more than once... Properly determining what triggers you want to use is the key of making things look good. They become a habit pretty quickly, you just need to look at them by separate groups - all the Trigger1s together, then all the Trigger2s, and all the Trigger3s... And all the TriggerAlls to wrap them all.
An example of triggers :
triggerall = command = "SmashKFUpper"
triggerall = power >= 1000
triggerall = statetype != A
trigger1 = ctrl
trigger2 = hitdefattr = SC, NA, SA, HA
trigger2 = stateno != [3050,3100)
trigger2 = movecontact
trigger3 = stateno = 1310 || stateno = 1330 ; From blocking
In this example, following here are the possible situations where the SCTRL those triggers are in can be activated (in addition to the requirement of inputting the command in all cases) :
- If :
- you have over 1000 units in your power bar
- AND you are not in the air
- AND you have control
- OR
- you have over 1000 units in your power bar
- AND you are not in the air
- AND you currently have a HitDef currently active with the attributes as listed
- AND you are not in one of the statedefs listed
- AND your current attack has just made contact
- OR
- you have over 1000 units in your power bar
- AND you are not in the air
- AND you are in one the state statedefs listed
As you see, the three TriggerAlls (including the command) are listed in all cases, they are a sine qua non condition.
One last thing about triggers is that they are meant to be used as part of an expression - a mathematical expression. We've just talked about the example of ctrl = 1 evaluating to "true" when ctrl is in fact equal to 1, but expressions can be a bit more generic. To begin with, the trigger itself (i.e. just "Ctrl" or "Pos X" or "StateNo" or "Var(8)") actually represent a number - the text itself, those sets of letters are not just a word, they return a value, the value it has at the instant it is used. When you do have control, the "Ctrl" trigger "returns" 1 - this means that writing "Ctrl" is the same as writing 1, at least at the instant it is used.
By extension, it is perfectly possible to just type "Trigger1 = Ctrl" without adding " = 1" (as written in the example above), because if you have control at that moment, this will return 1, so it will essentially be read as "Trigger1 = 1". For triggers, anything that is not 0 means "True" and 0 means "False", so checking for "Trigger1 = Ctrl" when you do have control ends up meaning "Trigger1 = True". It would be the same if you had typed "Trigger1 = Ctrl = 1", as it will be 1 = 1 (which is true), so again, "trigger1 = true".
Similarly, typing "Trigger1 = !Ctrl" (where the "!" means "not") would give "Trigger1 = not(True)" which reads "False" when you do have control - meaning the sctrl it is in will not be activated. Writing the same thing when you don't have control reads "not(false)", which is "true", so the trigger "!Ctrl" returns "true" when you don't have control.
|
Commands work in two steps. First, you define a button string input, giving it a name ; and then, you can trigger various things (especially changing state to the corresponding attack/movement state) with the appropriate state controller. Both parts are done in the CMD file, with the second done more specifically in StateDef -1. More details on that in a later section.
[Command]
name = "TripleKFPalm"
command = ~D, DF, F, D, DF, F, x
time = 20
The definition of the name TripleKFPalm is attributed to the button input sequence qcf, qcf, x.
|
Variables are a very important part of Mugen, one that will allow you to manipulate your character and your effects with a lot more variety and freedom.
A variable is basically a box in which you store a number, allowing you to look at that number at a later time and maybe manipulate it with any calculation you want. You want to remember a value you used one second earlier ? Make sure you stored it in a variable. You want to make calculations that change as time pass ? Use a variable. You want to remember something you determined earlier ? Assign a number to it, and put it in a variable, then when you look at that variable later on, you will know what the number corresponds to.
In a sense, conceptually, velocity and position are variables that have a name and that tell the Mugen engine to do very specific things - even life and power, even control, can be considered as variables, a box with a number stored which can be changed. You can look at them at any time and trigger various effects depending on their value at this instant.
There are 60 variables (from 0 to 59) that can contain an Integer (a whole number), and 40 variables that can contain a Float number (a number with a decimal) - the Vars and FVars, that is, var(0) to var(59) and fvar(0) to fvar(39). Mugen also defines a couple of particular additional variables, the SysVars, which are used to calculate very specific things, such as the direction you're jumping in. It is heavily recommended to not use them, unless you know exactly what you want to do with them. They are used in the common1.cns file.
So, you have a bunch of variables - a bunch of boxes in which you can put a number. You can pick one and decide that this particular variable -maybe var(10), or var(21), or maybe var(6)- will correspond to one specific thing. You can store the state number of the last attack you used in that variable, or you can store the number of times you used a certain attack in another variable, or you can store the number of time this particular attack has hit in yet another variable. You are the one who knows what that variable means, and you are the one who knows what the number in it corresponds to ; for Mugen, it is simply a number put in a box, the meaning is yours to remember. The number you put in that variable stays there. At a later time, you can look at that variable to know what its value is, and you can use that value to trigger certain effects, or make available some new actions.
One simple example is that variables can be used for things like mode change or Groove/Ism (from CvS2 and SFZ3) : at some point, you decide that one particular variable determines your current mode. This variable is given a particular value by default - the "normal" mode. Let's say that you decide that var(5) will contain your current mode ; now, let's decide that the value "0" means normal mode, and that the value "1" means power-up mode or evil mode. In your command file, you check the current value of that variable to determine what is available to you, by using that variable as a trigger. Then, with a particular command, you may want to be able to change your current mode - switching between normal mode and evil mode, for example. You simply have to modify the value in the variable you decided would determine the mode, and put a different value, which you have decided represents that other mode. Then, in your command files, the ChangeStates that required the variable to be set to the previous value will not trigger anymore, and other ChangeStates may trigger. Similarly, in a same move, the damage or velocity when in "power up" mode can be increased compared to the "normal" mode through a variable, simply by using a different value depending on the current value of the variable you are using.
Variables can be used for a lot of things. You can store a mode in it, or you can set up a combo where you decide that certain moves in that combo can only be chained into other moves if you have or have not already used yet some other moves in the current combo. You can use variables for a timer, too - you pick a variable, you set it to a certain value at the instant it should start ; then, in Statedef -2 (we'll be going over that in a moment), you constantly decrease the value of that variable by 1 on every tick. If you set the var to 120 and decrease it every tick, the variable will reach 0 after 2 seconds. You have just created a timer that counts down 2 seconds, and you can trigger anything you want when that timer has just finished counting.
Variables can be used for anything you can think of, even in rather surprising way as long as you have a little bit of imagination - and organization. They will be useful most of the time.
[State 1100, VarReset]
type = VarSet
trigger1 = !Time ; triggers right the instant I enter the current state
var(4) = 0 ; var(4) is set to 0
[State 1100, lv3detect]
type= varset
trigger1 = !time ; at the start of the state...
trigger1 = !AILevel && !var(4) ; ... and if var(4) is 0...
trigger1 = command = "KoHou3" ; ... and if I used the command listed...
var(4) = 3 ; ... then var(4) is set to 3
[State 1100, HeavyUppercut]
type = ChangeAnim
triggerall = !Time
trigger1 = Var(4) = 3
value = 1102
In this example, I initialize var(4) to 0 at the start of the state. Then, depending on the command I pressed, I change the value of the variable, also at the start of the state. And finally, at a later point in the action, I change the animation depending on the value of the variable - this mean that the animation changes depending on the command I pressed.
Last thing of interest, all variables from 0 to 59 (and float variables from 0 to 39) exist by default, and their default value is 0. If you have never modified a variable, it's there anyway, and its value is 0 until you change it ; you don't have to create the variables or delete it once you're done with it.
To note, later versions of Mugen to come will introduce named variables (you give them a name of your choice instead of calling them by their number), but this isn't the case as of the time this text is being typed.
|
Animation is self-explanatory. First, you define the animation (action) number. You give the group and image number of a sprite in the SFF, you give an axis (X and Y) offset, and you say for how many ticks it must be displayed. You can also specify transparency options. Next line means next sprite. Next action number means next animation. Example below.
Collision boxes are the important part of the game as a fight - what allows the characters to ram their boot up each other's ass. There are two types of collision (clsn) boxes : the attack boxes (clsn1, displayed in red) and the hit boxes, the boxes that say where you can be hit (clsn2, displayed in blue). Basically, if a red box of one character touches a blue box of the other character, an ass gets kicked.
Those clsn boxes are defined in the AIR file, putting the coordinates of the box before the sprite it will be applied to. There can be several boxes on a single sprite - and there will be, most of the time. There can be several clsn2s, there can be several clsn1s, there can be both, there can be none. If there is no clsn2 box on a frame, your character cannot be hit on that frame. If there is no clsn1, it cannot hit.
Clsn boxes are better made simple. Most of the time, you will only need maybe three clsn2 boxes on a humanoid character - the head, the body, maybe the legs if they are spread apart, and maybe the arms if they are spread. That is a commonly observed standard that was set by the SNK games - those where it was rather simple to display the collision boxes actually used by the game through dipswitches (debug settings hardcoded in the game for arcade machines). Now, tools can be made to extract the boxes from other games, such as Capcom games or other games like BlazBlue. Watch out, though, because some games have really, really WEIRD collision boxes (BlazBlue is a horror show) or just way too many. Overdoing the number of boxes serves absolutely no purpose at all. Most of the time you only need between one and four clsn2 boxes, and one to three clsn1 boxes.
[Begin Action 200]
Clsn2: 2 ; There will be two Clsn2 boxes on that frame
Clsn2[0] = -24, -88, 22, -1 ; the first, with the top left corner and bottom right corner
Clsn2[1] = -8, -103, 10, -84 ; and the second
200,0, 0,0, 2 ; for that frame : group number, image number, X and Y axis, number of ticks
Clsn1: 1 ; There will be one Clsn1 box on the upcoming frame
Clsn1[0] = 16, -90, 61, -74 ; the first
Clsn2: 3 ; There will be three Clsn2 boxes on that frame
Clsn2[0] = -24, -88, 22, -1
Clsn2[1] = -3, -103, 15, -84
Clsn2[2] = 18, -88, 59, -76
200,1, 0,0, 2 ; the above four boxes are for that frame
The first two frames of an action, with both Clsn1 and Clsn2 boxes.
There are some different ways to build your clsn boxes, ways that will affect the fairness of your character (having no clsn2 box on an attacking limb means that attack has virtually an infinite priority, as it can hit but can't be hit), ways that will affect the gameplay system (should you or should you not be able to hit your opponent by poking at his giant pole that sticks out over five meters in front of him ?) but this is a discussion that touches more than learning the tools to code, and also a discussion that will greatly change depending on what you want to do.
|
|