53106

Detecting and using collision detection between two different arrays to remove instances of them

Question:

I'm currently creating a small flash game using ActionScript and after receiving help for another issue I had on here, I've encountered another one when moving onto a different part of it.

This is the code I currently have:

var asteroidSpeed = 5; var soundExplosion:Sound = new ExplosionSound(); stage.addEventListener(KeyboardEvent.KEY_DOWN, onKDown); var newLaser:Array = new Array(); function onKDown(e:KeyboardEvent):void { keys[e.keyCode] = true; if (e.keyCode == 32) { /*laser.x = player.x + player.width/2 - laser.width/2; laser.y = player.y; addChild(laser);*/ for (var count=0; count < 4; count++) { newLaser[count] = new shipLaser(); newLaser[count].x = player.x + player.width/2 - newLaser.width/2; newLaser[count].y = player.y; addChild(newLaser[count]); } } } var spawnTimer:Timer = new Timer(3000); //timer will tick every 3 seconds spawnTimer.addEventListener(TimerEvent.TIMER, spawn, false, 0, true); //let's run the spawn function every timer tick spawnTimer.start(); var spawnPoints:Array = [0,100,200,300,400,500,550]; //your list of spawn x locations var spawnAmount:int = 4; //how many asteroids to have on the screen at once (you could increase this over time to make it more difficult) var asteroids:Vector.<asteroidOne> = new Vector.<asteroidOne>(); //the array for your asteroids - changed to vector for possible performance and code hint improvement (basically the same as Array but every object has to be of the specified type) spawn(); // calling it immediately //calling this will spawn as many new asteroids as are needed to reach the given amount function spawn(e:Event = null):void { if(asteroids.length >= spawnAmount) return; //let's not bother running any of the code below if no new asteroids are needed spawnPoints.sort(randomizeArray); //lets randomize the spwanPoints var spawnIndex:int = 0; var a:asteroidOne; //var to hold the asteroid every loop while (asteroids.length < spawnAmount) { a = new asteroidOne(); a.x = spawnPoints[spawnIndex]; spawnIndex++; //incriment the spawn index if (spawnIndex >= spawnPoints.length) spawnIndex = 0; //if the index is out of range of the amount of items in the array, go back to the start a.y = -50; asteroids.push(a); //add it to the array/vector addChild(a); //add it to the display } } player.addEventListener(Event.ENTER_FRAME, obstacleMove); function obstacleMove(evt:Event):void { for (var i:int = 0; i < asteroids.length;i++) { asteroids[i].y += asteroidSpeed; if (asteroids[i].y > stage.stageHeight || asteroids[i].x > stage.stageWidth || asteroids[i].x < -asteroids[i].width || asteroids[i].y < -asteroids[i].height) { //object is out of the bounds of the stage, let's remove it removeChild(asteroids[i]); //remove it from the display asteroids.splice(i, 1); //remove it from the array/vector continue; //move on to the next iteration in the for loop } if (player.hitTestObject(asteroids[i])) { trace("HIT"); removeChild(asteroids[i]); asteroids.splice(i,1); removeChild(player); // will add end-game trigger here soon. } } } function randomizeArray(a:*, b:*):int { return (Math.random() < .5 ) ? 1 : -1; } player.addEventListener(Event.ENTER_FRAME, laserCollision); function laserCollision(evt:Event):void { for (var i in newLaser) { for (var a in asteroids) { if (asteroids[a].hitTestObject(newLaser[i])) { trace("BOOM!"); var soundExplosion:Sound = new ExplosionSound(); var channel1:SoundChannel = soundExplosion.play(); removeChild(newLaser[i]); removeChild(asteroids[a]); } } } } addEventListener(Event.ENTER_FRAME, laserEnter); function laserEnter(event:Event):void { for (var i in newLaser) { newLaser[i].y -= laserSpeed; // Moves the laser up the screen if(newLaser[i].y == 0) { removeChild(newLaser[i]); } } }

