How I ported Anodyne, my Zelda-like game, to Android from Flixel (AS3), FlashDevelop, and Adobe AIR – in a few days, and for free!

In this post, I (Sean Hogan/seagaia) discuss how I ended up porting my in-development game, Anodyne, from its Desktop Adobe AIR version into an Android app by using FlashDevelop, and then how I implemented touch input using Adobe AIR’s APIs.

Two GIGANTIC MEGA-HUGE caveats

1. Anodyne has only a few controls that are at least a little natural for mobile interfaces – essentially the Game Boy with no select button. Without a doubt, that made this port very easy, the mappings for the controls were obvious.

2. Anodyne is also letterboxed (meaning there are empty margins to the left and right when I center the game on a landscape screen) because it has a 160×180 resolution (scaled accordingly). That made it easy to pick where to put the UI elements for controls.

YOUR MILEAGE WILL DEFINITELY VARY depending on what your game is, the resolution, etc. I’m not claiming you’re going to get some awesome 60 FPS app running Flixel which doesn’t use the GPU. In any case, hopefully this will be helpful in getting started in the right direction. I fucked up in quite a few ways doing this (more on that at the end ūüôā )

So, you’re making a game in FlashDevelop, and have made it work as an Adobe AIR app and it works great on the desktop. Awesome! (If you don’t, stop reading here and go see the earlier tutorial¬†on how to do that).

The discussion has a few parts:

1. Stuff you need to even do this

2. An explanation of the build scripts

3. How to get game onto phone

4. How I managed touch input.

5. How I fucked up before figuring this out

 

1. STUFF YOU NEED

  • Buy an Android phone/tablet. (Sorry. Emulators tend to be a miserable experience)
  • Windows (well…)
  • Start a new “mobile app” project in FlashDevelop.
  • Make sure you have at least the AIR SDK 2.6+ (By default, FlashDevelop should install with this)

2. BUILD SCRIPTS

There are a number of setup files packaged with FlashDevelop. If you started a fresh project, all of the IDs and paths should be okay. What I did was copy these scripts to my current project and rename them and edit their paths/etc. to make everything work. If you go that route, things will break at least 100 times, but in small, easily manageable ways (provided you don’t panic!). Namely, a lot of scripts call other scripts, so if you change a script’s name, you will need to change all references to that script in the other scripts.

Here are the scripts:

  • Run.bat Depending on what goto is uncommented (lines 7-11), this will run the game in a certain way. You may as well do Desktop for the fastest compile/test – tantamount to the normal build process -, or else you’ll have to transfer to your phone every time using some awful sockets library and sometimes you get mysterious errors and it takes 10 minutes to transfer a 45 MB file to your phone…but I digress
  • PackageApp.bat – This takes a SWF that FlashDevelop puts out, and then puts magic sauce on it, turning it into a .apk that your phone will run. If you want to test, pick [1] normal (apk) , or else on your phone the AIR Debugger will try to start, and then everything goes straight to hell.
  • bat/InstallAirRuntime.bat – If your phone is connected, then this script will detect it and install AIR on it. Or you could just download AIR from the Google Play Store.
  • bat/CreateCertificate.bat – This will create a certificate, which is needed to package your SWF as a .apk .
  • bat/SetupApplication.bat – This just sets up a lot of environment variables – name of your certificate, path to your game’s icons, application descriptor name, etc. Most of this is filled in by default.
  • bat/SetupSDK.bat – Sets up the paths to your FLex SDK and Android SDK. Most of this is filled in by default, though if you use different SDKs you will need to edit the paths (not that scary, I swear!)
  • bat/Packager.bat – Called last in the packaging process, does some magic and turns your game into a .apk , provided you did everything else right…

They’re actually relatively straightforward if you start from one of them and trace through what it does.

Anyways, once that’s all in place…you can try putting the game on your phone.

3. Getting that game on the phone

  • 0. Build your game in RELEASE mode.
  • 1.¬†Run PackageApp.bat . If all the scripts are set up fine, you should get <name of app>.apk in the dist folder.
  • 2. Open up your phone. Download ES File Explorer and Adobe AIR Runtime.
  • 3. Connect your phone to your computer, and drag the .apk file to your SD card or whatever
  • 4. Open up ES File Explorer on your phone, and click on the .apk file to install it, open it, etc. Game should run!

Note that your users will still need to download AIR on their own. There is a way to package AIR with your app, but you must use AIR 3.0+ and pick [3] captive in the PackageApp.bat build script. Note that Google Play Store apps have a size limit of 50 MB (stupid, right?) so keep that in mind. Additionally, Android will tell the user they need to download AIR if they don’t have it, so…

Also I don’t know shit (yet) about getting it into the store but I assume that’s relatively straightforward.

4. How I ported the game after dealing with all that bullshit

Things you will have to deal with in porting

  • Resolution issues. Game might not fit. Etc.
  • Space and Time issues
  • How to handle your UI, for different screen sizes, keep the game feeling okay.
  • Mapping touch input into whatever control handler you’ve programmed.
  • Phone events

Resolution issues

