New Developments

LostVectors.com Flash development is now Powered by Adobe CS5.5! What does this mean for fans of LostVectors.com? More awesome flash content, new games, and even games for mobile!

I’ve been using CS5 at work for quite some time now, but at home and for LostVectors.com I’ve been using CS3. Now with CS5.5 I’ll be able to publish games for mobile devices. I’m still experimenting and what I’ve found is that developing flash for mobile requires some extra consideration with respect to optimizing and dynamically adjusting content to fit various screen sizes.

As you may have noticed, I published a new game Omega Mega. This is sort of an experimental game that I hope to port to mobile in some form. I have already created a virtual thumb stick for touch screen devices and have a test version published to my android phone. I still need to do a lot of optimizing to improve the frame rate but hopefully in the near future I’ll have something on the Android Market.

As for Bowmaster Winter Storm, I took a break from development to get CS5.5 all setup and to develop Omega Mega. However I plan on continuing development soon with weekly updates as usual so stay tuned! And I know that “Winter” is not a very topical theme right now so you may see some interesting updates to the game leading up to this next winter when I plan on officially removing “beta” from the title.

Along with BWS updates you may see a new Space Game similar to the Space Combat Training Exercise 001 and Omega Mega games. I want to create a space shooter like Space Combat but with more stuff (weapons, ships, asteroids, upgrades). I created Space Combat 001 with an older version of Flash using AS3 which considerably slower than AS3 code. Omega Mega was an attempt to test the capabilities of AS3 code using similar functionality for the space ships in Space Combat. I’m pleased that I’m able to get increased performance with AS3 (with the help of some new optimization tricks I’ve picked up over the years). What this means for a space game is the ability to have more stuff (ships, lasers, asteroids) in the game which means even more epic space battles.

I got a lot of feedback from Omega Mega players wanting ship upgrades and the ability to shoot back. Stay tuned and you might see a new space shooter prototype. Perhaps I’ll call it “Omega Mega Vengeance” where you play as the son of the original Omega Ship commander who is taken captive by the factions who finally caught on to the fact that he kept blowing up everyone with The Omega. So now that they recognize your ship design and are hostile towards you on first site, you’re ship is now outfitted with laser guns. Of course, in order to have guns now you needed to sacrifice the use of The Omega so maybe you now drop mini-omega-bombs instead.

Expect to see new and exciting things on LostVectors.com coming soon! Enjoy your summer and stay tuned!

Planet Burster

Planet Burster! Defend your planet form spontaneously appearing planets. This is another Flash experiment for the mobile platform. This time it’s to test the touch functionality of the phone and how to detect and use touch events.

Get Adobe Flash player

If you have an Android phone with flash installed you should be able to play with this little toy by simply navigating to the following link using your phone’s web browser:

http://www.lostvectors.com/mobile/test6/

Note: this toy also works with the desktop because it detects whether or not to use touch inputs or mouse.

How to play:

Press or click anywhere on the screen, drag, then release. The velocity is fixed, so the dragging only effects the angle (the length of the drag line does not matter, except that you might find it easier to aim the longer the line is).

Technical Features:

Random Planet Generator: I used a set of layered clips to accomplish this effect. Layers: Ocean, Continents, Clouds, Polar Caps, Shading. The ocean, continents, and clouds have random color transformations and filters applied to get the random colors. I manually drew a set of continents in a long strip and then offset the strip and mask it using a circle outline of the planet (same for the polar caps and clouds). Just a few simple tricks and I get some pretty cool looking random planets. Some of the random planets look weird but occasionally they are very interestingly color coordinated.

Planet Burst Effect: This was also a major technical milestone that I’ve been working on in a different project that I integrated into this demo. I was inspired by the Tron Movie character death effects: how they broke up into a bunch of cubes. After studying and experimenting with the Bitmap, BitmapData and Matrix classes I was able to achieve cool burst effect. Many developers before me have already figured this stuff (the Bitmap and BitmapData classes have been out for some time now), but it was cool to finally get around to playing with these classes.

Screen Layout Autosize: If you rotate your phone the screen will automatically adjust. This toy will work on any screen size (it is not biased towards a particular phone).

Box2D Flash on Mobile Android