What I want to do is when an instance from the newLaser array collides with an instance of the asteroids array, to remove both from the scene / indexes (but only the two that collided and not all of the ones on the scene).

Currently, when a laser hits an asteroid, it removes the asteroid but not the laser and one of the asteroids on the current row stops moving and then the next row of asteroids spawns but does not move down.

I get this error too:

ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller. at flash.display::DisplayObjectContainer/removeChild() at _8_fla::MainTimeline/obstacleMove()

Any help would be greatly appreciated.

Answer1:

You error, is likely because you are running 3 separate enter frame handlers in the same scope, and removing items from arrays and display lists (that are referenced in multiple enter frame handlers). So you asteroid is removed from the display list in one, and then you try to remove it again in another.

There are also a whole lot of other issues with your code that will cause errors and undesired results. Things like for(var i in newLasers) - in that kind of loop, i will refer to the actual laser object not the index of the array. I've re-factored your code and added lots of code comments to <strong>hopefully</strong> give you an idea of where you were going wrong:

var spawnTimer:Timer = new Timer(3000); //timer will tick every 3 seconds var spawnPoints:Array = [0, 100, 200, 300, 400, 500, 550]; //your list of spawn x locations var spawnAmount:int = 4; //how many asteroids to have on the screen at once (you could increase this over time to make it more difficult) var asteroidSpeed = 5; var asteroids:Vector.<asteroidOne> = new Vector.<asteroidOne>(); //the array for your asteroids - changed to vector for possible performance and code hint improvement (basically the same as Array but every object has to be of the specified type) var lasers:Vector.<shipLaser> = new shipLaser(); //the array of lasers var maxLasers:int = 4; //the maximum amount lasers allowed at any given time var soundExplosion:Sound = new ExplosionSound(); stage.addEventListener(KeyboardEvent.KEY_DOWN, onKDown); player.addEventListener(Event.ENTER_FRAME, gameLoop); spawnTimer.addEventListener(TimerEvent.TIMER, spawn, false, 0, true); //let's run the spawn function every timer tick spawnTimer.start(); //start the spawn timer spawn(); // calling it immediately function onKDown(e:KeyboardEvent):void{ if (e.keyCode == 32) { //create ONE laser per button push (instead of 4 identical lasers) if(lasers.length < maxLasers){ //if player hasn't reached the maximum amount of lasers available var tmpLaser:shipLaser = new shipLaser(); tmpLaser.x = player.x + player.width / 2 - tmpLaser.width / 2; tmpLaser.y = player.y; addChild(tmpLaser); lasers.push(tmpLaser); } } } //calling this will spawn as many new asteroids as are needed to reach the given amount function spawn(e:Event = null):void { if (asteroids.length >= spawnAmount) return; //let's not bother running any of the code below if no new asteroids are needed spawnPoints.sort(randomizeArray); //lets randomize the spwanPoints var spawnIndex:int = 0; var a:asteroidOne; //var to hold the asteroid every loop while (asteroids.length < spawnAmount) { a = new asteroidOne(); a.x = spawnPoints[spawnIndex]; spawnIndex++; //incriment the spawn index if (spawnIndex >= spawnPoints.length) spawnIndex = 0; //if the index is out of range of the amount of items in the array, go back to the start a.y = -50; asteroids.push(a); //add it to the array/vector addChild(a); //add it to the display } } function gameLoop(e:Event):void { //LOOP through all the asteroids, give it a label (asteroidLoop) so we can break/continue it inside other loops asteroidLoop: for (var i:int = 0; i < asteroids.length; i++) { //check if asteroid is out of bounds if (asteroids[i].y > stage.stageHeight || asteroids[i].x > stage.stageWidth || asteroids[i].x < -asteroids[i].width || asteroids[i].y < -asteroids[i].height) { //object is out of the bounds of the stage, let's remove it removeChild(asteroids[i]); //remove it from the display asteroids.splice(i, 1); //remove it from the array/vector continue; //forget the rest of the code below and move on to the next iteration in the for loop since the asteroid is gone } //check if any lasers are colliding with this asteroid for (var j:int = lasers.length-1; j >= 0;j--) { //iterate over all lasers backwards if (asteroids[i].hitTestObject(lasers[j])){ trace("BOOM!"); var soundExplosion:Sound = new ExplosionSound(); var channel1:SoundChannel = soundExplosion.play(); //remove the asteroid removeChild(asteroids[i]); //remove it from the display asteroids.splice(i, 1); //remove it from the array/vector //remove the laser removeChild(lasers[j]); lasers.splice(j, 1); continue asteroidLoop; //break completely out of this inner for-loop (lasers) since the asteroid in the outer loop was removed, and move on to the next asteroid } } //check if this asteroid collides with the player if (player.hitTestObject(asteroids[i])){ trace("HIT"); //remove the asteroid removeChild(asteroids[i]); //remove it from the display asteroids.splice(i, 1); //remove it from the array/vector removeChild(player); spawnTimer.stop(); //stop spawning new asteroids //will add end-game trigger here soon. break; //break completely out of the asteroid loop if it's game over (as there's no point in checking the rest of the asteroids) } //we've made it this far, so let's just move this asteroid asteroids[i].y += asteroidSpeed; } for (var i:int = lasers.length-1; i >= 0;i--) { //iterate backwards lasers[i].y -= laserSpeed; // Moves the laser up the screen if (lasers[i].y <= 0){ //make this less than or equal to 0 removeChild(lasers[i]); //remove the laser from the display list lasers.splice(i, 1); //remove the laser from the array } } } function randomizeArray(a:*, b:*):int { return (Math.random() < .5) ? 1 : -1; }

