How do you detect collisions between two arrays? - actionscript-3

For future refrence this was the final code
for each (var bullet:Bullet in bulletList)
{
for each (var zombie:Zombie in zombieList)
{
if (zombie.hitTestObject(bullet))
{
stage.removeChild(bullet);
zombie.zombieShot(50);
}
}
}
Original Question Below
for each (var bullet:Bullet in bulletList)
{
if (zombieList.length > 0)
{
if (zombieList[h].hitTestObject(bullet))
{
bulletList[i].deleteBullet();
zombieList[h].zombieShot(50);
}
}
}
This is the code I have but it only detects the first zombie I spawn in, any help is appreciated.
if (countMePls<10)
{
countMePls++;
var zombie:Zombie = new Zombie(stage,Math.random() * stage.width,Math.random()*stage.height);
zombie.addEventListener(Event.REMOVED_FROM_STAGE,zombieRemoved,false,0,true);
zombieList.push(zombie);
stage.addChild(zombie);
}
and then...
function shootBullet():void
{
var bullet:Bullet = new Bullet(stage,Main.player.x,Main.player.y,Main.player.rotation - 90);
bullet.addEventListener(Event.REMOVED_FROM_STAGE,bulletRemoved,false,0,true);
bulletList.push(bullet);
stage.addChildAt(bullet,1);
}
this last bit is in Bullet.as
public function deleteBullet():void
{
this.parent.removeChild(this)
}

I think your issue comes from some basic confusion about for and for each. With for each you have no index variable, each iteration yields a new instance of the type in the collection which is referred to by the name you declare in the loop. In this case that is;
foreach (var bullet in bulletsList)
{
// do something with bullet
}
You probably actually want a nested loop, something that checks every bullet against each zombie to see if there was a hit, that would actually look like this;
foreach (var bullt in bulletsList)
{
foreach (var zombie in zombiesList)
{
if (zombie.hitTestObject(bullet))
{
bulletList.Remove(bullet);
zombie.zombieShot(50);
}
}
}
In your code you have the foreach loop giving you the current bullet object but then you never reference it within the loop, that doesn't make sense. This may not be exactly what you want but hopefully it will get you moving in the right direction. If you want to use those indexers then you need something like;
for (int i = 0; i < bulletsList.Length; i++)
{
for (int h = 0; h < zombiesList.Length; h++)
{
// do stuff with bulletsList[i] and zombiesList[h]
}
}
Note: this was originally tagged as C# and the code I've posted uses C# syntax. The explanation I've provided most likely applies either way, the OP's code doesn't really makes sense in any language I know of and the reasons are the same.

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
}
}
}
}

How to put "i" into a loop in Actionscript 3

I'm trying loops a bunch of buttons as below. I understand how loops work, but I'm not sure how to change the numbers below to 'i's in the loop if it were something like:
for (var i:Number=1; i<=10;i++){ }
Any help would be greatly appreciated! Thanks!
eyes1.addEventListener(MouseEvent.CLICK, eyes1action);
function eyes1action(event:MouseEvent):void{
eyes.gotoAndStop(1);
}
eyes2.addEventListener(MouseEvent.CLICK, eyes2action);
function eyes2action(event:MouseEvent):void{
eyes.gotoAndStop(2);
}
To answer the question directly, you can do something like this:
for (var i:int = 1; i <= 10; i++) {
this['eyes' + i].addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void {
eyes.gotoAndStop(i);
});
}
However, this is an awful idea. It would be better to assign a variable e.g. tf to each button and use that instead, with a single more generic handler. For example:
eyes1.tf = 1;
eyes2.tf = 2; // etc
Then:
function handleClick(event:MouseEvent):void {
var frame:int = event.target.tf;
eyes.gotoAndStop(frame);
}
And obviously:
eyes1.addEventListener(MouseEvent.CLICK, handleClick); // etc
You can extend SimpleButton and then add properties. Listener's function who created like this never remove.

AS3 (or AS2) - Global Variables as Local inside Functions

