How to shoot at the enemy that is farest forward? - actionscript-3

Okay so this has been bugging me all day so I thought I would post it here. This is such a specific topic that it was basically impossible to find any sort of references on how this would be done.
for (var i:int=0; i<=Main.bloonList.length-1; i++)
{
//loop through the children in enemyHolder
var cEnemy = Main.bloonList[i];//define a movieclip that will hold the current child
//this simple formula with get us the distance of the current enemy
if (Math.sqrt(Math.pow(cEnemy.y - this.y,2) + Math.pow(cEnemy.x - this.x,2)) < 100)
{
shoot(cEnemy);
timer = 0;
}
}
This is the code i have at the moment and i would like to know how to figure out which enemy is the farest along the track. I can find it by using this.
function onEnter(e:Event)
{
distanceTravelled=distanceTravelled+xSpeed+Yspeed
}
But how can I tell the for loop to target the one with the highest value?

Just find the highest distance value by updating a new variable (say for example highestDistEnemy) inside your current for loop. You initialize the variable with the first enemy MovieClip object, and only update it to a new enemy object when that enemy's distance is greater than the previous highestDistEnemy's distance. In code:
if(distance(curEnemyDistance) > distance(highestDistEnemy)) {
highestDistEnemy = curEnemy;
}
where distance just calculates distance as you're already calculating it and initialize highestDistEnemy to Main.bloonList[0] at the start of the loop.

Keep track of the furthest enemy after looping all enemies. At the end shoot.
pseudocode
var maxDistance = 0;
var furthesEnemy = null;
var currentDistance = null;
for (var i:int=0; i<=Main.bloonList.length-1; i++) {
//loop through the children in enemyHolder
var cEnemy = Main.bloonList[i];
//this simple formula with get us the distance of the current enemy
currentDistance = Math.sqrt(Math.pow(cEnemy.y - this.y,2) + Math.pow(cEnemy.x - this.x,2));
if (currentDistance > maxDistance) {
maxdistance = currentDistance;
furthesEnemy = cEnemy;
}
}
shoot(furthesEnemy);

Related

How to hitTest same Objects in one Array?

I want to create a stacking Game. Where when you tap the screen for instance a block falls down and a new one appears where the other one originally was. Now when the User taps the screen again the same block falls down and if aligned correctly stacks on top of the first one so one and so one. Keep stacking until you miss.
I thought creating an array and pushing each new object to that array would be able to hitTest between each new one etc and have them stack on each other. I realized I don't quite understand how to go about doing this. New instances are created so I got that down. Here is my code so far:
private function engineLogic(e:Event):void
{
stackingHandler();
}
private function stackingHandler():void
{
for (var i:int = 0; i < aCatArray.length; i++)
{
var currentCat:mcCats = aCatArray[i];
//HIT TEST CATS
}
trace("NUMBER OF CATS: " + aCatArray.length);
}
private function onTap(e:MouseEvent):void
{
//Move Down
TweenLite.to(cats, 1.0, {y:(stage.stageHeight / 2) + 290, onComplete: addCats});
}
private function addCats():void
{
//Create Instance
cats = new mcCats();
//Add Objects
addChild(cats);
//Push to Array
aCatArray.push(cats);
}
I would appreciate any help from you guys. Maybe if you can push me in the right direction. Thank you in advance!
It looks like the cats variable holds the object that is currently falling?
In that case you'd do something like this:
private function stackingHandler():void
{
for (var i:int = 0; i < aCatArray.length; i++)
{
if(cats.hitTestObject(aCatArray[i])) {
// collision detected!
// kill the Tween
// set the y position of the `cats` object
// so it appears on top of the object it collided with (`aCatArray[i]`)
// (it may have moved slightly past the object before doing this check)
}
}
}
So you're looping through the array and hit testing cats against every object in the array one at a time.
It might make more sense to use a basic gravity simulation, or just linearly increasing the y value instead of using a Tween, but you didn't ask about that.
You might also want to set a flag for whether or not an object is currently falling and use that to determine whether or not to run the stackingHandler. Otherwise, you'll just be continually hit testing all the objects when nothing is moving.
This is how I was able to fix it. Creating a double for loop. Checking if they are equal to each other continue and check for hitTest:
private function stackingHandler():void
{
for (var i:int = 0; i < aCatArray.length; i++)
{
var currentCat:mcCats = aCatArray[i];
for (var j:int = 0; j < aCatArray.length; j++)
{
var newCat:mcCats = aCatArray[j];
if (currentCat == newCat) continue;
//Hit Test between Objects
if (newCat.hitTestObject(currentCat.mcHit) && newCat.bFlag == false)
{
//Stop Moving
newCat.stopMoving();
trace("HIT");
if (highScore == 0)
{
addCats();
trace("ADD CATS 1");
}else
{
TweenLite.delayedCall(0.6, addCats);
trace("ADD CATS 2");
}
//Add Points
highScore ++;
trace(highScore + " Score");
//Set Flag boolean
newCat.bFlag = true
}
}
}
}