Recommend

  • How does adding a random number to the end of an AJAX server request prevent caching?
  • How to overload the calling process of any function
  • Extract audio frames from AMR-NB file
  • Bootstrap ScrollSpy skips section when no more scrollable area
  • No System image available when adding AVD in Android studio
  • Is there any way to center certain columns in table?
  • How to get style in Elm
  • Meteor: Block access to application if user's email is not verified
  • Authentication - JavaScript - Logout issue
  • phpmailer - How to verify a sent email arrived at its destination
  • command line of process by name
  • Using an STL Iterator without initialising it
  • Ruby and class variables in inherit class
  • Insertion large number of Entities into SQL Server 2012 [duplicate]
  • iOS Localization Doesn't Work with More Than 63 Files
  • why calling cd shell command through system() or execvp() from a child process won't work?
  • Most efficient way to move table rows from one table to another
  • Reading a file into a multidimensional array
  • Object and struct member access and address offset calculation
  • Hardware Accelerated Image Scaling in windows using C++
  • Magento Fatal error: Maximum execution error solution, on WAMP
  • How to delay loading a property with linq to sql external mapping?
  • QLineEdit password safety
  • Why winpcap requires both .lib and .dll to run?
  • AT Commands to Send SMS not working in Windows 8.1
  • VB.net deserialize, JSON Conversion from type 'Dictionary(Of String,Object)' to type '
  • retrieve vertices with no linked edge in arangodb
  • Rails 2: use form_for to build a form covering multiple objects of the same class
  • How can I get HTML syntax highlighting in my editor for CakePHP?
  • FormattedException instead of throw new Exception(string.Format(…)) in .NET
  • How do I configure my settings file to work with unit tests?
  • Change div Background jquery
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • apache spark aggregate function using min value
  • Is it possible to post an object from jquery to bottle.py?
  • Django query for large number of relationships
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • Binding checkboxes to object values in AngularJs
  • How can I use `wmic` in a Windows PE script?
  • How to push additional view controllers onto NavigationController but keep the TabBar?