ActionScript 3 : character hit test object with all objects in array - arrays

First of all thank you for the attention of anybody reading this question
I'm Indonesian, so apologize if my english was bad.
I'm currently in a school project creating touchscreen Android game using Flash ActionScript 3 or Unity, my current project is made using Flash with ActionScript 3. My current work is a Feeding Frenzy-like game which involves a female scuba diver which will annihilate a fish bomb falling underwater.
I'm trying to make the diver warned for all bombs in the screen. I have a BombsLayer class which will call a RegularBomb Class to fall in random x position. All RegularBomb instance are placed into an Array, then i use for each looping with hitTestObject so if the diver hit the transparent circle inside the movieclip, an exclamation sign will appear and sets the readyToDefuse boolean in diver class to true, and when the diver is away from bomb, the boolean will set to false, and the exclamation sign will dissapear.
My problem is the diver can only interact with the last bomb movieclip instace in the array. when the first bomb child added into the array and the diver reachs it, the exclamation sign would appear, but every time a new bomb instantiated the exclamation sign would disappear and i have to make the diver move to the new bomb instantiated to make the sign appear.
i have read the suggestion on this question : AS3 - array hit test in 'for each' loop only works properly with last object in array to remove the else statement in the for each loop, but by removing it will make the readyToDefuse remains True and the exclamation sign remains appearing.
i have done a google searching and nothing seems to answer my problem, i have to finish this game for one week until presentation and this had driving me confused for these past days..
here is my complete code for the Bombslayer Class :
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
public class BombsLayer extends MovieClip{
public var area:Sprite;
public var bombs:Array;
public var bomb:RegularBomb;
public var bombground:BombGround;
public var diver:Diver;
public var warner:BombWarn;
public function BombsLayer(character:Diver, warn:BombWarn){
// constructor code
area = new Sprite();
area.graphics.beginFill(000000, 0);
area.graphics.drawRect(0,0,2200,720);
area.graphics.endFill();
addChild(area);
diver = character;
warner = warn;
bombs = new Array();
var newBomb = new RegularBomb(Math.random()*area.width, diver, warner);
bombs.push(newBomb)
addChild(newBomb);
bombground = new BombGround(0, 670, this);
addChild(bombground);
this.addEventListener(Event.ENTER_FRAME, moveBomb);
}
function moveBomb(event:Event){
if(Math.random() <= 0.0005){
var newBomb = new RegularBomb(Math.random()*area.width, diver, warner);
bombs.push(newBomb)
addChild(newBomb);
}
for each(var bomb:RegularBomb in bombs){
bomb.moveDown();
if(diver.hitTestObject(bomb)){
warner.visible = true;
diver.readyToDefuse = true;
}
else{
warner.visible = false;
diver.readyToDefuse = false;
}
}
}
}
}
if needed i can upload the complete project too..
All helps would be appreciated.
Thank you!

The logic is wrong. You need to browse through the bombs and find one in contact with diver if any, and work with the only bomb. Otherwise the diver is ready to defuse bomb A but not ready to defuse B, C and D and thus is not ready at all.
function moveBomb(event:Event)
{
var aBomb:RegularBomb;
if (Math.random() <= 0.0005)
{
aBomb = new RegularBomb(Math.random() * area.width, diver, warner);
bombs.push(aBomb)
addChild(aBomb);
}
for each(aBomb in bombs) aBomb.moveDown();
// Find bomb in diver's vicinity.
aBomb = findBomb();
// The same as "if (aBomb != null)"
if (aBomb)
{
warner.visible = true;
diver.readyToDefuse = true;
}
else
{
warner.visible = false;
diver.readyToDefuse = false;
}
}
function findBomb():RegularBomb
{
for each(var aBomb:RegularBomb in bombs)
if (diver.hitTestObject(aBomb))
return aBomb;
return null;
}

Related

AS3- how to addchild this array(john) correctly

