Hi Everyone,
I'm very proud of all of you this week. You have been trying very hard to solve this problem of the back button. Below, you'll find the steps to solving it. You'll also see that the new stuff that I introduce here is much simpler and also has a graphic component. We're getting into what's known as the display and all of its possibilities. Good luck.
Carter-
- WEEK 8
- Classwork
- LINK class files
- Homework:
- Exercise 1: Look through the steps below to complete what you have begun in class.
- Below, you will find the script in the way it should have been when you began class this week:
- package {
- public class MPlay {
- public var mName:String;
- public var mVolume:int;
- public var mTList:Array;
- public var mMix:Boolean;
- private var _mSerial:String;
- private var _mTCurrent:int;
- public function MPlay(
- mSerial:String,
- mName:String="",
- mVolume:int=10,
- mMix:Boolean=false
- ):void {
- _mSerial = mSerial,
- this.mName = mName;
- this.mVolume = mVolume;
- this.mMix = mMix
- _mTCurrent = 0;
- mTList = new Array();
- }
- public function play():void {
- trace("Playing: " + mTList[mTCurrent]);
- }
- public function next():void {
- if (mMix) {
- _mTCurrent=Math.floor(Math.random() * mTList.length);
- } else {
- if (_mTCurrent==mTList.length - 1) {
- _mTCurrent=0;
- } else {
- _mTCurrent++;
- }
- }
- play();
- }
- public function get mTCurrent():int {
- return _mTCurrent;
}
- public function set mTCurrent(value:int):void {
- value = Math.max(0, value);
- value = Math.min(value, mTList.length - 1);
- _mTCurrent = value;
- public function get mSerial():String {
- return _mSerial;
- }
- var myMPlay:MPlay = new MPlay("Carter's Music Player", 15, true);
- myMPlay.mTList =
- ["The XX - Crystalized", "Fever Ray - If I Had a Heart", "Crystal Castles - Celestica", "Animal Collective - My Girls", "Bat for Lashes - Moon and Moon", "New Order - Crystal", "Cut Copy - Hearts on Fire", "Of Montreal - Gronlandic Edit", "Janelle Monae - Many Moons", "The Rapture - Get Myself Into It"];
- function onNextClick(evt:MouseEvent):void {
- myMPlay.next();
- }
- myMPlay.play();
- next_btn.addEventListener(MouseEvent.CLICK, onNextClick);
- We need a second button on the stage.
- We need this button to send the user to the previous song.
- That means we need a listener in the instance to handle the event when the user CLICKS on the 2nd button.
- It means that we also need a function in the instance to activate a method in the class. So far, we have two primary methods in our class: the play() method and the next() method. We don't want to call on either one of those because neither of those does what we need. What we need is something that goes backwards. In the end of this exercise, then, we'll have 3 primary methods in the class.
- Therefore, we'll need a 3rd method in our class that sends the user back to the previous song that was played, which we can call our back or previous method.
- So then, let us think about exactly what that new previous method and other pieces of code we have to add need to do:
- play-list—We have our current playlist which exists in an array property of the MPlay class, and it is named mTList (I named it this to stand for: music Track List). This is where our script gets the list of songs to play. Now, we did NOT put the actual list of songs here in this class definition, and you may wonder why we didn't: if almost everything else is here in the .as file where we define the class, why not the actual track list? It is because if we put it here, then we'd be defining the playlist for ALL instances of our class. That is to say, we'd be by default creating a song list for ALL music players, which means that everyone who initializes his or her own player will have to listen to the same track list, and that's no good. Therefore, we created the actual list of songs in our .fla file where we defined the particular player instance.
- play order—This list of songs in our array, mTList, does not necessarily define what order the songs are playing in. Recall, we have a property named mMix (I named it this to stand for music Mix), which has a boolean value of true or false. This property defines whether the music is going to play in order or whether it will mix up the tracks and shuffle them in some random order. Therefore, the songs may play in order, or they may not, and instead play in some random order. This means that we cannot just play the songs in backwards order the way they exist in the array mTList. Why, you may ask; well, because if I had elected to play the tracks randomly, I may have listened to track 7 and then the next track might be track 2. If I then select back, would it be correct to then go to the previous track in the list, to track 1???
- playED order—This means that we need to set up a new list of songs: the list of songs that have already been played. The moment I "hear" a song playing in our play list (mTList), then it should go into the already played list. Then, when I hear another song, whether it was in the same order of our mTList or not, it will go into the already played list, but only in the order that it was played. This new list should actually be a new array, one that is populated while the user plays the songs, not beforehand, because have no idea which order the songs will be played in. This means we will create the array before, but we will only fill it with songs (populate it) on-the-fly, during operation of the script. Let's name the new array mPList (for music Played List), and let's add it to our class in the same way we added the other array property:
- package {
- public class MPlay {
- public var mName:String;
- public var mVolume:int;
- public var mTList:Array;
- public var mPList:Array;
- public var mMix:Boolean;
- private var _mSerial:String;
- private var _mTCurrent:int;
- public function MPlay(
- mSerial:String,
- mName:String="",
- mVolume:int=10,
- mMix:Boolean=false
- ):void {
- _mSerial = mSerial,
- this.mName = mName;
- this.mVolume = mVolume;
- this.mMix = mMix
- _mTCurrent = 0;
- mTList = new Array();
- mPList = new Array();
- }
- public function play():void {
- trace("Playing: " + mTList[mTCurrent]);
- }
- public function next():void {
- if (mMix) {
- _mTCurrent=Math.floor(Math.random() * mTList.length);
- } else {
- if (_mTCurrent==mTList.length - 1) {
- _mTCurrent=0;
- } else {
- _mTCurrent++;
- }
- }
- play();
- }
- public function get mTCurrent():int {
- return _mTCurrent;
- }
- public function set mTCurrent(value:int):void {
- value = Math.max(0, value);
- value = Math.min(value, mTList.length - 1);
- _mTCurrent = value;
}
- public function get mSerial():String {
- return _mSerial;
- }
- }
- public function play():void {
- trace("Playing: " + mTList[mTCurrent]);
- }
It really only consists of a trace() action, but later on in the weeks to come, we'll put some actual audio functionality to it. Right now, it only simulates playing, which is fine for our concerns right now. The important thing to note is that it simply plays songs, any song, whichever song. It is NOT responsible for choosing which song it will play. That is the job of the next() method. This seems perfect when thinking about what we need: we need to create a list of songs that have already been played, in the order that they were played. So, how do we know that a song has already been played? Well, it appears in the trace as playing. The moment another song appears there, then the previous song has already been played and can go into our new list.
- public function play():void {
- trace("Playing: " + mTList[mTCurrent]);
- }
Here, we have the trace action, and it contains a concatenation. What is being combined is simply a string, the word "Playing", and a value from our array, mTList. As you know, an array, however, may contain numerous items of data; and ours currently contains 10 items of data. Each one is the name of one song. As you should also know, in order to indicate one single piece of data out of the many within an array, you must indicate the individual index number. Each item of data in an array has its own index number, and the counting of those numbers begins at 0. In that trace() statement we state the name of our array, mTList, and in between the square brackets, where we'd normally put the index number, we stated our variable, mTCurrent. However, by putting that variable there, we're actually putting a number between the brackets. Remember, this variable holds an integer between 0 and 9, referring to the number of music tracks we have in our playlist. So then, when we see this line of code:
- mTList[mTCurrent];
What we're actually seeing is the current song in our playlist. AHA!! That is exactly what we need. Remember, what we want is to add songs that have already been played to a new list, a new array we have decided to call mPList. Since that line above indicates the current song, when it's done being played, it should go into our new array. This means we can use that line to add a song into our new array.
- public function play():void {
- trace("Playing: "+ mTList[mTCurrent]);
- mPList.push(mTList[mTCurrent]);
- }
The array, mPList, is our new array, and we're using the new push() method to add the current song that has just been played, mTList[mTCurrent].
- We know how to find the last song: we must get the last index number. Remember from last week, in order to get the last index number, all we have to do is find out what is the length of our array (how many elements are in it), and then subtract 1 from that number. That will give us the last index number, and therefore the last item in our array;
- But we don't want the last item, we want the next to last item. This is also simple: what if we get rid of the last item in our array, just eliminate it, wouldn't the next to last song then be the last song? To do this, to eliminate the last item of an array, we can use the pop() method.
- mPList.pop()
It really is that simple. - Now, once we use this method, we can simply locate the next to last song (which will then be the last song), by finding the length and subtracting 1.
- mPList.length-1
- That above line of code will give us a number, and that number is the number of the track that played just before the last one played. It is the previous track number!!! Excellent, so now all we need to do is use that number to play the previous track:
- trace("Playing: " + mPList[mPList.length-1])
Our prev() method, then, only has two lines of code: - mPList.pop();
- trace("Playing: " + mPList[mPList.length-1])
- if(the last index number is greater than zero) {
- mPList.pop();
- trace("Playing: " + mPList[mPList.length-1])
- } else (if the last index number is zero) {
- trace("Playing: " + mPList[0])
- }
The question remaining from the above statements is how do we find out what goes in between the parentheses after the if statement. What thing contains the last index number? We already know that. Remember once again, the length of an array minus one gives us the last index number of that array. Therefore, instead of the words "the last index number is greater than zero" after the if, we should simply place:
- if(mPList.length-1) {
- . . .
We can do that, because remember we have to put something that is the equivalent of true or false between the parentheses of an if statement. Recall that the numberical equivalent of false is 0 and the numerical equivalent of true is 1. In truth, however, any number greater than zero would be true. Besides that, we can just discard the parentheses and the text between in the else part of the function. The else part of the function will simply play the first track over and over so long as the user continues to hit back even if he/she has reached the first track.
- Perhaps, your first question would be to ask, "what is the display?". What this is really about is stuff that is displayed in the player when you test a flash movie. It's about doing cool stuff with ActionScript. Many of you, I am sure, will be happy to know that after the last couple of weeks of all this typing and absolutely NOTHING visual, no graphics, nada, that here we begin doing graphic stuff again, but with code.
- What we're about to explore is known as the display list, in case you want to look it up in your own book or do a search online. As in many other things with ActionScript 3.0, the terminology is a bit deceptive and non-descriptive, but oh well. They didn't ask me.
- The display list is made up of a hierarchy of display objects. All of these belong to what is known as the DisplayObject class, which is just part of the DisplayObjectContainer class, both of which are built-in classes that are part of Flash when you buy or download it. There are many children of these classes, basically everything visual that you can put in or create in a Flash movie is part of a Flash class. Here are some examples of these classes:
- DisplayObject—This class provides basic graphical properties to objects, such as width, height, x, and y.
- InteractiveObject—This class provides various methods and properties that allow users to interact with objects in Flash, such as Movieclips.
- DisplayObjectContainer—This class provides the ability for some objects to contain other objects, such as Movieclips which may, for example, contain other Movieclips.
- Sprite—This class provides similar functionality to Movieclips. It is not something that you can create graphically by drawing it as you can with Movieclips, but may only be created through code.
- MovieClip—This class will be the most familiar to you as you have been creating Movieclips now for a few semesters. This class of objects have their own timeline and all the properties and functionality that go along with that, such as playing and stopping the timeline.
- So, let us get started. First, you'll need to create a new project folder named dma213_project_01. As you have surely noticed by now, in all classes that use coding such as HTML, JavaScript, and PhP, you need to be careful, specific, and tediously precise about naming and saving your files. ActionScript is no different, especially when you start working with classes.
- Open up a new .fla file and save it as display.fla within this new folder.
- Draw a perfect square with the dimensions 100 X 100 and with a rather thick black outline.
- Select this square (make sure you get both the fill and the stroke, and convert it into a symbol. Name it Square (upper-case S), select movieclip for type, make sure the registration point is the upper-left, and then, if necessary, click on the advanced button here to open up and see additional options. Once you do so, or if the convert to symbol box already opened up wide, check off where it says Export for ActionScript. Once you do so, you'll see the symbol name appear there (now also a class name) and what sort of class it is (MovieClip). The reason we're doing this is because we're going to save our class in a separate folder. As you've learned in other coding classes, it is always good to segregate your different types of files. It is no different in Flash. Moreover, in Flash, it is often possible to re-use your classes for other projects, so we will often locate them in other disparate folders. Now, click Okay.
- Now, with the symbol selected, give it an instance name of square (lower-case s).
- Now, within the folder that you've already created, you must create a new folder named wk8.
- Once you do that, back in Flash, Create a new ActionScript file for the document class. Save the file within the new wk8 folder and name it DisplayTest.as.
- Within the new .as file, type the following class definition and class constructor:
- package wk8 { /* package is named the same thing as the
folder where the class is located. */ - import flash.display.Sprite;
- public class DisplayTest extends Sprite { /* here, we are
using the properties of the Sprite class as
it already exists in Flash to indicate to
what family, or class, our own custom class
(DisplayTest) belongs.*/ - public function DisplayTest() {
- }
- }
- }
- But we have a couple more things to do before we can test this out. First, let's put a trace in our constructor method above so that it does something, and we're actually going to trace the instance name of the movieclip, square.
- package wk8 {
- import flash.display.Sprite;
- public class DisplayTest extends Sprite {
- public function DisplayTest() {
- trace(square);
- }
- }
- }
- Save that (but don't test yet because you'll get an error). Before you test it, since we have saved our class into a different folder, we have to specify that in our class instance, the .fla file. We have to indicate that the display.fla movie should use our DisplayTest class as its document class. So, click somewhere in an empty area of the stage to deselect all, and then open up the Properties panel to show the properties for the movie. Where it says Document class:, you need to type the path (using dot notation) to the class as follows: wk8.DisplayTest. Save your changes and test your movie.
- More than likely, you'll still get an error, one that mentions something about type not found and MovieClip. To get around this problem, you have to import the MovieClip class in the same way that you imported the Sprite clas:
- package wk8 {
- import flash.display.MovieClip;
- import flash.display.Sprite;
- public class DisplayTest extends Sprite {
- public function DisplayTest() {
- trace(square);
- }
- }
- }
Now, once you test your movie again, you should get some output that tells you the object with the instance name square is a movieclip: - [object MoveClip]
- Big deal!!! You might say sarcastically. Okay, so let's now modify our square by moving it to a new spot using new x/y coordinates, and let's also modify it's shape using width/height:
- package wk8 {
- import flash.display.MovieClip;
- import flash.display.Sprite;
- public class DisplayTest extends Sprite {
- public function DisplayTest() {
- trace(square);
- square.x = 300;
- square.y = 300;
- square.width = 200;
- square.height = 25;
- }
- }
- }
- Let's also rotate the object and change its opacity:
- package wk8 {
- import flash.display.MovieClip;
- import flash.display.Sprite;
- public class DisplayTest extends Sprite {
- public function DisplayTest() {
- trace(square);
- square.x = 300;
- square.y = 300;
- square.width = 200;
- square.height = 25;
- square.rotation = 60;
- square.alpha = .5;
- }
- }
- }
Below you have something like what your stage should look like in your .fla file.
And then you have what the .swf file should look like when you generate it, ctrl or cmd-enter.
- Depth—Normally, when working with objects on the stage, you manage depth primarily with layers. In ActionScript, the depth of an object is determined by an index number in an array of child objects on the stage. The higher the index number, the further toward the front of the movie that object appears. A Sprite instance or a MovieClip instance with an index of 0 will appear below another object with an index of 1. This depth of the display object may be manipulated, meaning that you can change the stacking order of the objects on the stage.
- Create a new ActionScript file, save it into the wk8 folder with the name of DepthTest.as. Then place the following lines of code inside of it:
- package wk8 {
- import flash.display.MovieClip;
- import flash.display.Sprite;
- public class DepthTest extends Sprite {
- public function DepthTest() {
- trace(getChildIndex(square));
- }
- }
- }
- Save this file as depth.fla, set the document class in the properties panel as before to wk8.DepthTest. If you test the movie now, you should see that the square object is at depth 0; but this is boring. Let's see what happens when we add a few more instances to the stage.
- In the .fla file, drag three more instances of the Square MovieClip symbol from the Library onto the stage, and make certain each is in its own layer. Move them around so that the squares overlap each other so that you can see which is on top of which.
- Provide each of these symbol instances with instance names, such as square_02, square_03, and square_04.
- Go back to the DepthTest.as file and add a few additional trace() statements:
- package wk8 {
- import flash.display.MovieClip;
- import flash.display.Sprite;
- public class DepthTest extends Sprite {
- public function DepthTest() {
- trace("square: " + getChildIndex(square));
- trace("square2: " + getChildIndex(square2));
- trace("square3: " + getChildIndex(square3));
- }
- }
- }
- Save your changes to the .as file, switch back to the .fla file, and test the movie. What you will find is that the symbols are arranged from level 0 to level 2.
- Manipulate Depth—Now that we have several objects to work with, we can begin to play around a bit with their depths using the setChildIndex() method.
- This method has two parameters that need to be satisfied: when using it, you must state two things, which object you want to manipulate, and then to which index level you want to move it.
- We'll first move the first square we had on the stage to the top of the display. As mentioned, we'll call the setChildIndex() method, passing the object named square and its new depth. Since we have only three objects, and since we are dealing with an array of 3 objects, the depths start at 0 and count up to 2 (0, 1, 2). We could use the number 2 as the top depth, but the best way to bring an object to the top of the list is to use numChildren to determine the highest depth. This property is much like the length property for arrays. If we wanted the last index of an array, we simply subtract 1 from the length (i.e. myArray.length-1). Therefore, we'll use numChildren - 1 to determine the highest index number. A parent object with three child objects has a top depth of 2 (0 for the depth of the 1st child, 1 for the depth of the 2nd child, and 2 for the depth of the 3rd child).
- package wk8 {
- import flash.display.MovieClip;
- import flash.display.Sprite;
- public class DepthTest extends Sprite {
- public function DepthTest() {
- trace("square: " + getChildIndex(square));
- trace("square2: " + getChildIndex(square2))
- trace("square3: " + getChildIndex(square3));
- setChildIndex(square, numChildren-1);
- trace("square: " + getChildIndex(square));
- trace("square2: " + getChildIndex(square2))
- trace("square3: " + getChildIndex(square3));
- }
- }
- }
- Once you save the above changes, and test your .fla file again, you'll see that the original first square is now at the top of the list (with a 2 as its index. The indexes of the other two objects have been reduced by one.
- square: 0
- square_02: 1
- square_03: 2
- square: 2
- square_02: 0
- square_03: 1
- Swapping Depths—Another way of changing the index level of an object is to swap its index with another of the objects. There are two ways of doing this: use teh swapChildren() method and pass the instance names of the objects that you want to exchange depths, and the swapChildrenAt() method and instead pass the index numbers that you want to switch with each other.
- First, let's swap the index levels of square_02 and square_03:
- package wk8 {
- import flash.display.MovieClip;
- import flash.display.Sprite;
- public class DepthTest extends Sprite {
- public function DepthTest() {
- trace("square: " + getChildIndex(square));
- trace("square2: " + getChildIndex(square2))
- trace("square3: " + getChildIndex(square3));
- setChildIndex(square, numChildren-1);
- trace("square: " + getChildIndex(square));
- trace("square2: " + getChildIndex(square2))
- trace("square3: " + getChildIndex(square3));
- swapChildren(square_02, square_03);
- }
- }
- }
- Now, let's try swapping the indexes of the objects at level 0 and 2.
- package wk8 {
- import flash.display.MovieClip;
- import flash.display.Sprite;
- public class DepthTest extends Sprite {
- public function DepthTest() {
- trace("square: " + getChildIndex(square));
- trace("square2: " + getChildIndex(square2))
- trace("square3: " + getChildIndex(square3));
- setChildIndex(square, numChildren-1);
- trace("square: " + getChildIndex(square));
- trace("square2: " + getChildIndex(square2))
- trace("square3: " + getChildIndex(square3));
- swapChildren(square_02, square_03);
- swapChildrenAt(0, 2);
- trace("square: " + getChildIndex(square));
- trace("square2: " + getChildIndex(square2))
- trace("square3: " + getChildIndex(square3));
- }
- }
- }
No comments:
Post a Comment