You’ve been waiting for it, and now I’m gonna go into detail about actions! Actions are the very core of a fighter in TUSSLE! Each tiny move your character can make is controlled by an action. Actions, in turn, control which actions are loaded and how to change when keys are pressed. The fighter object we discussed last week always has an action, even if that action is just kinda standing there. First off, we need to take a brief detour to explain what a state machine is, and how it applies to fighters.



The fighter always has an action. By default, the character is in the Neutral State. In this state, any input will produce a result. By pressing a movement key, you will then enter the Movement State, and will stay in this until you let go of the direction, or transition into Jump State or Attack State. (Or pivot, or shield, or damage, or grabbed, etc. but we’re keeping this simple for now). The important takeaway of this relation is that each state knows how to get to the other ones next to it, but don’t care about stuff that’s far away. The Movement State knows how to transition into Jump State, but doesn’t even have any idea what an Air Dodge even is.

Let’s delve into the anatomy of an action. As our example, let’s look at Hitboxie’s forward attack:

Starting at the top, we see that ForwardAttack inherits from the Action class (located in engine.action.Action). This defines the methods that this action then goes on to define. You’ll see some actions that instead inherit from baseActions.<something>, these are actions that basically work the same for everyone, such as walking, grabbing a ledge, or getting hit. Most of the functionality of these is in a library called baseActions in the engine folder. The only thing these actions tend to do is change sprites and hurtboxes accordingly and let the baseAction handle the moves.

The init function, like for every Python object, is called when the object is first created. This is where the action class sets its variables, like current frame, and length, which is given to it in the next line (this attack is 24 frames long.) SetUp is different from init in that it’s not called until this action is ready to be executed. The game might decide to pre-load an action before it’s actually ready, but these are things we don’t want to do until the action is really right at the gates. For the most part, you’ll be defining hitboxes and articles in this function. Hitboxes will be explained in more detail below.

The next (absolutely massive!) function is the update method. Update is the cornerstone of the entirety of TUSSLE! Each frame, every object is updated. The object knows what it’s doing last frame, and what new information has come in this frame, so it changes itself to what it should be doing this frame. Simple as that. On the very first frame (called frame 0 because programming), we stop our horizontal movement, and our horizontal acceleration, and change our sprite to the “fsmash” sprite (right now Hitboxie’s forward smash and forward tilt use the same sprite out of laziness, don’t tell anyone, okay?) For reference, here’s the sprite in question, annotated with frame numbers:

When it first changes, it stays on subimage zero (although, if you gave it a number after the sprite name, you could start at a different frame). All the way up until frame 14, all that changes is the subimage, every other frame (So Hitboxie renders at 30FPS, the rest of the game is 60 I swear!). On Frame 14, we add our hitbox to our owner’s (actor’s) list of active hitboxes. This means the hitbox is out into the fight and ready to hurt some people. On frame 16, we kill off the hitbox, removing it from the list of active hitboxes, and letting it eventually get deleted. It also goes up one more subimage. After that, it starts cycling subimages every other frame, until it’s last frame, at which time, it notifies its owner to politely switch back to neutral. At the end of the if statement, don’t forget to increase your frame count! (Aside: some actions actually occasionally subtract frames from this count. For example, if you want your jab to repeat while you’re holding the attack button, you could subtract enough frames to do the attack over again.)

The last method here is the stateTransitions function. It is called every frame, right before the update function. This function is where we check for buttons and change actions if necessary. For convenience, there’s tons of stateTransitions defined in baseActions. In this case, we’re loading up the Neutral State (the same one that’s called when you’re doing nothing) after frame 20. This means that, although your move has four more frames before it ends, you can do anything you could do at that time a little early to interrupt the animation. These are called IASA (Interruptable as soon as) Frames. You don’t have to have an entire state transition here, so if you were making a move that can chain into another move, you could check for the button for that in this frame, and change into it if you want.

Now that we’ve covered how actions transition you from state to state, how they change sprite animations, and how they activate their hitboxes, let’s look at what makes a hitbox actually work.

First off, DamageHitbox inherits from Hitbox. This really doesn’t add much functionality, but it allows other kinds of Hitboxes (such as windboxes, grab boxes, etc) to be able to collide with hurtboxes. The init function takes a whole buttload of data, but once that’s done, so is your hitbox! It’s ready to load up and hit people. Let’s break down the init data:

Center - the spot where the center of the hitbox is located. This is relative to the center of the owner. So, giving a center value of [20,0] (like the forward tilt above) would mean that the center of the hitbox is 20 pixels in front of Hitboxie, and 0 pixels up or down. This is in the form of [x,y], with positive x being forward, negative being backward, positive y being downward, and negative y being upward

Size - This is the size of the hitbox. It is in the form of [width,height].

Owner - the fighter that controls the hitbox.

Damage - How much percent this hitbox will do

BaseKnockback - This is the flat amount of knockback the hitbox will deal if the opponent is at zero percent.

KnockbackGrowth - This is the amount that the knockback grows by depending on how high the opponent’s percentage is

Trajectory - the direction it flings the opponent. This is always relative to the direction the owner is facing, with zero being straight forward, 90 being straight up, and so on.

Hitstun - This is a multiplier applied to the hitstun of the move (which is normally calculated by the knockback), so some moves can cause more hitstun or less.

Hitbox_id - This is a way to “group” several hitboxes together so that they can’t all hit the opponent at once (like if you want a sweet spot and a sourspot, you wouldn’t want both to hit, would you?) If two hitboxes are given the same ID, they won’t stack, and the earlier one will take precedence.

Weight Influence - A ratio of how much the opponent’s weight factors into knockback. Some moves don’t care how fat you are, they move you just the same, and others really struggle to send heavyweight flying. This number is simply multiplied with the opponent’s weight before calculating knockback.

Shield Multiplier - A ratio of how much damage this attack does to shields. Normally, this is based on percentage dealt, but if you want a move to be effective at killing shields (Like a Marth Shield Breaker), you can increase this multiplier

The rest of the hitbox is all bookkeeping and a bit too involved to deal with in this already huge Feature Friday update, so we’ll skip it for now. Basically, it tells the fighter who got hit to kindly go fling himself off in a direction.

By the way, here’s the calculation for the knockback:

p = percentage currently on the fighter

d = the damage the attack does

w = the weight of the fighter, multiplied by the weight influence

s = the knockback growth

b = base knockback

totalKB = (((((p/10) + (p*d)/20) * (200/(w+100))*1.4) + 5) * s) + b

Well, that about wraps it up for this week. It’s been a huge week in development for TUSSLE, We’re rewriting all of the horrible, awful Spaghetti Code I started with into something a little bit more robust. If you’ve been following along with the updates on our Twitter Feed of live updates to the game, you’ll see just how many new things we’ve got this week! Projectiles, a shield overhaul, a hitbox overhaul, collision detection improvements, and a working launcher! This means that you don’t need to have Python to run the game any more! That’s right, Project TUSSLE is now fully playable without needing to be a nerdy computer programmer like we are! Simply launch main.exe and the game will load up whatever you have on disk! No need to wait for us to build a new exe file, if you download any of our updates from the GitHub, you’ll be ready to play the new changes by firing up ol’ main.exe

If you have trouble running the game, please don’t hesitate to send us a bug report on GitHub, or on our subreddit. We’d love to hear your feedback, and want to address any concerns as soon as possible.

Tune in next week for more exciting episodes of Dragonball Z Project TUSSLE development! Until then, keep fighting your way!

-digi