Character Pipeline 6: Visual Coherence

This week I’d like to talk about how to design iconic characters using the concept of coherence. A coherent design is one in which all components work together to convey a single idea. Here are a few extremely coherent designs:

The aspects that make these designs coherent can be summed up in the following categories using these rules I made up:

1. Color

Game characters should have a single dominant or ‘key’ color, unless looking messy is important to their theme; even then it’s a bold move. Kratos has blood-red, Snake has subtle blue, Bayonetta has raven-black, etc. A lighter or darker version of the key color can be used as a minor color in order to produce depth. Depth in this sense is important because it adds complexity to the character without causing distraction. The palette can include more colors, but the entire design shouldn’t incorporate more than three, and the non-key colors should yield to the key color by being either less prevalent (like the maroon and gold on Bayonetta) or more neutral (like the white on Kratos).

2. Repetition

Shapes and colors need to be repeated in the design, or else they will look messy/unintentional. In the above examples you can see the repetition of the onion shape in the knight’s armor, and in the repeated gold pattern on Kratos’ waist cloth and his swords. The only exception is when a single piece is meant to be an iconic feature and a focal point, and there should only be one of these per character (the shape of bayonetta’s hair and Snake’s bandana, the chains on Kratos’ wrists). Normally, 3 a good number of times to repeat a non-focal design element.

3. Theming

