Archive for the ‘Files on the Web Server’ Category

Anatomy of a Web App

Tuesday, October 4th, 2011

Hello! Time to dissect the application I’ve mentioned several times already: Cruz.

Long before starting Cruz, I had built many, many software applications. Some used sophisticated requirements, design, and configuration management techniques. Others, not so much. This one falls into the “not so much” camp.

But Cruz, like many other applications I have built, has very sophisticated programming. With me, that’s just the way I do things. I take pride in my programming skills, and I will go the extra mile to develop to a high level the engine of any game I create.

Cruz is a Flash game. Many Flash games are rich in graphical and sound content, but they lack programming sophistication. Inability to program forces many designers to act at the mercy of whatever tools or engines others have built, which further limits the types of games they can create. Could a graphical designer who knows little about programming create something like Cruz? Well, read on, and see for yourself.

System Components

There are six main components of the Flash application:

  1. Flash file (Cruz.swf)
  2. Graphical content (embedded in Flash file in this case)
  3. Audio content (MP3s loaded at run time)
  4. Level design data (XML files in “Cruz” format)
  5. Server-side scripts and storage (PHP and text files)
  6. Client-side savegame, progress, and config info (Shared objects)

The Flash file is loaded first, usually as an embedded object in a web browser, with graphical content loaded automatically. The audio content is loaded in two contexts: the sound effects at the beginning (a preloader precedes the title screen), and the musical tracks on an as-needed basis.

The level design data is loaded on an as-needed basis per episode, which is only when the user starts a game for a particular episode. The server-side scripts are used when handling high score update and retrieval operations. The savegame, progress, and config info are periodically updated and saved by the Flash environment on the client side.

If you’re building a Flash application, there’s a good chance you won’t need to touch the XML API, or write server-side scripts, or use shared objects. You might not even need a preloader, choosing to embed everything in the SWF. This keeps everything simple, but it limits what you can do, programming-wise.

If you’re building a game designed to give the user a full experience of rich content, savegames, and high scores with competition from everyone in the world, the “web application” way to do it is substantially different from the “home PC” way to do it or the “game system” way to do it. Different APIs, different components, different implementations of components.

But the underlying programming effectively does the same stuff, no matter what the platform is. You have load operations, save operations, ins, outs, etc. Business logic is business logic in any language.

Classes and Programming

What about the programming for Cruz? Well, as managed applications go, there is little to the imagination. Let’s look at what Cruz implements for unique classes:

  • utils: Low-level utility functions, such as sign, absolute value, random chance, etc.
  • IPoint: Coordinate pair of integers (x and y).
  • Dir8: Eight-directional calculation functions and lookups; useful for 2-D gridded games.
  • FxCont: Field effect container class (a rectangular region with specific game properties).
  • objid: Enumerated constant and name lookup container for game object types.
  • fxid: Field effect and level feature lookups.
  • SF: Special flags-per-grid-cell storage and lookup.
  • SaveGame: Represents savegame data.
  • CruzOptions: Represents configurable options for the game.
  • Game_Characters: Storage and functionality for ASCII-noir characters used in background text.
  • RandInfoArray: Grid randomization functions.
  • CruzMedal: Storage and functionality for medals (unlockable achievements found in various parts of the game).
  • Sounds: Storage and functionality for sound effects and music.
  • PathCalc: Mouse click-to-move path calculation functions.
  • MsgParser: Special object message parsing class; used with tablets and special items.
  • GPlayer: The main character’s object (the player).
  • iobj: Individual game objects, capable of interaction. A single GPlayer individual is always present as the first individual.
  • rtobj: Real-time object, representing a short-lived, animated object in the game that does not interact with anything.
  • cruzparse: XML parsing functions for translating level design content into game data.
  • game: The main gameplay class. This covers most general gameplay business logic and functions.
  • cruz: The main interfacial class, controlling Flash-specific API operations and API callbacks, such as user input, timer, load complete, etc.

If I were writing in C# for a PC game, the class layout would look the same. If I were writing in C++ for a game console, the class layout would look the same.

With three exceptions, that is: enumerated constants, polymorphism, and server-side handling.

Enumerated constant definitions will look a bit different across languages. The differences across C++ and Java alone are pretty substantial. Enumerated constants are not directly supported in ActionScript, not even in AS3. If you want to make a constant, you must declare it as a named static constant in a class. I ended up doing this for fxid, objid, and SF classes, to name a few.

ActionScript does not support virtual functions. Even if you derive from a base class, you must cascade functions manually at every level of function implementation. This is annoying. For this reason, some objects, like iobj, were not broken into individual subclasses.

Server-side scripts are necessary for Flash applications that want to maintain a central data repository; there is no dedicated client-side API for handling server-side data. The PHP scripts are very simple. All that the scripts do is take HTTP requests from the Flash application and fire back resources at the application. Just a little text file cooking, that’s it.