I do not know how to add the john array and make a hittestobject with it.
Bal is a different class non relevant to this problem.
I've tried to do john[new Bal]
tried john[ k ]
tried z and to specify z as a for-loop but then i would just get Z balls place.
This is supposed to become a space-invader type of game. I'm trying to make a hit test object between HENK and the 'falling balls' (JOHN). I do not know how to work with arrays especially given the fact that is should be timer-triggered.
Thanks
public class Main extends Sprite
{
public var henk:Sprite = new Sprite();
public var level:Timer = new Timer (2000, 0);
public var valTijd:Number = new Number
public var i:Number = 2000;
public var john:Array = new Array();
public var k:Number = 9000;
public function Main():void
{
henk.graphics.beginFill(0xFF00FF);
henk.graphics.drawCircle(0, 500, 20);
henk.graphics.endFill();
addChild(henk);
level.addEventListener(TimerEvent.TIMER, up);
level.start();
henk.addEventListener(Event.ENTER_FRAME, muis);
henk.addEventListener(Event.ENTER_FRAME, hit);
}
public function up(e:TimerEvent):void
{
var tijdje:Timer = new Timer( i, 0)
tijdje.addEventListener(TimerEvent.TIMER, tijdLuisteraar);
tijdje.start();
i = i - 250;
}
public function muis (e:Event):void
{
henk.x = mouseX;
}
public function hit (e:Event): void
{
if ( henk.hitTestObject(john [k] ))
{
if (contains(john[k] ))
{
removeChild(henk);
}
}
}
public function tijdLuisteraar(e:TimerEvent):void
{
john.push(new Bal);
addChild(john[k]);
}
}
}
welcome to stackoverflow!
This problem is actually fairly simple, I will describe how you will probably want to use an array in the case you described.
At the part where you create new Balls you want to append them to an array, which will be something like the following:
var ball = new Bal();
john.push(ball);
addChild(ball);
This will go inside your timer-triggered function, obviously.
Secondly, you want to have a hitTestObject with henk and all of the balls stored in the john array.
for(var i = 0; i < john.length; i++) {
if (henk.hitTestObject(john[i])) {
// well, that's a bummer for your player, henk hit one of the balls in the john array
// display something like a message here
}
}
This will automatically detect the size of the array, so all elements are tested. Be careful with hitTestObject when you have a lot of elements in the john-array, this can slow down your game drastically.
Furthermore, reflecting your code I suggest the following:
remove public var i:Number = 2000; and public var k:Number = 9000;, these have no meaning anymore
use a mouse event to move your henk object, not an ENTER_FRAME. I guess you will be able to find how this works. This will only trigger the function when it has to do something, resulting in less CPU-power needed and a cleaner code.
if you want to make the game even cooler, you could add the support for using the arrow keys

Actionscript 3 eventlisteners, hittestobject and arrays of custom objects