As you can see from the characters mentioned, the dominant color can also be suggestive of a character’s personality and background. Conveying these is the most important part of establishing coherence in a character’s design, and the act of doing so is called theming. In order to have good theming, you should make sure that your character’s design says something about where they came from and where they fit in the universe. Bayonetta is a witch, so her clothes, accessories, and hair are evocative of the occult and the strange.  She is also meant to be strong and independent, so many of her design aspects are iconic of female dominance (note the librarian glasses and stiletto heels.

As a practical example, I’ll show some changes I made to the Joker in the process of finalizing his model and texture:

The first major alteration is that I changed his hands from exposed green skin to purple gloves. The use of a glove is important for theming, as none the characters in this world have flesh – they are magically animated playing cards. The purple color also goes a long way to enforce purple as the dominant hue in the design.

The second change was to add detail and color variance to the horns. The detail was important for theming, because the horns are meant to be demonic in addition to suggesting the role of a jester/joker. In the first model, the demonic aspect was underplayed and the form was just confusing. The color variance was important for producing depth.

That’s about the end of my rant on coherence. Hope you learned something!

Posted in Art, Character Art, Character Design, Design | Leave a comment

PBuffer and Post-Processes

One neat concept I learned about while researching deferred rendering was the PBuffer. The PBuffer is used for post-process effects and contains at least two screen-sized render targets that are swapped between each other while rendering each post-process effect sequentially. The final image from one effect is used as input for the next, creating a daisy chain of accumulating effects. To expand the number of possible effects the PBuffer can support, half and quarter-sized buffers can be used to scale down the previously rendered effect and used to support other effects (e.g. bloom).

For Card Kingdom, the following PBuffer serialization is used:

<ZeroPoint::Rendering::PBuffer>
  <Effects>
    <Effect>
      <ZeroPoint::Rendering::PBufferEffect
        index="0"
        render-half-quarter="false"
        shader="pbufferLightingEffect" />
    </Effect>
    <Effect>
      <ZeroPoint::Rendering::PBufferEffect
        index="10"
        render-half-quarter="false"
        shader="pbufferEdgeEffect" />
    </Effect>
    <Effect>
      <ZeroPoint::Rendering::PBufferEffect
        index="20"
        render-half-quarter="false"
        shader="pbufferDepthOfFieldEffect" />
    </Effect>
    <Effect>
      <ZeroPoint::Rendering::PBufferEffect
        index="100"
        render-half-quarter="false"
        shader="pbufferFXAAEffect" />
    </Effect>
  </Effects>
</ZeroPoint::Rendering::PBuffer>

For this implementation, index is used to order the effects easily, render-half-quarter is used to tell the PBuffer whether or not to render to the half and quarter-sized buffers, and shader defines what post-process effect to use. With this setup, it is quite easy to add, remove, replace, and reorder post-process effects without having to recompile the entire project.

The first effect, pbufferLightingEffect, combines the diffuse, specular, and lighting buffers together to give a base for all the effects, so it has be the first one. The next effect, pbufferEdgeEffect, uses the information from the edge detection pass to render an outline where an edge was found. Next, pbufferDepthOfFieldEffect uses the depth buffer and the previous rendered image to blur pixels that are out of focus (i.e. too far or too close to the camera). The last effect, pbufferFXAAEffect, is a full-screen anti-aliasing pass that uses the fast approximate anti-aliasing method. Because it’s an anti-aliasing pass, it has to be the last effect.

Here are each stage of the post-process effects separated:

Lighting only.

Lighting and Edges.

Lighting, Edges, and Depth of Field.

Lighting, Edges, Depth of Field, and FXAA.

As you can see, each effect accumulates to the final image. FXAA softens the edges from the depth of field, which blurs the edges from the edge detection pass and the lighting, diffuse, and specular combination. If the edge effect was swapped with the depth of field effect, edges would be rendered on top of the blurred image, giving all edges a sharper look no matter how far from the camera they were. This effect order renders as such:

Lighting, Depth of Field, Edge, and FXAA.

Although this looks nice, it is not as desirable as the original order because the edges on out of focus objects are the same as in focus objects, losing a lot of the depth of field effect. This is noticeable when comparing the last two example images.

Posted in Coding, DirectX 11, Engine, Graphics | Leave a comment

Controlling HTML Without A Keyboard or Mouse

Since the beginning of the Card Kingdom, we’ve been using XBox controllers as the main sources of input for the game. The controllers afford us preexisting control schemes, analog movement, and support for multiple players at once. What it does not support is a way to interact with HTML in a standard, keyboard and mouse way. To support this, I’ve been working on a UI Paneling System, written in jQuery, that does not rely on a keyboard or mouse for interaction, while still providing a robust framework on which a user interface can be built. The system is structured as the following:

  • The UI Container is the root for all panels. It handles what panel is being shown, when to transition to the next one, and dispatches input events down to the active panel.
  • A UI Panel is a single frame of the UI. It contains all the UI elements that should be displayed when shown. Custom show and hide animations can be set for the panel as well.
  • A UI Element Group is the root for all UI elements. It handles which element is active, dispatching input events to the active element, and can cycle through the elements using defined buttons. Wrapping around to the beginning or end of the list of elements is also supported.
  • A UI Element is a general container for actual UI controls and supports custom events for being selected and deselected.
  • A UI Slider is a control that acts much like a slider bar. It supports a minimum, maximum, and step values. The current value of the slider can be increased or decreased depending on defined controls.
  • A UI Toggle is a control that acts much like a check box. It supports being checked and unchecked with a defined button. This control can also be used as a button by disregarding whether or not it’s checked in the toggle event handler.
  • A UI Select is a control that acts much like a select list. It supports custom data that can be cycled through and selected with defined buttons. Wrapping of element selection is also supported.

Some other features of the system include:

  • Support for custom input handling at each container level (panel, element group, element, slider, toggle, select) that can be different than the normal process.
  • Stack-based panel transitions for “forward” and “backward” panel transitions
  • Custom enter and exit animations for both forward and backward panel transitions, as well as a hooks for when the transitions are complete.
  • UI Slider, Toggle, and Select have no predefined rendering methods, making each  fully and easily customizable.

The entire purpose of this system was to eliminate the need for a keyboard and mouse. In order to test this properly, I made a virtual XBox controller to simulate button presses that the system reads and responds to. The virtual controller and real controller, when hooked up to the engine, use the same function to send input events into the system, leading to a seamless transition from testing in the browser to playing in-engine.

Here is an example of the first pass of the main menu for the game:

For the main menu, when an element is active it slides over to the left, when inactive it slides back. This uses the UI Element’s onSelected and onDeselected hooks to animate the element. UI Toggles are used as buttons so when an element is selected, it transitions to a new panel. On the credits panel pressing any face button will return to the main menu, even though there are no controls on that panel. This is done with a custom input handler on the panel itself. The code for that looks like this:

$('#credits-screen').uiPanel({
	onButtonPress: function (button) {
		switch (button) {
			case Buttons.BUTTON_A:
			case Buttons.BUTTON_B:
			case Buttons.BUTTON_X:
			case Buttons.BUTTON_Y:
			case Buttons.BUTTON_BACK:
			case Buttons.BUTTON_START:
				this
				.data('container')
				.trigger('uiBack');
				break;
		}
	}
});

Overall, this was a very strange task to think about and work on: a user interface inside of a user interface. It seemed daunting at first to completely bypass the keyboard and mouse in HTML, but it works, and it works well. I am really quite happy with the results.

Posted in Coding, UI | Leave a comment

Gameplay Updates: Power-Ups, Juggernaut, Joker Cards, and … WHIRLWIND

It’s been some time since I last posted, so this post will detail all of the new gameplay features I put in during the last couple of weeks. We are coming close to our polish phase and we listed out several gameplay features that we wanted to see before then, so that we would have enough time to tune them. Thanks to a good engine design, these gameplay features were very quick to implement. Let’s get started.

Power-Ups

First off, we have power-ups. In addition to dropping coins, enemies, crates, and other objects have a chance to drop either a Heart, Diamond, Club, or Spade power-up. Each power-up affords the player something, whether it is an advantage in combat or a boost in health to keep him in the fray. These power-ups are described below:

  1. Heart: heals the player a small amount.
  2. Diamond: provides a shield that mitigates damage for a short duration. This power-up can stack.
  3. Club: provides a multiplier to damage for a short duration. This power-up can stack.
  4. Spade: grants the player a small amount of energy. Energy is used towards the player’s special attack, Whirlwind. (More on Whirlwind below)

Power-Ups
For the design of the power-ups, we used card suits, obviously. Using the suits was appropriate in that it supported the theme of the game. But they pose an interesting problem because, with the exception of the heart, the symbols are not representative of the advantages they grant. Nobody will be able to link the club with granting a damage multiplier, unless they saw it a few times and made the connection then. So, power-ups are under review by the design team.

Juggernaut

One thing we sought for our beta build was a bigger and meaner enemy. Unfortunately, we cut him for that build due to time constraints. But, we have him now. Meet the Juggernaut:

The Juggernaut is supposed to be a very intimidating enemy, and, from his size alone, that trait is clearly defined. His functionality is also a bit more complex as opposed to our other enemy designs. Rather than a single attack, the Juggernaut has three different attacks, each triggered once a certain attack range is hit. At the closest range, the Juggernaut performs a shockwave attack where he slams his shield to the ground. This attack knocks others away in addition to being quite powerful. The second attack is the Juggernaut’s most basic, the smash. With this attack, he swings his mace overhead, slamming it to the ground. Finally, the Juggernaut charges when his targets are too far away, inflicting massive damage.
Juggernaut Attacks
Quite a departure from our other enemies, but he was designed this way for a reason. Players are encouraged to find the “sweet spot” and remain there, beating him down until he is slain. That sweet spot is the smash range. Although encouraged, it is quite dangerous to be there, as the smash is quite powerful. If the player gets too close, the Juggernaut will perform the AoE shockwave, knocking the players into charge range, in turn triggering that attack. With the intricate design of these attacks, and how they relate to each other, the Juggernaut becomes an even bigger threat than we initially thought. How easily can you take him down?

Joker Cards

For our boss fight, the Joker, we will have several Joker Cards descend from the sky. Essentially, the Joker will utilize these Joker Cards for his power. The players are tasked with destroying these cards in order to weaken him. After a short duration, the cards will respawn from the skies and descend downward. (I am not going into too much detail on the mechanics of the Joker fight, because that is Jeff’s territory, but I’d like to show the effect we’re going for when the Joker Cards descend):

Whirlwind

Finally, the Whirlwind attack. Once the player gains enough energy, a resource collected via killing enemies, picking up the Spade power-up, and performing long combo chains, the Whirlwind special ability becomes available. While activated, the player will be able to walk the battlefield, cutting any and all enemies down (even the Juggernaut!). The attack also utilizes several trails, each offset at different locations with different sizes to completely sell the effect.

The Whirlwind wreaks havoc on the battlefield and leaves nothing but carnage behind. No enemy stands a chance to this devastating attack. This attack is only available once the player’s energy is full and it lasts a certain amount of time. Players should use the attack wisely, saving it for those “oh no” moments, or just activate it on a lone, unsuspecting goon and witness its awesome power…

I hope everyone has enjoyed this post and that all aforementioned features meet their expectations. Until next time, this is Gameplay signing off…

Posted in AI, Coding, Design, DirectX 11, Engine, Gameplay, Graphics | Leave a comment

Character Pipeline 5: UV Mapping for Artists

Left: happy UVs; Right: sad UVs

In a previous post I’ve detailed what makes a UV map good. Now I’m going to actually show you how to make a good UV map through proper use of symmetry, uniformity, and logical seam placement. Here is my workflow :

1. Know what things will repeat or have symmetry beforehand! If a face is symmetrical, delete one identical half before making you UVs. Then when you mirror the mesh to complete the face, the UVs for the left and right half of the face will share the same UV space. This will save valuable texture real estate and increase the fidelity of your model. Repeated elements (i.e. fingers) should share UV space as well, no element should need to show up on the texture twice.

This character has a lot of symmetry, so parts had to be deleted before mapping

2. Start with an automatic map. Select the whole model you intend to texture and go to Create UVs > Automatic Mapping. This will give you a starting point, and most importantly it will lay out all of the UVs you have not mapped so that you’ll know if you missed any.

3. Use planar mapping for everything. Select a set of faces that roughly share a plane and use the “Best Plane” option under Create UVs > Planar Mapping, then project. In the attribute editor for the projection you just created, set the projection width and height to 10. This way you are basically flattening out your model’s skin to make it easy to paint on, and you are scaling them all by the same factor so that each part will be correctly sized in relation to the other parts.

It is ok to use the cylindrical mapping tool for cylindrical elements (like fingers), just make sure that you keep the scale uniform and don’t make any unnecessary seams.

note: I typically place the UV’s I’ve projected in the 1, -1 (lower right) quadrant while working on them, so that I know that anything in that quadrant is done and anything in the 1, 1 (upper right) quadrant is not. If you do this, make sure that you move everything to the 1, 1 quadrant when you’re done or you might get errors.

I projected faces on this section of the foot based on how well I though I could paint them from that angle

3. Move and sew edges of UV shells where you don’t want to have seams. The most important idea in this step is that you want to group together all of the UVs that share a material if possible. This way you can more easily paint the object in 2D and you don’t end up with any awkward seams where there should be none.

connecting two UV shells using 'move and sew UVs'

4. Make it fit as tightly as possible. Now that we have all of our UV shells sewn together and uniformly scaled, we need to fit them into the UV square efficiently.  You can do this by moving, rotating, and mirroring your shells (scaling by -1 in the x or y), as well as by uniformly scaling all of the shells if you find that there is not enough (or if there is too much) space.

note: It is ok to scale some elements down further than the rest if you know that they either won’t be seen or won’t need any detail other than a flat color.

The bottom of the character's foot is almost never seen, so I can afford to scale down its UV shell

If you follow these steps, you should end up with a very efficient, paint-friendly UV map. Keep in mind there is no fast or easy way to lay out UVs for a complex low-poly model, but if you follow these steps, at least you’ll do it right.

Stay tuned for next week’s post, where I’ll talk about my texturing workflow.

 

Posted in 3D Modeling, Art, Character Art, Maya | Leave a comment

Tool Time – Interactive Wave Editor and Lessons Learned

Interactive Wave Editor

As the project nears completion, this will be the last Tool Time post, but I’m ending with a bang. A large part of Card Kingdom is its waves and their design. They are our main mechanic to convey progression and are used to teach the player how to play the game. Therefore, the design of these waves are incredibly important. Before how we were designing waves was on a whiteboard. We used different symbols representing each object type, labels for when and where objects would spawn, and tried to convey how the wave should flow through hand-waving and notes. We would then convert all that to fit in the XML Serialization of the wave, not really knowing exactly if the wave would work or the placement of objects were correct. This took time and a lot of guessing on the part of the designers, and was just an unpleasant experience all around.

The need for a tool to aid in the process of creating, tuning, and visually seeing what is happening in a wave was needed. Enter the Interactive Wave Editor. This tool lets designers create waves with a few mouse clicks and key presses. When complete, the wave can be exported to the proper XML Serialization format with a click of the button. The wave can also be “played,” as in it steps through time, displaying where and when a spawn occurs. Having the ability to “play” a wave will help in the tuning of the wave out of the engine. Without this feature, a wave would have to be run in the engine where the setup time is actually quite long. Loading and constructing all the objects, meshes, textures, and other assets, let alone have to play the wave in order to see if the timing and placement was correct, takes valuable time away from the designers.

The hours it took to build this tool will save countless more with its use.

Here’s an example wave built in the editor:

It’s really not that pretty to look at, but all the functionality is there. I could spend the time and make it pretty, but as with nature of my position on the team, I have other tasks that need to be done. If I had the rest of the project to work on this, it would be beautiful and have more time-saving features, such as an import, but as it stands now, I am very pleased with the results.

Some of the features the wave editor supports:

  • An interactive map that shows spawn locations and ranges
  • Dynamic cache definitions
  • Dynamic position creation and deletion
  • All the types of wave objects currently in use in the game with live updating links to caches and positions
  • “Playback” functionality to step through the wave
  • Export and Save properly formatted XML
  • Define multiple wave events with different parameters for each

You can try the wave editor here. If you come up with a cool wave, post it in the comments and maybe we’ll put it in the game. (Please note that this is an internal tool and will not be supported in the future. I also make no promises that any wave created will go in the final game.)

Lessons Learned

Seeing as this is the last Tool Time post, I will wrap up with some things I’ve learned while making tools for Card Kingdom.

You have to be ready to through out everything and/or have your code never be seen by anyone but yourself. Some programmers cannot get past this. They think every line they write is gold, infallible, and must be in the final production release of the product. As a tools programmer, your work is visible in the final product, it’s just not the line of code that detects when a sword strikes an object; it’s the line that helped the other developers tweak and refine that collision easily and quickly.

Spend the time now to save more in the future. This is probably the main reason tools programmers exist. A great example of this is the interactive wave editor. Before, each refinement of a wave would take, lets say, a minute for each change. If there are 100 changes that need to be made, that’s 100 minutes wasted. Multiply that by how ever many waves are developed and what seemed like a simple task has now taken up countless hours of someone’s time. The dozen or so hours it took to create the wave editor will save multitudes of hours as each tweak can be done and visually shown in seconds.

Functionality beats ascetics every time. This is not to say that a poor user experience is acceptable, but if you’re spending more time making it look pretty than functional, you’re doing it wrong. Functionality is king for a tool, next is ease of use. Marking options clearly with proper and understandable verbiage, having intuitive, natural controls, and providing a tutorial or “how to” section helps everyone involved, but the functionality needs to be there to begin with.

Mirror existing processes/methods, don’t create your own. A tool is supposed to make someones life easier by simplifying common and repeated tasks. Building off these tasks will make the tool easier to grasp by users, and it gives the programmer a solid set of requirements to build from. It falls in the “don’t change what isn’t broken” mentality. While developing the editor mode for the engine, I tried to mirror the free-look camera controls as closely to Maya’s controls as possible. Users that already have experience with Maya would not have to learn a new control scheme just for the engine. This made moving between the two applications seamless and gave me a solid base from which to test while developing.

Posted in Coding, Design, UI | Leave a comment

The Combat Corner – Hero 2.0, Iterating on Player Abilities, Part 2

In this part of our discussion of Hero 2.0, I’ll be going over, in great detail, the changes we made to the player abilities and why.

Designing anything is a process. This is a common theme in a lot of my posts but I can’t stress it enough. It’s been true with everything I’ve worked on and Card Kingdom is certainly no exception. When we started the enormous task of iterating on our attack system, we had to take baby steps since we knew many of our decisions would build off of each other. To do justice to the iterative nature of our development and give you some insight into our thought processes, I’ll chronologically discuss the changes we made from our Alpha build to our Beta (showed at GDC).

This graph shows our key points of iteration over time. The time in between sections was spent playtesting and polishing.

Direct and Area Attacks

In Alpha, we had two types of grounded attacks: Normal and Area attacks. Normal attacks had a forward conic collision as well as a bit of forward translation. Area attacks had radial collision, a wider range, no forward translation, and a knockdown effect on enemies. The idea was that a player would use Normals as their main attack and Area attacks as a crowd control tool to limit the amount of enemies they had to deal with and to create engagement opportunities. This ideal worked out generally but there were some major problems that were causing frustration in some players affecting the flow of combat.

Since the Hero could only face one of two directions but could still hit enemies at different depths, it was very possible for a player to engage enemies and end up passing them due to forward attack translation. Technically, players could use the Area attack to damage the enemies in that particular circumstance, but that resulted in the flow of combat being interrupted since Area attacks also knocked down enemies. To mitigate the flow-interruption problem and attempt to better accommodate player intent, we added more attacks to the Area attack combo sequence, removed their knockdown property, and more explicitly strengthened the distinction between Area and “Direct” (formerly known as “Normal”) attacks. This change allowed players to direct forward assaults toward enemy groups and use Area attacks to deal further damage while maintaining an appropriate range.

Combo Graph 2.0

Added capability yields added complexity, which, in turn, breeds potential ambiguity in regards to identifying player intent. Prior to the addition of Area attacks, the attack system only had to allow for the two attack combo sequences to be performed linearly; that is, we never had to consider a combo-ing into a Direct attack from an Area attack since the latter basically ended any combo string (due to the knockdown effect). Since we now had additional and more useful Area attacks, players would be more encouraged to use them and we would need to accommodate. So we needed to update the Combo Graph.

In Computer Science, there exists the concept of a graph as a model of representation for a collection of objects with pairwise relationships. Apropos to a combat system, a “combo” (subsequently linked attacks that are triggered without interruption) can be considered as a graph (or, more specifically, a Directed Acyclic Graph) so I like to organize our combo representation as such. This is what our first Combo Graph looked like back in Alpha:

Humble beginnings...

As illustrated above, combo-ing into an Area attack at any point would always end your chain. So, when we added more Area attacks, it forced us to think more meaningfully about the connections between the two combo tracks as well as the purpose of each attack on the two tracks. We began to establish more of a ‘rhythm’ with each track. Each attack’s damage, animation length and immediacy were tuned to fit with the pacing of the track. While each track’s attacks were designed independently, they were designed with a similar rhythm such that we could blend between the two tracks seamlessly and appropriately. Our next iteration looked something like this:

Closer, but still not quite right...

These connections reflected player intent much more accurately. A player who was deeply committed to a direct assault that suddenly had to switch into using attacks with more coverage would be sequenced into an Area attack of greater influence (as opposed to starting from the beginning of the track with a lighter attack).

Dashing

In addition to our Hero’s ground capabilities, we also had Jump and Jump Attack implemented in our Alpha build. For navigation, Jump served two simple purposes: to provide the Hero with a burst of speed for quickly moving around the map and an option for dodging attacks or threats. While these navigational utilities turned out to be quite useful and justified, the airborne aspect of jumping was never really utilized, as we had no airborne targets or grounded threats that could be jumped over.

Jump Attack was a bit of a different story. From day one, Jump Attack felt awesome. It was fast, powerful and felt badass. Players understood Jump Attack since, conceptually, it was just a natural combination of two simple and core abilities, jumping and attacking. Unfortunately, it suffered the same problem as Jump in that it served no airborne purpose. In fact, the attack itself was inherently grounded as it caused the Hero to burst forward toward the ground and create a powerful impact. So, while the attack itself was fun to use, there was essentially an extraneous step to using it as players had to jump before being able to execute the attack. Additionally, after we removed knockdown-type attacks, Jump Attack didn’t really offer any unique tactical advantages. As a result, we cut Jumping entirely and decided to try something new in its stead.

Enter the Dash ability. Dash is a ground-based burst of speed that allows the Hero to ‘pass through’ (ignore collision) enemies and also acts as an attack. It shares Jump’s execution flexibility as players are allowed to cancel attacks into Dash at nearly anytime so it is almost always a very safe avoidance option. Additionally, since players are not locked into an airborne state, many of their options are open again almost immediately, which allows for combo extension and rapid target changes. Being able to pass through enemies also greatly increased Dash’s avoidance as it can effectively remove players from most combat situations.

360 Heading Control

One of the biggest complaints we got about our Alpha build was that the game felt too slow. From the very first time it was brought up, we knew that simply changing the movement speed would not solve this problem but even with the addition of dashing and tuning for increased agility (movement speed, attack translations, range, cancel timings, animations), the pace of the game still didn’t feel right.

Some more critical playtesting revealed the real problem: basically, moving left or right was way faster and easier than moving up or down. Since players could move in any direction but could only face left or right, all the movement influences – attack translations, knockbacks, and dashing – were only applied horizontally which, comparatively, made vertical navigation seem much less effective (note: “vertical” actually refers to movement on the Z-axis since. The Y-axis is mostly irrelevant).

This wasn’t as simply solved as just allowing for more vertical movement influences, however. It seemed that there was inherent dissonance in our offering of analog movement with digital heading. So long as players could move in any direction but only move faster in some, there would be disparity between what the controls allowed and player intent. Ultimately, this concept of preferred axes made us call into question whether this two-way character heading system was appropriate for our game.

Horizontal traversal was much faster than vertical. Players could cover more ground horizontally in the same amount of time.

In an attempt to remain true to the “old school beat-em-up” feel, we started off with a locked, binary character heading system. Given that our characters are flat playing cards, doing so also ensured maximum character visibility, as they would always be seen from the best possible angle. As discussed, this movement model heavily imposes constraints on players; however, it is still a model that is commonly employed by games in this genre for a good reason: it simplifies combat as players only need to align their character with targets to successfully land attacks. But this simplification comes as a cost. Here were some of the large problems we found with this movement model:

  • Depth Perception
    • It is difficult for players to determine whether an attack will hit at different depths (we actually mitigated this by showing some feedback when enemies were in range).
  • Alignment
    • Players have to align themselves with enemies before attacking. While this is perfectly easy to understand and execute, it’s another step removed from players being able to express their tactical intent.
  • Collinear Targets
    • This is really a culmination of the last two problems. When players are nearby targets, horizontally aligned but at different depths (i.e., collinear about the Z-axis), combat becomes rather awkward, as players have to re-align themselves to be facing the target.

So, we removed the lock and all characters could now face in the direction they moved. Initially, I was afraid to even try this out since it was 1) not how most old school beat-em-ups functioned (there’s that “appeal to tradition” fallacy sneaking up on me again) and 2) opened up the potential to see the card-based characters from their thinnest angle. But, since the change was so trivial in terms of implementation, we tried it anyway and it turned out to work fantastically! As soon as anyone tried it out, there was no going back. It was hard to even imagine the game working any other way.

  • Intuitive Controls due to natural mapping
  • More direct confrontations with enemies
  • More intuitive target picking
  • More agility. In close ranges, players could use their attacks to close distance

