Flash AS2 - grouping enemies - algorithm

So I have a Flash ActionScript 2 code, which creates a preset amount of enemies, gives enemies stats, and makes them move around randomly. Code:
//Settings
var mapWidth:Number = 550;
var mapHeight:Number = 400;
var enemiesArray:Array = new Array();
var totalEnemies:Number;
var eClip:MovieClip;
//Math functions
function getdistance(x, y, x1, y1)
{
run = x1-x;
rise = y1-y;
return (hyp(run, rise));
}
function hyp(a, b)
{
return (Math.sqrt(a*a+b*b));
}
function resetDirection(mc:MovieClip)
{
mc.roamTime = random(50);
mc.t = mc.roamTime;
mc.roamDistance = random(60)+25;
mc.randomRoamDistanceX = (Math.random()*mc.roamDistance)+mc.xx-(mc.roamDistance/2);
mc.randomRoamDistanceY = (Math.random()*mc.roamDistance)+mc.yy-(mc.roamDistance/2);
mc.newRoamDistance = getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY);
mc.norm = mc.roamSpeed/mc.newRoamDistance;
mc.finalRoamDistanceX = (mc.randomRoamDistanceX-mc.xx)*mc.norm;
mc.finalRoamDistanceY = (mc.randomRoamDistanceY-mc.yy)*mc.norm;
}
//function to move enemies
function moveIt(mc:MovieClip)
{
//reduce roamTime;
mc.t--;
//move enemy to new position
if (getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY)>mc.roamSpeed) {
mc._x += mc.finalRoamDistanceX;
mc._y += mc.finalRoamDistanceY;
}
//rotate enemy
XXXdiff = mc.xx-mc.randomRoamDistanceX;
YYYdiff = -(mc.yy-mc.randomRoamDistanceY);
rrradAngle = Math.atan(YYYdiff/XXXdiff);
if (XXXdiff<0) {
cccorrFactor = 270;
} else {
cccorrFactor = 90;
}
//
mc.ship_mc._rotation = -(rrradAngle*360/(2*Math.PI)+cccorrFactor);
//check if time to reset, based on roamTime
if (mc.t<=0) {
resetDirection(mc);
}
}
//
// Generate Enemies
//
// set and save enemy stats
//
//
// createEnemies(number of enemies you want, movieclip where you want to create the enemies);
//
function createEnemies(amount:Number, targetLocation:MovieClip) {
trace("createEnemies: "+amount);
for (var i = 0; i<amount; i++) {
randomXpos = Math.round(Math.random()*mapWidth);
randomYpos = Math.round(Math.random()*mapHeight);
//add new enemy to map
var newEnemy:MovieClip = targetLocation.attachMovie("enemy1", "enemy1_"+i, targetLocation.getNextHighestDepth());
enemiesArray.push(newEnemy);
//
//set enemy stats
newEnemy.id = i;
newEnemy._x = randomXpos;
newEnemy._y = randomYpos;
//save x and y position
newEnemy.xx = newEnemy._x;
newEnemy.yy = newEnemy._y;
//
newEnemy.roamSpeed = 2
newEnemy.roamTime = random(50);
newEnemy.roamDistance = random(60)+25;
newEnemy.t = 0;
//
newEnemy.myHealth = 10;
newEnemy.myName = "Small Scout";
//
resetDirection(newEnemy);
//target enemy
newEnemy.onPress = function() {
trace("Enemy: "+this.tName+" "+this.id);
target_txt.text = this.myName+": "+this.id+" Health: "+this.myHealth;
};
newEnemy.onEnterFrame = function() {
moveIt(this);
};
}
}
start_btn.onRelease = function() {
if (start_txt.text == "Start") {
//run the create enemies function to start the engine
createEnemies(box_mc.numberOfEnemies.text, map_mc);
//hide start button
start_txt._visible =false;
this._visible = false;
box_mc._visible = false;
}
};
I want program enemies to be grouped (based on fireflies algorithm). My idea is write for loop to define attractiveness, but I don't know how to make my objects move to the most attractiveness. Maybe someone would help me with this problem?