Well, the market is full of phones of different sizes. Luckily you can scale the game relatively easily ¬†– check the stage object of your game, stage.width and stage.height will give you the full-screen sizes of the phone. Then from there just scale your main display object accordingly…you will have to choose how this works. Perhaps you show more of the game (if appropriate) or you just scale the game in cases where that would be totally inappropriate (as in Anodyne).

What I did: Anodyne fits nicely at 3x on most phones, though I’m planning to have options to center the game at an integer scaling (to avoid ugly pixels stretching). I will offer the option on tablets to integer scale to the max at first (this is what I do with the PC version – by default it stretches to the max integer scaling). The letterboxing margins are used for GUI elements.

Space and time issues

The phone is not your PC. If you’re lucky you might have 1 GB of RAM, and a few cores…but in general, if you’re using a CPU-based library like vanilla Flixel you probably won’t have performance as great as on your computer.

AIR/Android also seems to do something weird with space. As a reference point, Anodyne takes up ~40-50 MB of RAM running on PC (most of that space allocated for music), but 90-100 MB on my phone. Just little things to keep in mind – hacks you might get away with on the PC might not help on mobile devices. There are plenty of AS3 libraries that take advantage of the GPU, but I have no knowledge of how to use them.

What I did: Anodyne is luckily not very expensive – not too many sprites on the screen at once, logically it’s in a 160×180 px grid…so this wasn’t a problem for me.

Different icon sizes

Be aware of different icon sizes for phones and tablets! There’s a handy screen size chart here:¬†http://help.adobe.com/en_US/air/build/WSfffb011ac560372f-6fa6d7e0128cca93d31-8000.html and of course Google will let you find anything you want.

What I did: For Anodyne, I picked the average screen size and made the icons for the controls GUI fit something a little smaller. For larger (tablet) screen sizes I might make bigger icons – you can just dynamically choose what you want based on the screen size of the phone.

Mapping touch input…

Okay,well, to be honest, the difficulty here will lie entirely in how you manage your input. Anodyne gives an object to handle input, and then that object changes state based on the inputs – it has state variables for a button being down, just pressed, just released. Since I use flixel, I normally have the FlxG.keys… API calls to check the state of various things, and then I set the appropriate property on my input handler. This lets me use the input handler state throughout the game without worrying about what actually happens in the logic.

Thus, it was straightforward to map touch input to movement – just define what touch events should map to what. Anodyne has the following, done with only the following events. I added a listener to the stage object for these three events.

TouchEvent.TOUCH_MOVE РFired once per tick when a touch is on the screen. Useful for managing movement.

TouchEvent.TOUCH_END – Fired once, whenever a touch input is “lifted off” of the screen. Useful for stopping movement.

TouchEvent.TOUCH_BEGIN – Fired once whenever a touch input begins. Useful for attacking, pausing, moving around menus.

Note, that for the most part, Mouse move, mouse down, mouse up events – work the same, which makes them useful for debugging without sending the app to your phone every time. Keep that in mind!

HANDLING MOVEMENT

  • In short, I define “directional hitboxes”¬†for an “up”, “down”, “left”, “right” region. Some of the hitboxes overlap (so Up, left, etc) because we want diagonal movement. I position these on the screen, and then when a touch_move event comes in, I check the event’s “stageX” and “stageY” properties. If the event’s coordinates are in a directional hitbox, I then tell my input manager to have the “is this key pressed” state set to true for that direction.
  • If the touch is moved to a a deadzone, then all directional input stops.
  • There is an edge case, when a ¬†player lifts their finger off of a hitbox, for this, you need to add a listener for a¬†TOUCH_END¬†event, if there is a TOUCH_END event inside of one of the directional hitboxes, then stop all input.

In this early screenshot of the gui, you can see the directional hitboxes on the left, action hitboxes on the right. Notably, some of the directional hitboxes overlap, so I can have diagonal movement. I later moved the directional hitboxes closer together to have less of a “dead zone” where no input is registered.

ACTIONS

Menu movement: Just add a TOUCH_BEGIN listener. If the position of this event is in one of your hitboxes, then set the “just pressed” property of that key to true in your input manager.

MOVEMENT AND ACTIONS WORKING TOGETHER

Because I need movement to stop when there is a touch-move event not in a directional hitbox, we need the move events on the right side of the screen to not affect the left side. Just keep a state variable for what side of the screen the directional hitboxes are on, and then in the event handler for the TOUCH_MOVE event, ignore anything on the wrong side based on your state variable.

REPOSITIONING GUI

People will want to move with their Left or right hands, or flip controls…I just keep some state variables and when needed flip the positions of everything. There are a million ways to do this so I won’t bother explaining.

—-

Handling phone events

When you get a phone call or accidentally hit back/home, you don’t want to crash the game or keep the volume on.

Just listen for Event.DEACTIVATE and Event.ACTIVATE events Рhappens when game enters or exits due to whatever reasons. Add them to the stage object. For me, in DEACTIVATE , I just call SoundMixer.stopAll() to stop sounds, and then try to pause the game. Exiting your game should be through some other method through your menu, where you can just call NativeApplication.nativeApplication.exit();

Note that you will want to add actual icons and hide the hitboxes. That’s what I did, at least – so I can have gigantic hitboxes for the input but smaller icons to look nicer, and they can exist independently of eachother.