Special considerations

As far as the class implementation is concerned…well, it’s here where software engineers earn their pay. I have been programming for well over a decade. It takes skill to know how to properly use arrays, vectors, integers, floating point numbers, and strings. A surgeon can show off the anatomy of a rat, but he can’t tell the lay observer how to sew the rat up so that he instantly knows how to make it live and breathe again.

So I won’t go into the detailed design and cover every function in Cruz. Not today, at least. But I will discuss a very important aspect of programming for web applications: respecting the fact that what you are creating is a web application.

Decades ago, we never would have dreamed that so many of these web applications would conduct advanced calculations in the background. That’s what a client-side web application usually is: a background application. It can be an advertisement, or a game, or a slideshow, or a fundamental user interface needed to enter data into a form. Regardless of what the application is used for, it should be expected that the user’s computer will be doing other things than paying every bit of attention to running your web application.

This means that slack needs to be built into timing routines that might have demanded precision otherwise. Synchronization of animation frames and timer ticks is not guaranteed. CPU performance could be drained by a computer function not even remotely related to the web browser or its applications. The user might destroy your application’s operating environment at any time by closing the window, forcing you to update shared objects or call server-side scripts at key moments to avoid data loss.

Oh, and one final hiccup: the gargantuan task of making Cruz, a cutting-edge netted AS3 application, resemble the gameplay and timing mechanisms of Kroz, a non-netted Pascal application, written over 20 years earlier without any event-driven programming.

Now you know what went into Cruz. Web applications aren’t necessarily easier or harder to program than general-purpose applications–they’re just different.

But in some ways, they’re the same as ever.

A Game Resurrected!

Wednesday, June 8th, 2011

Hello; it’s been a while. There hasn’t been much to say on the formatting blog, since I’ve been busy working at GD and making the game engine Cruz in my spare time.

This is the subject today: Cruz, and its level design format. Pictured below is a screenshot of “Return to Kroz” played in the Cruz engine. As you can see, the game turned out rather well.

Cruz

Others seem to really like this game. You can play it at one of these locations:

http://www.chriskallen.com/cruz/
http://www.newgrounds.com/portal/view/569388

Moving beyond “amateur-experiment” games into “pro” games is something I’ve wanted to do for a long time, and it appears I’ve met success with the Cruz demo: I have successfully resurrected the Kroz series from the annals of DOS history.

CruzEditor, the subject of my last post, has not changed much. The game itself just reads the XML content created with CruzEditor. The devil, of course, is in the details of the XML content.

ActionScript 3 provides a robust API for parsing XML. You can reference individual branches of the XML “tree” via dynamic properties. For example, if XML has encapsulated an attribute of an element called “stuff,” you can access it from the top-level XML object by writing in the code “outer.inner.element.@stuff” without having to wade through string parsing routines or numerous “get” API functions.

Okay, but how does one store the level design content for Cruz, let alone all the Kroz games?

Of the eight Kroz games made by Apogee, each one was its own executable. Having a single application take on the level set-up responsibilities for all the games, each with its own subtle variations on format, was a big challenge. I have written a whole technical article about all the Kroz/Cruz differences here:

http://www.chriskallen.com/cruz/differences.html#differences

I decided that a hybrid of the original level design formats for Kroz and my own additions would be suitable. The character encodings for ordered levels would stay the same (with the exception of text), the unordered levels would be encoded as individual named assignments (not the hard-to-read DF assignments in the original Pascal), and level/episode features would have their own containers to allow for basic design tweaks, such as gravity, terrain growth, quake drop type, whether level was sideways, etc.

The advantage of the format is that it is way more manageable than before–as human-readable XML, it allows for no misunderstanding of what is represented.

The disadvantage is that the content is a lot larger than the original Kroz binary-encoded data. This might have been an issue 10 years ago, but with people streaming video to their computers, a few hundred kilobytes no longer matters as much.

Load times are reasonable for Cruz. Oddly enough, the John Wilson “Hidden Caves of Kroz” episode, which I had nothing to do with, has very long load times for some levels. I suspect that game’s metadata is handled much less effectively.

That there was no modding community for Kroz was disappointing. With CruzEditor, we can develop such a community–one in which anyone can write their own Kroz adventures. Finally!

Popularizing the series once again will be easy, too. Before Cruz, basic attempts at porting Kingdom of Kroz II had been done, but not the entire series. Now, at last, gamers can play the entire series online, including the mother lode of Kroz adventures, Lost Adventures of Kroz!

Of course, you can’t build a modding community if the moddable game isn’t good. Generally speaking, people don’t mod stuff that sucks, because it doesn’t become popular. So, I didn’t just simply recreate Kroz when I made Cruz–I gave it a big overhaul in terms of engine.