I change this line:
newEnemy.myHealth = 10;
on this
newEnemy.myHealth = Math.round(random(9)+1);
myHealth would be responsible for attractiveness. I try to use code from this site and modificate code to let objects with low attractiveness follow objects with large attractiveness. Also, I want to stop algorith, when they are in the groups.

Related

Cocos Creator js animate sprite

I have animated a sprite using a sprite sheet and the update function,
like so:
Note: I have dragged the plist into the atlas field of the sprite node (the same node the monster.js script is attached to) in the Ccos Creator UI.
//monster.js
onLoad: function(){
// change monsters face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
}
update: function (dt) {
this.timekeep += dt;
if(this.timekeep > 0.1){
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
self.getComponent(cc.Sprite).spriteFrame = atlas.getSpriteFrame(self.faces[self.monstersN]);
});
this.timekeep = 0;
this.monstersN++;
if(this.monstersN > 4){
this.monstersN = 1;
}
}
It actually works fine. I have already thought I should export the cc.loader.loaderRes into the onLoad function and save the atlas as a global var instead of loading every time the update is called.
However…seeing that there are built in animation functions, this can’t be the correct solution. So I tried this:
onLoad: function () {
// change monster face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
var sprite = self.getComponent(cc.Sprite);
var animFrames = [];
for (var i = 1; i < 4; i++) {
var spriteFrame = atlas.getSpriteFrame(self.faces[i]);
var animFrame = new cc.AnimationFrame();
animFrame.initWithSpriteFrame(spriteFrame, 1, null);
animFrames.push(animFrame);
}
var animation = sprite.Animation.create(animFrames, 0.2, 100);
var animate = sprite.Animate.create(animation);
sprite.runAction(animate);
});
},
I get this error:
cc.AnimationFrame is not a constructor
So then I tried this:
onLoad: function () {
// change monster face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
self.atlasA = atlas;
});
var sprite = this.getComponent(cc.Sprite);
var animFrames = [];
for (var i = 1; i < 4; i++) {
var spriteFrame = this.atlasA.getSpriteFrame(this.faces[i]);
var animFrame = new cc.AnimationFrame();
animFrame.initWithSpriteFrame(spriteFrame, 1, null);
animFrames.push(animFrame);
}
var animation = sprite.Animation.create(animFrames, 0.2, 100);
var animate = sprite.Animate.create(animation);
sprite.runAction(animate);
},
I get this error:
Cannot read property ‘getSpriteFrame’ of undefined
How can I use cc.animate to change the sprite using the spritesheet I have. All I want to achieve is to move through the plist in the order the images are in the plist, repeated until the monster is put back into the pool it came from.
Here is the solution for anyone who may still be looking.....
cc.AnimationClip.createWithSpriteFrames([sf1, sf2, ...], fps)

Delete specific image from loader

