“A Stitch in Time” demo has been released

After many long months and a lot of hard work, Matt Kempke and I have finally launched the demo game of “What Makes You Tick: A Stitch in Time”. This is the first game released with Lassie Shepherd, and showcases most of the engine’s multimedia capabilities. For those who remember and love classic adventure games… enjoy!

http://www.lassiegames.com/games/stitch_demo

Advertisements

Creating Day and Night

The demo of “What Makes You Tick – A Stitch in Time” is releasing soon (March 18th), so it seems as good a time as any to discuss some aspects of what’s on the way. So, one of the big features of Stitch is that we built the world to be playable at both day and night, with player-controls for switching between the two. While this feature was one of the most painful aspects of game production, it was ultimately one of the most rewarding as well.

Day and night at the Ravenhollow docks.

I believe it was Matt (my partner on Stitch, and inspired by his childhood of playing Zelda games) who initially proposed the idea of time changes during an early brainstorming session. While I didn’t object to the idea from a tech standpoint, I also didn’t really expect to go through with it… In my experience, massive labor-intensive features generally have a way of working themselves out of a product. Only later did I realize my oversight: massive features only work themselves out of client projects where the client doesn’t want to pay for a grandiose vision. Unfortunately, features do not work themselves out of your own projects unless you heart-wrenchingly cut them (hence the reason we are each our own worst clients!). While I remained leery of the idea, Matt wrote it into his first draft of the script and it became a lock-in. However, that’s not to say that we didn’t make ANY cuts. Matt’s first version of the script actually included three times of day: sunrise, daytime, and night. Wow – that would have been a ton of work (I emphasize that now that we’ve implemented ONLY day and night). Thankfully, it was a pretty easy decision to cut back to just the two; mainly because:

  1. We were concerned with making the world so faceted that the player would miss connections between the different times of day. We decided that a player would have plenty to figure out with only two times to work between.
  2. After some early artwork tests, it became clear that the original idea of rendering all scenes as daytime and then just adding color overlays for the alternate times was not going to work. The artwork looked very flat, so we were going to need to render every lighting scheme as a custom painting (and two paintings for each room was enough!).

So after the day/night concept was locked in, it was time to think through the technical solution. One “easy” idea that was quickly thrown out was to create two separate instances of the world: one in daytime, one at night. While the idea seemed lucrative because of its simplicity (just swap the player into the same point of the other world instance, right?), it just didn’t make sense. We had a ton of puzzles planned, and while some puzzles were unique to day and night, the majority would be universal between times. That meant that all universal puzzles would need to be coded, tested, and debugged twice (once for each world instance)… and that doesn’t even take dialogue into account. The world is full of dialogue responses, so each world instance would need to be edited and maintained separately. Finally, multiply this scenario by roughly 20 rooms and you’ve got an extremely formidable challenge. So, that got me thinking of sneaky alternatives to pull off day and night without the development overhead.

This led me to build a layer setting within the Lassie engine called “frameOffset”. The concept is pretty simple: Lassie assigns a MovieClip as the image of each layer within a room, then tells that clip to go to a frame based on the layer’s current display state. Adding a “frameOffset” basically tells the layer to figure out which frame it should display, then go to that target frame +X. This allowed us to start building all graphics with day and night states, where the night graphic was placed on a timeline frame immediately following its daytime counterpart. At night, all dynamic layers receive a frameOffset of “1”, which causes them to go to the frame after their baseline daytime state. Suddenly, this process became a whole lot more manageable: create all rooms once, then just track whether their graphics should be skinned as day or night. Of course, we still needed to add lots of conditional logic to control puzzle behavior between day and night, but that was a minor endeavor compared to what it would have taken to maintain separate world instances.

Overall, time-of-day was a tough process that made for twice the art production, extra programming, and a general feeling of exponential complexity. I’ll admit, I had a moment of weakness where I tried to narrow the scope of day and night down to just work within the center of Ravenhollow (about 3 scenes). However, Matt never budged on keeping the whole world playable in both times of day, and he was right. It IS better this way. We think our fans will really enjoy act 2 of Stitch (the largest act), where day and night is fully utilized. While we’ll be introducing the time switching scenario in act 1 (the demo area), the process will be linear so that the world state only changes once. However, in act 2 the player gets complete control of the clock!

