We will examine several ways to create BOUNDARIES for the stage or object(s) on the stage. However, to appreciate this topic better, we will create an object (in our case, a ball) using a class and give it some type of behavior (i.e., bouncing). The steps for each of the varies levels are basically the same, so you can skip to the appropiate level as you see fit.
First, let's create a class with a bounce behavior and built-in boundaries code. Will will write a series of "if" statements that will "check" to see if the ball crosses those boundaries (right/left and top/bottom). Remember that Flash coordinates are measured from the top/left corner of the stage with positive values going to the right and downward. (See figure to your right)
package { // Import needed classes import flash.display.MovieClip; import flash.events.Event; public class Boundary_Starter extends MovieClip { // Set Horizontal/Vertical velocity (speed and direction) public var velocityX:int = 8; public var velocityY:int = -8; // Create Constructor Function public function Boundary_Starter () { addEventListener (Event.ENTER_FRAME, onEnterFrame); } // Call onEnterFrame handler (at frame rate) private function onEnterFrame (eventObject:Event):void { // Move ball based on velocity this.x += velocityX; this.y += velocityY; // Reverse horizontal direction if Ball hit left of stage if (this.x < 0 ) { velocityX *= -1; } //Reverse horizontal direction if Ball hit right of stage if(this.x > 550) { velocityX *= -1; } // Reverse vertical direction if Ball hit top of stage if (this.y < 0) { velocityY *= -1; } // Reverse vertical direction if Ball hit bottom of stage if (this.y > 400) { velocityY *= -1; } } } }
NOTE: The use of the word "this" is optional but highly recommended because it reinforces that concept of "object.property." It also lets you know that the code is "attached" to an object–in this case, the Boundary_Beginner symbol. The use of velocityX *= -1 or velocityY *= -1 will cause the current value of these variable to be negative; hence, causing the ball to move in the opposite direction. We could had used velocityX = -velocityX or velocityY = -velocityY as well; however, the former is less typing.
The problem with the following code is two-fold:
Let's correct these two problems by substracting out half the width of the ball (this.width/2) in our code and then consolidating the boundary code into two code blocks instead of four by using the OR operator since the result of the VelocityX and VelocityY is the same.
Revise the code above as follow, then save and test movie again.
package { // Import needed classes import flash.display.MovieClip; import flash.events.Event; public class Boundary_Beginner extends MovieClip { // Set Horizontal/Vertical velocity (speed and direction) public var velocityX:int = 8; public var velocityY:int = -8; // Create Constructor Function public function Boundary_Beginner () { addEventListener (Event.ENTER_FRAME, onEnterFrame); } // Call onEnterFrame handler (at frame rate) private function onEnterFrame (eventObject:Event):void { // Move ball based on velocity this.x += velocityX; this.y += velocityY; // Reverse horizontal direction if Ball hit left/right of stage if (this.x - this.width / 2 < 0 || this.x > 550 - this.width / 2) { velocityX *= -1; } // Reverse vertical direction if Ball hit top/bottom of stage if (this.y - this.width / 2 < 0 || this.y > 400 - this.width / 2) { velocityY *= -1; } } } }
Another potential problem with the previous boundary code (lines 27 and 32) is that they are hard-wired to "fixed" sizes (width/height) of the current stage. If you know the stage size will not be changed, this is OK. However, if you want to make your code dynamic so that it can work with ANY stage size you can revise the code by using the stage property to ascertain the width and height of the stage.
package { // Import needed classes import flash.display.MovieClip; import flash.events.Event; public class Boundary_Intermediate extends MovieClip { // Set Horizontal/Vertical velocity (speed and direction) public var velocityX:int = 8; public var velocityY:int = -8; // Create Constructor Function public function Boundary_Intermediate () { addEventListener (Event.ENTER_FRAME, onEnterFrame); } // Call onEnterFrame handler (at frame rate) private function onEnterFrame (eventObject:Event):void { // Move ball based on velocity this.x += velocityX; this.y += velocityY; // Reverse horizontal direction if Ball hit left/right of stage if (this.x - this.width / 2 < 0 || this.x > stage.stageWidth - this.width / 2) { velocityX *= -1; } // Reverse vertical direction if Ball hit top/bottom of stage if (this.y - this.width / 2 < 0 || this.y > stage.stageHeight - this.width / 2) { velocityY *= -1; } } } }
NOTE: Notice that the fixed width and height (550 and 400) has been replaced with their dynamic counterpart (stage.stageWidth and stage.stageHeight) to make the code reusable for any stage size.
Instead of getting the boundaries of the stage, you could also get the boundaries of the object on the stage (in our case, the ball).
package { // Import needed classes import flash.display.MovieClip; import flash.events.Event; import flash.geom.Rectangle; public class Boundary_Advanced extends MovieClip { // Set Horizontal/Vertical velocity (speed and direction) public var velocityX:int = 8; public var velocityY:int = -8; // Boundary rectangle of ball public var bounds:Rectangle; // Create Constructor Function public function Boundary_Advanced () { addEventListener (Event.ENTER_FRAME, onEnterFrame); } // Call onEnterFrame handler (at frame rate) private function onEnterFrame (eventObject:Event):void { // Move ball based on velocity this.x += velocityX; this.y += velocityY; // Get rectangle boundary of ball bounds = getBounds(parent); // Reverse horizontal direction if Ball hit left/right of stage if (bounds.left < 0 || bounds.right > stage.stageWidth) { velocityX *= -1; } // Reverse vertical direction if Ball hit top/bottom of stage if (bounds.top < 0 || bounds.bottom > stage.stageHeight) { velocityY *= -1; } } } }
NOTE: The bound properties (top, right, bottom and left) are used to define the bounds of the ball. The ball is then "check" to determine if it is at an edge of the stage.
In this example, we add additional code so the balls' colors will be random. In addition, another class is used to create multiple balls from within the original class.
First, let's create a class similar to the previous example:
package { // Import needed classes import flash.display.MovieClip; import flash.events.Event; import flash.geom.Rectangle; import flash.geom.ColorTransform; public class Boundary_Expert extends MovieClip { // Set Horizontal/Vertical velocity (speed and direction) public var velocityX:int = 8; public var velocityY:int = -8; // Boundary rectangle of ball public var bounds:Rectangle; public var randomColor:ColorTransform; // Create Constructor Function public function Boundary_Expert () { // give the ball a random color randomColor = new ColorTransform(); randomColor.color = Math.random() * 0xFFFFFF; this.transform.colorTransform = randomColor; addEventListener (Event.ENTER_FRAME, onEnterFrame); } // Call onEnterFrame handler (at frame rate) private function onEnterFrame (eventObject:Event):void { // Move ball based on velocity this.x += velocityX; this.y += velocityY; // Get rectangle boundary of ball bounds = getBounds(parent); // Reverse horizontal direction if Ball hit left/right of stage if (bounds.left < 0 || bounds.right > stage.stageWidth) { velocityX *= -1; } // Reverse vertical direction if Ball hit top/bottom of stage if (bounds.top < 0 || bounds.bottom > stage.stageHeight) { velocityY *= -1; } } } }
(Optional) Let's test colorTransformation in another way.
var multipleBallTest:Boundary_Expert = new Boundary_Expert; multipleBallTest.x = stage.stageWidth/2 multipleBallTest.y = stage.stageHeight/2 addChild(multipleBallTest)
Finally, let's create another class to create multiple balls bouncing on the stage when the stage is clicked.
package { import flash.display.MovieClip; import flash.events.MouseEvent; public class MultipleBalls extends MovieClip { // Set number of balls to create private static const BALLS_TOTAL:uint = 100; // Create constructor function public function MultipleBalls () { stage.addEventListener (MouseEvent.MOUSE_DOWN, onMouseClick); } // onMouseClick event handler private function onMouseClick (eventObject:MouseEvent):void { //Remove eventListener; otherwise, each time the stage is clicked, a new set of balls will be created. stage.removeEventListener (MouseEvent.MOUSE_DOWN, onMouseClick); for (var i:uint = 0; i < BALLS_TOTAL; i++) { // Create new Boundary_Expert var ball:Boundary_Expert = new Boundary_Expert(); //Resize balls by 50 percent ball.scaleX = ball.scaleY = Math.random()*1 ball.alpha = Math.random()*1 // Create balls at mouse click location ball.x = eventObject.stageX; ball.y = eventObject.stageY; // Create random velocity for balls ball.velocityX = (Math.random() * 25) - 15; ball.velocityY = (Math.random() * 25) - 15; // Display balls on stage addChild (ball); } } } }