Having some trouble with collision using Arrays and Childs - actionscript-3

So, i was working on a game and i got some trouble at the part where i was coding the collision detection between my character and an item. When both collide, the item should dissapear, but it crashes the game. I'm coding using Flashdevelop and Starling. Here's my code:
private function collision(object1:DisplayObject, object2:Sprite):Boolean
{
var area1:Rectangle = object1.getBounds(stage);
var area2:Rectangle = object2.getBounds(stage);
if (area1.intersects(area2)) {
return true;
}
return false;
}
private function collisionPlayerItem(object:Player):void
{
for (var i:int = 0; i < itemArray.length; i++) {
if (collision(object.areaBody(), itemArray[i])) {
if(stage.contains(itemArray[i])){
map.removeChild(itemArray[i]);
life -= 1;
}
}
}
itemArray is where all the items are stocked in.
areaBody is the hitbox of my character.
The moment my character touch an item, the game crashes.
In flashdevelop there is no hitTestObject also.
Someone knows whats happening?

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

Problems with an object appearing on a frame I don't want it to appear on AS3

I am a total noob at AS3, roughly 1 year experience so please be lenient with me :)
I currently am making an endless runner game and I'm making the obstacles spawn using this method
var therespawn:RespawnObject;
var thecone:trafficcone;
var started:Boolean = false;
var dx:Number = 10;
var dy:Number = 10;
stage.addEventListener(Event.ENTER_FRAME, startGame);
addEventListener(Event.ENTER_FRAME, collision);
addEventListener(Event.ENTER_FRAME, coneCollision);
function startGame(evt:Event):void {
if (started == false) {
spawnHazard();
}
}
function spawnHazard() {
started = true;
therespawn = new RespawnObject();
addChild(therespawn);
thecone = new trafficcone();
addChild(thecone);
therespawn.x = -50;
therespawn.y = 310;
thecone.x = 600;
thecone.y = 310;
}
function collision(evt:Event):void {
thecone.x -= 15;
if(thecone.hitTestObject(therespawn)) {
thecone.x = 600;
}
}
Now the only way to finish the game or end it is to get hit by an obstacle which ive shown down below:
function coneCollision(evt:Event):void {
if(MainChar.hitTestObject(thecone)) {
gotoAndStop("frameFive");
}
}
Everytime the highscore frame appears the cone is still spawning and despawning, why is that?
I haven't declared them as global?
Any help appreciated, thanks!
You can fix your problem by setting started to false:
function coneCollision(evt:Event):void {
if(MainChar.hitTestObject(thecone)) {
started = false;
gotoAndStop("frameFive");
}
}
The flash timeline really only has to with the way MovieClips are visually displayed as children of the stage. Removing an object from the timeline doesn't just suddenly nullify all the code associated with that object. In other words, your ENTER_FRAME method still runs in the background even if the object is no longer a child of the Stage, regardless of the frame number for the MovieClip. If you're serious about coding you might consider investigating in Classes and Object Oriented AS3. Classes are much nicer to work with than the Flash timeline.

Remove bullet when hit a wall

I'm making an AS3 platform game where the player can shoot some bullets.
When the bullet is touching an enemy, the enemy die and the bullet is removed.
I've succeed do to that but now I'd like to remove the bullet if it hit a wall and I can't figure out how to do so.
So far, here's my code for removing the bullet when touching an enemy :
public function checkCollisions() {
// enemies
for(var i:int=enemies.length-1;i>=0;i--) {
if (hero.mc.hitTestObject(enemies[i].mc)) {
// is the hero jumping down onto the enemy?
if (hero.inAir && (hero.dy > 0)) {
enemyDie(i);
} else {
heroDie();
}
}
for (var j:int = 0; j < bulletList.length; j++) // for each bullet in the bulletList
{
if (enemies[i].mc.hitTestObject(bulletList[j]) )
{
trace("Bullet and Enemy are colliding");
enemyDie(i)
bulletList[j].removeSelf();
}
}
}
I've defined my wall and floor like this :
public function examineLevel() {
fixedObjects = new Array();
otherObjects = new Array();
for(var i:int=0;i<this.gamelevel.numChildren;i++) {
var mc = this.gamelevel.getChildAt(i);
// add floors and walls to fixedObjects
if ((mc is Floor) || (mc is Wall)) {
var floorObject:Object = new Object();
floorObject.mc = mc;
floorObject.leftside = mc.x;
floorObject.rightside = mc.x+mc.width;
floorObject.topside = mc.y;
floorObject.bottomside = mc.y+mc.height;
fixedObjects.push(floorObject);
}
}
I've tried to put this in my checkCollisions function but it's not working :
for(var k:int=0;k<fixedObjects.length;k++)
{
if (fixedObjects[k].hitTestObject(bulletList[j]) ){
trace("hit wall");
}
Do you know what do I have to put in order to remove the bullet when it's touching a wall (or floor) ?
Thx
The array fixedObjects holds references to Object instances. However, hitTestObject(obj) is a public function of the DisplayObject class, and the obj parameter needs to be an instance of DisplayObject.
If the code snippet you provided is exactly the same as what you used in your game, there should be runtime error messages generated.
Could you please verify whether this is the cause of failing to detect collision?

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

Detect when the last item in an array has come to a stop

I've got an array of sprites which I'm animating by incrementing their rotationX property. What I want is for them all to disappear once the last item in the array has come full circle. The problem is that their rotation speeds are being generated by a randomized function, so I can't just go to the end of the array to find the last one. Each time it will be a different one.
So I have an array of Sprites:
for(var i:int=0; i<arrSprites.length; i++)
{
addChild(arrSprites[i]) ;
}
Then I have my event listener:
addEventListener(Event.ENTER_FRAME, loop);
And my handler:
private function loop(e:Event):void
{
for(var i:int=0; i<arrSprites.length; i++)
{
var currentSprite:Sprite = arrSprites[i];
if(currentSprite.rotationX < 361) //this will detect the first one
//to finish but I want the last
{
currentSprite.rotationX += arrSprites[i].speed; //random speed
}
else
{
deleteTheSprites(); //removes all sprites and does other stuff
}
}
}
There's got to be an elegant way to do this. Anyone know what it is?
Thanks,
David
private function loop(e:Event):void
{
var finished : int = 0; // will count the number of sprites finished
for each (var current:Sprite in arrSprites)
{
if (current.rotationX < 361) current.rotationX += current.speed;
else if (++finished == arrSprites.length) deleteTheSprites(); // executes only if all sprites have finished
}
}