Glide update: Tween overwriting

I’ve just added support for property overwriting to Glide, my Tweening engine for C#. This functionality exists in Actuate (a great Haxe library from which I’ve taken a lot of inspiration) and I’ve wanted it in Glide for a while now because it’s just so darn handy.

Imagine you start a tween off on its way:

// move image to (100, 200) over five seconds
Tweener.Tween(image, new { X = 100, Y = 200 }, 5);

…but then something changes, and now you want your image to travel instead to (X = 500) instead, and it should only take two seconds:

Tweener.Tween(image, new {X = 500}, 2);

At first this will work fine, but when the second tween finishes, suddenly the first one takes precedence again and your image will keep moving towards (X = 100). You could cancel the first tween, but that would also cancel the movement towards (Y = 200).

Now, creating a new Tween on an object that’s already being tweened will cancel the movement of any properties that are currently being tracked. In the example above, the new X tween would overwrite the old one, the original Y tween would keep on working, and there’s no need to manually cancel anything.

The old behavior is still available; just pass false to the overwrite parameter. I’m pretty sure that won’t be necessary in the majority of cases, but it does exist if you want it.

Glide update: Structs don’t work that way

Glide has seen some modest adoption despite the fact that I’ve barely made any effort to get the word out. A handful of developers have contacted me thanking me for the project and asking for help, which I’m always glad to offer. One issue in particular has come up a few times recently, and it relates to the way .NET handles structs.

Structs are passed and returned by value, not reference. This means that when you assign an instance to a variable, that new variable has no relationship to the original object; any properties set on it will only apply to that variable. This is a problem in Glide, since I have to store a reference to the tween’s target object in order to apply the transformations. Worst of all, while normally this issue would be caught at compile time, it’s impossible to detect when you’re using reflection to set values, and the resulting behavior was that the operation would appear to silently fail.

Today I made some changes that should help users realize when they’re attempting to tween an incompatible type. Passing an instance of a struct to the tweener will result in a compile-time error, and if you sneakily box your variable into an Object it will throw an exception at runtime. This still doesn’t solve the problem of how to tween these types of properties, but I’ve got you covered on that front as well.

Glide already has support for extension classes that allow you to add specialized behavior for tweening your own types, but this feature wasn’t really documented anywhere. Now it is! I’ve added a wiki to the Glide Bitbucket repository with an example showing how to tween an XNA Vector2. It should be pretty simple to modify for your own needs…maybe a StringTyper extension that causes letters to show up over time like a typewriter, or a GlitchString that fills the whole string with garbage and slowly fills in the correct letters.

Stuck Scripting overhaul

Early on in the development of Slide (before Iridescence had come to be), I added support for small script files to allow levels to contain more complicated puzzles without running into false positives that caused the reset button to show up while the level was still perfectly solvable. I was using C# at the time, and options for proper scripting languages on the .NET platform are shamefully limited, so I rolled my own.

Here’s a sample of what it looked like:

R > B;
G > B;
B > G ! B -> [B];
B > R ! B -> [B];

The use-case for stuck scripts is extremely specific, so the language itself didn’t need too many bells and whistles. All I needed to do at any time was compare the number of game objects of a given color, and check if pawns had a valid path to their targets. The snippet above basically translates like so:

The puzzle is unsolvable if any of these are true:

there are more red pawns than blue
there are more green pawns than blue
there are more blue pawns than green, unless all blue pawns can reach a target
there are more blue pawns than red, unless all blue pawns can reach a target

Needless to say, it’s as ugly as it is functional, and adding new features proved difficult. The inflexibility of the original design meant for some truly impressive hijinks as I tried to implement more complex behaviors with only the original syntax.

Today I stripped the whole system out and replaced it with a new one. Since I’m using Haxe for this remake, I was able to take advantage of hscript, a subset of Haxe that allows for runtime interpretation. Now, the script above looks like this:

var reds = count(Pawns.Red);
var greens = count(Pawns.Green);
var blues = count(Pawns.Blue);

if (reds > blues) fail();
if (greens > blues) fail();

if (blues > greens && !hasPathToExit(Pawns.Blue))
	fail();

if (blues > reds && !hasPathToExit(Pawns.Blue))
	fail();

Much better.

The original scripting system was designed as a black box, with a minimal number of inputs and outputs. By keeping the interface consistent between implementations, I was able to completely change the underlying code without changing any other aspect of the program. It’s nice to be able to change something so integral to the gameplay without worrying about side effects.

Glide update: From()

I made a small addition to Glide, my tweening library for C#. You can now specify starting positions for the variables you’re tweening, useful for when you need to change a variable instantly and then tween back to the default value. I use this when I’m making things flash for alerts or other important things for the player to notice.

tweener.Tween(sprite, new { Scale = 1 }, 1)
    .From(new { Scale = 1.5f });

