ActionScript 3 Looping - actionscript-3

I just started using Looping in AS3 recently and I have much to learn. here is the question. Below is a Loop that puts 5 balls one on top of the other on the stage. So far so good. however, I'd like to create a situation when clicking on a button, the bottom ball is removed, and then each ball take the place of the ball below it one by one, continue this for each click until all the balls are gone. . I have created this situation with add/remove child and I thought it could be more efficient with looping. I just don't know how to access the balls since I don't have instance name or class name that I can reference too.
var ball: gBall4M;
var i: Number;
for (i = 0; i < 5; i++) {
ball = new gBall4M();
ball.x = 331.30;
ball.y = 25 + i * 17
addChild(ball);
}
function release2Ball2(event: MouseEvent): void {
This is the effect I want to get https://youtu.be/B4GLolw8QVA

As mentioned in the answer of #daniel-messer, you can use an Array to store your balls, and for the second part of your question, when removing the last ball and moving the other ones, you can use array.pop() to remove the last element of the array, and then you can use array.map() to move the other balls :
function release2Ball2(event:MouseEvent): void
{
if(balls.length > 0){
ball = balls.pop(); // remove and get the last element of the array
ball.parent.removeChild(ball); // remove that element from the DisplayObjectContainer
function move_ball(item:Ball, index:int, array:Array):void {
item.y += 17;
}
// move the rest of elements
balls.map(move_ball, this);
}
}
EDIT :
Take a look on the code working, I added numbers to understand how balls are moving :
Your full code can be like this :
var balls:Array = [],
ball:gBall4M;
for (var i:int = 0; i < 5; i++) {
ball = new gBall4M();
ball.x = 331.30;
ball.y = 25 + i * 17;
balls.push(ball);
addChild(ball);
}
btn.addEventListener(MouseEvent.CLICK, release2Ball2);
function release2Ball2(event:MouseEvent):void {
if (balls.length > 0) {
ball = balls.pop();
ball.parent.removeChild(ball);
function move_ball(item:gBall4M, index:int, array:Array):void {
item.y += 17;
}
balls.map(move_ball, this);
}
}
EDIT 2:
To do that kind of animation, you can use a Timer like this :
var balls:Array = [],
ball:gBall4M;
for (var i:int = 0; i < 5; i++) {
ball = new gBall4M();
ball.x = 30;
ball.y = 25 + i * 17;
balls.push(ball);
addChild(ball);
}
btn.addEventListener(MouseEvent.CLICK, release2Ball2);
function release2Ball2(event:MouseEvent):void {
if (balls.length > 0) {
ball = balls.pop();
ball.parent.removeChild(ball);
if(balls.length > 0){
timer.start();
}
}
}
var timer:Timer = new Timer(150);
timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent){
if(balls.length >= timer.currentCount){
balls[balls.length - timer.currentCount].y += 17;
} else {
timer.reset();
}
})
Which will give you something like this :
Hope that can help.

Just save the instances inside an array or similar that you can use later.
I hope you are using a code file and not writing the code directly inside a frame inside the flash editor. Otherwise you might end up with issues.
Something similar to this should work
package {
class Main {
var balls:Array = [];
function createBalls() {
var ball: gBall4M;
var i: Number;
for (i = 0; i < 5; i++) {
ball = new gBall4M();
ball.x = 331.30;
ball.y = 25 + i * 17;
balls.push(ball); //Save them to array
addChild(ball);
}
}
function release2Ball2(event: MouseEvent): void {
var clickedBall:gBall4M = event.currentTarget as gBall4M; //this might be wrong depending on what you are listening for, and what type of object gBall4M is...
for(var i=0; i<balls.length; ++i) {
if(balls[i] == clickedBall) {
balls[i].splice(i, 1); //remove instance from array
removeChild(clickedBall); //remove instance from display list
break;
}
}
}
}
}