5. HOW I FUCKED UP

1. You don’t need to install some Android SDK or fake-phone manager if you have a phone already. Nor do you need to use the adb thing to transfer files…just drag and drop with a USB cable. Much faster. I did so much of this and it was a huge waste of time.

2. For the love of god, don’t add separate event handlers for every single hitbox. I had 16 at ¬†one point, one for each cardinal direction, because of all this stuff going wrong with touches lifting and…just don’t. What I have above is much simpler.

Those mistakes cost a lot of hours but NOW I KNOW and SO DO YOU.

…And that’s it!

If you liked this, check out my game, Anodyne , maybe even play its demo .

Or you know, follow me on Twitter, 

-Sean Hogan

Making a Flixel game work cross-platform

It’s been a while. I swear that second design post will appear someday.

One of the many things I’ve been doing recently while working on Anodyne is to get it able to run on Mac, and Linux. Doing it for Windows and Mac is incredibly easy with Flashdevelop, as they set up all the scripts for you. Problem is that it works with AIR 3.1 by default, which is a no-no for Linux. So, adventure time.

I think it might be helpful for others who have to deal with this crap later, so here’s a quick guide on getting your flash game, or swf or whatever, packaged with Adobe AIR, IF YOU USE FLASHDEVELOP AS YOUR IDE.

“I want to make my game playable on EVERYTHING with an AIR Installer!”

Great. Just make a project template for “AIR AS3 Projector” project. Copy-pasta your source from the folder you usually build.

Now before you do anything else…

Guess what? AIR only works on versions 2.6 and earlier for Linux. This means you get to jump through some hoops. If you have a recent version of Flashdevelop, you probably have the Flex 4.6 SDK + AIR 3.1 SDK. This is no good.

Go download the Flex 4.5 (and only 4.5) SDK, and unzip that shit into flashdevelop’s Tools folder.

Project -> Properties ¬†-> SDK -> Manage -> Click on Installed flex sdks -> click on the “…” -> add -> enter the path (should be “Tools\your-folder-here”).

If you did everything right, close and open that properties dialogue box, and you should be able to choose an SDK with Flex 4.5A and AIR 2.6.

Great! One more thing. Make sure you open “application.xml” and change the namespace to 2.6. There’s a thingy at the top of that file that probably says 3.1, change it to 2.6. Now everything will work.

Congrats, you are almost done. Build your project to test it with the Debug AIR thingy, if that works, you’re golden – just run the certificate-gen script, and then run the package script (the one in the same level as the application.xml).

And boom, you have a magic AIR installer you can send off anywhere. Magic cross-platform support, hooray.

Getting sprites and maps into Anodyne

In this short post I want to talk a bit about how my game, Anodyne loads things like the dungeon and the enemies. We’re on IndieDB now, so check that out as well.

There’s an earlier post that goes into more specifics with the XML, although this post covers it as well.¬†, which was written when I was doing this groundwork back in March.

First we have the ideas that need to be implemented – after I design some dungeon rooms or program some enemies, it’s time to put them into the map editor, which is a way to make your levels and export them into data that the game can use to create the actual areas. The map editor I use is DAME, which works well with Flixel, the AS3 framework I use for Anodyne.

The game’s maps are tiled in the editor and export to plain text in the CSV format – just lines of comma-separated numbers which correspond to specific tiles.

The CSV is then read by the game, and in conjunction with a tileset .png image file, creates the in-game environment, and additionally sets properties for tiles – such as callbacks (for holes), or whether or not you can walk on the tile.

The entities (treasure boxes, enemies, etc.) are also placed inside of DAME, but instead export to XML. There’s an earlier post on the specifics, but each map in the game exports a bunch of sprites for that map, as well as some metadata that I use in-game to give certain behaviors, and also the x and y coordinates. In the game, there are “field” areas and “dungeon” areas.

In field areas, the camera moves with the player, much like platformers. These areas are more for transitory, open-world like places. Currently, I just spawn all the sprites at once, which obviously isn’t very efficient. I don’t want to waste time optimizing what works fine, so if I reach the point where performance takes a hit I’ll probably stick in a distance metric that determines whether I bother updating a sprite, that has some timeout to see if the sprite should be revived.

Anyways…on to the dungeon areas.

The dungeon areas are a little more interesting. Although the entire map CSV is loaded into memory, only two 10×10 chunks of tiles are actively being drawn at once, and only sprites from one 10×10 section are being updated, to increase performance.

When you first enter a dungeon area, the initial chunk is loaded, and that’s where the player is instantiated. Then, I set a few bounds where if the player crosses them, we freeze the controls, load the next chunk into memory, and pan the camera to the next room. This way, I only need to maintain 3 tilemap objects, one, which contains the entire map in memory stored as an array, which makes it easier to obtain chunks for the 10×10 rooms. And then two 10×10 chunks because we want the previous room to still show when scrolling – so when we transition rooms, the current map buffer sends its data to a previous map buffer, and the current map buffer loads the next map.

The sprites also have to be arranged a little differently to load them on a per-room basis, so once at the start of the game, we take the very wide XML tree, and determine what sprites fall into which rooms, and create subtrees for each room. This way when we enter a room, we just lookup that tree and instantiate all of its entities.