I recently started using an Android 2.2 OS phone which has Flash 10. I’ve been toying with developing simple demos to test out the Flash capabilities of the phone. Then I decided to test out a simple Box2D demo I made as a modification of the demo by plasticsturgeon. Box2DFlash is an open source Physics Engine. Check it out. I look forward to working with it more in the future.

The demo ran quite smooth on the phone surprisingly staying close to 30 fps.

Below is the demo, but to get the full effect browse to the link using an Android 2.2 phone with Flash 10 installed.

mobile link: http://www.lostvectors.com/mobile/test4

Get Adobe Flash player

Modifications to the original demo by plasticsturgeon.com:

– Click (touch) to full screen mode.
– Zoomed camera focused view that pans with the target body
– Bodies jump as soon as they fall asleep

Here’s another mod I created to test user control of a single body using keyboard input. Use WASD to control the focused body (W is Jump). Note: this demo is intended for desktop computer with a keyboard and not a mobile device.

Get Adobe Flash player

User Controlled Body Mod Features:

– Added “hero unit” user control of a single body using speed-capped impulse
– Detected edge collision to allow jumping only when grounded

To view this in it’s own window visit http://www.lostvectors.com/box2d/demo1

Resources:
Box2DFlash
Plastic Sturgeon Box2D Hello World Demo
Flash Sizing Zen

Jack-o-Lantern Maker

Get Adobe Flash player

Here’s a draft version of a Jack-o-Lantern Maker I made. I’m still adding to it. I will be adding more shapes soon. Stay tuned. Let me know what you think in the comments.

Controls:

Click and drag an item from the right side to the left side of the screen.

Click on a mode button along the bottom to change the mouse tool mode. To use a tool, click on the tool button then click on the piece you want to manipulate with that tool.

Tool modes (from left to right):
1. Drag Piece (click-hold-release)
2. Rotate Piece (click-hold-release)
3. Scale Piece (click-hold-release)
4. Flip Horizontal (click to toggle)
5. Flip Vertical (click to toggle)
6. Delete (click to delete)

Automagically Optimized Flash Graphics Experiment

There have been some questions as to why some of the graphics in Bowmaster Winter Storm are more detailed than they need to be (see this forum post). This prompted me to share my findings on Flash’s automagical ability to optimize graphics.

I’ve done various graphics performance tests and experiments over the years but haven’t really shared my observations. One of the tests was to determine how much the Flash player optimizes graphics on its own without the use of developer code (e.g. cachAsBitmap) or graphical modifications (e.g. Modify >> Shape >> optimize).

In this demo the frames per second is displayed to indicate performance. The native flash fps setting published for this animation is 35 so the fps reading will never go above this number.

The animations displayed use both lines (red) and fills (black) and have lots of point data (more detail than you can see at the default zoom level). The animations use both shape and motion tweens. The motion tweens change the scale, rotation and color properties. No code or graphics techniques have been used to attempt to optimize these animations.

What this experiment will demonstrate is Flash’s ability to optimize graphical performance without the use of any additional developer tricks.

These experiments require that you perform the steps mentioned in order to see the expect results. Specific results will vary depending on your CPU speed but you should still be able to notice trends.

Get Adobe Flash player

Download Source

Experiment 0: Observer Animation As-Is
Expected Results: FPS should be below 35
Conclusion: The graphics are too much for the CPU to process at the optimal speed.

Experiment 1: Off Screen Performance
Steps: click-hold-drag animation off screen
Expected Results: The FPS should jump up to 35
Conclusion: Flash does not use up CPU to render graphics that are off screen.

Experiment 2: Scaling and Performance
Steps: Click “reset” button. Scroll the mouse wheel to change the size of the animations. Expected Results: When the animation is made really small the performance increases. When the animation is made really big, the performance my also increase as other animations no longer fit on the page (similar to Experiment 1) or decrease as more detail is visible for the animation that is still on the page.
Conclusion: Flash optimizes graphical processing according to the size of the graphics. Even if the graphics are highly detailed natively, if they are made really small then Flash is able to use less CPU.

