This is a question that I see come up again and again on forums. Someone will be asking for help, and someone else will reply with some helpful code. Then the first person will many times come back with: "Thanks! But, I'm a total beginner! So just where do I put that code?" Therefore, I thought I would write an article that answers that question, and also outlines the many places where it's possible to put code using the Flash authoring tool, some of the advantages and disadvantages of each approach, and finally, what I believe to be a really good way to structure your files and folders for a Flash project.
I have covered the classpath before in my first tutorial Make your own reusable classes with Flash and AS3, but if you read that and still didn't quite get it, this tutorial really drives it home, along with some helpful illustrations. Hopefully it will not be humanly possible to read this present tutorial and come away not understanding it. At least that's my goal, so let's see if that turns out to be the case, shall we?
For our example application, we're just going to take a simple MovieClip object and give it drag and drop behavior. Then we'll investigate all the different places we can put that code and make it work.
Question on Organizing
I like the structure you laid out for organization. However, from what I understand, I would need to replicate my stash of classes that I collect from 3rd parties (like tweenlite), if I am going to have multiple projects. I think your structure infers that the "working folder" only contains one project. Maybe i am wrong about that. but if it only contains one project, and i put tweenlite underneath, then i am going to need to replicate that for each project.
Is there a way to deal with that? I am not really concerned about disk space...it is more the thought of needing to copy new classes that i get into multiple folders.
Let me know.
Thanks, Chi
Sharing class libraries amongst projects
Chi,
My tutorial here only dealt with the idea of one project, so sorry for the narrow focus. You can share class libraries with multiple projects just by setting a classpath to them in your (fla's) publish settings, on a project by project basis. I showed in the tutorial how to set a classpath.
What I failed to bring out is that there is a browse button that will let you browse your system to set the classpath. Your class libraries can actually be anywhere on your hard drive, but I have myself found it handy if they reside in some folders that are just above all of the projects in the directory tree.
Like so:
classes
com
greensock
... // etc
projects
project1
project 2
... etc
In the above, the project1 and project2 folders would be similar to the "working folder" in my tutorial example, and would each contain bin, lib, and src files. Then you could just open the fla file in each project, go to the publish settings, and set a classpath for the classes folder.
The ../src classpath I recommended in the tutorial would still apply. This is a relative reference. You would add to that another classpath to your class library, only this one would be an absolute reference.
Hope that helps, if not, I'd be glad to explain it in more detail. But yeah, you can share your class library(s) amongst projects, no problem!
--Jody
thanks
yep...that is what i was thinking of doing.
thanks,
chi
Thank You
I am a student and Jody quickly and clearly answered my question with AS3. I appreciate his knowledgeable and fast feedback!
keyboard listening question
Hi Jody,
xmiller again. Still reading a lot of your stuff and learning tons along the way. My question today has to do with when i tried to add a keyboard listener into your tutorial on using AS3 classes for navigation.
I added in this code to the intro class constructor:
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
and this as a seperate function:
private function onKeyDown(e:Event):void {
trace("a key was pressed");
}
That gave me error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Intro()
at Main()
So, I knew trying to access the stage was a problem. I replace stage with "this" for my event listener. The code now compiled and ran, but keypresses were not registering, until i actually mouse clicked on the instruction button. once i did that, then keyboard events started popping up with traces. how do i put the screen into focus for keyboard events without requiring the user to click somewhere?
I know you are busy, so I will try to donate as I ask questions to help offset your time a little.
Thanks, Chi
Figured it out...
I think i figured it out. if I put
stage.focus=this;
into frame 1 of the Intro instance timeline, that seems to do the trick without errors. Let me know if this is not the right way to do this.
Thanks, Chi
not quite figured out
well, it works -- until i click anywhere on the stage (not on a button)...then it stops working until i click on a button again.
any help is appreciated.
Chi
Keyboard listeners
Chi, I kind of prefer adding keyboard listeners to the stage. That way, they work no matter which object on the stage might have focus. Also, your fix causes you to put code in the timeline.
Your original line that added the event listener to the stage would have worked if you had placed it in the added handler. Remember in the tutorial I showed how to write ADDED_TO_STAGE event handlers? This is done mostly to detect when the stage property gets its value. Your class's constructor runs when outside code says "new."
Example (suppose this line is in my Main class):
var intro:Intro = new Intro();
This line makes a new instance of the Intro class (right side of the equals sign), which causes the class's constructor to run. The new instance is assigned to the variable intro (left side of the equals sign).
On the other hand, the ADDED_TO_STAGE event is triggered when outside code says "addChild."
Example (again, in the Main class):
addChild(intro);
This adds the intro instance to the main timeline object. When it does, the intro instance dispatches the ADDED_TO_STAGE event, and if a listener has been defined inside the Intro class, it will be called. To set this up, you add an event listener for ADDED_TO_STAGE in Intro's constructor, and write an addedHandler function for it. Then, inside the addedHandler, you now have a valid reference to the stage, so you can go ahead and add your keyboard listener to the stage.
One thing I kind of regret in the tutorial is telling people to center the registration point of their screens, which is not really a good idea. I feel it's best to create screens with their registration point in the upper left hand corner. However, I left it in because it did demonstrate that you have a valid stage reference, because the code used the stage property for centering purposes.
Now you see, though, that there might be other reasons for needing a valid stage reference, like adding keyboard listeners.
[[EDIT: Suggestion--When you add your keyboard event listeners to the stage in your addedHandler function, be sure to remove them again in your removedHandler function. The reason is that event listeners added to the stage remain in effect even after your screen is removed from the display. Remember, your screen has not been removed from memory, just from the display.]]
Naturally, I am glad that you are getting a lot out of my other articles. And don't worry, I am always glad to help if I can.
Thanks Again!
Jody,
Makes perfect sense. I had actually tried to add it into my addedHandler function, but inadvertantly left off the "stage." piece of the event listener, so it was still losing focus when i clicked on the stage. And yes, I actually still had the code in my "removeHandler" function, so it works beautifully now. I do think that this is a better example of using the the "added to stage" event handler than the positioning. btw...in my application, i had already changed the registration point to upper left. Creates messiness with my HTML build when positioned in the center.
Thanks again. I know you aren't doing this for the $'s, but i still want to contribute from time to time.
Chi
Stuck on video cuepoints
Hi Jody,
I know you don't have much written on video playback, but thought it was worth asking you anyway. i am trying to add a cuepoint in and then stop the video at that cuepoint. Below is the stripped down version of my AS3.0 called phpTest, which is just a class built as you described in AS3 classes tutuorial. The player is sitting in a video layer in the "phpTest" instance of the "phpTest" linked movieclip.
First problem. I have tried putting the cuepoint listener in a bunch of different places, but nothing seems to work. The video plays fine and fetches clips fine. But I can't get the listener to kick me into the videopause function. All my clips are much longer than 1.1 seconds. Currently the listener is sitting in the addeventhandler section.
Second problem i am having is the issue that first pass through, the playclip() seems to fire before my PHP script has finished getting the filepath for the video (happens in getpitch() and showresult() functions). But once through, it then just uses the filepath retrieved from the last time and works fine. Not sure how to stop it from going to "playclip()" before it has completed the getpitch() and showresult() functions.
As always, appreciate any insight you can provide.
package {
import flash.display.*;
import flash.events.*;
import flash.net.*;
import flash.text.*;
import fl.video.FLVPlayback;
import fl.video.MetadataEvent;
public class phpTest extends MovieClip {
var filepath:String = "";
public function phpTest() {
addEventListener(Event.ADDED_TO_STAGE, addedHandler);
addEventListener(Event.REMOVED_FROM_STAGE, removedHandler);
getPitchBtn.myText.text = "Get Next Pitch";
getPitchBtn.addEventListener(MouseEvent.CLICK, getPitchBtnClicked);
}
private function addedHandler(event:Event):void {
player.addEventListener(MetadataEvent.CUE_POINT,videopause);
}
private function removedHandler(event:Event):void {
}
private function getPitchBtnClicked(event:Event):void{
getPitch(); //function that goes to database and retrieves information about the video and which video to play
player.addASCuePoint(1.1,"ASpt1"); //set cuepoint 1.1 seconds into the video
playclip(); //function that plays the specfified clip
}
private function playclip():void {
player.play("http://pseudo01.hddn.com/vod/seetheseams.chificiency/"+filepath);
}
private function videopause(m:MetadataEvent):void
{
trace("made it into videopause function");
player.stop();
}
//function to go get the pitch and associated data
private function getPitch ():void {
//variables that we send to the php file
var phpVars:URLVariables = new URLVariables();
//we create a URLRequest variable. This gets the php file path.
var phpFileRequest:URLRequest = new URLRequest("http://develop.myownurl.com/php/getpitch.php");
//this allows us to use the post function in php
phpFileRequest.method = URLRequestMethod.POST;
//attach the php variables to the URLRequest
phpFileRequest.data = phpVars;
//create a new loader to load and send our urlrequest
var phpLoader:URLLoader = new URLLoader();
phpLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
phpLoader.addEventListener(Event.COMPLETE, showResult);
//now lets create the variables to send to the php file
//this also acts to ensure that the PHP is called everytime instead of caching
phpVars.systemCall = "placeholder";
//this will start the communication between flash and php
phpLoader.load(phpFileRequest);
}
private function showResult (e:Event):void {
//display the results from the PHP query and store the userID in order to find the account on update
filepath = e.target.data.result_path;
trace("filepath = " + filepath);
}
}
}
Add cue points AFTER defining source
I did a little bit of research for you. I found this in the adobe livedocs in the entry under the FLVPlayback component:
"Cue point information is wiped out when the source property is set. To set cue point information for the next FLV file to be loaded, set the source property first."
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/fl/video/FLVPlayback.html#addASCuePoint()
Examining your class, you use the play() method of the FLVPlayback component to start the video playing. The first parameter is the url of the video to play. The first parameter is also named "source." So I surmise that this is the same as setting the source property for the component.
Further examining your class, you can see that you clearly set the cuePoint FIRST, then you tell the video to play. Telling the video to play sets the source property, which wipes out the cue point information (according to the above quote from livedocs).
Therefore, all you have to do is to move the command to set the cue point to a place AFTER the play command is given. So move this line:
player.addASCuePoint(1.1,"ASpt1");
Take it out of the getPitchBtnClicked() function, and place it into the playclip() function instead, so that your playclip function reads:
private function playclip():void {
Once again you nailed it...
Works perfectly now! Thanks so much. I have been using live docs a lot...they are very useful. In fact i read the whole damn section on cuepoints, but didn't even think to read the FLVPlayback section.
I am not even sure I would have figured out that I was wiping it out with my play command. I am still getting used to OOP...i think very serially.
Thanks, enjoy the rest of whats left of the weekend. Have lunch on me tomorrow.
Chi