Third and final question before I hit the sack!
How do you create preloaders in AS3? Iv looked up the Flash help and a few online tutorials and they all require I load in
import fl.containers.UILoader;
import fl.controls.Label;
import fl.controls.ProgressBar;
import fl.controls.ProgressBarMode;
at the beginning of my script. But when I do that I get a list of errors (8 to be exact) all saying this kind of thing
'definition fl.controls:ProgressBar could not be found.
Thanks again for all your help, i've uploaded the la-*test*-('") version to www.pigstylearts.co.uk/portfolio/portfolio.html , its starting to look more like I want it! Once I get the basics working I'll start refining the experience with subtle vfx and maybe a few subtle sounds here and there.
Matt Kempke- 04-05-2008
impressive!!
bigmac- 04-05-2008
Oh and i've been meaning to ask you, should I be being pernickety about deleting event listeners if I don't need them? Like only having event listeners on the menu buttons when the menu is actually open, that kind of thing? Or does it not make much difference to memory?
Hehehe; these are all things I haven't been going into to avoid confusion. However, since you're asking... YES. Removing event listeners is HUGE. Objects with registered event listeners are subscribed to active memory, so are not eligible for garbage collection (which is the Flash memory purge mechanism). So, things to know:
A) What is it? The Flash garbage collector is a sweep algorithm performed by the Flash player that weeds out expired (currently unused) memory blocks. This is an automated routine that you (the developer) cannot control. Flash will run the garbage collector only when it decides it needs to free up memory. There are sneaky tricks that you can do to force the garbage collector to run, however there's a better change that you'll hurt performance more than improve it if you try to manually control the GC routine.
B) What does the GC target? The garbage collector flushes out any objects floating in memory that are no longer referenced by any other object held within active memory. The primary ways that an object (we'll call it "Bob") is held in memory are:
- variables and/or properties of other objects reference Bob
- Bob is contained within a parent object's display list
- Bob is referenced within an array
- Bob has a subscribed listener object that still exists within active memory
So, the long and short of this is: ALWAYS remove event listeners. Also nullify all references to an object when it's no longer needed. With AS3, it's now a good habit to set all objects up with both constructors AND destructors to manage the object's transition both in and out of memory. This is particularly crucial for objects like Timers and MovieClips which have a reoccurring event subscription that actively consume memory. These types of objects should be stopped (stop();) before being released into inactive memory for garbage collection.
bigmac- 04-05-2008
hmm... do I need to start going into custom classes if I just want to get the imported child movie to display text contained in an array from the parent movie? I've tried putting
caption_txt.text = stage.portfolioData[projectIndex].slides[slideIndex].caption;
in the child's timeline but it can't read see the array when its imported.
For your first big project, sure... that does work! And it's a good transition for getting your feet wet with programming an interface. However, you'll discover with experience the short comings of that sort of solution and ways to do this more efficiently.
Also, i've created a function called clearStage to make all the slides exit right and clear the stage, but when I try to call it it says 'TypeError: Error #1010: A term is undefined and has no properties.'
Can you see any problems?
function clearStage():void {
var currentX:Number = main.photo_mc.x;
var rightEdge:Number = stage.stageWidth;
var exitRight:Tween = new Tween(main.photo_mc, "x", Regular.easeIn, currentX, rightEdge+400, 1, true);
var timer:Timer = new Timer(1000,1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, deletePhotos);
function deletePhotos(evt:TimerEvent) {
removeChild(main.photo_mc);
}
}
clearStage();
Without knowing what "main" is, I can't say for sure as to where the error is... however if I had to take a wild stab at it, I'd say that "main" is the undefined term with no properties given that it is not defined within the method.
bigmac- 04-05-2008
How do you create preloaders in AS3?
Wait, wait, wait... we covered this! I know we did; probably back somewhere around page 3. We got a working preloader script put together, I know because I've added it to my code snippits library at work that I use for fast reference.
As for the whole Flash UI progress bar thing, that is utter and complete CRAP!!! I'll endorse using Flash components when you need a complicated mechanism like a List or a ComboBox, but for a ProgressBar? Don't use the Flash out-of-the-box junk... especially when you're a designer!! :P Make your own graphics! It's unbelievably simple... just make a 100 frame movieclip with any visual progress animation that you like; then stop it's timeline and add a line into your preloader script like this:
myProgressClip.gotoAndStop(Math.floor(myProgressClip.totalFrames*percentLoaded));
fatbuoy1- 04-06-2008
ALWAYS remove event listeners.
Ok i'll start looking into doing that then.
sure... that does work!
... it doesnt though. Is there anything extra I need to do to get it to reference the parent movie specifically?
Without knowing what "main" is
Main is just a movie clip that i've placed on the stage to create all the photos within.. I figured it would be a simple way of keeping the menu on top all the time. When I say main.photo_mc, it says a term is undefined and has no properties... and when I try stage.main.photo_mc or just photo_mc it says 1119: Access of possibly undefined property main through a reference with static type flash.display:Stage (or photo_mc).
UPDATE: Hmm ok the problem only seems to come up when I try to actually CALL the clearStage(); function, and this is the exact error message.
TypeError: Error #1010: A term is undefined and has no properties.
at portfolio_fla::MainTimeline/clearStage()
at MethodInfo-63()
Wait, wait, wait... we covered this! I know we did
Ah... so we did! Sorry, I thought it was AS2 we had covered this in. Thanks... one thing though, how do I add a movie from my library to the stage through actionscript? As far as I can tell Flash wants me to export it as a class or something and then import it again... is that the only way?
Thanks again. Would be interested in knowing what you think of the way the site actually looks and works, since you're doing this kind of thing every day!
fatbuoy1- 04-06-2008
Hm... I can't get the loaderInfo to be more specific.
var slideRequest:URLRequest = new URLRequest(portfolioData[projectIndex].slides[slideIndex].url);
//Create a loader object
var slideLoader:Loader = new Loader();
//Initiate a load request
slideLoader.load(slideRequest);
var slide:DisplayObject = slideLoader;
slide.x = -(photoWidth/2);
slide.y = -(photoHeight/2);
photo.addChild(slide);
slideLoader.addEventListener(Event.ENTER_FRAME, checkProgress);
function checkProgress(evt:Event):void {
trace(slideLoader.loaderInfo.bytesTotal);
trace(slideLoader.loaderInfo.bytesLoaded);
var fileSize:Number = slideLoader.loaderInfo.bytesTotal;
var amountLoaded:Number = slideLoader.loaderInfo.bytesLoaded;
var percent:Number = Math.round((amountLoaded / fileSize)*100);
trace(percent+"%");
}
At the moment, it's just returning the bytesTotal and bytesLoaded for the whole movie, rather than for each individual slide being loaded.
bigmac- 04-06-2008
Hey Chris,
In RE to reactions to your portfolio... cool. I think the experience is fresh and unique, although right now its cumbersome. I'll start at the beginning and work through...
1) The menu. I like it, though its expected. I'd say you could get some more mileage out of that tween. If its timeline, I'd make dynamic with a Strong.easeInOut on it for some additional snap. It's amazing how much personality tweens have once you start seeing them constantly. Also, make the menu items have a hand cursor with a roll state. You can do this by drawing out custom button clips, or just addin "buttonMode=true", "useHandCursor=true" to whatever is there.
2) The section index. Obviously, the previous section's photos need to clear out before the new section draws. Sounds like you're working on it. Also, the presentation in its current state isn't very helpful to me as a user. It just gives a stack of photos that I'm not sure what to do with. Consider having all the photos shrink and fan out as an index view.
3) Viewing the photos. I see where you're going with this stack metaphor, and while it's creative, it's not very practical from a human interaction standpoint. Navigation is inconsistent, it's hard to find things, it's easy to miss things, it requires th user to figure out what they're doing. And as per Steve Krug's book which is the bible of the interactive design world, "Don't Make Me Think". Outstanding book. If you don't have it and are getting into interactive design, get it....
http://www.amazon.com/Dont-Make-Me-Think-Usability/dp/0321344758/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1207536429&sr=8-1
Truth be told, I'd say that the user should not have the ability to click and drag photos. It's ineffective for the goals of the piece, which is to make people look at your work. Since people don't know your work the way you do, they need you to lay it out for them in a neat, clean, and organized way that they can flip through with a single button.
So, would definitely not scrap the concept. I think it's very strong, although in its current state the interactive model is one that I, as a resume reviewer, would see as inexperienced. How would I evolve it? I'd hit on usability...
A) when the photos come in at the beginning of the section, I'd start them off with a thumbnail index view, which could be as simple as tweening the photos into a grid of small slides. Also, a "browse gallery >>" button to start a pagination view.
B) When the browse mode begins, shuffle the photos back into a stack and push them over to the far left side of the screen, cutting off most of the photo so you can just see the edge of the stack. Use a next and previous button to shift photos off the stack and into the center display area. Pull photos from the top as you go through, and shuffle them from the center back to the bottom of the stack.
C) include a button that directs back to the index view.
Okay, so that was a lot, and I hope you don't take any offense to it. I like the idea and I think it's looking great! As for the work, I think you've got some great design talent. I absolutely love the vernacular design piece... that's a really strong print design and I think you've done a great job photographing it. Cinderella was a photo series I take it? So, I have to ask... who where the models? I know how college students end up using themselves for a lot of projects, so you aren't the guy in that series, are you? That actually made me kind of curious... if you have a self-portrait, email it to me! It's always nice to have a face to go with a voice and the other end of a forum exchange :P
bigmac- 04-06-2008
... it doesnt though. Is there anything extra I need to do to get it to reference the parent movie specifically?
Hmmm... well, I must admit that I'm not a terribly good authority on how to manage data within a timeline-scripted environment. It was slightly confounding before in AS2, and is even more so now in AS3 with each loaded document having its own native stage and root reference. So, I never bother with that stuff, I just make them classes. It's pretty simple if you want to give it a shot... But again, you need to look up what a class is and what the difference between instance and static members are. I could explain it, but it's extremely well documented Computer Science knowledge. In fact, lets looks at Wikipedia. Whao.. big shocker. Wikipedia has an outstanding OOP write up (it was created by computer nerds, afterall). http://en.wikipedia.org/wiki/Object_oriented.
Main is just a movie clip that i've placed on the stage to create all the photos within.. I figured it would be a simple way of keeping the menu on top all the time. When I say main.photo_mc, it says a term is undefined and has no properties... and when I try stage.main.photo_mc or just photo_mc it says 1119: Access of possibly undefined property main through a reference with static type flash.display:Stage (or photo_mc).
Hmm. First on the note about using a "stage" reference... that doesn't really work. a Stage is a specialized version of a DisplayObjectContainer that does not directly contain instances; it just contains a single display instance which is the document class. The document class is the thing that you're working in within the root timeline, and you can always call down to it using the reference "root". So, try that. Access targets through root.
Now, next question... what is "photo_mc"? Is that a photo instance that you've created within main? If so, I think I see your problem. You're treating this like AS2, where all movieClip instances were given instance names that could be targeted with dot-notation references. Alas, that is no more (thank goodness!). Dot-notation references cannot tap directly into the display list. They can only hit properties of an object. So, you could add a property reference to each child movieClip as they are created, but that's messy. You should just stick to the child node accessors, those being: getChildAt(index); or getChildByName(name);. ChildByName is pretty slow, so you should avoid using that method whenever possible. I find there is not much I can't do by looping through the display list.
Ah... so we did! Sorry, I thought it was AS2 we had covered this in. Thanks... one thing though, how do I add a movie from my library to the stage through actionscript? As far as I can tell Flash wants me to export it as a class or something and then import it again... is that the only way?
LOL... you're getting hung up on the "export" term in "export for ActionScript". Exporting a class is not a literal process of export and importing... at least not to you as the developer (Flash is doing it all automatically behind the scenes). It's better to think of "Export For ActionScript" as meaning "Give me the ability to dynamically create instances of this MovieClip". Just turn on that option, leave it exported in the first frame, and give it an instance name. Then you can create instances of that clip using "var myClass = new MyExportedClass();".
bigmac- 04-06-2008
Oh, and last thing... concerning this script:
function clearStage():void {
var currentX:Number = main.photo_mc.x;
var rightEdge:Number = stage.stageWidth;
var exitRight:Tween = new Tween(main.photo_mc, "x", Regular.easeIn, currentX, rightEdge+400, 1, true);
var timer:Timer = new Timer(1000,1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, deletePhotos);
function deletePhotos(evt:TimerEvent) {
removeChild(main.photo_mc);
}
}
clearStage();
I wouldn't advise that you use nested methods at this point. While it IS possible, it goes into heavy-OOP theory of how it works and how to do it correctly... it all comes back to that discussion of "scope". I don't bother nesting methods because its so easy to do wrong.
fatbuoy1- 04-07-2008
Thanks for the feedback! I find it very helpful :D Yeah thats me in the pics, I took all of them except the ones with me in them (hough the ones with me in the background are composited so I took the foreground shots). That project is part of a motion graphics piece made up of stills... which i'm intending to insert on a slide at the beginning (top) of the pile, once I get round to working out how to add video into Flash properly.
I appreciate the constructive criticism on the navigation side of things. Im wanting to be original (though I know this sort of thing has been done before), but I want to be original in a way that makes navigation BETTER. Basically I like the idea of being able to look at 5 or 6 slides of my work at a time (depending on your screen resolution) and compare them, so thats what the drag and drop functionality is for. However I realise its not very intuitive (I havnt had one person be able to work out that you CAN drag and drop without me telling them!). So I think I do need a next/previous interface that pops up and allows them to automatically flick through the photos. I like the idea of pushing them all down to the bottom of the screen (kind of like you suggested) and then sliding them up to the centre one by one. In most cases I want them to flick throught them in the order they're stacked, so thumbnails wouldn't be ideal for that, though by version 2.0 maybe i'll have a selection of possible layouts (grid, stack, etc).
BTW, also to be added to this are intro slides which come out at the top of every photo pile and contain a bit of info on each project. Also I want to add a box that slides up at the bottom of each slide on rollOver containing captions for that slide (if there are any) and also options for that slide like resize, delete, download, etc.
I wouldn't advise that you use nested methods at this point
Nested methods being... having function deletePhotos() INSIDE function clearStage()? to be honest thats kind of how the whole thing is written at the moment! Like, the createPhoto() function contains all of the variables etc for creating the photo, it also contains the loader creation and slide creation, and all the drag and drop functions... I did this because it seemed a good way of making sure each photo had these functions to itself, and that clicking on one didnt lift the whole pile... and it worked so I never asked about it!
Don't know if that makes sense, heres the whole script of the createPhoto() function, obviously you wont read it all but it will give you an idea of how much of a mess i've made :P
function createPhoto() {
var objectIndex:Number = slideIndex;
//Create photo shape
var photoWidth:Number = 600;
var photoHeight:Number = 400;
var photo:Sprite = new Sprite();
photo.graphics.lineStyle(30, 0xffffff, 1,true,"normal",null,"round");
photo.graphics.beginFill(0xffffff, 1.0);
photo.graphics.drawRect(-(photoWidth/2), -(photoHeight/2), photoWidth, photoHeight);
photo.graphics.endFill();
//add the photo to the DisplayObjectContainer
photo.name = "photo"+(slideIndex+1);
main.addChild(photo);
//throw photo in
var randomX:Number = 340+(20*Math.random());
var randomY:Number = 220+(20*Math.random());
var randomRotateStart:Number = -25+(50*Math.random());
var randomRotate:Number = -5+(10*Math.random());
var throwPhotoX:Tween = new Tween(photo, "x", Regular.easeOut, 720*Math.random(), randomX, 0.8, true);
var throwPhotoY:Tween = new Tween(photo, "y", Regular.easeOut, -600, randomY, 0.8, true);
var throwPhotoRotation:Tween = new Tween(photo, "rotation", Regular.easeOut, randomRotateStart, randomRotate, 0.8, true);
//add drop shadow filter to photo
var photoShadow:DropShadowFilter = new DropShadowFilter();
photoShadow.distance = 2;
photoShadow.angle = 25 - randomRotate;//globalLighting
photoShadow.blurX = photoShadow.blurY = 5;
photo.filters = [photoShadow];
//////////////////////////////////////////LOAD IMAGE AND PRELOAD////////////////////////////////////////////////////////////
//Add the slide on top of photo
//Create a URL Request
var slideRequest:URLRequest = new URLRequest(portfolioData[projectIndex].slides[slideIndex].url);
//Create a loader object
var slideLoader:Loader = new Loader();
//Initiate a load request
slideLoader.load(slideRequest);
var slide:DisplayObject = slideLoader;
slide.x = -(photoWidth/2);
slide.y = -(photoHeight/2);
photo.addChild(slide);
slideLoader.addEventListener(Event.ENTER_FRAME, checkProgress);
function checkProgress(evt:Event):void {
trace(loaderInfo.bytesTotal);
trace(loaderInfo.bytesLoaded);
var fileSize:Number = loaderInfo.bytesTotal;
var amountLoaded:Number = slideLoader.loaderInfo.bytesLoaded;
var percent:Number = Math.round((amountLoaded / fileSize)*100);
trace(percent+"%");
if (percent >= 100) {
slideLoader.removeEventListener(Event.ENTER_FRAME, checkProgress);
}
}
//Photo RollOver
function photoRollOver(evt:MouseEvent) {
photo.addEventListener(MouseEvent.MOUSE_DOWN, photoDrag);
photo.addEventListener(MouseEvent.MOUSE_UP, photoDrop);
}
function photoRollOut(evt:MouseEvent) {
photo.removeEventListener(MouseEvent.MOUSE_DOWN, photoDrag);
photo.removeEventListener(MouseEvent.MOUSE_UP, photoDrop);
}
//Make Photo draggable
var scaleUp:Number = 1.1;
var scaleDown:Number = 1;
function photoDrag(evt:MouseEvent):void {
photo.startDrag();
trace(photo.name);
var liftPhotoX:Tween = new Tween(photo, "scaleX", None.easeIn, scaleDown, scaleUp, 0.1, true);
var liftPhotoY:Tween = new Tween(photo, "scaleY", None.easeIn, scaleDown, scaleUp, 0.1, true);
//Bring to front
var frontIndex:int = (main.numChildren)-1;
main.setChildIndex(photo,frontIndex);
}
function photoDrop(evt:MouseEvent):void {
photo.stopDrag();
var dropPhotoX:Tween = new Tween(photo, "scaleX", None.easeIn, scaleUp, scaleDown, 0.2, true);
var dropPhotoY:Tween = new Tween(photo, "scaleY", None.easeIn, scaleUp, scaleDown, 0.2, true);
}
//Photo-specific menu
function photoOver(evt:MouseEvent) {
var captions:MovieClip = new MovieClip;
addChild(captions);
}
//Delete Photo
function photoDelete(evt:MouseEvent):void {
removeChild(photo);
}
photo.addEventListener(MouseEvent.ROLL_OVER, photoRollOver);
photo.addEventListener(MouseEvent.ROLL_OUT, photoRollOut);
}
I think i'm gonna have to get loking into classes, this is getting complicated!
bigmac- 04-07-2008
Yeah, classes make life way easier. I do see why you're using nested functions... You've got this set up as a large procedural factory that is building out objects AND detailing everything that they do. I'm all but too familiar with scripts that look like this given that I wrote code like this all throughout college and my first job. However, I know how ugly this gets too and how difficult it becomes to grow it, given that it does not use OOP theory and encapsulation.
fatbuoy1- 04-07-2008
Ok... heres my understanding so far.
OOP is about grouping and sub-grouping things together. In my example, I need to create a class called 'photo', which contains sub classes like 'image','video', and 'description'. The parent class 'photo' may have static properties which apply to ALL its members, such as its size and appearance, and methods like drag and drop functionality. It may also have instance properties which vary according to each member created... if its a video then it may have a play button on it, if its an image it may have a print button. So static applies to ALL members of the class, like ALL members centre roughly around 10px from d centre, but each instance has a specific x and y value.
How close am I? :D And if i'm pretty close, how do I go about making that??
bigmac- 04-07-2008
Pretty close... that's a good start. For starters we'll expand upon the static versus instance discussion. You are correct in that static members are class-level attributes, and therefor all instances of that class share that information. However, stuff like drag and drop scripts don't work as static members of a class. You need an instance of the class on stage in order to interact with it, right? ...So, that behavior needs to be written for the instance. Think of a class as a prototype for all objects that are spawned from that class. Specific bits of data like a color, size, shape, speed, etc that apply to all instances could be static attributes. However all the guts of how each object behaves needs to be written as "template" code that will be used by each instance. Make any sense?
Also, it's not uncommon to make classes that will NOT be instantiated. This is known as a "static class" given that it is entirely composed of static members. A static class is extremely useful for things like... wait for it... DATA SHARING. If you set up a static class who's entire job is to just sit around an hold data, then everything that needs data can import the class and pull data from it. This is WAY more effective than storing data in some remote area of your timeline architecture and having to try to hit it. Heaven forbid you should ever change your document composition and break all references that you made to a data source. The static class for holding and providing data just makes way more sense.
So, I'm not going to get into building instance classes during my lunch break, given that they take a bit more setup, plus you have more to read up on them... look up what a class constructor is, what it does, and how it is named. We'll just do a dirt simple static class setup for your data model for now.
Now, I'm going to start you the RIGHT way instead of the easy way. It's more explanation, but its the way this should be done. Packages... packages are just folders that contain scripts. However, each class starts with a package declaration to tell where it is located within your script library. So, let's start you with a good form library. Build the following directory structure within your project directory (the same directory that holds your portfolio FLA)...
com > carmstrong > portfolio
get into the habit of developing within this library structure. It adds a lot of folders to flip through as first, but as your code library grows, it keeps things organized. "com" is a general universal name that acts as root of code bases. It stands for "Component Object Model". Next directory is the author. You could, say, download Adobe's open-source AS3 code library which gets filed neatly as "com.adobe" next to your own directory of code. Third deep, "portfolio"... that's the name of the project. From there, you can start building package structures (large or small) on a project by project basis. LOL, I think I've got some structures within Shepherd that go fifteen directories deep (but it's a really complex app).
Now, a data class for your portfolio might look like this:
package com.carmstrong.portfolio
{
public final class DataSource
{
public static var data:Object;
}
}
This would get saved into a new ActionScript document placed within the specified package directory with a name matching the title of the class, here being "DataSource.as". Ah, and for information about how to name classes, read the document that I've written for shepherd at: http://lassie.gmacwill.com/help/docs/medialib/process.php#step4. Read the section called "naming classes".
And finally... to plug data in and pull data out of this class, just import this class anywhere you need to use it. You know how to do that, you have to import Flash classes all the time...
import com.carmstrong.portfolio.DataSource;
Then you can insert and pull data from this class by referencing
DataSource.data = new Object();
var x = DataSource.data.sfoo;
As your app grows, you can add static getter / setters to pull specific bit of data from the source directory structure so that you don't need to reference elaborate paths each time. Okay, I've got to work. Keep reading up on class instances and constructors.
fatbuoy1- 04-07-2008
look up what a class constructor is, what it does, and how it is named.
Ok... im still a bit hazy on this one, but is a class constructor basically setting out the different properties of a class, like when using the drawRect(x,y,width,height) class, the constructor determines the different properties of the instance to be created(eg. x, y, width and height?)
Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.