“A Stitch in Time” Demo Announced

It’s been a long haul developing “What Makes You Tick: A Stitch in Time” (more than a year in the making). Even now while main production winds down, we still have a long way to go through a comprehensive testing and refinement process. So, the full game won’t be ready for a while yet. However, in the meantime there’s some exciting news…

March 18th has been officially announced as the release date of the “What Makes You Tick: A Stitch in Time” demo game. The demo will be available for free download, and will include the complete first act of the full game. The demo delivers four playable rooms, 15 character appearances, lots of great artwork and music, and perhaps a few surprises! The game experience amounts to the combined effort of many talented people, and my co-author, Matt, and I are very pleased with the result. That said, we’re excited to share the game with our friends and fans! For more information and all the latest news on “A Stitch in Time”, visit the game’s official website at http://www.lassiegames.com/stitch.

This release is also big news for the Lassie game engine. The Stitch demo will assume the role of the official Lassie Shepherd demo game for showcasing the engine’s core features. Lassie enthusiasts who are curious about what’s possible with Shepherd may be interested to see the demo in action… the game makes use of everything from basic room transitions to heavy cache tracking and dynamic logic features.

Whether you’re a designer, a developer, or just a general game enthusiast, we hope you’ll stop in on Match 18th to celebrate this release with us!

Flash and Fullscreen

Flash’s fullscreen display implementation is one of the most deceptive aspects that I’ve come across within the Flash platform. On the surface, fullscreen is an unbelievably simple and clean-cut feature: you set the stage’s “displayState” property to either StageDisplayState.FULL_SCREEN or StageDisplayState.NORMAL. However, once you really get digging into fullscreen implementation, you discover all kinds of weird nuances that make this seemingly simple feature a real headache. So, I’ll run through my laundry-list of gotchas and development tactics that I’ve picked up over the years. Here goes…

Toggling fullscreen

Generally I implement a toggle button to click in and out of fullscreen mode. This is super easy to set up, and just uses the basic fullscreen controls of Flash. Nothing fancy going on here; I’d just set this as the CLICK handler of my toggle button…

private function _onToggleFullscreen($event:MouseEvent):void {
 var $fs:Boolean = (stage.displayState == StageDisplayState.FULL_SCREEN);
 stage.displayState = $fs ? StageDisplayState.NORMAL : StageDisplayState.FULL_SCREEN;
 }

Responding to displayState changes

Now, it’s not uncommon to want to rearrange your display a bit when entering/exiting fullscreen mode. I generally shift the alignment, scale, and proportions of elements on screen to better fit the display in fullscreen mode. Now, it would seem like we could just add this reformatting logic into the fullscreen toggle button’s event handler (above) where we actually toggle the displayState. However, this doesn’t work in practice because Flash Player automatically activates the ESC key as an exit from fullscreen mode. This provides a back-door to changing the displayState without going through your toggle button. As a result, all mode-change logic should occur in response to the stage’s RESIZE event (which will trigger in response to your toggle button, and in response to exiting fullscreen with ESC). So, do this:

stage.addEventListener(Event.RESIZE, this._onStageResize, false, 0, true);
function _onStageResize($event:Event):void {
 // perform actions in response to stage resize here...
}

Configuring the fullscreen presentation

The next nuance of this process is considering how you want to present your content in fullscreen mode. By default, your stage will be upscaled to fill the screen along with black space to fill up any differences in aspect ratio. This upscaling is controlled by another stage property called “scaleMode”, which has a set of value constants defined in the StageScaleMode class. By adjusting the stage’s scaleMode property, you can define how stretching is (or is not) applied. But wait, there’s more! Also check out the stage’s “align” property which goes hand-in-hand with the scaleMode property. The “align” property (set to one of the StageAlign class constants) will define how an unscaled stage positions itself while in fullscreen mode.