OK I figured it out. using this code on frame 1
function release2Ball2(event: MouseEvent): void {
if (ballA.length > 0) {
ball = ballA.pop();
removeChild(ball);
ball = null
gotoAndPlay(2);
}
}
stop();
using this code on frame 10:
for (i = 0; i < ballA.length; i++) {
ballA[i].y += 17;
stop();
That does the trick.
Thank you so much for your help

Related

AS3 - Array called into a new function... HOW?

Sup everyone, well since my last post as been super fast to fix due to my tired eyes. I'm gonna ask you one more favor...
It's about an Array, so before i had only one "target" showing. So i thought my game was way to simple...
So i decided to add more target that moves, and place with random math...
Well they are correctly placed, but only one is moving. I think is the first one that is being created....
This is my line of code :
// Creating multiple targetwith ADDCHILD and ARRAY at different location //
var arraymc_target:Array = [];
for(var i:int = 1; i<8; i++)
{
var mc_target:target = new target();
mc_target.x = Math.floor(Math.random() * 400);
mc_target.y = Math.floor(Math.random() * 550);
addChild(mc_target);
arraymc_target.push(mc_target);
}
// Creating the TARGETS MOVEMENT //
function goesside_1(event:Event):void {
mc_target.x -= 2;
if (mc_target.x < -20){
mc_target.x = 550;
}
}
mc_target.addEventListener(Event.ENTER_FRAME, goesside_1);
// ----------------------------------------------- //
Your main issue is that in goesside_1, you're moving mc_target which is simply a reference to the last instance of target you created in the loop and pushed to the array.
Another quirk I noticed is that you're adding the ENTER_FRAME listener to one of your targets instead of to the stage.
What you want to do is add the listener to the stage, and then loop over each of the targets in your array:
var arraymc_target:Array = [];
for(var i:int = 1; i<8; i++)
{
var mc_target:target = new target();
mc_target.x = Math.floor(Math.random() * 400);
mc_target.y = Math.floor(Math.random() * 550);
addChild(mc_target);
arraymc_target.push(mc_target);
}
// Creating the TARGETS MOVEMENT //
function goesside_1(event:Event):void {
for each(var mc_target:target in arraymc_target)
{
mc_target.x -= 2;
if (mc_target.x < -20){
mc_target.x = 550;
}
}
}
stage.addEventListener(Event.ENTER_FRAME, goesside_1);

hitTestObject doesn't work with veritable

trying to make bomb explode on impact when it hit the balls at the bottom of the stage, with if (bomb1.hitTestObject(ball)) { .But when the bomb hit one of the balls nothing happened. it works with other objects that are placed on stage but not with the balls.ball is a variable for 8 balls spread randomly on the bottom of the stage.
import flash.events.Event;
bomb1.gotoAndStop(1);
var minLimit: int = 31;
var maxLimit: int = 42;
var range: int = maxLimit - minLimit;
var balls: Array = [],
ball: bomb30a;
for (var i: int = 0; i < 8; i++) {
ball = new bomb30a();
ball.x = 150 + i * (Math.ceil(Math.random() * range) + minLimit);
ball.y = 350;
balls.push(ball);
addChild(ball);
}
thisButton.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler);
function fl_MouseClickHandler(event: MouseEvent): void {
bomb1.gotoAndPlay(1);
this.addEventListener(Event.ENTER_FRAME, handleCollision);
}
function handleCollision(evt: Event): void {
if (bomb1.hitTestObject(ball)) {
this.removeEventListener(Event.ENTER_FRAME, handleCollision);
bomb1.stop();
bomb1.bomb2.gotoAndPlay(31);
}
}
stop();
You are making eight bomb30a Objects, but you keep assigning them to the same variable, ball. This means that ball will, after your loop, refer to the last one only. So, when you do the hitTest, it is checking only the last ball you created. You will need to do a loop through your balls Array and try the hitTest on each on separately, as in...
for ( var i:int = 0; i < balls.length; ++i )
{
if ( bomb1.hitTestObject( balls[i] ) )
{
...
}
}

Objects to bounce around the screen?

I would like to make the 5 'burger' objects bounce around the screen so they are harder to shoot as is the aim of my game. But, so far they are only lining up at the top of the stage so it's way too easy to play. Would I need to create 5 separate objects with 5 separate instance names etc.
This is what I have so far:
var firing:Boolean = false;
var bullet:Bullet1 = new Bullet1();
stage.addEventListener(KeyboardEvent.KEY_DOWN, keydown);
function keydown(event:KeyboardEvent):void {
switch(event.keyCode) {
case Keyboard.LEFT :
ball.x -= 10;
break;
case Keyboard.SPACE :
if (!firing) {
fire();
}
break;
case Keyboard.RIGHT :
ball.x += 10;
break;
case Keyboard.UP :
ball.y -= 10;
break;
case Keyboard.DOWN :
ball.y += 10;
break;
default :
break;
}
}
stage.addEventListener(KeyboardEvent.KEY_DOWN, keydown);
function fire() {
addChild(bullet);
firing = true;
bullet.x = ball.x;
bullet.y = ball.y - 60
;
}
addEventListener(Event.ENTER_FRAME, movestuff);
function movestuff(event:Event):void {
if (firing) {
bullet.y -= 20;
if (bullet.y < 0) {
firing = false;
removeChild(bullet);
}
}
}
var numBurger:Number = 5;
var array:Array = new Array();
for (var i:uint = 0; i<numBurger; i++) {
var burger:Burger = new Burger();
array.push(burger);
addChild(burger);
burger.x = 100 + 100*i;
burger.y = 50;
}
addEventListener(Event.ENTER_FRAME, checkCollision);
function checkCollision(event:Event)
{
for (var i:uint=0; i<array.length; i++)
{
if (array[i].hitTestObject(bullet))
{
removeChild(array[i]);
array.splice(i,1);
return;
}
}
}
Thanks for any help.
No, you would not have to create each movie clip separately if you use a loop to create randomized x and y locations for each burger. You can also use Math.random() to give a random speed and direction to each burger. In the code below these values are held in "direction_ary" array. This code creates five MovieClips of the "Burger"class, and places them at random points on the screen. The code also creates random speeds and directions for each MovieClip:
import flash.events.Event;
function find_random(max,min){
return Math.round(min+(max-min)*Math.random());
}
var ary:Array = [];
var direction_ary:Array = [];
for(var i:uint=0;i<5;i++){
ary[i]=new Burger();
ary[i].name="burger"+(i);
ary[i].x=find_random(stage.stageWidth-ary[i].width,ary[i].width);
ary[i].y=find_random(stage.stageHeight-ary[i].height,ary[i].height);
addChild(ary[i]);
direction_ary[i]=[find_random(5,-5),find_random(5,-5)];
for(var e:uint=0;e<100;e++){
if(direction_ary[i][0]==0||direction_ary[i][1]==0){
direction_ary[i]=[find_random(5,-5),find_random(5,-5)];
}else{
break;
}
}
}
stage.addEventListener(Event.ENTER_FRAME,update_burgers);
function update_burgers(e:Event){
for(var i:uint=0;i<5;i++){
if (ary[i].x>stage.stageWidth||ary[i].x<0){
direction_ary[i][0]*=-1;
}
if (ary[i].y>stage.stageHeight||ary[i].y<0){
direction_ary[i][1]*=-1;
}
ary[i].x+=direction_ary[i][0];
ary[i].y+=direction_ary[i][1];
}
}
The code is fairly self explanatory. Good luck with your project.
Cheers,
Drake Swartzy

How can I turn an AS2 snow effect into a AS3 snow effect?

So I manage to find a snow effect that I like and wanted to use it but I realized it was in AS2 and I need it to be in AS3. Since there isn't a small difference between AS2 and AS3 I'm here to find some in these matter.
As you can see in the fla provided I also want to control the wind and speed by buttons.
Here is a link to the AS2 snow effect: http://www.freeactionscript.com/download/realistic-snow-fall-snowflake-effect.zip
This is the code in AS2:
//settings
var speed:Number = 2;
var wind:Number = -2;
var movieWidth:Number = 550;
var movieHeight:Number = 400;
createSnow(_root, 100);
function createSnow(container:MovieClip, numberOfFlakes:Number):Void
{
//run a for loop based on numberOfFlakes
for (var i = 0; i < numberOfFlakes; i++)
{
//set temporary variable and attach snowflake to it from the library
var tempFlake:MovieClip = container.attachMovie("snow_mc", "snow"+container.getNextHighestDepth(), container.getNextHighestDepth());
//variables that will modify the falling snow
tempFlake.r = 1+Math.random()*speed;
tempFlake.k = -Math.PI+Math.random()*Math.PI;
tempFlake.rad = 0;
//giving each snowflake unique characteristics
var randomScale:Number = random(50)+50;
tempFlake._xscale = randomScale;
tempFlake._yscale = randomScale
tempFlake._alpha = random(100)+50;
tempFlake._x = random(movieWidth);
tempFlake._y = random(movieHeight);
//give the flake an onEnterFrame function to constantly update its properties
tempFlake.onEnterFrame = function()
{
//update flake position
this.rad += (this.k / 180) * Math.PI;
this._x -= Math.cos(this.rad)+wind;
this._y += speed;
//if flake out of bounds, move to other side of screen
if (this._y >= movieHeight) {
this._y = -5;
}
if (this._x >= movieWidth)
{
this._x = 1
}
if (this._x <= 0)
{
this._x = movieWidth - 1;
}
}
}
}
//buttons
//wind
left_btn.onRelease = function()
{
wind = 2;
}
none_btn.onRelease = function()
{
wind = 0;
}
right_btn.onRelease = function()
{
wind = -2;
}
//speed
slow_btn.onRelease = function()
{
speed = .5;
}
normal_btn.onRelease = function()
{
speed = 1
}
fast_btn.onRelease = function()
{
speed = 3
}
It's going to be really quite similar.
The first thing would be, instead of:
var tempFlake:MovieClip = container.attachMovie("snow_mc", "snow"+...
you want something like:
var tempFlake = new snow_mc();
container.addChild(tempFlake);
Then convert all the property names such as _x etc to their AS3 equivalents (no underscore, scaleX in place f _xscale etc), Math.random() * 50 in place of random(50).
Replace all onRelease with addEventListener(MouseEvent.CLICK, function() {})
Finally instead of tempFlake.onEnterFrame you'll need one frame loop something like:
function onFrame(event: Event): void {
foreach(var child: MovieClip in container) {
child.rad += ... etc
}
}
addEventListener(Event.ENTER_FRAME, onFrame);
These steps should be sufficient to get it working as AS3. Once it's running, you could go further to make it more AS3 by creating a SnowFlake class that encapsulates all the properties and updates for one snowflake.

Action Script 3. Delete object when mouse clicked

I'm creating flash game, Idea is falling objects (in this case apples) from the sky and player need to click on apples, after apple is clicked It must be deleted and Score updated by 10 points.
Here is my part of code where apples is spawning:
public function startGame()
{
speed = C.PLAYER_SPEED;
gravity = C.GRAVITY;
score = C.PLAYER_START_SCORE;
randomChance = C.APPLE_SPAWN_CHANCE;
apples = new Array();
mcGameStage.addEventListener(Event.ENTER_FRAME,update);
}
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
newApple.y = C.APPLE_START_Y;
apples.push(newApple);
mcGameStage.addChildAt(newApple,0);
}
//Move Apples
for (var i = apples.length-1; i >= 0; i--)
{
apples[i].y += gravity;
if (apples[i].y > C.APPLE_END_Y)
{
mcGameStage.removeChild(apples[i]);
apples.splice(i,1);
}
}
//txtScore.text = String(score);
}
}
And here is code which should delete apples by mouse clicked. But It doesn't work, I don't have any errors, just not deleting apples. Could you help me please?
function onClick(evt:MouseEvent):void{
var apples = evt.target;
for (var iz = apples.length-1; iz >= 0; iz--)
{
//Register hit
score += C.SCORE_PER_APPLE;
mcGameStage.removeChild(apples[iz]);
apples.splice(iz,1);
}
}
UPDATE
So my code now looks like:
public function startGame()
{
speed = C.PLAYER_SPEED;
gravity = C.GRAVITY;
score = C.PLAYER_START_SCORE;
randomChance = C.APPLE_SPAWN_CHANCE;
apples = new Array();
mcGameStage.addEventListener(Event.ENTER_FRAME,update);
}
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
newApple.y = C.APPLE_START_Y;
apples.push(newApple);
newApple.addEventListener(MouseEvent.CLICK, onClick);
mcGameStage.addChildAt(newApple,0);
}
//Move Apples
for (var i = apples.length-1; i >= 0; i--)
{
apples[i].y += gravity;
if (apples[i].y > C.APPLE_END_Y)
{
mcGameStage.removeChild(apples[i]);
apples.splice(i,1);
}
}
txtScore.text = String(score);
}
function onClick(evt:MouseEvent):void{
var apples = evt.target;
apples.visible = false;
//mcGameStage.removeChild(apples);
score += C.SCORE_PER_APPLE;
}
}
}
I use this apples.visible = false; instead mcGameStage.removeChild(apples); and It's all right.
Just I misunderstood why my score not updating? Always show 0.
And sometimes I can't set apples invisible by 1 click If it is click on top of apple nothing happens, I need to click on apple's center to hide It, why I have this problem?
If you are serious about game development, you should think about code bloat. In your case, you don't need any apples array - your display list, courtesy Flash Player, is already able to contain the apples in a sorted linked list structure - much more efficient for the kind use you intend for it - deleting and adding apples. If you dedicate a container sprite just for containing apples, you get two benefits: 1) you get a free display list of apples and 2) if you register a mouse click event listener for this sprite (which contains only apples), then every click is on an apple and event.target will reflect it.
Review the altered code carefully:
public function startGame()
{
speed = C.PLAYER_SPEED;
gravity = C.GRAVITY;
score = C.PLAYER_START_SCORE;
randomChance = C.APPLE_SPAWN_CHANCE;
mcApples = new Sprite();
mcApples.addEventListener(MouseEvent.CLICK, onClickApple);
mcGameStage.addChild(mcApples);
mcGameStage.addEventListener(Event.ENTER_FRAME, update);
}
private function update(evt:Event)
{
//Spawn new apple
if(Math.random() < randomChance)
{
var newApple = new Apple();
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
newApple.y = C.APPLE_START_Y;
mcApples.addChild(newApple);
}
//Move Apples
for (var i = 0; i < mcApples.numChildren;)
{
var apple = mcApples.getChildAt(i);
apple.y += gravity;
if(apple.y > C.APPLE_END_Y)
{
apple.parent.removeChild(apple);
continue;
}
i++;
}
}
function onClickApple(event: MouseEvent):void
{
var apple : Apple = event.target;
apple.parent.removeChild(apple);
score += C.SCORE_PER_APPLE;
}
The important changes and their effects are thus:
Dedicated sprite mcApples where apples are added and removed from.
No need for an array of apples, Flash Player keeps track of apples in mcApples container.
Mouse clicking listener setup guarantees any click is on an apple.
So, no splicing of arrays required and no need for explicit function references in Apple class or adding event listener for each new apple.
As an extra piece of advice, you should be careful binding your logic to enter frame events - the faster the frame rate, the faster the call frequency - usually no problem, but sometimes not what you want. I would bind the update call to a timer event instead ;-)
private function update(evt:Event)
{
//Spawn new apples
if (Math.random() < randomChance)
{
var newApple = new Apple(appleClick);
newApple.x = Math.random() * C.APPLE_SPAWN_END_X + C.APPLE_SPAWN_START_X;
newApple.y = C.APPLE_START_Y;
apples.push(newApple);
mcGameStage.addChildAt(newApple,0);
}
//Move Apples
for (var i = apples.length-1; i >= 0; i--)
{
apples[i].y += gravity;
if (apples[i].y > C.APPLE_END_Y)
{
mcGameStage.removeChild(apples[i]);
apples[iz].destruct();
apples.splice(i,1);
}
}
//txtScore.text = String(score);
}
function appleClick(pApple:Apple):void{
for (var iz = apples.length-1; iz >= 0; iz--)
{
if (apples[iz] == pApple)
{
//Register hit
score += C.SCORE_PER_APPLE;
mcGameStage.removeChild(apples[iz]);
apples[iz].destruct();
apples.splice(iz,1);
break;
}
}
}
....
public class Apple extends Group or something
{
private var m_fCallback:Function;
public function Apple(pCallback:Function):void
{
addEventListener(MouseEvent.CLICK, onClick);
m_fCallback = pCallback;
}
private function destruct():void
{
removeEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(pEvent:MouseEvent):void
{
m_fCallback(this);
}
}
I do not see any event listener added for onClick(). Be sure to check that your event listener is added, and put a trace or an alert in your onClick() function so that you can confirm that the code is actually reached.