I'm assuming there's something easy i'm overlooking here.
But basically, What i'm trying to do is just simply.. I guess code would be a better explanation, here it goes:
tobj = (an Array containing objects.)
for(i = 0; i < tobj.length; i++) {
tobj[i].func = function() {
trace(i);
}
}
Basically, i understand what happens here.. i as the global variable changes, so if i execute that function it'll retrieve the last value of i regardless of what it was when it was assigned. Basically I'm trying to figure out here is what approach to use to convert i as a global, into a local, so that when i execute the function on the object, it'll output the variable as it was assigned.
Hope it's understandable and straight forward. Thanks in advance.
If you add parenthesis after the closing bracket of your function declaration, it will run the function:
var tobj = [new Object(),new Object(), new Object()];
for(var i = 0; i < tobj.length; i++) {
tobj[i].func = function() {
trace(i);
}() // < ------
This would trace: "0", "1", "2"
Simple Solution... There might be another way, but this is what worked for me. Just took walking away from it for a few minutes.
tobj = (an Array containing objects.)
for(i = 0; i < tobj.length; i++) {
tobj[i].func = function() {
assigner(i);
}
}
function assigner(var) {
trace(var);
}

Error #1010 after splicing from array

I have an issue here. Every five seconds the spawnEnemies is fired. It creates a movieclip, sets it position and adds it to the stage and an array. In the function checkBullet I check if the bullet hits one of the enemies. If it does, the bullet and the enemy are removed from the stage, and the enemy is spliced from the array. But an error is thrown once I hit an enemy:
TypeError: Error #1010: A term is undefined and has no properties.
If I comment out the arrayEnemies.splice(i,1) line, it works fine but then it isn't removed from the array. This is in itself not an issue, but naturally I don't like to keep unnecessary data in my array. Any help on this?
function checkBullet(event:Event) {
if(stage.contains(mcBullet)) {
for(var i:int = 0; i < arrayEnemies.length; i++) {
if(arrayEnemies[i].hitTestPoint(mcBullet.x, mcBullet.y, true)) {
stage.removeChild(mcBullet);
this.removeChild(arrayEnemies[i]);
arrayEnemies.splice(i,1);
bulletOnStage = false;
}
}
if(mcBullet.x > 800) {
stage.removeChild(mcBullet);
bulletOnStage = false;
}
}
}
function spawnEnemies(event:TimerEvent) {
var enemie:MovieClip = new box_mc();
enemie.name = "mcBox" + event.currentTarget.currentCount;
enemie.x = 850;
enemie.y = Math.floor(Math.random()*(1+155)+255);
addChild(enemie);
arrayEnemies.push(enemie);
}
function moveEnemies(event:Event) {
for(var i:int = 0; i < arrayEnemies.length; i++) {
arrayEnemies[i].x -= 5;
}
}
This will be caused by working on an array that you are interating through, you should hold a ref to the stuff you want to remove then do it after the loop.
Your problem is that if the bullet hits two enemies, you try to remove it from the stage twice. This will throw an ArgumentError.
If you need to test against all enemies (assuming multiple enemies can be hit by the same bullet), you also need to decrement i when you remove an element from your enemy array.
function checkBullet(event:Event) {
if(stage.contains(mcBullet)) {
if(mcBullet.x > 800) {
stage.removeChild(mcBullet);
bulletOnStage = false;
}
for(var i:int = 0; i < arrayEnemies.length; i++) {
if(arrayEnemies[i].hitTestPoint(mcBullet.x, mcBullet.y, true)) {
if(stage.contains(mcBullet)){
stage.removeChild(mcBullet);
}
this.removeChild(arrayEnemies[i]);
arrayEnemies.splice(i,1);
bulletOnStage = false;
i--;
}
}
}
}
Bit of an older question but thought I'd throw in my answer too for anyone that might end up here.
Like Neil said, editing an array that you're itterating through (in this case arrayEnemies) can cause concurrent update problems.
My prefered solution is to use a seperate toRemove array and remove them after the update, for example:
var enemies:Array();
//Lets assume at some point this is populated with Enemy objects
function update():void
{
var toRemove:Array = new Array();
//May want to keep and clear an array instead to avoid creating a new one each update
foreach(var enemy:Enemy in enemies)
{
enemy.update();
if(enemy.markedForRemoval())
toRemove.push(enemy);
}
foreach(var enemy:Enemy in toRemove)
enemies.splice(enemies.indexOf(enemy), 1);
}

ActionScript - Retrieving Index Of Specific Filter

i have a few filters on a sprite. on mouse over i would like to access one of the filters in the filters array, but i'm having a bit of trouble trying to accomplish this.
mySprite.filters = [new DropShadowFilter(), new GlowFilter(), new BlurFilter()];
mySprite.addEventListener(MouseEvent.MOUSE_OVER, mouseOverEventHandler);
function mouseOverEventHandler(evt:MouseEvent)
{
//obtain indexOf the GlowFilter
trace(evt.currentTarget.filters[evt.currentTarget.filters.indexOf([Object GlowFilter])]));
}
the above code doesn't work. what's the proper way to get the index of a specific filter in a filters array?
If I understand correctly, you're essentially trying to do this:
var index:int = evt.currentTarget.filters.indexOf([Object GlowFilter]);
The bracketed part is not valid Actionscript it shouldn't even compile. What you need to do is to iterate over the filters and test them yourself since there's no way to search for a specific class with indexOf.
Try this instead:
function mouseOverEventHandler(evt:MouseEvent) {
var glowFilter:GlowFilter;
for (var i:int = 0; i < evt.target.filters.length; i++) {
if (evt.target.filters[i] is GlowFilter) {
glowFilter = evt.target.filters[i];
break;
}
}
}
Also, if you're going to fiddle with the filters in the array Flash won't accept in-place modifications, so you need to re-set the array once you've changed it:
function mouseOverEventHandler(evt:MouseEvent) {
var glowFilter:GlowFilter;
for (var i:int = 0; i < evt.target.filters.length; i++) {
if (evt.target.filters[i] is GlowFilter) {
glowFilter = evt.target.filters[i];
break;
}
}
if (!glowFilter) return;
glowFilter.blurX = 10;
var filters:Array = evt.target.filters;
filters[i] = glowFilter;
evt.target.filters = filters;
}