Players could now direct their attacks in any direction which, in turn, resulted in much more expressive gameplay and allowed player intent to come through much more clearly.

Attack Differentiation

After doing some external testing with our new combat systems and tweaks in place, we found we were running into a new problem: players were having trouble seeing the difference between the two types of attacks. We were not effectively communicating the unique affordances of each attack. Considering our audience, this problem should have been expected, as our attack affordances were very subtle (speed, area coverage, hit stun, mobility, damage).

To address this problem, we decided to attach the additional and ancillary property of “cutting direction” to attacks. The hope was that, by explicitly communicating a superficial differentiation, players would become more observant and look for other, more subtle differences. As such, we associated an attack’s cutting direction with a specific death animation (e.g., a kill from a vertical attack would slice the enemy in half vertically) so that their aesthetic presence would be first recognized and would, perhaps, encourage more experimentation.

Additionally, we tuned the two types of attacks to feel and behave more like “light” and “heavy” attacks. Vertical attacks were “heavy” since they were more damaging, slower, and interrupted enemy attacks. Horizontal attacks were “light” as they were quick and safe, did not do as much damage and did not interrupt enemy attacks (instead, they simply slowed down enemy attack animations). Even more explicitly, there are some game elements that require the player to use heavy attacks such as enemies with metal shields and metal, destructible crates.