During a transition, I also move all the old sprites from the room being moved out to another array so that they still appear, and I then clear them out of memory once the map completely moves over. This way we don’t have an awkward disappearance of all the enemies in one room as we transition, and we additionally see all the entities in the next room as we transition.

The entire game’s XML is serialized, as the XML stores the state of enemies that are needed to be permanently dead (bosses), or entities that need to stay open forever once opened (gates, locked doors).

This means that updating a released version isn’t really an option, as we’d need a way to patch the game’s XML tree. Oh well. But it’s not like I want to release a game that isn’t content complete, so it’s not really an issue, I’d hope. Will just have to be careful with save bugs, which we will hopefully iron out in testing and so forth.

That’s the general idea for all of the dataflow, and there’s not much magic going on. Maybe later I’ll talk about how some of the basic entities work and communicate, which also isn’t particularly complex since only a limited set of entities actually interact with eachother, by design, for simplicity. Or, how I go about bosses, or the player interactions…hm.

 

If you’d like to know anything very specific about this process let me know and I’ll write something up about it!

follow me to see if i finish Anodyne.

Inspiration Dave, finally finally done.

Done as in released on the interwebs for real. The past 2 months have included sponsor branding/ads – first time I’ve done it, zooming in the game because it looked too small earlier, playtesting it way too many times, fixing a difficulty curve, crushing edge-case bugs of hell, fixing some glitch with the scores, and removing that performance issue.

But it’s over. Time to move on. Well, I have already been moving on, but in full ūüėõ

I think I’m going to go do homework for the time and deal with everything later. Hope it gets frontpaged on NG and passes judgment on Kongregate x__x

May expand this to talk about more later, but this is a milestone for me, even if the game doesn’t do very well. Because it’s F-I-N-I-S-H-E-D.

 

If you some how got to this blog without seeing the game, play it here and help it get out of judgment hell on Kongregate: http://www.kongregate.com/games/Seagaia/inspiration-dave

 

or give it a vote at NG!

http://www.newgrounds.com/portal/view/595009

 

Or discuss on reddit.

http://www.reddit.com/r/IndieGaming/comments/t9fad/i_finally_released_my_platformer_inspiration_dave/

http://www.reddit.com/r/WebGames/comments/t9r1f/inspiration_dave_a_timed_platformer_with_short/

Well, this is embarrassing.

This is a story that happened today…after using Flixel, an AS3 game framework, for a good number of months.

So, garbage collection in flash/as3 or whatever. AFAIK, garbage collection is an algorithm object-oriented programming languages implement in order to free up memory that had been allocated earlier. In some ways, a more friendly alternative to the malloc/free of C we (maybe) all know an dlove.

Flixel works in these objects called “FlxStates” which, in some ways, act as things you can stick objects you want to display in. Say I switch from a menu to the world map, which are both modeled as FlxStates. I had naively assumed that in doing so, Flixel ¬†would have marked all of the objects I added to it as null in its call to the FlxState’s destroy(), so that they would be freed from memory by the garbage collector. To my surprise, today I pop open the code for FlxGroup (the class FlxState extends)’s “destroy” method and…

public function destroy():void {}

oh, shit.

For some reason since memory management isn’t so explicit (see: C programming language) in as3, I somehow assumed that flixel would deal with the marking of ¬†things as null, but this is behavior that has to be customized.

Using a framework, really the only things that I allocate that AREN’T added to the FlxState are arrays of strings or whatever. So it was just a straightforward exercise of null’ing the objects in the FlxState one by one when switching states.

And that fixed everything…more or less. Before, at least 20-30 MB were being allocated whenever I entered a stage, some of that being freed (or reused? not sure) when I re-enter stages. Of course, that adds up over time, although on full one-sitting test plays I never noticed a problem. Probably because we’re so spoiled with memory nowadays… ūüôā

Anyways, a game I had worked on for a few months now runs a few FPS faster than I ever thought it could. Luckily, this didn’t cause too much problems with the game design I made while playing it slow.

So, rookie error. But better late than never, right?

Ludum Dare 23 – “Naos”, a postmortem

This past weekend I made a game, “Naos”, for Ludum Dare 23, around the theme “Tiny World”. If you haven’t played Naos yet, you should do so now, the blog post will make more sense.

http://www.ludumdare.com/compo/ludum-dare-23/?action=preview&uid=7853

The sound.

Aesthetics were very important for me in this jam game. So I tried to pick carefully what kind of music I wanted to write. The game wasn’t supposed to represent a wholly realistic thing, so the music sort of reflects that in a haunting/minimal way (the organ-like house loop, the chime-like thing in the forest). The more action-like piece at the cliff helps to show that there is some action going on there (i ended up redoing this one the most…). As for the intro/ending thing…I couldn’t really think of a fitting melody, so I added some fancy-ass white noise that I thought fit.