Adding a new child movieclip

I am trying to get a cube movieclip to create another instance of itself and then add it to the stage at the coordinates right next to the previous one. However I can't get it to keep adding more children/ can't figure out how to access the childs coords. I attempted to add a new movieclip:mc every iteration of the for loop with the vertical and horizontal counting back by 50 every time and then,on a different thought process, i tried adding a new child every loop but I don't know how to access that childs properties. Any help would be appreciated. Thank you.
var countV:int=600;
var countH:int=600;
stage.addChild(havenAlpha);
var moveHOrV:Boolean=true;
var mc:MovieClip = new haven_Expand();
for(var i:int=0; i<=5; i++){
if(moveHOrV == false){
stage.addChild(mc);
countH=countH-50;
mc.x= countH;
moveHOrV=true;
}else if(moveHOrV == true){
stage.addChild(mc);
countV=countV-50;
mc.y=countV;
moveHOrV=false;
}
trace(countV,countH,moveHOrV,i);
stage.addChild(new haven_Expand())
stage.addChildAt(new haven_Expand(),countH);
}
In most Object oriented languages, variables are just pointers to the actual objects. So changing what is stored in a variable, doesn't actually make what was stored there previously go away.
To that end, you can just make one var to store each new object created every iteration. Like so:
stage.addChild(havenAlpha);
//this var will store the clip from the preivous iteration, but we'll start it off with the first item
var prevClip:MovieClip = new haven_Expand();
prevClip.x = 600;
prevClip.y = 600;
stage.addChild(prevClip);
var curClip:MovieClip; //used in the loop below to hold the current iterations item
for(var i:int=0; i<=5; i++){
curClip = new haven_Expand();//create new clip
stage.addChild(curClip); //add it to the stage
if(i % 2){ // % (modulous) gives you the remainder of the division, so this effectively will be false (0) every other time
curClip.x = prevClip.x - curClip.width; //place this new clip just to the left of the last iteration's clip
curClip.y = prevClip.y;
}else if(moveHOrV == true){
curClip.y = prevClip.y - curClip.height; //place this new clip just on top of the last iteration's clip
curClip.x = prevClip.x;
}
prevClip = curClip;
}
I'm not sure though if the x/y math is what you desire. This will make them distribute in a diagonal fashion. Are you actually wanting horizontal rows? I can update to show you that if desired.

How to check if objects position is greater than an array of objects AS3

Hey everyone so I'm trying to figure out how to check if one movie Clips x position which is called ball is greater than an array of objects x position which is called car. So I have an array setup with the car the car's main timeline consist of 4 frames that holds the same movie Clip just different sizes on each frame to make the game harder.
So what I want to do is check whenever the ball has jumped over the current car then add plus one to the score. But I am having trouble trying to figure this out. Here is what I have so far:
In my Enter Frame Game Loop I have the Function checkAddPoints:
private function gameLoop(e:Event):void
{
checkBunnyHitObstacles();
checkAddPoints();
}
Then The function:
private function checkAddPoints():void
{
for (var i:int = 0; i < aCarArray.length; i++)
{
var currentCar:car = aCarArray[i];
if (ball.x > currentCar.x)
{
nScore ++;
updateCurrentScore();
}
}
}
So I am getting the current car in the loop and trying to check if the ball has jumped over it. I thought the most logical thing to do was to check if the ball x position was greater than the car x position then it would work. But it just adds a endless amount of numbers and not just one like I want.
Does anyone know what i need to do?
UPDATE: This seems to work haven't had any errors yet
if (currentcar.x - 15 < ball.x && currentCar.x + 15 > ball.x)
{
trace("AddPoint Success");
nScore++;
updateCurrentScore();
}
Storing flag aboud award status in the car should help in your task. If you add flag to the car, let's say car.isAwarded, by default isAwarded is false, you will be able award only once for every car:
private function checkAddPoints():void {
var i:uint, len:uint = aCarArray.length, currentCar:car;
for (i; i < len; ++i) {
currentCar = aCarArray[i];
//Award only once
if (!currentCar.isAwarded && ball.x > currentCar.x) {
nScore++;
currentCar.isAwarded = true;
updateCurrentScore();
}
}
}