Experiment 3: Adjusting the Built-In Quality Settings
Steps: Click “reset” button. Click on the quality toggle button labeled “high” by default.
Expected Results: The performance will increase significantly (without moving or scaling the animation) as the quality setting is decreased.
Conclusion: Flash is able to reduce the processing load of graphics by reducing the quality of the graphics. What is significant about this is that the quality settings can be changed on the fly with a simple line of code. In other words, it is very easy for a developer to make a global change to graphics to improve performance without having to manually change the native graphics (which can be a time consuming process).

Summary

We can see that Flash does a lot to optimize graphics on its own. Flash seems to perform some sort of culling to reduce CPU load by not rendering graphics that are off screen. Flash also seems to optimize graphics that are still on screen but have been scaled down in size. It’s as if the extra detail that exists in the native graphics that is too small to see is not being processed by the CPU. And finally, we see that by changing Flash’s built in quality settings we can drastically change both the performance and graphical quality of a Flash animation.

Every project is different and it is no trivial task balancing quality and performance. If the project is light on animation but heavy on graphics then performance can be sacrificed to improve graphical quality. But with game development users want both. Game developers must determine how to spend their time (a limited resource) and understanding Flash’s built in graphical optimization functionality is essential for determining how to prioritize application development efforts.

Calling all Beta Testers

Bowmaster Winter Storm Beta is now playable if you haven’t noticed. The game is constantly evolving with new updates every Friday (so far so good). Due to the frequency of changes it is not always possible to fully test the game and sometimes new features cause new issues. It is because of play testers like you that report new issues (see contact form) we’re able to find and fix bugs before the game is fully released. For this LostVectors is truly grateful. However, if you want to be even more helpful here’s how.

Download and install the debug version of the Flash player for your preferred browser (warning: read on before installing):

http://www.adobe.com/support/flashplayer/downloads.html

This works similar to your normal player but in the event of an error a popup window will appear with detailed information about what caused the problem. You can then copy this message and send it with your bug report.

WARNING: If you choose to install this debug player your eyes will be opened to how often in general Flash content has errors. This means that you may see error popups when visiting other sites with Flash content. With the normal Flash browser plugin, any errors that occur are simply swept under the rug for no one to see. The application fails silently and in some cases the bug may not have a significant impact on overall functionality. These runtime errors can be the fault of the developer not handling error events such as loading errors, or it can be caused by traditional runtime bugs like null pointers.

If you choose to install the debug player you can always reinstall the normal flash player if you wish.

As always if you decide to report a bug then please be as specific about the situation when the bug occurred along with any instructions on how to demonstrate the bug.

localToGlobal, globalToLocal, locoToLoco

This week’s BMWS update is the result of some significant technical milestones both recent and past that enable the new Mage and Pikeman features. The new Mage magic shield and the Pikeman helmet features are brought to you by some nifty utility functions.

One of the significant challenges in flash games is being able to manage and use coordinate systems. Every MovieClip has its own relative coordinate space and may be a parent to any number of children MovieClips (each with their own coordinate spaces). To make maters more interesting, these MovieClips can be skewed, scaled and rotated independently meaning that their coordinate systems rarely lineup with the global coordinate system.

With respect to game objects represented by one or more MovieClips, it becomes tricky when you want to determine how to compare coordinate information from one game object to another. For example, the GameLevel MovieClip may contain a PikeUnit and within the Pikeman there are multiple body parts, one of which is a helmet. Let’s say that the Pikeman is in the middle of the GameLevel screen at position 1000 (out of a total width of 2000). The Pikeman’s helmet, however, exists in the Pikeman’s coordinate system and relative to the origin (where the feet are) the Helmet is at position -50,0.

The goal of this last BMWS update was to allow for armor parts to pop-off if the armor takes enough damage. The challenge is how do we take a helmet that is at position -50,0 and exists in the Pikeman MovieClip and place it in the GameLevel MovieClip as an independent object in a spot that is virtually the same spot but in a new coordinate system.

You can’t simply take the helmet and place it in GameLevel with “addChild” because the Helmet’s previous x/y coordinate values are preserved. So doing so will place the helmet at position -50,0 relative to the GameLevel’s origin which is at the top left portion of the screen and thus using GameLevel.addChild(Helmet) will place the helmet at the left edge and slightly below the top of the screen). We run into similar issues with respect to scale and rotation.