I have three images all from the same loader on screen. I need to delete a specific (targeted) bitmap once clicked. I have an onClick function below, any help is greatly appreciated. Thanks!
var nb_images:int = 3;
var bmp:Bitmap = new Bitmap;
var img_margin:int = stage.stageHeight/3.5;
var img_request:URLRequest;
var img_loader:Loader;
var images_container:Sprite = new Sprite();
addChild(images_container);
function remove_all_images():void {
for (var i:int = images_container.numChildren - 1; i >= 0; i--) {
images_container.removeChildAt(i);
}
}
function load_images():void {
remove_all_images();
for (var i:int = 0; i < nb_images; i++) {
img_request = new URLRequest('../img/planet' + (int(nb_images * Math.random())) + '.png');
img_loader = new Loader();
img_loader.load(img_request);
img_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, on_img_loaded);
}
}
function on_img_loaded(e:Event):void {
e.currentTarget.removeEventListener(Event.COMPLETE, on_img_loaded);
bmp = e.currentTarget.content;
bmp.x = 600, bmp.width = bmp.height = 80;
bmp.y = images_container.numChildren * (bmp.height + img_margin);
images_container.addChild(bmp);
stage.addEventListener(MouseEvent.CLICK, onClick);
function onClick(event:MouseEvent):void {
removeChild(e.target);
}
}
load_images();
Okay, first thing I did here was remove var bmp:Bitmap = new Bitmap. You're creating a reference you don't really need, so let's get rid of that altogether.
Now, in your on_img_loaded method, you're going to want to create a new Bitmap for each loaded image.
var bmp:Bitmap = e.currentTarget.content;
Then, you'll need to add the event listener directly to an InteractiveObject rather than the stage. Bitmaps are not InteractiveObjects, so we'll need to wrap it in something else before adding the listener.
var sprite: Sprite = new Sprite();
sprite.addChild(bmp);
addChild(sprite);
sprite.addEventListener(MouseEvent.CLICK, onClick);
Finally, create a method to remove the clicked Bitmap from images_container (note here I removed the nested function - this prevents argument ambiguity and is generally good practice).
function onClick(e:MouseEvent):void
{
images_container.removeChild(e.currentTarget);
}
This is the relevant code in its entirety (untested).
//remove var bmp:Bitmap = new Bitmap from the beginning of the code
function on_img_loaded(e:Event):void {
e.currentTarget.removeEventListener(Event.COMPLETE, on_img_loaded);
var bmp:Bitmap = e.currentTarget.content;
bmp.x = 600, bmp.width = bmp.height = 80;
bmp.y = images_container.numChildren * (bmp.height + img_margin);
var sprite: Sprite = new Sprite();
sprite.addChild(bmp);
addChild(sprite);
images_container.addChild(sprite);
sprite.addEventListener(MouseEvent.CLICK, onClick);
}
function onClick(e:MouseEvent):void
{
e.currentTarget.removeEventListener(MouseEvent.CLICK, onClick)
images_container.removeChild(e.currentTarget as DisplayObject);
}
Hope this helps!