Object removed from screen before the relevant command is called (Error #1009)

I'm sorry if it's asking for too much, but I'm too confused by now. I'm making this really simple shooter game for my nephew in AS3. It all seems to be working just fine, except for one really annoying error that keeps popping up every second or third time the game is launched.
IT is Error #1009: Cannot access a property or method of a null object reference. The problem is always with parent.removeChild(this) command in the relevant class (EnemyClass, BulletClass or MissileClass). This happens in two cases: either when checkFinishConditions method in Main is called and the EnemyClass instance needs to be deleted. So if I get the #1009 error does this mean the instance has already been deleted? The second situation is when inst.hitTestObject(enemyInstance) is checked in Main class. Does this mean the EnemyClass instance has already been deleted somehow? I'm totally lost here to be honest.
private function checkCollision():void
{
//loop through missiles
for (var i:int = 0; i < aMissileArray.length; i++) {
//get the current missile
var currentMissile:missileClass = aMissileArray[i];
//loop through enemies
for (var j:int = 0; j < aEnemyArray.length; j++) {
var thisEnemy:EnemyClass = aEnemyArray[j];
if (currentMissile.hitTestObject(thisEnemy)) {
var thisExplode:ExplosionClass = new ExplosionClass(thisEnemy.x,thisEnemy.y);
addChild(thisExplode);
currentMissile.destroyThis();
aMissileArray.splice(i,1);
thisEnemy.deleteEnemy();
aEnemyArray.splice(j, 1);
aDamageArray.splice(j, 1);
scoreValueText += 1;
j--;
i--;
}
//break;
}
}
//loop through bullets
for (var l:int = 0; l < aBulletArray.length; l++) {
//get the current missile
var currentBullet:BulletClass = aBulletArray[l];
//loop through enemies
for (var k:int = 0; k < aEnemyArray.length; k++) {
var currentEnemy:EnemyClass = aEnemyArray[k];
if (currentBullet.hitTestObject(currentEnemy)) {
currentBullet.destroyThis();
aBulletArray.splice(l, 1);
aDamageArray[k] -= 1;
l--;
if (aDamageArray[k] < 1) {
//create an explosion
var thisBulletExplode:ExplosionClass = new ExplosionClass(currentEnemy.x,currentEnemy.y);
addChild(thisBulletExplode);
currentEnemy.deleteEnemy();
aEnemyArray.splice(k, 1);
aDamageArray.splice(k, 1);
scoreValueText += 1;
k--;
}
break;
}
}
}
}
There is alot of code to look over, but one potential issue I see is here :
for each(var currentDieEnemy:EnemyClass in aEnemyArray) {
aEnemyArray.splice(0, 1);
currentDieEnemy.deleteEnemy();
}
The potential issue is that you are 'assuming' that the order of this loop is sequential based on the actual index order of the Array. You might want to stick a trace in there to verify that is actually what is happening, because I believe it's possible that they can be out of order.
See this question for details -- For-Each Loop AS3: Is the direction guaranteed?
So imagine the scenario where the 3rd item in the array is first and you splice the item at the 0 index. Now, you have an item in the array that is removed from the display list, but not from the array. So what happens when you get to that item ? Pretty much what you are describing will happen since the parent property is null, since you already removed it from the display list.
The way to fix that is to do something like this :
while (aEnemyArray.length > 0)
{
var currentDieEnemy:EnemyClass = aEnemyArray[0];
currentDieEnemy.deleteEnemy();
aEnemyArray.splice(0,1);
}
I found another issue in this block of code :
for (var j:int = 0; j < aEnemyArray.length; j++) {
var thisEnemy:EnemyClass = aEnemyArray[j];
if (currentMissile.hitTestObject(thisEnemy)) {
var thisExplode:ExplosionClass = new ExplosionClass(thisEnemy.x,thisEnemy.y);
addChild(thisExplode);
currentMissile.destroyThis();
aMissileArray.splice(i,1);
thisEnemy.deleteEnemy();
aEnemyArray.splice(j, 1); // now array composition is different.
aDamageArray.splice(j, 1);
scoreValueText += 1;
}
}
When you loop through an Array and splice an item at the loop index, you have to realize what happens to the composition of the array. Here's an example
Suppose enemy3 needs to be spliced because of a collision. Given your code, this is what happens :
Before (j == 2)
(0) enemy1
(1) enemy2
(2) enemy3
(3) enemy4
(4) enemy5
AFTER
(0) enemy1
(1) enemy2
(2) enemy4
(3) enemy5
So when the loop continues, j will now increment and equal 3.
The result is that enemy4 doesn't get evaluated as the composition of the array collapses to fill the hole created by the splice and you didn't adjust your loop index variable.
So, what you can do in that situation is simply decrement the loop index variable at the end of the block like so :
aEnemyArray.splice(j, 1); // now array composition is different.
aDamageArray.splice(j, 1);
scoreValueText += 1;
j--; // decrement loop index variable.
So while this is one solution, the main point to take away here is the change in the composition of your Array after a splice.
Yep, you are splicing your objects from arrays in a weird way. First, you are traversing the array forwards and splicing in the loop. This can lead to issues of several bullets not trigger collisions when they should, or say not move. See, if you are running your loop for bullets at index i, once you call bullets.splice(i,1); the bullet that was to be iterated next becomes at position i, then you increment i and that bullet remains unprocessed.
Next, you have nested loops, and in the inner loop you are removing an object from OUTER loop. This means once you did a removal of the outer loop's object, your inner loop is now invalidated, you have to preemptively terminate inner loop.
//loop through bullets
for (var l:int = aBulletArray.length-1; l>=0; l--) {
// first, traverse both arrays backwards
//get the current missile
var currentBullet:BulletClass = aBulletArray[l];
//loop through enemies
for (var k:int = aEnemyArray.length-1; k>=0; k--) {
var currentEnemy:EnemyClass = aEnemyArray[k];
if (currentBullet.hitTestObject(currentEnemy)) {
currentBullet.destroyThis();
aBulletArray.splice(l, 1);
aDamageArray[k] -= 1;
if (aDamageArray[k] < 1) {
//create an explosion
var thisExplode:ExplosionClass = new ExplosionClass(currentEnemy.x,currentEnemy.y);
addChild(thisExplode);
currentEnemy.deleteEnemy();
aEnemyArray.splice(k, 1);
aDamageArray.splice(k, 1);
scoreValueText += 1;
}
// and since we don't have "currentBullet" anymore, do this
break;
}
}
}
Fix all the other iterations through your arrays where you do splicing, like I did in this part of code, and you should avoid 1009 errors in these loops.
Also, you should not post your entire project code, but instead post only relevant parts, say an entire function that's reported as throwing an error, and explain which line is producing the error - it's written as number in the error's stack trace.

How to compare properties of objects inside a vector?

I have a couple of display objects moving around the screen, the all belong to the same Vector.
I would like to create a function that lets me pick an object with the lowest x value at the moment the function is called.
This is quite easy and if you're into programming, you should be able to do it yourself, but if you're a beginner, I'll give you some code:
var vec:Vector.<DisplayObject> = new Vector.<DisplayObject>();
function getLowestXObject():DisplayObject
{
var minX:DisplayObject = vec[0];
for(var i:int = 1; i < vec.length; i++)
{
if(minX.x > vec[i].x)
{
minX = vec[i];
}
}
return minX;
}