At this point, our attack affordances can be described as such:

  • X Button Attacks
    • Light damage
    • Quick recovery
    • Horizontal cutting direction
    • Wide area coverage
  • Y Button Attacks
    • Heavy damage
    • Slow recovery
    • Vertical cutting direction
    • Narrow area coverage
    • Breaks metal objects

Combo Graph 3.0

Players were catching onto to differences between attacks so, now, it was time to update our combo graph again to reflect new behavioral findings. We often found using light attacks to soak in damage up until the last second and dash-cancelling to avoid damage. We also saw players starting off engaging enemies with heavy attack but later canceling into light attacks when enemies later surrounded them. To accommodate these common use cases, we updated the combo graph.

Sometimes, even the smallest changes can make a big impact

The biggest change here was that the light attack sequence was now shorter but much quicker (because of the short recovery period of “Horizontal 2”) and the third horizontal attack, the one with the most area coverage and longest recovery period, could only be used if cancelled into from the heavy attack sequence. This change was most often more properly associated with player intent.

Concluding Lesson

Iterating on the player abilities is a long and often never-ending process. Adaptive designers need to be ready to observe player tendencies, extrapolate misconstrued intent, and tune mechanics and abilities accordingly. What is most important to remember is that, since this is a process, things decided on and implemented earlier on in the process are likely to be proven wrong later. Designers must look critically at all systems and be careful not to take anything for granted or forget about things that have stuck around for a while.

