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.
|
|