Monday, July 14, 2008

Animated Gradient Masks (or how to thrash a cpu)








(use keyboard "x" to light and extinguish the firefly's light)

OK, two quick notes on this one before I start:
1) The details will make or break your project. When I studied architecture we learned that it's better to build 20% less building and put that extra time and money into the little details. You can't just shave 20% off your requirements, but the math is still the same. You really need to budget in the time for the little things. I say all of this as an apology for not paying attention to the details myself. Unfortunately, with these little examples I'm tossing up I just don't have time to do more than reach a proof of concept point, so you'll have to forgive me. For instance, I would have preferred to give the bug a little random drifting motion when stopped and to use scaling to allow it drift "up and down" as well. It could also use some buzzing wings. For the time being though we're just going to have to settle for seeing the masking work.
2) Animated Gradient Masks will KILL your CPU. Flash 10 will have access to the GPU, but I'm withholding judgment on whether that will be any easier on the CPU.

OK, on to the post: What I wanted to do with this one was to demonstrate how an animated gradient mask can do a great job of imitating uneven light flickering. A candle would have probably been more appropriate as a source (I don't think fireflies flicker that much) but hey, I wanted to do a firefly. The way this works is by first placing a darkened background on stage. After that, I create three light pools. The first two are very close in size, and shift positions slightly at a very high rate to create the flicker. The third has a wider radius and is more diffuse, giving a general lighting effect. For each of the three light pools I have a full copy of the background, this time brightly lit, added to the stage. Each of these instances has a mask applied to it by simply calling MovieClip.mask. Finally, I add an elliptical shape to each of the mask MovieClips, and apply a blur filter to that shape. I also set the alpha back to around 30%. This gives me my three dim, overlapping pools of "light" (where the bright versions of the background show through the mask). The two flicker pools are animated on enterFrame to create the flicker. The last thing to do is to have all three light pools track the firefly, which is as simple as setting the x and y of the elliptical shapes within each mask to the x and y of the firefly. I'll post some code on that a little later.

I'm going to reiterate that animating the gradient mask really pushes the CPU. Pull up your CPU gauge of choice and switch the light on and off while watching it to see how bad it is. This technique is best for temporary effects, such as flares. I've used it to show candles lightening then brightening a room. Once the general level of light gets high enough to drowned out the flickers I just removed them and saved that CPU. Hopefully the flash rendering engine will continue to improve.

Next up? I'm not sure. I have a lot of little things I'm working on, but something in the back of my head keeps nagging me to go ahead and build a game in Silverlight. We'll see...

Wednesday, July 2, 2008

TextFlow

TextFlow

I had absolutely nothing to do with Textflow, but I wanted to put it up here because it's a fantastic practical use of Flash. It's really worth checking out the demo. As a guy who spends a lot of time in both database design and working with RIA technologies this application is exciting to me. Check it out.

OK, I promise to update with some of my own work soon. I have one more flash movie I'll probably post in the near future (not counting updates to Bacterium) which will show how to create some seriously realistic lighting effects with animated alpha masks (yes you can), and then I may share some javascript fun.

Thursday, June 19, 2008

Bacterium (or: not really inverse kinematics)







Use arrow keys to control paramecium.

Keep an eye on this one, I'm going to be updating it several times. I just wanted to go ahead and put the first version out there. The idea on this project was to create something that moved a little bit like an amoeba or a paramecium might. In my mind that meant something that had a slightly larger head than tail, that was jointed in the middle, and that head a "tail" that sort of trailed along behind it in a blob like fashion.

So, to get things started I created a "bone" class. This class consists of basically two stored points with a line drawn between them, and a spring and friction setting. I added a couple of small boxes on the end of each bone just to make the joints more visible. There a several methods that can be used to animate each bone. The ends can be set directly, you can use a "pull" method in which one end is set directly (usually an anchor) and the rotation is a function of it's current rotation compared to it's anchor object's rotation, with spring and friction applied.

GeSHi © 2004, Nigel McNie


  1.     public function PullBone(sx:Number, sy:Number, sr:Number):void


  2.     {

  3.         SetRotation();

  4.        

  5.         var r:Number = sr - boneRotation;


  6.         if (r < -180) { r = r + 360; }

  7.         if (r > 180) { r = r - 360; }


  8.        

  9.         var ra:Number = r * (spring);


  10.        

  11.         rv += (ra);

  12.         rv *= (friction);


  13.         boneRotation += rv;

  14.  

  15.         x1 = sx;

  16.         y1 = sy;


  17.         x2 = sx + (Math.cos(boneRotation * Math.PI / 180) * initialLength);


  18.         y2 = sy + (Math.sin(boneRotation * Math.PI / 180) * initialLength);


  19.        

  20.         SetBone(x1,y1,x2,y2);

  21.     }




P.S. the code above is highlighted using GeSHi, which seems pretty cool so far.

If you look at the code above, you can see that it compares the difference in rotation between the bone and it's parent (anchor) which is passed in as "sr". We normalize that done to a number no greater than 180 and no less than -180. That's important to keep from getting some strange effects when the angles of either object change from 360 to 1 or vice versa. After that, spring is applied based on the difference in rotation, which will cause the bone to respond more strongly when it is farther out of line with it's anchor. Friction is used to slow the reactions over time.

The bone class is used by another class called "Paramecium". This class builds the little fella you see on screen using bones and a couple of circles. There isn't much magic in him. Most of it is in the bone class. The next step will be to add a couple of cross bones, or ribs, to the paramecium. I'll use those to curve a line around the skeleton I've built and fill it with an appropriate color or pattern. I can then add a couple of highlight graphics based on the circle or rib positions to make it look a little more "real", although photo realism is certainly not what I'm going for here. I just want something that would be appropriate for a game hero or villain.

Mostly what I wanted to do was to go ahead and get this beginning file uploaded. I'll refresh it soon and possibly change this post drastically as I do. In the end I think I'll get this guy doing exactly what I want, then translate into Silverlight to build a game around. I'm thinking Silverlight on this one because I've built tons of games in flash (and Shockwave, for those of you old enough to remember that) but I haven't built one in Silverlight yet.

Stay tuned, more to come...

Thursday, May 29, 2008

Actionscript 3.0 with Ballons and Wind (and Clouds, oh my)








*Note* I imported the vector graphics into Flash as bitmaps, which forced me to turn on smoothing for the animations, which makes the balloons look blurry. I will fix that as soon as possible. On to the regularly scheduled post:

When I work on a flash project one of my primary goals is to create something that will continue to be interesting, especially to me. With games, this means that being the one who wrote the code shouldn’t mean that the game isn’t still challenging to me. I should still be able to have fun playing it, and consequently it should have enough unpredictability that it will keep a certain replay value with it's audience (or at least I hope so). With scenes like the one above, it means making the elements react to random environment changes as opposed to looping a frame driven animation. It’s just more fun for me knowing that I’m never going to see the exact same scene twice, and I think it gives me more range in what I can create. The blimp and balloons above follows this idea. Everything in the scene other than the blue sky is controlled by script. With that being said, lets take a look at what's running the show here.

There are three classes at work in the scene above, a Balloon class, a Tether class and a Cloud class. The Cloud class was almost an afterthought. I decided the scene needed clouds to convey the motion better, so I put Cloud.as together. As it turned out, that make a huge difference in how the motion is perceived. So what does Cloud.as do? Basically, when a Cloud object is instantiated, it creates an array of 3 to 6 cloud images from a pre-populated library. Each cloud has it's alpha set to around 0.5 when it is instantiated. The first cloud is the “master” cloud for that group, and its size is randomly scaled. Its velocity is then scaled according to its size, so that smaller (father away) clouds move slower than larger (closer) clouds. The rest of the clouds in the array are scaled down in relation to the primary cloud, and given a *slightly* different velocity to create a shifting effect. I don't have the motions 100% prefect yet, but they are close enough to go ahead and post this experiment. The main movie is in charge of randomly creating clouds, adding them to the stage, and destroying them when they move off stage. The cloud instances are stored in an array so that they are easy to manage and remove. Quick Tip: when looping an array where you intend to remove items with .split, *loop backwards*. If you loop forwards you will end getting an error as item indexes change do to the removals. On to the Tether class.

The Tether class is the primary reason I wrote this. I wanted to play around with creating a string/rope/flexible thingy class that would react properly to gravity and end points. The class draws two lines, a main line and a highlight line, between two objects using Flash’s graphics methods. I'm not completely pleased with that yet either. Sometimes the main line and highlight line shift too much, and it creates a distracting "blinking" effect. That's irritating enough that I'll go ahead and fix it this weekend. The two lines are anchored by two objects (balloon objects in this case), which are passed in by reference, and curve through a third anchor point, which is where the real code in this experiment is concentrated: determining whre that point goes, and where it's control point should be. Placing the middle anchor point and its control point is handled by two functions. The first function determines how far to the left or right of center, on a line drawn between the two end points, to place the a middle anchor point. This determination is made based on the relative Y position of the two end points. To see what this is trying to emulate, hold a string between both hands, at an equal height, with enough slack to get a little droop. Now lower one hand. See how the lowest point (the curve) in your string shifts towards the hand that is lower? That is what we want to mimic. I did that with the code below:


private function GetAnchorPointPosition():Point
{
var spX:Number = _startPointObject.x + _spOffsetX;

var spY:Number = _startPointObject.y + _spOffsetY;
var epX:Number = _endPointObject.x + _epOffsetX;

var epY:Number = _endPointObject.y + _epOffsetY;
 
var slope:Number = (epY - spY) / (epX - spX);

var apDropY:Number = GetAnchorPointDropDistance();
var midPoint:Point = new Point(spX + ((epX - spX)/2), spY + ((epY - spY)/2));

 
// anchor point origin is determined as a percentage of the line between Obj1 and // Obj2 based on diff in height
var percentile:Number = (spY - epY) / _maxObjectDistance;
var lineTravel:Number = _currentDistance * percentile;

 
var cartAngle:Number;
cartAngle = Math.atan(slope);
 
var dx: int;

var dy: int;
dx = lineTravel * Math.cos((cartAngle * Math.PI / 180));
dy = lineTravel * Math.sin((cartAngle * Math.PI / 180));

 
var aPoint:Point = new Point(midPoint.x - dx, midPoint.y + dy + apDropY);
 
return aPoint;

}



The second function determines how far the line should droop, based on the distance between the two objects compared to the maxObjectDistance, which is fancy code talk for how long the rope is supposed to be (yes it is fancy code talk, the camel casing proves that).


private function GetAnchorPointDropDistance():Number
{
return _maxObjectDistance - _currentDistance / 2;

}


The Balloon class is pretty simple. It works on the same spring and friction ideas that you can get from the excellent book, ActionScript 3.0 Animation from Friends of Ed. I’ll go into more detail on this later. For tonight, I think this will wrap up my first post on Flash.

Ok, I lied, one more thing. Remember that good Flash work is a combination of design skills and coding skills. Avoid the temptation to rely completely on either of those. Being a code god will not make you a good Flash developer, and neither will being a design genius. The art counts, and the implementation counts. That’s what makes Flash (and soon Silverlight) fun. You have to bridge both worlds, and that's what this blog is going to mostly be about. Using both halves of your brain to create great design and interaction.

-- That Steve Guy