Showing posts with label design patterns. Show all posts
Showing posts with label design patterns. Show all posts

Tuesday, February 18, 2020

The Poor Man's Gameplay Cue in UE4

I have some time this morning to collect my thoughts, so one thing I want to do is share a quick post here about something interesting I encountered a few days ago.

On Feb 13, Epic hosted a Live from HQ stream on Game Jam Tips and Tricks, which you can find archived on YouTube. In this stream, Michael Noland introduced a useful pattern for UE4 Blueprint programming that I had not seen or thought of before. He mentions that it is inspired by the Gameplay Abilities system, which I am sure I have tried to learn more than once, and each time I think, "This is amazing and also way out of scope for my project!" Then, I forget the important details and carry on. The Gameplay Abilities system is still (or again?) something I want to invest some time in understanding, and I'm hoping in part that by recording this smaller version here, I'll give myself and others an anchor to understand the more complex version.

At 54:15, Noland begins an explanation of why Sound Cues are a useful extension of normal Sound classes. I've been a fan of Sound Cues at least since working on Kaiju Kaboom, where I wanted variation on sound effect volume and modulation. He builds on this, starting around 56:26, explaining the value of decoupling game effects ("juice") from the core game rules. In particular, he mentions that certain blueprints will be high-contention, such as pawns, game modes, and player controllers. Separating the game effects from the other rules means that multiple people can be working simultaneously without version control conflicts, since these behaviors are now in different files.

After a few minutes, he ends up with a hierarchy like this (changing his naming scheme slightly to follow the Gamemakin Style that I prefer):

When the BP_StandardGameplayCue is spawned, it plays any sound, particle effect, or camera shake that has been set, checking via validated get. Noland points out that a slightly more robust system would have to account for who instigated the effect so that it could, to cite his example, do something like set that character on fire or give him a halo.

I hope that write-up is useful, if for nothing else than to help me remember this interesting pattern next time I'm working on a collaborative jam project or trying once again to make sense out of Gameplay Abilities. I wonder if I had known this a few weeks ago if I could have unleashed my son a bit more freely to work on visual effects in Disarmed.

Wednesday, September 18, 2019

Revisiting the state analysis of Every Extend

Back in 2007, my first Computer Science education research paper was published in the proceedings of SIGCSE. The paper provides an overview of how game programming can be used as a motivating context for learning design patterns. One of the examples in the paper, which I have used for years, is the behavior of the player-controlled bombs in the inimitable Every Extend, which can be used to explain the State Design Pattern. In the paper, I argue that the player's pawn can be described by a state machine like the following.
In yesterday's meeting with my CS315 Game Programming students, I was inspired to create a UE4 tutorial video about using state machines for state management. In particular, I wanted to show how an enumeration can be used to define the possible states, and then behavior can be switched depending on the current state. This is not, of course, the State Design Pattern, but it's a heck of a lot better than an ad hoc collection of Boolean variables. It also follows from Michael Allar's Gamemakin' UE4 Style Guide that is mandatory for my students, which says:
Do not use booleans to represent complex and/or dependent states. This makes state adding and removing complex and no longer easily readable. Use an enumeration instead.
To prepare for the video, I have spent a few hours the last two days building a simple playable framework similar to Every Extend. Over a decade ago, I did a similar exercise in Java to produce EEClone. This time, I did it in UE4. (A bit of an aside: Every Extend is like my kata for new game programming frameworks. I use the essential gameplay of it as a case study to understand how game engine functions. Of course, then, when I first started learning UE4, I tried making an Every Extend clone, but it went quite poorly. After a few years of working with UE4, it's become a lot easier to get the game up and running!)

With my gameplay framework in place, I started working on the diagram shown above to use in my series of game programming tutorial videos. However, as I looked at the diagram, I realized I had a rather fundamental problem: these are not the states of the player bomb. It's true that these are, abstractly, states of the game, but they are not the states of a single stateful object. Instead, what I had programmed was leading into the following state model:
That is, a player bomb is created, which has it play a spawning animation. When that is completed, then the player becomes vulnerable to collisions but can also press Space to explode. However, unlike in the initial analysis, there are no other states after this. If the player presses Space or is hit by an obstacle, the player's bomb is destroyed: that actor—that object—no longer exists. It is the game mode that either counts down to respawn or waits until a chain of explosions is complete and then counts down to respawn. These states are not part of the player pawn.

This observation shoots a hole in my plan to make a video using the Every Extend example. I still want to make a video about state analysis, but I need to find a better example—one where a single actor's state is interesting enough to be modeled but simple enough to fit into a tutorial video. Please feel free to share your suggestions in the comments.

Wednesday, April 3, 2013

Java Generics Trivia: A Tale of Syntax Discovery and Clean Code

I have spent years working with Java, although never as intensively as during my graduate school years. A significant part of my effort in graduate school was in gaining a deep understanding of the semantics of Java. There have been a lot of changes in Java since then—generics being among them. Today, while doing some programming, I came across something that I didn't know you could do.
I am writing a generic fixed-size grid class: it contains width*height elements that are indexed by <column,row> pairs. When faced with the problem of making a grid in a specific size, my first thought was to do it this way:
class Grid<T> {

  public static Grid create(int width, int height) {
    return new Grid(width,height);
  }

  private Grid(int width, int height) {
    ...
  }

}

However, I am also trying to follow Clean Code as closely as I can. In particular, I wanted to reduce all my methods to zero or one parameter, so I decided to introduce a builder here instead of the static factory method. In fact, I had just shown a similar example in CS222 last week—though, notably, without generics.

My refactored version, then, looked like this:
class Grid<T> {
  public static <T> Builder<T> width(int width) {
    return new Builder<T>(width);
  }

  public static final class Builder<R> {
    private final int width;

  private Builder(int width) {
    this.width = width;
  }

  public Grid<T> height(int height) {
    return new Grid<T>(width, height);
  }
}

Isn't it pretty? No method has more than one parameter, and the structure of the method calls enforces that I cannot get a Grid object without specifying its width and height. I returned to my calling code—a private createGrid utility method within my test suite for this class—and replaced the call to the static factory method with the following. (Note that Integer here is the data stored in the grid and is not related to the int width and height; the dimensions are always int regardless of the stored data since I am dealing with a discrete grid.)
Grid<Integer> grid = Grid.width(10).height(10);

I was surprised when the compiler complained. It sure looks a lot like the handy type-inferring methods of Guava such as Lists.newArrayList, that keep me from having to pepper new and angular braces throughout my code. Yet, the compiler insists that it cannot convert a Grid<Object> into a Grid<Integer>.

Clearly the problem is with the generics. To test my understanding of type inference, I converted the code to the following:
Grid.Builder<Integer> builder = Grid.width(10);
Grid<Integer> grid = builder.height(10);

This worked fine, but it obviously is not the kind of code I want to write when creating grid objects. If I was happy with this kind of awkwardness, I wouldn't have pedantically followed Clean Code in the first place.

I could not see a clear escape from here, but I began to wonder what kind of syntactic stunts I could pull to get this to work in fewer characters. I tried the following on a whim:
Grid<Integer> grid = Grid.<Integer>width(10).height(10);

If this kind of code showed up in Naftalin and Wadler's book on generics that I read six years ago, I certainly don't remember it. I pride myself on my mental Java compiler, but my brain still stutters when I look at this code.

The good news is that it works, and I learned something about the language in which I like to claim expertise. (I suppose I knew enough to know what to try, and that says something.) The bad news is that there is still a DRY violation in the generic types. If you can see a way to eliminate that, let me know!