Obviously you could just set the values manually before telling them to tween, but this is a nice shortcut if you’re setting a lot of them at once.

You can download Glide here.

Haxe macros are amazing

Here’s a neat trick I discovered today while working on Iridescence.

Haxe has native macros that are very different from those found in C; rather than using a separate pre-processing language, Haxe macros are simply snippets of Haxe code that are run at compile time instead of run time.

In native builds, Iridescence populates its soundtrack dynamically by searching for all song files in the /assets/music folder. On more restrictive platforms like Flash, all assets have to be known at compile time so they can be embedded in the SWF, which meant I needed to create a list of files manually and update it whenever I added a new song. I wrote this little macro to iterate through the music folder at compile time and build a list of song files automatically.

macro public static function getSongList(extension:String)
{
	var songs = FileSystem.readDirectory("assets/music")
		.filter(function(s) return s.endsWith(extension))
		.map(function(s) return "assets/music/" + s)
		.array();

	return Context.makeExpr(songs, Context.currentPos());
}

Color/Shift input woes

When I released the Color/Shift demo, one of the main issues that were being reported was that dragging the pawns around was really difficult. This confused me as I had spent a lot of time painstakingly tweaking the controls so that sliding pieces felt natural and responsive, but it was obvious by watching people play that there was something seriously wrong. I made some changes to try to make it better, but the result was still pretty bad. The pawns would slide around loosely in any direction they wanted until crossing a grid line, at which point they would snap to an axis and move along it, It didn’t feel good, and it introduced all kinds of new problems including the possibility of phasing through objects or traveling in two directions at once. Worst of all, it still didn’t address the issue entirely.

Dwm 2013-11-11 10-21-38-83

Yuck. 🙁

I let it be and moved on to other things, planning to come back to fix it later. There was probably a little bit of hubris involved, if I’m being completely honest with myself; if I didn’t have a problem controlling the game, other people shouldn’t either, right?

A few days after leaving the issue behind, I was working on my laptop (most of Color/Shift’s development has been done on my desktop computer) and suddenly started having the same problem as my testers. Pawns were moving sideways when I wanted to move up, and sometimes they wouldn’t even move visibly before smacking into a wall to either side. What was going on?

As best as I can figure, the input issues had to do with the sensitivity of the mouse being used for control. My desktop has a high DPI gaming mouse with the sensitivity cranked way up, and my wireless mouse and laptop trackpad are much less precise. Armed with this new information, I set about making things right.

angle0

Here’s a visualization of the way I’m handling input now. When the user presses the mouse button, the pawn remembers where the pointer was when it was pressed. In the image above, it’s right in the center of the piece.

At this point, no dragging is actually done yet. The mouse must move 7px in any direction before the pawn will move at all; this is represented by the circle cutout at the center of the transparent fans.

When the mouse has moved far enough from its original position, its angle to that position is checked. If the angle is within 30° of an axial direction, the pawn is then allowed to move on that axis. If not, no movements are made.

angle1

The angle is relative to the mouse click position, so it’s possible to start the drag by clicking anywhere.,

I still need to stress-test this to make sure it works for everyone, but it feels much better with all of my mouse devices and I have yet to move a piece in a direction I didn’t intend since improving this mechanic. Feedback is important! Listen to your testers!

 

Action scheduling with Lua

One of the downsides to moving between programming languages is that you inevitably lose all the base code you’ve gotten used to using. When I was using Actionscript 3 regularly, I wrote Slang to meet the lack of a scripting language that ran inside of Flash and ended up using it for a number of purposes in my subsequent game projects. The most useful application I found for it was for setting up cutscenes and scripted sequences, and I’ve missed using it now that I’m spending more of my time using C#.

Rather than porting Slang to C# (which would have been quite an ordeal), I’ve been playing around with Lua in an attempt to recreate a similar system. Here’s the first draft of how a scene might be set up.

Continue reading →

Must’ve been rats!

This past weekend I participated in the Global Game Jam with Chris Logsdon and Paul Ouellette. The theme was “heartbeat”, so we made a stealth game called “Must’ve been rats!” in which you have to search for a briefcase containing a beating heart so you can escape in a heart-powered elevator.

Download here!

Overall I’m pretty satisfied with the way this jam turned out. We had a lot of fun designing the gameplay and systems, and the game is feature complete despite having only one level at the moment. Even after testing and debugging for 48 hours straight I still enjoy playing the game, which feels like an accomplishment of its own. Still, it’s not a game jam if you don’t make some stupid mistakes and learn a few things, so here are my Things That Went Right and Wrong.

What went right

Flashpunk

At this point I can’t imagine using anything but Flashpunk for my game jam needs. Paul was able to pick it up fairly quickly, despite the fact that he hadn’t used it at all until a few days before the jam. Chris and I have used it a number of times, and even so we both found new features that we’d never known about. The API feels complete and intuitive, and it seems like there’s a function or class for everything we could ever need.

