*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
No comments:
Post a Comment