I like the chimes piece the most, and would like to expand upon that. I feel like part of it was definitely influenced by listening to the Fez OST ( http://disasterpeace.com/ )way too much over the weekend Рespecially with the bitcrushing it uses, which I felt I may have overused in a place or two. Two pieces in particular I found salient were Spirit and Nature.

https://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F44156155 Seagaia – Songs from Naos (Ludum Dare 23) by seagaia

Graphics style…WHY? MY EYES!

Admittedly the game’s blur was a bit much. I did think it suited the quiet/haunting/ethereal-esque nature of the game, though. I wanted to try the scribbly style. Spending more time would have of course improved…well, everything. In a normal setting they wouldn’t be that rushed, I’d use a tablet, etc. Right now, it looks just good enough to not seem completely sloppy. (But is, still, of course, sloppy :P)

I was playing a lot with BitmapData objects in AS3 (surprisingly for the first time…why? I don’t know…but now I’ve got a level of comfort). They more or less represent what will be drawn to screen. And you can do interesting things like pull out certain color channels, transform them, and superimpose them on the original graphic. Or, you can blur things at different levels. The way I did blurring wasn’t ideal, I surely could come up with a more plug-and-play way of doing it, rather than the somewhat terrible way I have now (at least it’s organized terribly), which was to copy the sprite’s data, and keep some external data that determines how much to blur it – essentially, I have a copy of the data – I copy it to the displayed sprite, blur it, draw that to the screen, etc. The same idea goes for the color offsets. I played around until it looked okay.

I also played with a new logo for Seagaia today. It shows up on the intro screen. I like it. It’s a bit of a rip-off from. It was fun to make, at least the top part. There’s this nice thing in GIMP where you can copy and paste every other row, and then you make it a bit transparent, modify it a bit and superimpose it to get this neat shadow-y effect.

oh so how was the coding

Straightforward for the most part. Every room was a different state, with its own events and so forth.

Became an ugly mess near the end with the event coding since I haven’t figured out a nice way to do events with flixel yet…want to definitely figure that out. I’ve been asking around a bit, but not much in the way of detailed cutscenes. x_x

Since I already talked about the graphics coding, the only really interesting aspect was the events. How do they work? Well, for one, it helps to draw a tree of your dependencies with state variables. For example, “E_CLIFF_2” represents the 2nd cliff cutscene, “DRAWING_1_DONE” represents finishing the second drawing. And so every iteration of the game loop, depending on what screen we’re in, we check to see if we need to start an event. Essentially, events just freeze character controls, and wait for some condition (my player’s x being at some point, pressing x to advance text) to occur. Each event has an “event_pos” variable that is incremented when that condition is true, bringing the event to the next part (text, movement, whatever).

While this method works for a game jam, it doesn’t really scale well (see the other game I’m making) when it comes to moving many sprites that you don’t want to have to hard code into the game…and it’s a bit hard on the coder with the repetitive switch statements (see. https://github.com/SeanHogan/seagaiald23/blob/master/src/CliffState.as¬†JEEZUS.)

An interesting bug resulting from this was that I didn’t nest one of the “if you press x increment the event counter” things deep enough, so if a player pressed X before they should have on the forest screen, you would be frozen when you actually pressed X over the right thing. Thanks to my friend Runnan for showing me that issue…gah!

One way this could have been done better is to have only checked for events once upon entering a screen, or have had some single “an event happened” variable to be checked, rather than all of these conditions on every iteration of the game loop. While this is okay because performance didn’t really become an issue here, it would be something to think about in some sort of later implementation.

so what the hell was this about?

it’s a secret! well, a few people have messaged me on NG about it, surprisingly. My interpretation of it is more or less solidified, but it’s interesting to see other people’s takes on it as well. In lieu of not looking all pretentious, i won’t write about it here. but if you’d like to know, shoot me a message.

that’s all for now.

if you found this interesting, you should follow me on twitter . http://www.twitter.com/seagaia2

sprite placement in new game.

I wrote earlier about wanting to have certain sprites (enemies, locked doors, etc), have state that is persistent in a number of levels – screen-local (respawning when leaving/entering a room), map-local (enemies don’t respawn tiill you leave a dungeon and re-enter), and global (bosses stay dead, unlocked doors stay open!)

I kind of figured out a way to deal with this. ¬†I never sucked it up to figure out some stuff with the wonderful DAME exporter (an awesome map editor for flixel/flashpunk/etc games) and its lua exporter business…but then I did, sort of, at least enough to make it kind of do what I wanted.

Every map I make is split into grids, because that’s how I want the camera to work. I also only want to load sprites on a certain grid. Currently when I export the sprites from DAME, they end up all under one XML <level> node. This is fine, but on a big map when I want to load certain sprites for a grid, I’d have to calculate every single object’s grid x and y coordinates!! Although that would probably work fine, that’s not as nice. So, I did the following:

After embedding the XML from DAME into my game, I iterate through its <level> nodes (remember, level nodes just correspond to contiguous “areas” in my game – perhaps a floor of a dungeon, someone’s house, etc.). I create a new XML (one that will be serialized/saved and later checked to determine state of a room) object, and create a new <level> node. For every object (enemy, door, etc) in the <level> node of the DAME XML, I convert its x and y coordinates into grid-coordinates, so [0,screen_width) -> 0, [screen_width,2*screenwidth) -> 1, etc. I check if I’ve already added a <grid> node to my new <level> node, if so, I append the object to the grid node, otherwise, make a new grid node, append it to the level node, and append the object to the grid node.

Conceptually I guess this wasn’t too unwieldy, but it took a little time to figure out the syntax and what not.

This DAME-generated XML:

<root>
	<level name="Dungeon_Test">
		<Slime x="96" y="32" p="1" alive="true" />
		<Slime x="128" y="32" p="1" alive="true" />
		<Slime x="80" y="32" p="1" alive="true" />
		<Slime x="176" y="224" p="1" alive="true" />
		<Slime x="224" y="368" p="1" alive="true" />
		<Slime x="80" y="256" p="1" alive="true" />
		<Slime x="16" y="336" p="1" alive="true" />
		<Slime x="32" y="352" p="1" alive="true" />
	</level>
	<level name="Area_X">
		<Slime x="80" y="80" p="1" alive="true" />
		<Slime x="0." y="32" p="1" alive="true" />
		<Slime x="16" y="112" p="1" alive="true" />
		<Slime x="48" y="32" p="1" alive="true" />
		<Slime x="48" y="80" p="1" alive="true" />
	</level>
</root>

is transformed to this XML (which will end up being serialized and used in the game):

<root>
  <level name="Dungeon_Test">
    <grid grid_x="0" grid_y="0">
      <Slime x="96" y="32" p="1" alive="true"/>
      <Slime x="128" y="32" p="1" alive="true"/>
      <Slime x="80" y="32" p="1" alive="true"/>
    </grid>
    <grid grid_x="1" grid_y="1">
      <Slime x="176" y="224" p="1" alive="true"/>
    </grid>
    <grid grid_x="1" grid_y="2">
      <Slime x="224" y="368" p="1" alive="true"/>
    </grid>
    <grid grid_x="0" grid_y="1">
      <Slime x="80" y="256" p="1" alive="true"/>
    </grid>
    <grid grid_x="0" grid_y="2">
      <Slime x="16" y="336" p="1" alive="true"/>
      <Slime x="32" y="352" p="1" alive="true"/>
    </grid>
  </level>
  <level name="Area_X">
    <grid grid_x="0" grid_y="0">
      <Slime x="80" y="80" p="1" alive="true"/>
      <Slime x="0." y="32" p="1" alive="true"/>
      <Slime x="16" y="112" p="1" alive="true"/>
      <Slime x="48" y="32" p="1" alive="true"/>
      <Slime x="48" y="80" p="1" alive="true"/>
    </grid>
  </level>
</root>

By this chunk of AS3 code (FYI, there are some static thingies from me playing around calling this function from elsewhere, also saveXML needs to be referenced globally)


[Embed (source =  '../xml/Seen.xml', mimeType = "application/octet-stream")] public static const EmbedXML:Class;
public static var embedXML:XML = new XML(new EmbedXML);
public static var saveXML:XML = <root> </root>;

public static function embed2saveXML():void {

    var savelevel:XML; //Will be a level node for our saveXML tree
    var o:XML; //Generic object XML
    var level:XML; //For each "level" (house/dungeon/whatever)
    var grid:XML; //Represents a "grid"
    var grid_exists:Boolean; // Set to true when an existing grid is found
                             // while iterating through some level's grids
    var name:String;
    var x:int; var grid_x:int;
    var y:int; var grid_y:int;

    //Every level corresponds to a floor of a dungeon,
    //a house, the world map, etc.
    for each (level in embedXML.level) {
        savelevel = <level/>;
        savelevel.@name = level.@name;
        // These are all the DAME objects.
        for each (o in level.*) {
            //convert XY into Grid X,Y.
            x = parseInt(o.@x);
            y = parseInt(o.@y) + HEADER_HEIGHT;
            grid_x = x / Registry.SCREEN_WIDTH_IN_PIXELS;
            grid_y = y / Registry.SCREEN_HEIGHT_IN_PIXELS; 

            // Append the object "o" to the grid node if it already exists.
            grid_exists = false;
            for each (grid in savelevel.grid) {
                if (grid.@grid_x == grid_x.toString() && grid.@grid_y == grid_y.toString()) {
                    grid.appendChild(o);
                    grid_exists = true;
                    break;
                }
            }
            // Otherwise, create a new grid node and append "o" to it.
            if (!grid_exists) {
                grid = <grid/>
                grid.@grid_x = grid_x.toString();
                grid.@grid_y = grid_y.toString();
                grid.appendChild(o);
                savelevel.appendChild(grid);
            }
        }
        //Finally, append the transformed level node to the serialized XML.
        saveXML.appendChild(savelevel);
    }
}

Is there a better way to do this? Probably! But this works…it seems. Of course, more attributes will have to be added and what not to deal with state, but this is a good base for that.

inspiration dave: platformer movement

A little background, first – I finished my first “real” Flixel game last week, “Inspiration Dave” – it’s a maybe hour-few hour long platformer driven by mechanics of par times and collectible items, as well as silly unlockable secrets…mostly a game to get my feet wet in starting and finishing a game…cutting my teeth, so to speak. Had to fit dev time in between all the schoolwork and obligations I’ve put upon myself, but I managed to put a good chunk of time in over the past 7/8 weeks. Possibly more than I spend on the other stuff. I’m hoping some sponsor will find it in their heart to host it before I give up and just throw it on a bunch of sites. But what matters is that I finished it.

Anyways, player movement. It was a fun thing to think about and implement.

Inspiration Dave started as my first ludum dare entry and attempt at making a game. It was terrible. The difficulty was ridiculously hard and the controls were static and merciless….but I thought it had concepts that could have been expanded on. Anyways, I mostly want to talk about the controls.

My first attempt at controls was this terrible kludge of if statements…it worked, sort of, but putting any sort of flexibility was a massive pain, so I just rehauled the whole thing as a state machine diagram. This was considerably easier. The controls are by no means perfect, but they’re decent for the game I think (You can be the judge if you play it some day!).

Dave has a few states – still, walking, running, jump from walk, jump from run, air drag after walk, air drag after run. By putting Dave in various states, I could transition to other states when certain conditinos are met, thus making debugging movement orders of magnitude more simple. For example, in S_STILL (still state), there are no buttons pressed. Dave has his normal standing frame. If left is pressed, we go to S_WALK, where input is handled – setting velocity to a predetermined number, and so forth. This is more or less how the rest of movement is handled. When Z is held, Dave enters S_RUN – jumping, S_RUN_JUMP, and letting go of directional keys puts you in the air drag state, where you’re slowed down horizontally in air.

These variables were tweaked until things felt okay. One of my biggest issues was figuring out how exactly to change velocity when Dave moves left and right in midair – in some platformers, the fairness of precision jumping (single width block to the next) is a matter of how well this velocity change is taken into account. If you just switch the sign on the velocity, suddenly you’re traveling the other direction and going to miss the platform and must mash left and right to land, if you don’t give enough velocity when switching, it’s easy to go too early or late and be screwed. ¬†I think I ended up using some sort of halved velocity with deceleration in my movement scheme. It seems to feel fine.

And that was movement.

A lot had to be tweaked to fit in with the level design – precision jumping between spikes is needed, and we need to give an intuitive way to control jump height, which was handled simply with variable jump height. This way, you can make a short-distance hop, or a short-distance jump over something high, etc.

Screen transitions, legend of zelda gbc games

So, a favorite set of games of mine has always been the legend of zelda GBC games (link’s awakening, oracle of seasons, oracle of ages – yes, LA was on the Game boy originally but they’re similar in gameplay mechanics/graphics)

Image

The game uses 16×16 tiles, and every room is 10 by 8 tiles. Pretty amazing if you ask me. Dungeons and the map are laid out in a grid of these 10×8 tile rooms. It’s quite elegant how they did this and managed to well, make it work on something so tiny. I’m pretty impressed!

I was interested in using a similar type of map system in my next game, and got thinking about what it would take to do in Flixel. Quite a fun problem to think about. Let’s see. These are my initial thoughts and attacks at the problem, maybe you’ll learn something too.

Requirements:

-Touching the edges of a map must push you a tile forward, but move the camera view an entire screen in the direction of travel.

-Enemies and events need to be able to be triggered. Unlocked doors must stay open, bosses defeated stay dead, etc. That is, each screen must be able to maintain state for some period of time

-Enemies/bullets can’t travel from one screen to the next.

Tackling this problem one step at a time:

1. Making the map appear. Using tilesets, just draw this in a map editor. For simplicity let’s say I’m going to use one tileset for my map tiles. Then I export this gigantic map as a CSV (comma¬†separated¬†values – like “1,2,3,4,4,4,4”) , which with a quick calculation probably wouldn’t be more than a couple hundred KB (assuming I have over 100 tiles, my screens are 8×10 tiles, and I have like a 1000 screens, which is probably overcounting by a bit). Not a memory problem, in any case. We can pick which of the tiles we want to assign certain properties. E.g., some tiles act as holes, some as spikes that do damage – we can either replace these tiles with sprites at draw-time, change their properties to be one way, etc.

A few caveats with this. Drawing the whole map is obviously a horrible idea, we don’t want to have to deal with that being redrawn constantly, and in any case it’s just inefficient. So, we’ll want to only show one part at a time, and maybe have neighboring grids in memory for easy drawing, which leads to

2. Traversing the map.

Ahead of time, we know that our screens can be represented as a grid of points – you might start at screen (4,2). Now, luckily, our screens are equal sized *and* grids! So, it’s just a matter of some array index trickery and we can pull out grid-sized chunks from our whole-map CSV. We might have small 80-member CSVs (10×8) of mappings to tiles, one for the current screen, and one for up, down, left, and right (if they exist). So, we’d create tilemaps out of these CSVs and have them drawn. ¬†When we want to move screens, we just push our character a tile forward, and move the camera an entire screen in whatever direction. Watch a video of zelda to see how this works. It visually works quite well and you can’t really tell that your character has moved completely across the screen!

Once you’re in the new map, of course you will trash those other tilemaps from memory, and find your new neighbor tilemaps, and load those into memory.

It’s kind of like your traversing a building, but you only really can see parts at a time and process that visually. If we had to process every thing in the building at once, even though we’re not there, that would be tiring!

3. Dealing with sprite generation.

In a screen , we’ll have enemies, one-way doors, locked doors, NPCs, etc. I’m not sure 100% how I want to do this. I could create a tilemap that maps tiles to certain enemies. That is how I did pills/notes/doors/entrances in my previous game. That might be annoying on my end because I would have to hand-code this mapping. But it wouldn’t be TOO annoying. However, I would end up with an enemy/sprite whatever CSV map the same size as my map-map. The other idea is exporting data to XML and parsing that instead, but maybe that would take up more space in the XML file. Not something to worry too much over, though. In some way, there will be a way to map sprites to tiles, etc.

4.  But what if we unlock a door? NOW WHAT? OR KILL A BOSS?

There’s a few ways to go about it. My favorite at the moment would be to store a dictionary into the save file for our “state” – it would have two keys, an “area’ and “subarea” key. E.g., “Dungeon 1, screen (2,3)”. With in it is just an array of objects. When you enter a screen, this array is generated from anything that holds state – a boss that may be alive at first, but dead forever later, a teleporter that is activated only past a certain event in the game. The state of tehse objects is saved as necessary, so if the boss is dead then I’d leave some data in my array saying that the boss should be dead.
How will this be made to work? Well, there are different kinds of sprites. There are sprites that don’t really have state – say a turnstile object, or a one way door. These things are *Always* where they are on the map, no matter what! Thus we don’t label them as stateful. A boss, on the other hand, will be “stateful” – is it dead? or alive?

So, we just take our array of numbers that maps to certain sprites. I’ll have to hard code whether a sprite is stateful, but if it’s not, we stick it on the screen. Otherwise, we look into our saved data for the specific screen’s ¬†“state”. If it doesn’t exist, this means we have visited the screen for the first time, and so everything should have ¬†default behavior ( a door should be locked, the boss should be there, etc.) If the entry in our large dictionary IS there, we use the state that we stored (maybe one door is open, a wall is broken,…)

This very well might be what I go with, it seems like it would work quite nicely. I shouldn’t need to store more than a few things per screen, anyways, so storage shouldn’t be an issue.
5. Enemies shouldn’t be able to move between screens! Or maybe they should for scary effects!

Not too hard. Just set bounds on where it can move based on what screen it spawns on. Maybe set “max/min x/y” value when you create the enemy object ,and don’t let it move outside. Likewise with bullets!

—–

So that lets us create dungeons, bosses, and some basic state. There is, of course, the question of how to handle global state (what dungeons are open? What events have I triggered? Etc), but that comes more into play with the actual game, I’d say.

An elegant way of handling events would be what to think about next, I think…

 

annnnd it kind of works, screen moving. I have a LOT to think about still, though,.

World maps and my platformer

A question I’ve been dealing with recently is how to handle designing the world map for my Flixel-based timed platformer. Why even deal with world maps as a level select? They strike me as important ways to engage the player with curiosity and a sense of exploring and adventure – a prime example would be almost any various ROM-hack of Super Mario World – in many ways, part of the fun is unlocking various levels to see what will pop up next. ¬†In addition, they’re incredibly fun to design and draw.

The over 80 level exits in Super Mario World made unlocking new paths a reward.

 

Rayman's World Map, with a wicked song to boot

 

 

Figuring out how to go about programming one in a clean way has been a bit of a challenge. The Flixel framework seems more than capable of allowing the programmer to do something like this. The new levels must be unlocked/animated when returning to the world map upon success, and player input must be paused – however, we’d like to have animations in the world map while the level is being unlocked.

I have two ideas for implementing this so far…

In my game, levels are unlocked via

A. gaining enough total pickups in the levels (An okay analogy might be the electoons in Rayman, except unlocking more stages than just Candy Chateau) will unlock special levels, and

B. beating a stage opens up an adjacent one.

I was thinking of maintaining a state variable for the World Map – ¬†something like “unlockingDone” or what not – which would work a bit like this. Beating a stage will modify a global-state count of the pickups. On the create() method of the World Map class, we can check to see if a new stage needs to be unlocked. If so, we can add it to an array, or perhaps queue of “things to unlock” – then in our update look, we simply set some state variable to prevent player input, and set timers so that after some time interval, pop something off of that queue (or just maintain an incremental index into the array), and animate it. That much seems simple, but I’m wondering how to store it. There seems to be two ways. The first would be to store every set of things to unlock as objects in an external Registry class – maybe “WorldMapObjects” – holding say, the level marker and two smaller markers forming a path to it. It could have an ID, and a boolean, “unlocked”. So when we load the world map, we automatically iterate through the WorldMapObjects and ¬†draw every unlocked thing to the screen.

The other way is to just maintain an array (in some global context) of “Levels unlocked”. So in WorldMap’s create(), you call this giant method that checks for every level being unlocked – ¬†we can also maintain an array, “Level *just* unlocked”, so if a level isn’t unlocked but was *just* unlocked, we add that level’s world map markers to a queue/array as before, yadda yadda.

Both solutions seem like they’d work, but perhaps the former lends itself to possible re-use, while the latter would be this hacky thing that “works”. Hm.

And of course there’s other cool things – the music, sound effects on the map, how to animate the text for level titles, hmmm…