Now, while the “stage.align” property is a good concept, it has one blatant omission: there is no StageAlign.CENTER option to place the unscaled stage in the center of the screen while in fullscreen mode. This oversight confounds me, and even a good technical explanation from Adobe would not excuse the feature omission in my opinion. So, if you do want to center unscaled content within fullscreen mode, you’ll need to set the stage’s scaleMode to “NO_SCALE”, the stage’s align to “TOP_LEFT”, and then manually do the math to center your root display item within the visible stage boundaries.

Other weird stuff about fullscreen mode

I’m not even sure how to categorize these items, so I’ll just make a list of all the other “gotchas” that I’ve run into…

1) Fullscreen mode does NOT work in a test publish running within the Flash IDE. You’ll need to place the SWF into a browser or publish a projector to have your fullscreen button work.

2) Fullscreen will only work within a web browser if you’ve included a [allowFullScreen=”true”] parameter within the Flash embed tag.

3) Flash does not respond to keyboard input while in fullscreen mode (grumble). I’ve looked for the rationale behind this restriction, but have found nothing other than Adobe citing it as a “security measure”. As of Flash Player 10, they threw us a bone and gave us the arrow keys, SPACE, and TAB as fullscreen freebies. Otherwise, you can only get unrestricted fullscreen keyboard access by going through AIR.

SWFAddress revisited

It’s been a year since I’ve done anything with SWFAddress, and in that time I’ve received many support questions in response to my last blog post on the subject. So, now that I’m back into SWFAddress on a new project, I’ve finally gotten around to posting a sample implementation of a SWFAddress proxy class in my previous post, available here:

https://lassieadventurestudio.wordpress.com/2008/10/09/better-swfaddress/

I hope it’s useful!

AS3 ‘Stitch’ Particles

Happy Holidays! Well, it ’tis the season an the snow is falling, so I thought it might be appropriate to post some relevant ActionScript. So to spread some winter cheer, I’m releasing the AS3 particle library that I wrote for the (numerous) particle effects used in my current game project, “A Stitch in Time“. This particle demo includes a small sampling with snow, fire flies, will-o-wisps, and water bubbles. These core effects have been adapted into many forms in many areas within the game world.

In that demo, all four effects are driven by the same codebase. The particle system is just composed of two base classes: a particle and a particle field. From there, all implementations of the various particle effects just customize the appearance of the particle and the behavior of the field. The source files are available.

So: enjoy, stay warm, and happy holidays! I’ll post again next year after getting back from some holiday travel around South America. Or who knows… maybe I’ll post an update from the road.

“A Stitch in Time” Website

In other project-website related news, we’ve recently launched the official “A Stitch in Time” website, available at http://www.lassiegames.com/stitch.

Stitch is the follow-up to Matthias Kempke’s 2007 release, “What Makes You Tick?”. Matt and I partnered up to build this sequel and have been actively developing it within Lassie Shepherd over the past year. While there is no playable demo released to the public yet, the game is making good progress and we still hope to release it in the first half of 2010. In the meantime, the website will act as the definitive source of news about the project.

Lassie website status

Howdy folks – as many people have apparently noticed, the Lassie website has gone down at it’s old address. This was partially planned, although mostly just bad planning on my part by not getting the new site location set up before my old web hosting expired. So, I’ll be slowly resurrecting the site on my new server over the coming weeks. While there’s not much up there right now, the site’s new address is: http://lassiegames.com/lassie/

Sorry for the confusion, and thank you all for you patience! I’ve appreciated all the comments and emails which have expressed gratitude toward the Lassie project and hoped it would be back soon. Rest assured–Lassie isn’t going away… there are just too many great game ideas out there to call it quits!

Just for SEO and skimming readers, again, the new website address will be: http://lassiegames.com/lassie/

Lassie Shepherd Released

Lassie Shepherd –a complete SCUMM-style adventure game engine built in AS3– is finally released. It’s only taken me two years and a whole lot of lost sleep… The system still isn’t perfect, but then, it will NEVER be perfect; so this is as good a time as any to release it.