The key to solving this issue is understanding these MovieClip member functions:

1
2
localToGlobal(point:Point):Point
globalToLocal(point:Point):Point

The first function localToGlobal takes a point object that represents a point value relative to the local coordinate system of the “this” MovieClip and returns the same point as it relates to the global space (stage).

With our helmet example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// instance reference names:
// gameLevel is a MovieClip with stage unit coordinates
// pikeUnit is a MovieClip child of gameLevel
// helmet is a MovieClip child of pikeUnit

var helmLocalPoint:Point;
var helmGlobalPoint:Point;
var helmet:MovieClip; // shorthand reference

// helmet is a child of pikeunit which is a child of gameLevel
helmet = pikeunit.helmet;

// local point relative to the pikeUnit coordinate system
helmLocalPoint = new Point(helmet.x, helmet.y);

trace(helmLocalPoint); // outputs (x=0, y=-50)

// global point relative to stage coordinate system
// (same coordinate system as gameLevel in this example)
helmGlobalPoint = gameUnit.localToGloba(helmLocalPoint);

// the helmGlobalPoint is virtually the same spot visually
// but the values are relative to the global coordinate system
trace(helmGlobalPoint); // outputs (x=1000, y=524)

If you were to draw a circle at helmGlobalPoint its center point will perfectly line up with the visual location of the helmet.

So using these functions enable me to make helmets pop off the heads of pikemen.

When the unit’s helmet has no more hit points:
Step 1: make existing helmet invisible
Step 2: store the helmet’s local position, scale, and rotation information
Step 3: load a copy of the same helmet and update its scale, rotation, and position using the stored pikeman’s helmet information and converting those values to relative values in the GameLevel (stage) space.
Step 4: add the helmet copy to the GameLevel (make it visible).

The new helmet should now exist in its new coordinate space but appear to be placed in the same exact location relative to the pikeman’s head.

This example shows how you would convert from localToGlobal, but you may want to go the other direction in which case you use globalToLocal. An example of this seen when a projectile hits a mage’s magic shield.

A projectile exists just like a pikeman in the GameLevel space. When a projectile hits a magic shield it causes an energy shockwave to be displayed in a masked MovieClip. This visual effect briefly exposes the magic shield. In order to achieve this effect we must perform something similar to the helmet example but going from global coordinates to local coordinates. We now want to take a projectile’s global position and place a shockwave in a child clip of an MagicShield movieclip. Think of MagicShield as you would a Pikeman MovieClip in that it exists as a child of GameLevel. Placing a shock wave inside the MagicShield is like placing a helmet inside a Pikeman.

Understanding localToGlobal and globalToLocal is an essential fundamental Flash development skill.

The above examples show how to go convert points between local and global coordinate systems but what if you want to convert points from a local position in one DisplayObject to another local position in a different DisplayObject. This is often the case in LostVectors games especially. For example, the Space Combat Simulation Training 001 uses this concept for overlaying HUD indicators like the current target highlight box or the current target pointer arrow. The Space Combat game was especially tricky because game view uses a scrolling camera that can be rotated and zoomed (scale change) rather than a fixed view that uses the stage’s global coordinate system which is what Bowmaster does.

To help convert between two DisplayObject coordinate systems I created the following utility function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/***
 * @author Jason Reinsvold
 * Returns a point object that represents the x/y position of where pt is as a local point of
 * the toDomain. The fromDomain is where pt currently resides. The return newPt is the point
 * that exists relative to the toDomain but overlaps exactly with the pt with respect to the
 * global point coordinates.
 *
 * This function is useful for determining the equivalent point across different coordinate
 * systems. For example, if you have a UI window that is scaled and moved and you have a global
 * overlay highlighting system for drawing boxes over all objects. The overlay will draw boxes
 * relative to its own coordinate system but it needs to be able to determine what points are
 * equivalent to the UI window. This function helps with that conversion.
 */

public static function translatePoint(pt:Point, fromDomain:DisplayObject, toDomain:DisplayObject):Point
{
   var newPt:Point;
   newPt = pt.clone(); // clone point so that original point is not modified
   newPt = fromDomain.localToGlobal(newPt);
   newPt = toDomain.globalToLocal(newPt);
   return newPt;
}