Good designers are diligent, humble, and ready to kill babies.

Thanks for reading. Until next time…

————

Claude Jerome

Posted in Design | 1 Comment

Designer Den: Player Personalities

Last time we talked about creating a simple and natural control scheme and the usability of those controls. This time we will talk about our target demographic and types of players in it.

Target demographic means to us is a gender and age group of players that would want to play Card Kingdom.

We choose males as are gender target because it was easier for us to place our self’s in the player mind set being male.

We understand that male want to have a level of mastery and completion to prove they’re the best.  Males tend to like destroying things and leaning by trial and error.

We then targeted age’s 10-13 preteens with 7-9 kids in mind creating a game for the older brother that the younger brother could play. The reason for 7-9 age groups this is the youngest kids can start to solve hard problems and read. 10-13 is boys become very passionate about their interest.

The mix of the two ages covers males of any age Teens, Young Adults, and 20’s or 30’s just bigger kids.

Next we created a psychographic profile for types of players based on what motivates them. Here are some examples with names so when we talk about them we can remember who they are and what they do.

Tactical Tony

Combat complexity is the draw for Tactical Tony and figuring out game at an expert level. The quality of his choices should be the limiting factor between success and failure. Tactical Tony is clear and precise thinker who prefers freedom of thought and action.

He thinks through tough battle situations to out maneuver and outsmart enemies. He is naturally adept at the controls and knows how to use them correctly. Tactical Tony likes to find his enemies weak points and positions himself to maxims damage in the face of challenge.

 