Systemic design with message passing

We designed our base engine as a set of systems that communicated with each other indirectly through message broadcasting, instead of directly through function calls. This allowed us to focus on programming the rules of the game world instead of specific interactions between different entity types. Even though getting each system working correctly was a challenge, adding new rules and rule responses is quite simple.

Data-driven workflow

We did all of our level design using Ogmo Editor, and as usual it served us well. Since we used a tileset for our levels’ art and a grid for collision and pathfinding, I modified my OgmoWorld utility classes to automatically import each of these types automatically and take advantage of FLAKit‘s live reloading capabilities. These changes will be included when I get around to officially releasing OgmoWorld.

What went wrong

Systemic design with message passing

Yeah, I know this one is in both groups. That’s deliberate.

Despite the fact that message passing is really cool and allows for some interesting emergent interactions, it’s not a good fit for everything. One example of a poor application is updating each enemy with the player’s position. My solution was to broadcast a message that told the player to report back with his position. This was slower and less elegant than searching the world for the player instance, and I wish I had realized that sticking rigidly to message passing was a bad approach.

Preconceived ideas

Chris and I had decided we wanted to make a stealth game before the jam started. Even though we didn’t do any kind of brainstorming beforehand, that decision still limited our ability to be creative with our interpretation of the theme. Fortunately we still managed to stay in scope and get the game to feature-complete, but I still wish we had come into the jam without any plans.

 

Overall, I’d call this Game jam another success. Make sure you play the game!

Data-driven action scheduling in Flash

One of recent experiments in game development has been to orient my workflow away from code and towards data. When I use Flash, I’ve started using Ogmo Editor to design my levels, XML to handle settings, and Slang to handle game logic whenever possible. As a result, a lot of the code I’ve written recently can be easily reused across projects, and my classes are systemic and steer clear of situation-specific behavior. It’s been quite fulfilling and has done wonders for my iteration time; the focus on data instead of code means that I can take advantage of live-reloading for nearly every aspect of development. It’s not uncommon for me to work for an hour without ever closing my game, as I can simply reload all assets and data with the press of a button.

Today I’ve been working on Humphrey’s Tiny Adventure: Remastered, a post-compo version of my first 48 hour game. There are a number of places in the game where I need to set up events on a timeline, which I’ve done a few times already (see here and here), and each time I used some variation of traversal over a queue of function closures. While this approach worked well enough, it was tedious to set up and a pain to debug, not to mention the fact that it was anything but systemic. The most criticized aspect of the Ludum Dare version of Humphrey was that the intro cutscene was too long, and I agree. I think I knew that even before I released the game, but there was no way I was diving into that code to change it.

For Humphrey: Remastered, I was determined to achieve the same type of event scheduling in a data-driven way. Thanks to Slang, I was able to do just that. Here are the scripts for a scene I’ve been testing that involve two actors; Humphrey and Abe. This won’t be in the finished game, but it’s a good demonstration of the system’s capabilities.

action {
        print "start"
        delay 3
        done
}

action {
        print "after delay"
        give-cue "humphrey done"
        done
}
action {
	print "start abe"
	done
}

action {
	await-cue "humphrey done" {
		print "got cue"
		done
	}
}

Actions are called sequentially by the actor that the script is attached to. Each action block defines a set of statements that will be run as the events are executed. Calling done moves to the next action, and delay causes the actor to stop executing actions for the given number of seconds.

The give-cue and await-cue functions allow actors to pass messages between each other. In the above example, Humphrey give a cue to tell that he’s finished a set of actions, and Abe, who has been waiting for that cue, executes his final action in response.

There are only a few control functions involved, but so far the system has proven to be very powerful, and more than capable enough for the needs of this project. With the addition of message passing and response, specialized actor classes will be able to define custom behaviors while allowing the system to remain pure.

I’m quite happy with the way this has turned out. It’s fun to experiment with what can be done with Slang even in its current, quite minimal state.

 

 

Slang 2.0

I’ve recently been working on Slang, my scripting language for Flash, and yesterday I accidentally rewrote the entire thing. I started out refactoring of the parser, and ended up completely redesigning the way the language is executed.

The biggest internal change is that source must now be compiled before execution. This allows for a performance boost when running scripts multiple times, as the bytecode can be cached. Compiling is still quite fast, though, so it’s just as easy to use Slang in a dynamic way, such as an in-game console.

Another feature in this version is the introduction of Scopes. A Scope is a simple data structure which contains statements and can be executed by the application. Currently, they are used for conditional statements.

if condition {
    print "true!"
}

ifelse condition {
    print "true!"
} {
    print "false!"
}

In the future, they will also allow closures and script functions.

With the addition of Scopes, the use of semicolons as artificial separators is no longer necessary, and they have therefore been removed from the language keyword set.

With this release I’ve moved Slang out of FLAKit and into its own repository. You can follow it here.