A Flash Developer Resource Site

Page 1 of 2 12 LastLast
Results 1 to 20 of 26

Thread: How to make a movieclip automatically launch another?

  1. #1
    Junior Member
    Join Date
    Mar 2011
    Posts
    17

    How to make a movieclip automatically launch another?

    I'm trying to make a football game whereby the player stops footballs kicked by the computer from entering a goal...

    So far i've got the player controlled goalie moving back and forth upon keypress, and I have tweened the scorer continuously moving left and right at the top of the screen.

    Is it possible to make the scorer automatically launch a ball movieclip straight down the screen whenever a specific interval of time has passed?

    How?

    Thanks in advance for your time

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Yes.

    Use a Timer to time your interval. Set a listener on that Timer for TimerEvent.TIMER, and in that listener launch the ball.

  3. #3
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    Quote Originally Posted by 5TonsOfFlax View Post
    Yes.

    Use a Timer to time your interval. Set a listener on that Timer for TimerEvent.TIMER, and in that listener launch the ball.
    Thanks for your help!

    I've done that and got ...

    Code:
    var kickTimer:Timer = new Timer(1000);
    kickTimer.addEventListener(TimerEvent.TIMER, timerListener);
    function timerListener (e:TimerEvent):void{
    trace("ball kicked");
    }
    kickTimer.start();
    ... and the trace shows that the timer works.

    How could I go about making a new instance of the ball movieclip from my library appear on the screen at the same point as the scorer, then move down the y axis?

    >_<

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Make sure you export your ball clip for actionscript and give it a class name, like "Ball". If you want only one ball, then do this:

    Code:
    var kickTimer:Timer = new Timer(1000, 1);
    var ball:Ball;
    kickTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timerListener);
    function timerListener (e:TimerEvent):void{
      trace("ball kicked");
      ball = new Ball();
      ball.x = scorer.x;
      ball.y = scorer.y;
      addChild(ball);
      ball.addEventListener(Event.ENTER_FRAME, moveDown);
    }
    kickTimer.start();
    
    function moveDown(e:Event):void{
      DisplayObject(e.currentTarget).y+= 1;
    }
    You could use a tween instead of the moveDown function on enterframe.

    If you want multiple balls, do this:
    Code:
    var kickTimer:Timer = new Timer(1000);
    var balls:Array = [];
    kickTimer.addEventListener(TimerEvent.TIMER, timerListener);
    addEventListener(Event.ENTER_FRAME, moveBallsDown);
    function timerListener (e:TimerEvent):void{
      trace("ball kicked");
      var ball:Ball = new Ball();
      balls.push(ball);
      ball.x = scorer.x;
      ball.y = scorer.y;
      addChild(ball);
    }
    kickTimer.start();
    
    function moveBallsDown(e:Event):void{
      for (var i:int = 0; i < balls.length; i++){
        balls[i].y += 1;
      }
    }
    You will want to put in some sort of check in either case to remove the ball when it is no longer on the screen or in bounds or whatever.

  5. #5
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    Thanks for the quick reply, i'll work on it asap

  6. #6
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    Both of those options work to a certain extent, but... [here it comes]

    My 'scorer' movieclip moves left and right on a 100 frame motion tween, so every time the tween loop starts again:

    For the first option you suggested: a new ball is released at the same place each time [aka the same place the scorer gets to 1000 ms after the tween begins]

    For the second option: balls are released every 1000 ms as required but every time the scorer tween loop starts again the balls already kicked freeze in position and stop moving.

    If there a way to make the scorer move left and right along the stage just using actionscript in a 1 frame show instead of using the motion tween?

    OR

    Code:
    var kickTimer:Timer = new Timer(1000, 1);
    ^ Instead of the 1000 could I set it to release at a random interval? Thereby when the scorer tween loops the ball won't always be released at the same spot?
    A function like:
    Code:
    Math.floor(Math.random() * 2000) + 500;
    Where would I assign the result of this function to the kickTimer?

    Sorry to be a pain - Just struggling to see how everything should fit together properly >_<

  7. #7
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    You can change the Timer's delay by changing its delay property. You'd want to do that inside the TimerEvent listener.

    Of course you can make the scorer move left and right with just script. I'd use a tweening library like TweenLite, but you could do it with an ENTER_FRAME listener.

    I don't know what a "tween loop" is, but if you are re-entering the frame, then the code which declares the balls array will execute again, leaving the existing balls stranded (because they are in the old array, not the new array).

  8. #8
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    Tweenlite looks very useful thanks - having a go now.

  9. #9
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    More problems - >_<

    I'm struggling to get the mc to move left after it's reached the right hand side of the stage. I can make it jump back to the far left and start travelling right again, but not slowly move back left all the way...

    So far i've done:

    Code:
    addEventListener(Event.ENTER_FRAME, moveRooney);
    function moveRooney(e:Event):void
    		{
    			
    			rooney.x+=10;
    			if(rooney.x>=stage.stageWidth-rooney.width)
    				rooney.x-=550;
    			if(rooney.x<2)
    				rooney.x+=10;
    		}
    Thanks in advance to anyone kind enough to lend a hand.

  10. #10
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    This line in your enter frame handler:
    Code:
    rooney.x+=10;
    Makes rooney move to the right 10 pixels each frame. To make it move left, that would have to be a subtraction. So, instead of hardcoding the 10, you can make the amount depend on the direction. And then instead of directly changing rooney's position when it hits the borders, change the direction.

    Code:
    var direction:int = 1;
    function moveRooney(e:Event):void{
      rooney.x+= 10 * direction;
      if((rooney.x>=stage.stageWidth-rooney.width) || (rooney.x<2)){
        direction *= -1;
      }
    }

  11. #11
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    That works fantastic thankyou, just need to sort out the the collision detection now.

    I'll post the game here to show you when it's finished

  12. #12
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    It just makes no sense... Every time I fix something 12 more errors spring up :/

    As soon as the frame starts I get the output:

    TypeError: Error #2007: Parameter child must be non-null.
    at flash.display::DisplayObjectContainer/removeChild()
    at main::as/ballHitPlayer()

    When the falling balls hit the player instead of tracing a 'hitt' and removing the ball the output returns:

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

    I've googled the errors but can't find anything useful for this situation...

    My as is:
    Code:
    stop();
    //declare velocity variables
    var xVelocity:int = 5;
    
    
    
    //add our KEY_DOWN listener
    stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
    
    //function to be called when a key is pressed down
    function onKeyPressed(evt:KeyboardEvent):void {
    	
    	//a switch/case statement is like having a bunch of if statements
    	switch (evt.keyCode) {
    		case Keyboard.LEFT:
    			player.x -= xVelocity;
    			break;
    		case Keyboard.RIGHT:
    			player.x += xVelocity;
    			break;
    		default:
    			trace("keyCode:", evt.keyCode);
    	}//end of switch
    }//end of onKeyPressed function
    //Math.floor(Math.random() * 2000) + 500;
    var direction:int = 1;
    addEventListener(Event.ENTER_FRAME, moveRooney);
    
    			function moveRooney(e:Event):void
    			{
     			 rooney.x+= 10 * direction;
     			 if((rooney.x>=stage.stageWidth-rooney.width) || (rooney.x<2))
    			 {
        			direction *= -1;
     			 }
    			 }
    		
    var kickTimer:Timer = new Timer(3000);
    var ballArray:Array = [];
    var ballcounter:int = 0;
    var firstKick:int = 0;
    var gameOver:Boolean = false;
    var ball:Ball;
    kickTimer.addEventListener(TimerEvent.TIMER, timerListener);
    
    
    addEventListener(Event.ENTER_FRAME, ballHitPlayer);
    
    function timerListener (e:TimerEvent):void{
      trace("ball kicked");
     
      //balls.push(ball);
      ballArray[ballcounter] = new Ball();
      ballArray[ballcounter].x = rooney.x;
      ballArray[ballcounter].y = rooney.y;
      ballArray[ballcounter].name = 'ball'+ballcounter;
      addChild( ballArray[ballcounter]);
      
      ballArray[ballcounter].addEventListener(Event.ENTER_FRAME, moveBallsDown);
      ballArray[ballcounter].addEventListener(Event.ENTER_FRAME, ballHitPlayer);
    
      ballcounter++;
    }
    kickTimer.start();
    
    function moveBallsDown(e:Event):void{
    	e.target.y += 10;
    }
    
    
    function ballHitPlayer(e:Event):void{
    
    		if(e.target.hitTestObject(player))
    		{
    			removeEventListener(Event.ENTER_FRAME, ballHitPlayer);
    			stage.removeChild(getChildByName(e.target.name));
    			trace('hitt');
    		}
    }
    I have tried commenting out the removeChild and removeEventListener:
    Code:
    function ballHitPlayer(e:Event):void{
    
    		if(e.target.hitTestObject(player))
    		{
    			//removeEventListener(Event.ENTER_FRAME, ballHitPlayer);
    			//stage.removeChild(getChildByName(e.target.name));
    			trace('hitt');
    		}
    }
    And that stops any errors, but continuously traces 'hitt' even before a ball has been kicked...

    Where do I even start lol?

    Once again thanks for reading this far!

  13. #13
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Two related problems.

    1. You are trying to remove the ball from the stage, but it was added to the root. You can't remove it from something it's not a child of.
    2. You are using getChildByName(e.target.name). This is stupid, because in the best case, you get: e.target. Why bother asking flash to look up a reference to something you already have a reference for?

  14. #14
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    Thankyou!
    So I changed the ballHitPlayer function to:
    Code:
    function ballHitPlayer(e:Event):void{
    
    		if(e.target.hitTestObject(player))
    		{
    			removeEventListener(Event.ENTER_FRAME, ballHitPlayer);
    			stage.removeChild(e.target.name);
    			trace('hitt');
    		}
    }
    It's still not tracing any hits, and the output error has changed to:

    TypeError: Error #1034: Type Coercion failed: cannot convert "ball7" to flash.display.DisplayObject.
    at main::as/ballHitPlayer()
    That's related to the ball being added to the root not the stage?

  15. #15
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    ... yeah, you kinda took away the wrong point.

    Do not use names when you want to use things.

    Also, stage is still not the root.

    Code:
    function ballHitPlayer(e:Event):void{
      if(e.target.hitTestObject(player)){
         var thisball:DisplayObject = DisplayObject(e.currentTarget);
         thisball.removeEventListener(Event.ENTER_FRAME, ballHitPlayer);
         removeChild(thisball);
         trace('hitt');
      }
    }
    You need to call removeEventListener on the same thing you added the listener to. You also need to call removeChild on the same thing that you called addChild on. And you need to pass removeChild a DisplayObject, not a String.

    You might notice that the ball's name property is now completely unused. This is intentional. Stop naming stuff that doesn't need names.

  16. #16
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    I think I understand...

    It didn't realize it was supposed to remove the ball because it was looking for a string containing the name?

    If I wanted it to move to the next frame on hit could I use a similar function but using
    Code:
    nextFrame();
    instead of
    Code:
    trace('hitt');
    I was going to ask you to explain the difference between the stage and the root but I can probably google that on the bus home!

    Thanks a lot. =]

  17. #17
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    It didn't realize it was supposed to remove the ball because it was looking for a string containing the name?
    I don't know what that means.

    Yes, you could put nextFrame() in the same function to move to the next frame. However, this strikes me as a bad idea since multiple balls might hit, causing multiple calls to nextFrame.

    The stage is the start of the displayList tree. Normally, it has 1 child, the root. The root corresponds to the main timeline or document class instance. If you just call
    Code:
    addChild(something);
    in your framescript, then something is a child of the root, not of the stage.

  18. #18
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    Quote Originally Posted by 5TonsOfFlax View Post
    I don't know what that means.

    Yes, you could put nextFrame() in the same function to move to the next frame. However, this strikes me as a bad idea since multiple balls might hit, causing multiple calls to nextFrame.

    The stage is the start of the displayList tree. Normally, it has 1 child, the root. The root corresponds to the main timeline or document class instance. If you just call
    Code:
    addChild(something);
    in your framescript, then something is a child of the root, not of the stage.
    Right, so if I wanted to make it a child of the stage I should call

    Code:
    stage.addChild(something);
    Instead? For example here:

    Code:
     ballArray[ballcounter] = new Ball();
      ballArray[ballcounter].x = rooney.x;
      ballArray[ballcounter].y = rooney.y;
      ballArray[ballcounter].name = 'ball'+ballcounter;
      stage.addChild( ballArray[ballcounter]);
    Not

    Code:
     ballArray[ballcounter] = new Ball();
      ballArray[ballcounter].x = rooney.x;
      ballArray[ballcounter].y = rooney.y;
      ballArray[ballcounter].name = 'ball'+ballcounter;
      addChild( ballArray[ballcounter]);
    Hmm... If

    Code:
    function ballHitPlayer(e:Event):void{
      if(e.target.hitTestObject(player)){
         var thisball:DisplayObject = DisplayObject(e.currentTarget);
         thisball.removeEventListener(Event.ENTER_FRAME, ballHitPlayer);
         removeChild(thisball);
         trace('hitt');
      }
    }
    Removes only the ball that hit the player, how could you remove every single child of the ballArray on the screen?

    I tried just setting

    Code:
    ballArray = []

    But that doesn't remove the display objects already on the screen!

  19. #19
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Quote Originally Posted by MrGuinney View Post
    Right, so if I wanted to make it a child of the stage I should call

    Code:
    stage.addChild(something);
    Instead?
    If you did want that, yes. But you don't want that.

    You aren't using ballArray at all in the posted code. You can get rid of it entirely unless you are using it somewhere else.

    If you want to keep it, then be sure to remove the entry from the array as well as the display:
    Code:
    function ballHitPlayer(e:Event):void{
      if(e.target.hitTestObject(player)){
         var thisball:DisplayObject = DisplayObject(e.currentTarget);
         thisball.removeEventListener(Event.ENTER_FRAME, ballHitPlayer);
         removeChild(thisball);
         ballArray.splice(ballArray.indexOf(thisBall), 1));
         trace('hitt');
      }
    }
    To remove all the balls at once, you can iterate through the ballArray
    Code:
    for (var i:int = 0; i < ballArray.length; i++){
      removeChild(ballArray[i]);
    }
    ballArray = []; //can do this, or do a similar splice inside the loop.  If other stuff has a reference to ballArray, do the splice.

  20. #20
    Junior Member
    Join Date
    Mar 2011
    Posts
    17
    That's really helpful, thanks.

    It works well, except I have two similar functions -

    Code:
    function ballHitPlayer(e:Event):void{
      if(e.target.hitTestObject(player)){
         var thisball:DisplayObject = DisplayObject(e.currentTarget);
         thisball.removeEventListener(Event.ENTER_FRAME, ballHitPlayer);
         removeChild(thisball);
         ballArray.splice(ballArray.indexOf(thisball), 1);
        trace('hitt');
         score++;
      }
    }
    and
    Code:
    function gameIsOver(e:Event):void{
    	if(e.target.hitTestObject(line)){
    		var missedball:DisplayObject = DisplayObject(e.currentTarget);
    		missedball.removeEventListener(Event.ENTER_FRAME,     gameIsOver);
    		removeChild(missedball); //the ball is removed - so i assume the function works up to here 
    		ballArray.splice(ballArray.indexOf(missedball), 1); // but fails here?
    		for (var i:int = 0; i < ballArray.length; i++)
    		{
      			removeChild(ballArray[i]);
    		}
    		gameOver = true;
    		kickTimer.stop();
    		nextFrame();
    		trace('gameover');
                   
    	}
    }
    First one clears the ball and increments the score if the player catches the ball, the second one is supposed to clear all the balls and send the player to the next frame...

    In the next frame is a button which sends the player to the previous frame to 'restart' the game...

    Everything works fine if no balls have been caught, but if the player has caught a ball then gameIsOver fails and generates an error.

    TypeError: Error #2007: Parameter child must be non-null.
    at flash.display:isplayObjectContainer/removeChild()
    at main::as/gameIsOver()
    I'm guessing this is because ballHitPlayer has removed a child from the array that gameIsOver also tries to remove [when it clears the array?] but finds it null?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center