Tactical Tony wants to use his tools of battle in an illogical manner without unexpected constraints. When he has found the pattern in game play he is having the most fun.

Skillful Sean

The challenge of victory against overwhelming odds is the draw for Skillful Sean and he also wants to improve his abilities as a player and emerge victorious over friend or foe. Skillful Sean is an enthusiastic individual who enjoys being in the spotlight.

He triumphs over his adversaries with long optimal combo strings, dashing at the right time, and expert breaker use. He likes to be in continues motion on the battlefield using his dash to connect his attacks from enemy to enemy.

 

Skillful Sean wants his victories to push him to his limits barely surviving with fast reaction control. He enjoys mastering the game performing at the best of his ability to insure brave and bold victory.

 

Masher Matt

The thrill of cutting down enemies and dominating the battle field is the hook for Masher Matt. He delights in the ease of mindless play. The feeling of power and control of the action hero keeps him going.

He rapidly presses one button at a time expecting little to no resistance in his actions. He doesn’t like thinking about what he is doing be rather enjoys seeing amusing actions come from his avatar as it dancing around the battle field.

Masher Matt wants repetitive worry free gameplay that appeal to his deploying imagination. He avoids anything that might break his immersion.

Most players are hybrids and do not fit into one. These are names we give to our plyers  motivations not their format of play