Why Is My Genetic Algorithm Terrible (Why Doesn't It Converge)?

I wrote a quick experiment with a genetic algorithm. It simply takes a grid of squares and tries to mutate their color to make them all yellow. It fails miserably and I can't seem to figure out why. I've included a link to JSFiddle that demonstrates working code, as well as a copy of the code in its entirety.
http://jsfiddle.net/mankyd/X6x9L/
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div class="container">
<h1>The randomly flashing squares <i>should</i> be turning yellow</h1>
<div class="row">
<canvas id="input_canvas" width="100" height="100"></canvas>
<canvas id="output_canvas" width="100" height="100"></canvas>
</div>
<div class="row">
<span id="generation"></span>
<span id="best_fitness"></span>
<span id="avg_fitness"></span>
</div>
</div>
</body>
</html>
Note that the below javascript relies on jquery in a few places.
// A bit of code that draws several squares in a canvas
// and then attempts to use a genetic algorithm to slowly
// make those squares all yellow.
// Knobs that can be tweaked
var mutation_rate = 0.1; // how often should we mutate something
var crossover_rate = 0.6; // how often should we crossover two parents
var fitness_influence = 1; // affects the fitness's influence over mutation
var elitism = 1; // how many of the parent's generation to carry over
var num_offspring = 20; // how many spawn's per generation
var use_rank_selection = true; // false == roulette_selection
// Global variables for easy tracking
var children = []; // current generation
var best_spawn = null; // keeps track of our best so far
var best_fitness = null; // keeps track of our best so far
var generation = 0; // global generation counter
var clear_color = 'rgb(0,0,0)';
// used for output
var $gen_span = $('#generation');
var $best_fit = $('#best_fitness');
var $avg_fit = $('#avg_fitness');
var $input_canvas = $('#input_canvas');
var input_ctx = $input_canvas[0].getContext('2d');
var $output_canvas = $('#output_canvas');
var output_ctx = $output_canvas[0].getContext('2d');
// A spawn represents a genome - a collection of colored
// squares.
var Spawn = function(nodes) {
var _fitness = null; // a cache of our fitness
this.nodes = nodes; // the squares that make up our image
this.fitness = function() {
// fitness is simply a function of how close to yellow we are.
// This is defined through euclidian distance. Smaller fitnesses
// are better.
if (_fitness === null) {
_fitness = 0;
for (var i = 0; i < nodes.length; i++) {
_fitness += Math.pow(-nodes[i].color[0], 2) +
Math.pow(255 - nodes[i].color[1], 2) +
Math.pow(255 - nodes[i].color[2], 2);
}
_fitness /= 255*255*3*nodes.length; // divide by the worst possible distance
}
return _fitness;
};
this.mutate = function() {
// reset our cached fitness to unknown
_fitness = null;
var health = this.fitness() * fitness_influence;
var width = $output_canvas[0].width;
var height = $output_canvas[0].height;
for (var i = 0; i < nodes.length; i++) {
// Sometimes (most times) we don't mutate
if (Math.random() > mutation_rate) {
continue;
}
// Mutate the colors.
for (var j = 0; j < 3; j++) {
// colors can move by up to 32 in either direction
nodes[i].color[j] += 64 * (.5 - Math.random()) * health;
// make sure that our colors stay between 0 and 255
nodes[i].color[j] = Math.max(0, Math.min(255, nodes[i].color[j]));
}
}
};
this.draw = function(ctx) {
// This draw function is a little overly generic in that it supports
// arbitrary polygons.
ctx.save();
ctx.fillStyle = clear_color;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
for (var i = 0; i < nodes.length; i++) {
ctx.fillStyle = 'rgba(' + Math.floor(nodes[i].color[0]) + ',' + Math.floor(nodes[i].color[1]) + ',' + Math.floor(nodes[i].color[2]) + ',' + nodes[i].color[3] + ')';
ctx.beginPath();
ctx.moveTo(nodes[i].points[0][0], nodes[i].points[0][1]);
for (var j = 1; j < nodes[i].points.length; j++) {
ctx.lineTo(nodes[i].points[j][0], nodes[i].points[j][1]);
}
ctx.fill();
ctx.closePath();
}
ctx.restore();
};
};
Spawn.from_parents = function(parents) {
// Given two parents, mix them together to get another spawn
var nodes = [];
for (var i = 0; i < parents[0].nodes.length; i++) {
if (Math.random() > 0.5) {
nodes.push($.extend({}, parents[0].nodes[i]));
}
else {
nodes.push($.extend({}, parents[1].nodes[i]));
}
}
var s = new Spawn(nodes);
s.mutate();
return s;
};
Spawn.random = function(width, height) {
// Return a complete random spawn.
var nodes = [];
for (var i = 0; i < width * height; i += 10) {
var n = {
color: [Math.random() * 256, Math.random() * 256, Math.random() * 256, 1],
points: [
[i % width, Math.floor(i / width) * 10],
[(i % width) + 10, Math.floor(i / width) * 10],
[(i % width) + 10, Math.floor(i / width + 1) * 10],
[i % width, Math.floor(i / width + 1) * 10],
]
};
nodes.push(n);
}
return new Spawn(nodes);
};
var select_parents = function(gene_pool) {
if (use_rank_selection) {
return rank_selection(gene_pool);
}
return roulette_selection(gene_pool);
};
var roulette_selection = function(gene_pool) {
var mother = null;
var father = null;
gene_pool = gene_pool.slice(0);
var sum_fitness = 0;
var i = 0;
for (i = 0; i < gene_pool.length; i++) {
sum_fitness += gene_pool[i].fitness();
}
var choose = Math.floor(Math.random() * sum_fitness);
for (i = 0; i < gene_pool.length; i++) {
if (choose <= gene_pool[i].fitness()) {
mother = gene_pool[i];
break;
}
choose -= gene_pool[i].fitness();
}
// now remove the mother and repeat for the father
sum_fitness -= mother.fitness();
gene_pool.splice(i, 1);
choose = Math.floor(Math.random() * sum_fitness);
for (i = 0; i < gene_pool.length; i++) {
if (choose <= gene_pool[i].fitness()) {
father = gene_pool[i];
break;
}
choose -= gene_pool[i].fitness();
}
return [mother, father];
};
var rank_selection = function(gene_pool) {
gene_pool = gene_pool.slice(0);
gene_pool.sort(function(a, b) {
return b.fitness() - a.fitness();
});
var choose_one = function() {
var sum_fitness = (gene_pool.length + 1) * (gene_pool.length / 2);
var choose = Math.floor(Math.random() * sum_fitness);
for (var i = 0; i < gene_pool.length; i++) {
// figure out the sume of the records up to this point. if we exceed
// our chosen spot, we've found our spawn.
if ((i + 1) * (i / 2) >= choose) {
return gene_pool.splice(i, 1)[0];
}
}
return gene_pool.pop(); // last element, if for some reason we get here
};
var mother = choose_one();
var father = choose_one();
return [mother, father];
};
var start = function() {
// Initialize our first generation
var width = $output_canvas[0].width;
var height = $output_canvas[0].height;
generation = 0;
children = [];
for (var j = 0; j < num_offspring; j++) {
children.push(Spawn.random(width, height));
}
// sort by fitness so that our best comes first
children.sort(function(a, b) {
return a.fitness() - b.fitness();
});
best_spawn = children[0];
best_fitness = best_spawn.fitness();
best_spawn.draw(output_ctx);
};
var generate = function(spawn_pool) {
// generate a new set of offspring
var offspring = [];
for (var i = 0; i < num_offspring; i++) {
var parents = select_parents(spawn_pool);
// odds of crossover decrease as we get closer
if (Math.random() * best_fitness < crossover_rate) {
var s = Spawn.from_parents(parents);
}
else {
// quick hack to copy our mother, with possible mutation
var s = Spawn.from_parents([parents[0], parents[0]]);
}
offspring.push(s);
}
// select a number of best from the parent pool (elitism)
for (var i = 0; i < elitism; i++) {
offspring.push(spawn_pool[i]);
}
// sort our offspring by fitness (this includes the parents from elitism). Fittest first.
offspring.sort(function(a, b) {
return a.fitness() - b.fitness();
});
// pick off the number that we want
offspring = offspring.slice(0, num_offspring);
best_spawn = offspring[0];
best_fitness = best_spawn.fitness();
best_spawn.draw(output_ctx);
generation++;
return offspring;
};
var average_fitness = function(generation) {
debugger;
var a = 0;
for (var i = 0; i < generation.length; i++) {
a += generation[i].fitness();
}
return a / generation.length;
};
//Draw yellow and then initialize our first generation
input_ctx.fillStyle = 'yellow';
input_ctx.fillRect(0, 0, input_ctx.canvas.width, input_ctx.canvas.height);
start();
// Our loop function. Use setTimeout to prevent things from freezing
var gen = function() {
children = generate(children);
$gen_span.text('Generation: ' + generation);
$best_fit.text('Best Fitness: ' + best_fitness);
$avg_fit.text('Avg. Fitness: ' + average_fitness(children));
if (generation % 100 === 0) {
console.log('Generation', generation);
console.log('Fitness', best_fitness);
}
setTimeout(gen, 1);
};
gen();​
I've commented the code to try to make parsing it easy. The basic idea is quite simple:
Select 1 or 2 parents from the current generation
Mix those one or two parents together
Mutate the result slightly and add it to the next generation
Select the best few parents (1 in the example) and add them to the next generation
Sort and slice off N results and use them for the next generation (potentially a mix of parents and offspring)
Rinse and repeat
The output never gets anywhere near yellow. It quickly falls into a steady state of a sort that looks awful. Where have I gone wrong?
Solved it. It was in the "from_parents" method:
if (Math.random() > 0.5) {
nodes.push($.extend({}, parents[0].nodes[i]));
}
else {
nodes.push($.extend({}, parents[1].nodes[i]));
}
The $.extend() was doing a shallow copy. The obvious solution was to either put true as the first argument which causes a deep copy. This, however, is incredibly slow performance-wise. The better solution was to remove the $.extend() from that chunk of code entirely and instead to move it up to the mutate() method, where I call $.extend() only if a node is actually about to be changed. In other words, it becomes a copy-on-write.
Also, the color I put in the fitness function was wrong :P

Making falling objects come at random angles in AS3

I am making a missile defense type of game and am trying to get the missiles to fall at random angles. I also need the bullet image to turn at the angle I am shooting at. I am very unfamiliar with angles in AS3 so I need some help.
Code:
import spark.components.Image;
public var missiles:Array;
public var bullets:Array;
public var playerLife:Number;
public var targetX:Number;
public var targetY:Number;
public function init():void {
startGame();
}
public function onEnterFrame(e:Event):void {
if(Math.random() <.05 ){
//make a new missle
var newMissile:Image = new Image();
//draw to is
newMissile.source = "assets/missileDown.jpg";
//position it
newMissile.x = Math.random() * stage.stageWidth;
//animate it
newMissile.addEventListener(Event.ENTER_FRAME, onMissileEnterFrame);
//add it to missle array
missiles.push(newMissile);
//add it to the screen
gameGroup.addElement(newMissile);
}
}
public function startGame():void {
//makes new arrays
//gets rid of old arrays
missiles = new Array();
bullets = new Array();
//set player life
playerLife = 5;
//show player life
playerHealth.text = String(playerLife);
//add animation and mouse interation
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.CLICK, fireWeapon);
//set game over alpha
gameEnd.alpha = 0;
reset.alpha = 0;
//set game start alpha
playerHealth.alpha = 1;
healthLabel.alpha = 1;
}
//updates the missle
public function onMissileEnterFrame(e:Event):void {
//reference to target
var targetMissile:Image = Image(e.currentTarget);
//move missle down
targetMissile.y += 10;
//if missle has gone too far, remove it and player loses life
if(targetMissile.y > stage.stageHeight) {
playerLife --;
removeMissile(targetMissile);
//show player life
playerHealth.text = String(playerLife);
}
//if player is dead, game over
if(playerLife <= 0) {
gameOver();
}
}
//update bullet
public function onBulletEnterFrame(e:Event):void {
//get reference to bullet
var thisBullet:Bullet = Bullet(e.currentTarget);
//animate towards point..
//calculate difference between current position and desired position
var diffX:Number = thisBullet.targX - thisBullet.x;
var diffY:Number = thisBullet.targY - thisBullet.y;
//move 10% of difference closer
thisBullet.x += diffX * .1;
thisBullet.y += diffY * .1;
//chekc for overlap between bullet and missles
for(var i:Number = 0; i < missiles.length; i++) {
//if they do overlap, remove missle
if( thisBullet.hitTestObject(missiles[i]) ) {
removeMissile(missiles[i]);
removeBullet(thisBullet);
break;
}
}
//if we're 'close enough' to the target position, remove bullet
if(Math.abs(diffX) < 10 && Math.abs(diffY) < 10) {
removeBullet(thisBullet);
}
}
//gets rid of a missle
public function removeMissile(targetMissile:Image):void {
//removes the missle from the missiles array
for(var i:Number = missiles.length - 1; i >= 0; i--) {
if(missiles[i] == targetMissile) {
missiles.splice(i,1);
break;
}
}
//don't animate anymore
targetMissile.removeEventListener(Event.ENTER_FRAME, onMissileEnterFrame);
//remove from stage
gameGroup.removeElement(targetMissile);
}
//removes bullet from stage
public function removeBullet(targetBullet:Bullet):void {
//stop animation
targetBullet.removeEventListener(Event.ENTER_FRAME, onBulletEnterFrame);
//remove from stage
gameGroup.removeElement(targetBullet);
}
//shoot a bullet at the mouse position
public function fireWeapon(e:MouseEvent):void {
//make a new bullet
var newBullet:Bullet = new Bullet();
newBullet.addEventListener(Event.ENTER_FRAME, onBulletEnterFrame);
//position near the earth in the center
var halfStage:Number = stage.stageWidth / 2;
newBullet.x = halfStage;
newBullet.y = 500;
//set target
newBullet.targX = stage.mouseX;
newBullet.targY = stage.mouseY;
//add it to the stage
gameGroup.addElement(newBullet);
}
//you lose
public function gameOver():void {
//remove missles
for(var i:Number = 0; i < missiles.length; i++) {
removeMissile(missiles[i]);
}
//stop interaction
stage.removeEventListener(MouseEvent.CLICK, fireWeapon);
//stop animation
this.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
//set game start alpha
playerHealth.alpha = 0;
healthLabel.alpha = 0;
//set game end alpha
gameEnd.alpha = 1;
reset.alpha = 1;
}
]]>
</fx:Script>
onEnterFrame
...
//position it
newMissile.x = Math.random() * stage.stageWidth;
//rotate it
newMissile.rotation = - (Math.random() * 60 - 30);
onMissileEnterFrame
...
//move missle down
//targetMissile.y += 10;
targetMissile.x -= 10 * Math.sin(targetMissile.rotation * Math.PI/180);
targetMissile.y += 10 * Math.cos(targetMissile.rotation * Math.PI/180);
fireWeapon
...
//set target
newBullet.targX = stage.mouseX;
newBullet.targY = stage.mouseY;
newBullet.rotation = - Math.atan((newBullet.x - newBullet.targX) / (newBullet.y - newBullet.targY)) * 180/Math.PI;