This function first converts the input point relative to the “fromDomain” to a global point and then takes that new global point and converts it to a local point relative to the “toDomain”.

Also, this function is generalized such that it will act like localToGlobal or globalToLocal provided you pass the stage as either toDomain or fromDomain respectively (this is because one of the internal localToGlobal or globalToLocal calls returns the same point value, acting like a no op).

I also created similar functions to handle converting scaling and rotating but doing this was a bit more challenging because there are no built-in localToGlobalScale or localToGlobalRotation functions.

Bowmaster Winter Storm Bug Fix

An issue that caused some users to experience a dark black screen after purchasing upgrades has been fixed. Game on!

www.lostvectors.com/winterstormbeta

The issue was introduced in a recent update and had to do with the new “auto place skill into action bar after purchase” feature. This issue is fixed and the new feature works fine. Now when you purchase an upgrade that is a bow type skill (i.e. shoots a projectile) the skill is automatically placed in the next available slot in your action bar. So you no longer have to manually place it after you purchase it by clicking on the in-game skill book. You can still use the skill book and manually place skills, but this just eliminates any extra steps and makes it easier for new players to see and use skills they purchase.

AS3 Memory Fail

I’ve been too busy to update the devlog recently but I have in fact posted new content to Bowmaster Winter Storm every Friday for the past few weeks. Go check it out if you haven’t taken a look lately.

www.lostvectors.com/winterstormbeta

I’ve had some recent major triumphs, some mini defeats and mini triumphs lately. In the not so distant past I had some issues with a memory leak in Winter Storm. After much investigation and some thrashing I decided it was time to do some much needed refactoring. At this time I still had no real idea where the cause of the leak was.

My first step was to create a more formal process for handling event listeners. In AS3 I take issue with the lack of management functions that exist for working with events. The event model is much improved over AS2, but a few things caused some issues for me.

Function “removeEventListener” does not provide feedback on whether the operation was successful.

Ideally you would always call this function with the correct parameters to remove an event listener. However if you mistakenly give just a single incorrect parameter then the removeEventListener function call fails silently. The event listener that you though you removed remains in memory along with all of its attached references thus causing a memory leak.

for example:

1
myHugeObject.addEventListener("destroy", handleDestroy);

… later in the process, somewhere else in the code…

1
myHugeObject.removeListener("destroyed", handleDestroy);

Note: The event string parameter is the incorrect string. Syntactically there is no error. The program will compile. Not only that, but there is also no runtime error as well. Even though no such listener exists with the signature of event string “destroyed” and “handleDestroy” the function will not throw an error.

Even if you now do this:

1
myHugeObject = null;

The object remains in memory, now with no way to reference it, hence memory leak.

I was certain that I used removeEventListener responsibly and everywhere I added a listener I made sure to include a removeEventListener in a destroy function that was called when the object is no longer used. The problem was that I had made the mistake I described above. I found this out with the help of a custom event management class I created called EventManager.

Essentially I created a class to handle all event listener adds and removes so that all such operations could be audited for validity.

My syntax changed from:

1
2
myDispatcher.addEventListener("event", listenerFunc);
myDispatcher.removeEventListener("event", listenerFunc);

to:

1
2
EventManager.addListener(myDispatcher, "event", listenerFunc);
EventManager.removeListener(myDispatcher, "event", listenerFunc);

By funneling all event listener add and remove calls through this static class I was able to provide extra debugging feedback. For example, whereas before with removeEventListener if you attempted to remove an event listener that does not exist Flash would not care to inform you. With EventManager, if you call removeListener and it cannot find the listener you’re looking for a runtime error will be thrown.

EventManager essentially maintains a global registry of all event listeners that is now visible to the developer. I had to convert hundreds of calls to add/removeEventListner to use EventManager but it was worth it. With the added visibility and error checking of my EventManager class I was able to see when and if the registry was continually growing instead of staying within a certain size. And upon initially testing the fully converted code I immediately discovered a few listeners that were lingering and occasionally had runtime errors indicating that I was attempting to remove events listeners that did not exists.