The compiled build is posted on the Lassie website; feel free to download and have a go. I encourage developers to turn to the Lassie Forums to set up a peer-to-peer support community. Unfortunately, I have no availability to commit to technical support. All I can say is —as always— good luck and happy adventuring!

Easy Blowfish Text Encryption

All security considerations aside, text encryption is great just for keeping curious editors out of a plain text file. Case of point: I build XML driven Flash games. While I don’t necessarily care if a player “looks under the hood” at the XML data, I would rather that they not try to cheat gameplay by manually tweaking XML configuration. So, a quick encryption of the XML works great to impede manual edits.

So, I’ve always turned to Blowfish for a quick encryption. Blowfish is a two-way cipher that can both encrypt and decrypt text. And thankfully, the fine folks at the AS3 Crypto project on Google code have included an AS3 implementation of the algorithm as part of their open source library. However, the AS3 Crypto library is pretty extensive; and likewise, it takes some extensive research to figure out all the parts and pieces. In my case, I wasn’t so worried about security as I was about having something easy that would generate an encryption. So, I put together this utility class which exposes a simple interface to the Blowfish algorithm and only imports the necessary library items (this import amounts to 11Kb, rather than the 40Kb of the full AS3 Crypto library). You’ll need to download the AS3 Crypto library to go with this utility class.

package
{
 import com.hurlant.util.Base64;
 import com.hurlant.crypto.symmetric.PKCS5;
 import com.hurlant.crypto.symmetric.ECBMode;
 import com.hurlant.crypto.symmetric.BlowFishKey;
 import com.hurlant.crypto.symmetric.ICipher;
 import com.hurlant.crypto.symmetric.IPad;
 import flash.utils.ByteArray;

 public class Blowfish
 {
 /**
 * Encrypts a string.
 * @param text  The text string to encrypt.
 * @param key  A cipher key to encrypt the text with.
 */
 static public function encrypt($text:String, $key:String=""):String
 {
 try
 {
 var $output:ByteArray = new ByteArray();
 $output.writeUTF($text);
 var $pad:IPad = new PKCS5();
 var $cipher:ICipher = _getCipher( $key, $pad );
 $pad.setBlockSize( $cipher.getBlockSize() );
 $cipher.encrypt( $output );
 $cipher.dispose();
 return Base64.encodeByteArray( $output );
 }
 catch ($error:Error)
 {
 trace("An encryption error occured.");
 }
 return null;
 }

 /**
 * Decrypts an encrypted string.
 * @param text  The text string to decrypt.
 * @param key  The key used while originally encrypting the text.
 */
 static public function decrypt($text:String, $key:String=""):String
 {
 try
 {
 var $input:ByteArray = Base64.decodeToByteArray( $text );
 var $pad:IPad = new PKCS5();
 var $cipher:ICipher = _getCipher( $key, $pad );
 $pad.setBlockSize( $cipher.getBlockSize() );
 $cipher.decrypt( $input );
 $cipher.dispose();
 $input.position = 0;
 return $input.readUTF();
 }
 catch ($error:Error)
 {
 trace("A decryption error occured.");
 }
 return null;
 }

 /** @private builds a Blowfish cipher algorithm. */
 private static function _getCipher( $key:String, $pad:IPad ):ICipher {
 return new ECBMode( new BlowFishKey(Base64.decodeToByteArray( $key )), $pad );
 }
 }
}

Implementation of this Blowfish utility class is extremely easy. Just import the class, then call its static encrypt() and decrypt() methods. The first param of each method is the text to encrypt, and the second params are the encryption key. When decrypting text, you must provide the same key that the text was originally encrypted with. Here’s a sample implementation:

import Blowfish;
var $key:String = "lockme";
var $encryption:String = Blowfish.encrypt("Don't read this text!", $key);

trace( $encryption );
// return: "sm63oSsAgk0T8TWad0vjRMv5KV7COH80"

trace( Blowfish.decrypt($encryption, $key) );
// return: "Don't read this text!"