Actionscript - randomly drop from moving plane MC

I wasn't quite sure how to describe my problem in the subject. I have a plane MC and a crate MC. The plane only flies along the y axis from the bottom of the screen to top. Along the way I want it to randomly drop the crate MC. My code is below. The problem is that the crates spontaneously keep spawning and not near the plane.
function movePlane():void
{
var tempY:Number;
var tempX:Number;
var tempCrate:MovieClip;
var tempPlane:MovieClip;
for (var j:int =planes.length-1; j>=0; j--)
{
tempPlane = planes[j];
tempPlane.y += tempPlane.planeSpeed;
tempCrate = new Crate();
tempY = Math.floor(Math.random() * tempPlane.y);
tempX = Math.floor(Math.random() * tempPlane.x);
}
tempCrate.y = tempY;
tempCrate.x = tempX;
addChild(tempCrate);
}
Edited answer:
To make a crate drop on each plane once you can create this behavior by creating a timer on each plane with a random time value. Like this:
function addRandomCreation():void{
var animationTime:Number = 5000; //The time the planes will be animating in ms
for(var i:int = 0; i < planes.length; i++){
var planeTimer:Timer = new Timer(Math.round(animationTime * Math.random()));
planeTimer.addEventListener(TimerEvent.TIMER, timerComplete(i));
planeTimer.start();
}
}
function timerComplete(planeID:int):function{
return function(event:TimerEvent):void{
event.target.stop();
event.target.removeEventListener(event.type, arguments.callee);
var tempCrate:MovieClip = new Crate();
tempY = Math.round(Math.random() * planes[planeID].y);
tempCrate.y = tempY;
tempCrate.x = planes[planeID].x;
addChild(tempCrate);
}
}
Edited answer:
This will create a crate on the same x axis as the plane it's being created by.
function movePlane():void
{
var tempY:Number;
var tempX:Number;
var tempCrate:MovieClip;
var tempPlane:MovieClip;
for (var j:int =planes.length-1; j>=0; j--)
{
tempPlane = planes[j];
tempPlane.y += tempPlane.planeSpeed;
tempCrate = new Crate();
tempY = Math.floor(Math.random() * tempPlane.y);
tempCrate.y = tempY;
tempCrate.x = tempPlane.x;
addChild(tempCrate);
}
}
You have have to use addChild each time you create a new Crate otherwise it will just create a lot of crates which only the last one will be added to the stage. To do this you have to move the addChild into the loop.
function movePlane():void
{
var tempY:Number;
var tempX:Number;
var tempCrate:MovieClip;
var tempPlane:MovieClip;
for (var j:int =planes.length-1; j>=0; j--)
{
tempPlane = planes[j];
tempPlane.y += tempPlane.planeSpeed;
tempCrate = new Crate();
tempY = Math.floor(Math.random() * tempPlane.y);
tempX = Math.floor(Math.random() * tempPlane.x);
tempCrate.y = tempY;
tempCrate.x = tempX;
addChild(tempCrate);
}
}

Resources