ASCII characters have been replaced with actual sprite models. Animation is now much better. Sound effects are mostly the same due to nostalgia, but there are a few new ones as well. Timing is controlled and reasonable, which was a big problem with Kroz games as CPU speed increased. And most important of all–I wrote an entire musical score for the game, something Kroz didn’t have originally.

There is one thing missing from this whole enterprise–the author’s blessing. You might wonder why I’d do all this without consulting him?

First of all, I didn’t think I needed any sort of official go-or-no-go from 3dRealms. The source code was released as Freeware, and I picked it up and ran with it–my own way.

The other reason is that they probably don’t care much about the Kroz franchise anymore. At this time, it seems like they’re actually going to release Duke Nukem Forever, after a decade of anticipation. Who cares about some stupid, outdated text-mode game that has aged terribly and means almost nothing to modern gamers?

Answer: I do!!

Local File Manipulation with Flash

Monday, March 1st, 2010

For the last several months, I’ve brought myself up to speed on the Flash platform. This a very common environment for the creation of animation, movie clips, and games that are designed to play in an embedded application. This usually means a web browser.

I find Flash useful for game programming, because it’s cross-platform and doesn’t require a separate download. Give someone a link, and -BAM- they’re playing the game. That’s all you need.

But (and there’s always a “but”)…

What about loading and saving of data files to secondary storage?

The general trend for language runtime development is to add more features, give more flexibility, run on more target platforms, etc. Basically you start small and conquer more territory over time. For Flash, it’s no different: it used to be just a sandboxed environment with arcane scripting, focusing mostly on the animation side of things. Then animation expectations got bigger, with a third dimension. Then people wanted more high-level language features; AS3 is now a lot more akin to Java than ever before. Then people wanted full control over files, local and remote. And control over cookies. And the ability to network remotely. And the ability to–

Whoa, whoa, whoa, whoa! Slow down! Are we talking about a sandboxed environment anymore? It seems like you can do anything from Flash now, including program viruses that infect the moment the animation plays! That’s a risk that Adobe has realized and tried to mitigate.

The Flash security settings are actually designed with a lot of foresight. The Adobe AIR platform, created to act as a Flash-based runtime on the server, can do just about anything with files, much like Java, .NET, Perl, or PHP. If your web server supports AIR, the sky is the limit.

But an SWF in your web browser is another story. The sky is NOT the limit–you can only climb a few feet up the mountain if you’re not using AIR. If a Flash SWF file is run as an embedded control in the browser, you don’t have as much control over networks or files. Mainly:

1) Accessing client data, like cookies, is much harder.
2) Network-based communications face many restrictions (can’t “bot” users who run SWF files).
3) Files can be read with URLRequest, URLLoad, etc. But writing to them is nearly IMPOSSIBLE.

Point #3 has been the biggest disappointment to me in terms of game programming. Writing back data to the web server, even if it’s just a dopey high score list, is WAY harder than I think it should be. But it’s also understandable. Flash is an animation platform–Adobe wants to keep it that way. Would-be virus programmers be damned.

But…what if I just want to make an online level editor and save my work that way? You mean I can’t even do something as simple as fopen, fwrite, and fclose in the same freaking directory as the SWF?

I’m a resourceful sort of person. I didn’t want to believe Flash was so restrictive. And it turns out, it’s not.

There are roundabout ways to save data. The Flash security settings, by default, let you access HTML pages and data files in the same directory as the SWF. You just need to be tricky about how you “read” a file.

In the case of http://www.chriskallen.com, the answer lies in PHP. The following Flash code uses sendToURL to “load” a PHP file. But notice that we’re putting a GET variable, text1field.text, into the URL:

function xferClick(e:MouseEvent):void
{
//Compose URL.
var urlstring:String = text2field.text;
var varstring:String =
"?parameter=" + text1field.text;

//Send request (don't check result).
var myrequest:URLRequest = new URLRequest(urlstring + varstring);
sendToURL(myrequest);
}

This means that we’re loading a dynamic web page–a PHP web page–by virtue of a custom input in a GET variable. Unlike non-AIR Flash, PHP can manipulate files locally. As part of the web page “load,” the server-side PHP script gets executed, causing the GET variable to be “saved.”

The SWF can read the data back by invoking URLRequest. No problem!

What does the user see when sendToURL is invoked? Depends on the browser. Since HTTP is stateless, the user might notice that the status bar indicates web traffic. Nearly invisible web traffic, but to be sure, it’s there.

I’ve got my strategy for loading and saving files. Yours can be the same, or it can be much different. You could use Perl instead of PHP. You could install the AIR runtime on the web server, if you have that ability (I don’t). You could use ASP or JSP. The list goes on and on.

Did someone say something about a sandbox?