Posted in Design | Leave a comment

Character Pipeline 4: Advanced Animation Workflow Part 2

This week I continue where I left off with more important best-practices for 3D character animation. Class is in session, so prepare to be schooled:

Rule # 5. Work in small files

Don’t make all of your animations in the same file. Video game animations are subject to extreme amounts of iteration, and if you have to change the way the character throws a grenade, and later on in the sequence you have a bunch of other animations, then you have to shift the entire sequence down to accommodate for any length discrepancy that ensues. Worse, it is impossible to keep multiple versions of each action on hand if you are continuously working from the same giant file.

Below you can see the animation files I’m using for the juggernaut enemy. This particular character has separate files for his idle, walk, smash, shockwave, charge, and death animations.

Rule # 6. Use clips to bridge movements

In Maya it is possible to create animation clips using the trax editor. These clips can be stored in folders and subsequently added to characters in other files sharing the same rig and controls. Using this method, you can take multiple animations and combine them into a single sequence, changing the order as you see fit. Note: This will not work at all if you haven’t followed the best-practices listed in the previous post.

In order to import the bomber into the game, all of his animations needed to be a part of a single sequence, so I recorded clips from each of his @ files and pieced them together using the trax editor as depicted below:

Rule # 7. Apply good naming and versioning conventions