Another desperately stuck first year student here. And I have to use FlashCS as my coding environment. And it sucks. So I'll try some well constructed and clear questions. There is:
public var object: symbol1;
public var objectarray: Array = new Array();
in my main. Then a function there that uses a timer and spawns a new object and pushes it onto the array:
object = new symbol1;
objectarray.push(object)
but then when I trace() the .length of the array it displays TWO numbers of the array length every timer period in the output. As in:
1 1 2 2 3 3
etc. This is my first mystery. Why two not one? because there is no way I'm calling the function that includes the trace () twice. Also I think I need to be able to remove my object from the objectarray when it goes off the stage, but the objectarray.pop() doesn't seem to work if I use it like so in a function:
if (object.y == stage.stageHeight)
objectarray.pop()
As in I try trace() the array.length before and after the .pop(), but it just keeps going up by one every timer period.
And the other, bigger issue is I want to know if you are allowed to put the .addEventListeners that you usually place right under the main function of any class into a statement loop. As in I've got
class extends Main {
class function() {
for (var i:Number = 0; i < objectarray.length; i++){
objectarray[i].addEventListener(Event.ENTER_FRAME, collision);}}
And then, if it is allowed, the program doesn't seem to enter the collision function of this same class anyway.
function collision (event:Event) : void{
if (this.hitTestObject(object)){
trace('hit');}}
so I searched and ended up adding a
var clip:MovieClip = MovieClip(e.target);
in the first line of the function, but then it didn't work and I realized I on't understand what's it meant to do, what's going on anymore and what is the syntax for this casting.
Thank you very much.
Edit/Update: adding more of my code eventhough I hate copypasting it like this. This is the symbol class that is going to change when an object of another class hits it
public class Head extends Main {
public function Head(){
this.stop();
for (var i:Number = 0; i < nicesnowflakearray.length; i++){
nicesnowflakearray[i].addEventListener(Event.ENTER_FRAME, snowhit);
}
}
public function snowhit(event:Event) : void {
if (this.hitTestObject(nicesnowflake)){
//I changed this line to (e.currentTarget.hitTestObject(nicesnowflake)) as Atriace suggested, but nothing changed, and I just don't understand why my version wouldn't work.
trace("hit");
}
}
And this is the class that spawns the objects that are supposed to hit the Head object:
public class Main extends MovieClip {
public var nicesnowflake: fallingsnow;
var nicesnowflakespawntimer: Timer = new Timer(1000);
public var nicesnowflakearray: Array = new Array();
public function Main() {
nicesnowflakespawntimer.addEventListener(TimerEvent.TIMER, nicesnowflakespawn);
nicesnowflakespawntimer.start();
}
public function nicesnowflakespawn(event:TimerEvent) : void {
nicesnowflake = new fallingsnow;
nicesnowflake.x = Math.random()* stage.stageWidth;
nicesnowflake.y = - stage.stageHeight + 100;
nicesnowflakearray.push(nicesnowflake);
stage.addChild(nicesnowflake);
trace(nicesnowflakearray.length);
}
Why two, not one?
Anytime you extend another class, it implicitly calls the parent class' constructor. We know this as super(), and can be quite handy. This is why you're getting doubles on your trace statement. Technically, you can choose not to call super().
.pop()
It should remove the last element from that array, however, I'm thinking that if an arbitrary object leaves the stage, you can't be gauranteed it'll be the last element. Ergo, you want splice()
if (object.y == stage.stageHeight) {
objectarray.splice(objectarray.indexOf(object), 1)
}
Event Listeners
I didn't follow your quandary, so I'll just try to rewrite what I think you were trying to do.
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
private var objectarray:Array = []; // Note, I haven't populated it with anything, I'm assuming you have.
private var theWall:MovieClip = new MovieClip(); // I haven't added this to the stage, or given it shape. You need to for hitTestObject to work.
public function Main() {
// This is your constructor.
for (var i:Number = 0; i < objectarray.length; i++) {
objectarray[i].addEventListener(Event.ENTER_FRAME, collision);
}
}
private function collision(e:Event):void {
if (e.currentTarget.hitTestObject(theWall)) {
trace('hit');
}
}
}
}
Of note, you may want to look at a guide to hitTestObject() if it's giving you issues.

AS3 using an array in 2 different classes

for my school I have to create a small flash game.
I'm trying to create a sidescrolling flying game where you can also drop bombs.
The thing I'm not sure about is my bombs array I created this array in my plane class where the bomb movieclip is added to the array but I want to remove the bomb after it collided with an object in the bomb class but I'm not quite sure how to go about this the pushing of the bombs into the array goes fine. so this is what I have so far with regards to the array
for the variables:
public var bomb:MovieClip;
public var bombs:Array;
In the main function
public function McPlane() {
bombs = new Array();
In my update function
if(Input.bomb){
if(bombs.length <=1){
var bomb = new Bomb();
stage.addChild(bomb);
bomb.x = this.x + 30;
bomb.y = this.y + 16;
bombs.push(bomb);
so far this all works,
my question is can I use the same array in my bomb class where I want to... pop the array when it collides with other objects? and if so how do I go about it ?
You could remove the bomb from bombs in plane class.Add an event listener for bomb when it created in plane class and the bomb will dispatch the target event when it collides.
var bomb = new Bomb();
stage.addChild(bomb);
bomb.addEventListener("bombCollides", onBombCollideHandler);
private function onBombCollideHandler(e:Event):void {
var bomb:Bomb = e.target as Bomb;
if (bomb) {
var index:int = this.bombs.indexOf(bomb);
//if find the target bomb, remove it
if (index != -1) {
bombs.splice(index, 1);
}
}
}
In Bomb class
public class Bomb {
private function collide():void {
//do some check if collide
this.dispatchEvent("bombCollides");
}

AS3 - MovieClip array: play each movie after another

AS3 Newbie here... very confused, please be kind ;)
I have a MovieClip (rozette), which contains 7 instances of a MovieClip (circle). circle contains an animation and I would like to play each instance of it within rozette consecutively.
Questions - do I need to use an array? Is using eventListener the best way to do this? If so, how can I create an eventlistener for each item in the array? And what kind of event am I listening for?
Many thanks. Kat
You can see some options given as answers here:
Flash AS3 - Wait for MovieClip to complete
Basically I would think you want to have an array and a counter for which one you're on, each time the "playNext" function gets called, you should increment the counter and pull the next movie clip from the array. What this means is the order of elements in the array will dictate the order they play in. Something like:
private var myArray:Array = [mc1,mc2,mc3]; //list all the movieclip instance names here
private var counter:Number = 0; //start off on the first element, arrays in AS3 start at 0
//Play the next clip
private function playNext():void {
//Check that we're not at the end of the list, if so just return/stop
if(counter>myArray.length-1)
return;
//grab the next clip
var curClip:MovieClip = myArray[counter] as MovieClip;
//increment the counter for next time
counter++;
//when the last frame gets hit call this function again
curClip.addFrameScript(curClip.totalFrames-1, playNext);
//play the clip
curClip.play();
}
From your constructor of your Main class you would want to call playNext() once to get things rolling.
import com .greensock.*;
import com. greensock.easing.*;
var s1:b1=new b1();
var s2:b2=new b2();
var s3:b3=new b3();
var r1:Array = new Array();
r1.push(s1);
r1.push(s2);
r1.push(s3);
function ff (){
var i = 0;
while (i < r1.length) {
r1[i].visible=false
r1[0].visible=true
addChild(r1[i]);
i++;
}
TweenMax.staggerTo(r1, 0.4, {visible:true},0.2);
}
bb.addEventListener(MouseEvent.CLICK,cliki4x);
function cliki4x(e:Event):void{
ff ();
}

having issues working with movie clips inside of an array [as3]

In a game I'm making, I'm trying to have sprites put on top of a hit box. The best way I could think of accomplishing this is to make two arrays; one for the hit boxes, and one for the sprites, and then have the sprites stay on top of their respective hit-box via a for loop that will be in its own script.
Problem is, is that when I try to get the MovieClips in either of the arrays to do anything, it doesn't work. If I do a trace on the X or Y location of the sprites, I get "undefined" in my terminal. I'm going to explain this from the top down.
Here is an excerpt from my class that contains the for loop (Dasengine is my main class fyi)
for(var i:Number = 0; i < Dasengine.ovrcnt.length; i++){
trace(Dasengine.ovrcnt[i].x); //returns "undefined"
trace(Dasengine.ovrcnt[i]); //returns "object Onmea"
Dasengine.ovrcnt[i].x = Dasengine.enemycnt[i].x;//this isn't working
}
In another script when an enemy spawns, they go through this method.
if(ENEMY SPAWN CONDITION IS MET ){
Dasengine.baddie = new nme_spawn.Enemya(); //ENEMY HITBOX
Dasengine.Obaddie = new nme_overlay.Onmea(); //ENEMY's sprite
Dasengine.enemycnt[cntup] = [Dasengine.baddie]; //Enemy's Hit box movie clip is put in array meant for holding enemy movie clips
Dasengine.ovrcnt[cntup] = [Dasengine.Obaddie]; //Enemy sprites that go over the hit boxes are stored here
cntup++; //this is so movie clips are put in new parts of the array
}
in my main class, the movie clips are declared as follows also I have the addChild functionality in there.
public static var Obaddie:nme_overlay.Onmea;
//^variable for sprite
public static var baddie:nme_spawn.Enemya;
//^variable for hitbox
also Obaddie= Overlay baddie. Its the MovieClip that acts as what goes on top of the hitbox, this is what the player will see
badde = is simply the hitbox. This contains the "meat" of the enemy ai.
I talked about this with some friends and they thought I might need to define what 'X' is inside of the class of the object that is in the array. So I did the following
package nme_overlay {
import flash.display.*;
import flash.events.*;
import nme_spawn.*;
public class Onmea extends MovieClip{
// Constants:
// Public Properties:
// Private Properties:
public static var xloc:int = 0;
// Initialization:
public function Onmea() {
this.addEventListener(Event.ENTER_FRAME, overlaya);
}
private function overlaya(e:Event){
xloc = 55;
//trace(xloc);
}
}
}
and then for the looping class I did this
for(var i:Number = 0; i < Dasengine.enemycnt.length; i++){
trace(Dasengine.ovrcnt[i]);//returns "object Onmea"
trace(Dasengine.ovrcnt[i].xloc);//still returns "undefined"
}
Your xloc variable is static--it belongs to nme_overlay, the Class, not any particular instance. If you were to do this in your code AND you had strict mode on (which I suspect you do not, because there's a lot of stuff in your code that should be giving you at least warnings), you'd get an error that would tell you exactly that:
for(var i:Number = 0; i < Dasengine.enemycnt.length; i++){
trace(Dasengine.ovrcnt[i]);//returns "object Onmea"
trace(nme_overlay(Dasengine.ovrcnt[i]).xloc);//still returns "undefined"
}

Resources