|
|||
|
Portfolio suggestions Lab 7: Critter rainbow Labs 1-2, Object style Lab 6: Critters Invaders improved Lab: Class invaders Object orientation KidsTeam project Portfolios revisited Revised syllabus Submitting card projects Preloading Object sound Timeline sound Class e-mail Teams Project ideas Greeting card project Lab: Scene Scroller Deluxe image browser Lab: Image Browser Random numbers Lab: Scripted Animation ActionScript basics Scripting and design Initial syllabus Course overview |
Lab 7: Critter RainbowConcept Here's a further evolution of our artificial life system: this time introducing variety or speciation to our simple bugs. As you can see, the bugs here now come in colors: red, green, blue, and gray. They still interact and reproduce as they did last week -- the code controlling those functions is basically unchanged, except for a few refinements. But now there's a twist added on the reproductive logic: if two bugs of the same color collide, they produce an offspring of that color; but if two bugs of different colors collide, the offspring is gray. If two gray bugs collide, the offspring's color is chosen at random. Colors of the initial parent bugs are chosen randomly, also. This introduces a deliberate flaw: if both bugs are the same color at start, there will never be any mutation. (Reload the page if that's what you see in the example below.) Can you think of a way to correct this problem? Architecture As before, there are two files in play here: a Flash source file called critterKinds.fla and an ActionScript 2.0 class file called Critter3.as. The Flash source file has the same characteristics as last week's: one layer, one frame, one Movie Clip in the Library. Root script in the source file The root script in the Flash file has some differences we need to consider. Here's the whole thing:
_root.population = new Array();
_root.serialNum = 0;
for(i=0; i<2; i++)
{
newBug = _root.attachMovie('bug','bug'+_root.serialNum,
_root.getNextHighestDepth());
_root.population.push(newBug);
_root.serialNum ++;
//assign color/kind
bugColor = new Color(newBug);
colorCast = Math.floor(Math.random()*3);
switch(colorCast)
{
case 0:
bugColor.setRGB(0x0000CC);
newBug.myKind = "blue";
break;
case 1:
bugColor.setRGB(0x00CC00);
newBug.myKind = "green";
break;
case 2:
bugColor.setRGB(0xCC0000);
newBug.myKind = "red";
break;
}
}
The population array and the serial number variable are carried over from last time. We're also still using that two-iteration for loop to generate the ancestor bugs. There's an important refinement in the bug-creation section. Instead of pushing the name of the new bug onto the population array, we push the entire object onto the array. This is a much better way to proceed, because it removes the necessity of converting object values to string values, and lets us directly assign properties of the object. Note that we use the variable newBug to store the object itself that we create with attachMovie(). This may seem strange, but ActionScript variables can indeed contain objects. More new code here handles the "kind" (coloration) of the bugs. ActionScript allows us to assign color to a Movie Clip by creating a Color object, which is attached to the Movie Clip through an argument in the constructor: bugColor = new Color(newBug); Again, notice that we're using that variable newBug to represent the newly created object. Once we've assigned a Color object to the new bug, we use the setRGB() method to assign a color value. That value is determined by random selection, parceled out through a switch statement. This is the first time you have seen switch. It's a streamlined way to handle multiple conditions, substituting for the chain of ifs we used before. Notice that we insert a break after each condition. Though it probably doesn't save much time here, the break statement is a standard part of the switch structure. Critter3 class As before, the major scripting in this project resides in the class definition. Most of the variables are brought along from last week's project. The checkString variable is gone, since this week we'll do our hit tests directly upon objects. A few variables are added: var myKind:String; var otherKind:String; var bugColor:Color; var newBug:Object; The two string variables myKind and otherKind store color values. Though we could just get the RGB values of the color objects attached to these Movie Clips, the strings encode the colors in English, making it easier to understand the program. We also need a variable to hold a Color object, and a local version of the newBug variable we also saw back in the main movie source, which is declared as Object (though it could also have been declared as MovieClip). The Constructor method of this class is identical to last week's example. Bugs come into the world in the same basic way, though they are assigned color/species identity shortly thereafter. Those details are dealt with within the enterFrame handler, to which we now turn. The "mortality" section is unchanged from last time except for one small but important improvement. You'll remember that when each bug dies, we scanned the population array to remove its name from the list. In this week's version, the population array contains not names but objects. So the comparison statement looks like this: if(this == _root.population[i]) Instead of checking this._name against an item in the array, we now check the object itself. The "Collisions and Consequences" section now looks like this:
contact = false;
for(var i:Number=0; i<_root.population.length; i++)
{
if(_root.population[i] != this &&
this.hitTest(_root.population[i]))
{
contact = true;
otherKind = _root.population[i].myKind;
break;
}
}
if(contact == true && contactClear != true)
{
bounceBack();
contactClear = true;
//MAKE NEW CRITTER
_root.serialNum ++;
if(_root.population.length < 20) //limit of 20 bugs
{
newBug = _root.attachMovie('bug','bug'+_root.serialNum,
_root.getNextHighestDepth());
_root.population.push(newBug);
bugColor = new Color(newBug);
//ASSIGN COLOR/KIND
if(this.myKind == otherKind)
{
newBug.myKind = this.myKind;
switch(this.myKind)
{
case "blue":
bugColor.setRGB(0x0000CC);
break;
case "green":
bugColor.setRGB(0x00CC00);
break;
case "red":
bugColor.setRGB(0xCC0000);
break;
case "gray":
randomColor();
}
}
else
{
bugColor.setRGB(0xCCCCCC);
newBug.myKind = "gray";
}
}
Again, we'e strealined last week's code by using direct, object-to-object comparisons in the collision tests; but that's the only difference from the previous structure. The additions here are essentially the same as the additions you saw in the main movie source: we use a newBug variable to hold the newly created object, and this allows us both to store the object in the population array and to assign the object a color. Also added in the collision-detection section is code that extracts the color value of the other object, stored in the variable myKind. Doing this allows us to create different reproductive consequences. When two bugs of different colors breed, their offspring is gray. When two bugs of the same color breed, their offspring inherits that color, unless both parents are gray. Gray bugs produce offspring whose color is chosen at random. The randomColor() method is very much the same as the random color selection (using switch) that you saw in the main movie's root script. Source Files You'll find the source files for the main Flash movie, critterKinds.fla, and the Critter3 class, Critter3.as, in the shared SDE folder on student-iat.ubalt.edu. Look in the idia610 directory, and within that, in lab07. Acknowledgements Various folks, notably including Roni Noone, have suggested improvements in this code base, particularly the use of object-to-object comparisons. I'm also indebted conceptually to an earlier project by Yoram Chisik, "The Peg People of Pago Pago Go Bumpus in the Night" (Spring, 2003). |
||
|
|||