It is critical that you keep your work organized! Any names given to assets or asset-related files and folders should be descriptive and consistent. I can outline my organization strategy in the following steps:

7.1 Use Maya’s project window to create a basic folder structure that will contain all assets related to the game

7.2 Create sub-directories specific to your project’s needs (i.e. scenes/enemies/joker/)

7.3 Establish a naming convention and a compound word methodology (I use headlessCamelCase) and apply it to all files.

This makes it much easier to find what you are looking for in a given folder: If all of the juggernaut’s texture files are named based on the same convention, then you can scan the file list alphabetically  for juggBodyTex.png, and it will be right next to juggCardTex.png and juggBodyTexNRML.png

7.4 Add version numbers to anything that you change, so you can save multiple copies without it becoming confusing.

You’ll be glad you did this when you’re working on joker@laugh_v019 and you delete the history such that you need to revert to joker@laugh_v018 so that you lose 10-30 minutes of work instead of hours. Also when Claude asks for joker@laugh_v006 because it would be perfect for the laugh attack idea he wants to prototype.

That’s really all there is to it. Good luck and happy animating!

-Johnny

Posted in Art | Leave a comment

More Lightning and Shadows

More Lightning

In a somewhat recent post, I showed off the initial stages of the lightning effect that I’ve been working on. One of the major hurtles that was tripping me up, and the reason why in the old video it is hard to actually see the lightning, was the blend states in DirectX 11. There is a flag in the blend state descriptor called IndependentBlendEnable. If this is set the false, all render targets that are bound only use the first render target blend descriptor. For many applications this works perfectly fine. For others, this breaks everything. Well, not break per-se, but gives unintended, unwanted, and incorrect results. So, the issue that I was running into was when rendering the depth render target, the blend mode was set to additive. It was trying to additively blend the depth with an already existing depth value or zero from the depth render target. The fix was to specify IndependentBlendEnable = true and define the depth render target to use an alpha blend to overwrite any value that was previously rendered.

Once this was fixed, I could move forward and test the new flashing and jitter functionality. The lightning can now flash any color and for a specified amount of time. Jitter is added in the geometry shader when the lines are “exploded” out into two intersecting planes and oscillates the points some amount over time. This gives the effect a more “alive” feel, as bolts no longer just sit in the air, waiting to fade out.

Here is a demonstration of the new lightning:

Shadows

The next thing I wanted to tackle was shadows. I already had crude shadow mapping implemented for spot lights and somewhat for direction lights before we went to GDC, but I was incredibly unhappy with the results and disabled it for the build. Every bad thing that could happen in shadow mapping was present in the old version: the shadows were aliased; they had horrible banding on near-parallel surfaces; objects close to a plane “Peter Panned” (“Peter Panning” is a term for a shadow that separates from an object when it’s close to or on a plane).

Now that there is more time, relatively speaking, I took up the task to re-implement shadow mapping. After going through online and book resources, I realized I wasn’t far off from a working solution; I just needed to tweek some values and properly setup my orthographic projection, among other things.

Since the game mainly takes place in a confined space and there isn’t much in the background going on, I do not need to implement anything fancy when it comes to shadow mapping. The only fancy aspect to the shadows is that I’m using PCF, percentage-closer filtering, soft shadows. PCF in DirectX 11 is quite nice as it has hardware support for doing the depth comparison by way of SampleCmp and SampleCmpLevelZero (which is the same as SampleCmp, but for MIP level 0 only). These functions do a comparison on the hardware and return either true or false, 1 or 0, if the comparison passes or fails, respectively. The calculation for the percent of a surface being shadowed or not then becomes simply this:

const float dx = 1.f / SHADOW_MAP_SIZE;
const float2 offsets[9] =
{
	float2( -dx, -dx ), float2( 0, -dx ), float2( dx, -dx ),
	float2( -dx,   0 ), float2( 0,   0 ), float2( dx,   0 ),
	float2( -dx,  dx ), float2( 0,  dx ), float2( dx,  dx )
};

float shadowPercent = 0;
[unroll]
for( int i = 0; i < 9; ++i ) {
	shadowPercent += shadowMap.SampleCmpLevelZero(
		shadowComparisonSampler,
		shadowTexturePosition.xy + offsets[i],
		shadowTexturePosition.z - DEPTH_BIAS
	);
}
shadowPercent /= 9.f;

A depth bias, defined as DEPTH_BIAS above, is something that needs to be tuned to your needs. This bias eliminates severe banding in the scene when set to a small value, but also causes “Peter Panning” if set too high. During my initial testing, here are the differences between not having a depth bias and having one.

Without a depth bias:

With a depth bias:

Once all the kinks were worked out, here are the resulting shadows:

Posted in Coding, DirectX 11, Engine, Graphics | Leave a comment