So this was a major triumph in my battle against those evil pesky memory leaks. After fixing all the issues with event listeners I thought I was sure to see no more memory problems. While I did notice fewer memory issues, I still noticed some instances where memory usage would continue to creep up. It was then that I decided to revisit the method of disposing of application objects.

For all of my objects I have some form of “destroy” function that is called when the object is no longer needed and this function primarily just removed event listeners. I didn’t attempt to nullify references to other objects stored as member data within this object because I figured as long as my application didn’t refer to this object (i.e. store a reference to it) then garbage collection would eventually take care of everything.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class ObjectA
{
   public var m_objB:ObjectB;
   public var m_objC:ObjectC;

   public function destroy():void
   {
      // remove listeners
   }
}
class MainApp
{
   public var m_objA:ObjectA;
   ...

   public function startNewLevel():void
   {
      m_objA = new ObjectA();
   }

   public function showUpgradesMenu():void
   {
      // show upgrades
   }

   public function endLevel():void
   {
      m_objA.destroy();
   }
}

With this design, the ObjectA’s destroy function would only remove listeners. Also, in MainApp, the reference to m_objA is only overridden when startNewLevel() is called. Therefore even though endLevel() was called, if the next step is to call showUpgradesMenu() the user may be looking at new upgrades to purchase for a while before startNewLevel() is called. In the meantime the reference to m_objA still exists even though it’s destroy function was called, and within it exist references to instances of ObjectB and ObjectC.

I decided to take a more aggressive and proactive approach to freeing memory. I made the design decision to nullify all member data object references whenever  an object is destroyed and then also nullify the current reference to the destroyed object.

The new way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class ObjectA
{
   public var m_objB:ObjectB;
   public var m_objC:ObjectC;

   public function destroy():void
   {
      // remove listeners
      nullifyReferences();
   }

   public function nullifyReferences():void
   {
      m_objB = null;
      m_objC = null;
   }
}
class MainApp
{
   public var m_objA:ObjectA;
   ...

   public function startNewLevel():void
   {
      m_objA = new ObjectA();
   }

   public function showUpgradesMenu():void
   {
      // show upgrades
   }

   public function endLevel():void
   {
      m_objA.destroy();
      m_objA = null;
   }
}

You may think that just setting m_objA to null after the destroy() call should be enough, and for what you can see in this example it definitely would be, but in the context of a larger application there may exist other references to m_objA so simply nullifying it in MainApp will not guarantee that it is a candidate for garbage collection.

So I applied this design strategy to my game application. It was a bit tedious but worth it because a useful side effect of nullifying member references after destroying an object is that any other objects that may have been incorrectly using an object after destruction can no longer access public member data in the destroyed object. What happened in my game after I implemented this design was that the game application started to show runtime null reference errors everywhere in application was using a destroyed object when it wasn’t supposed to.

As part of a “design by contract” approach the game application is not supposed to use destroyed objects. This means that instead of checking “isDestroyed?” every time I want to use an object’s data, I make sure that the code doesn’t try to use destroyed objects in the first place. For instance, game unit AI is not supposed to target units that are destroyed, so when the application returns a list of all the closest enemies it makes sure to not return any “destroyed” enemies. The AI can assume the list of enemies it received consists of only “alive” enemies (a precondition for using the list). For the most part, I did a good job of ensuring that destroyed objects were not used. However, just like the event listener issues mentioned above, there were a few instances where I made mistakes.

So with a little bit of debugging and redesign I was able to not only improve memory usage efficiency but I was able to locate erroneous areas of my code. Since this design overhaul the game is running much more smoothly and previous failed memory tests are now passing and I now have a good infrastructure in place to prevent further memory issues. Now I can focus my efforts on more of the fun stuff like creating new content and game balancing.

Rest

Yeah, so I’ve been working a lot and have been writing several devlogs but haven’t had a chance to post them until now. In short, I’ve been so busy working that I tend to use every last minute of the night performing "just one more test." I’m taking this short break to post these updates. I recommend starting with Tell Me Where It Hurts Part Part 1 and then moving on up. I hope this squelches any concerns that maybe I was slacking off this month. Time for a break.