View Full Version: Actionscript 3

lassie >>Discussions >>Actionscript 3


<< Prev | Next >>

bigmac- 04-07-2008

Not quite... The constructor is the thing that builds the instance. The Class constructor is called when you do "var obj = new Object();". The "new" method creates a new instance of the object by running the constructor. A constructor should build out the different components of the object. In the case of a simple slide show, the constructor would probably create a Sprite object to load a photo into, and create a text field to display a caption. So, a constructor does exactly what its name implies: it constructs the object. A constructor method cannot return a value, and it must be named the same as the class. For example... package { public class MyCoolClass { public function MyCoolClass():void { // this is the constructor method } } } Okay, so that covers constructors. Now lets touch on a couple more cornerstones before getting into the nuts and bolts of implementing your slide classes. So, read up on inheritance. It's another bare bones foundation principal of OOP, and will make sense of super constructors (which are very important). Also, it wouldn't hurt to look up the difference between public and private members since you'll be seeing a lot of them, they're pretty simple, and they really help you segment your OOP design.

fatbuoy1- 04-07-2008

Hmm... inheritance allows sub classes to inherit properties/code from their parent classes... so the different instances that belong to the slide/photo class; image, title, and video all inherit the properties of their parent class, i.e. they are all white and rectangular with drop shadows. However they only inherit the public or protected properties... they dont inherit private properties. Im guessing that a superconstructor can be used to create any of the instances that belong to the slide class?

bigmac- 04-07-2008

Again, close. You're on the right track, but you've got a gray area in the distinction between inheritance and composition. The easy way to think of this is with the phrases "is" and "has". If we extend a Sprite to a subclass called "Photo", then Photo IS a Sprite... or rather, Photo is a Sprite with additional properties that make it a Photo. Now, our Photo object HAS a child sprite that we'll load an image into, and it HAS a text field that we'll drop a caption into. That image sprite and text field do not extend from the Photo class so are NOT Photo objects themselves, they are just elements that make up a Photo object's composition. This is actually a fiercely debated area within OOP as to which model is better – inheritance or composition. While all OOP programmers embrace both techniques, there is great discussion over which model to rely more heavily on in application design. Ultimately, it comes down to what makes more sense to the individual developer, given that everyone's brain works differently. These are the reasons why writing code is such a ridiculous creative art form. You can build anything in any way, so the way you DO build it all comes down to a matter of personal style.

bigmac- 04-07-2008

So, here you go; this should get you rolling! This is an ultra-simple drag and drop rectangle based upon your photo object that you were setting up. While the technicals are substantially less than where you are, what should be useful is the structure. You can use this as a framework to start building off of. package com.carmstrong.portfolio { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.text.TextField; public class Photo extends Sprite { public static const PHOTO_WIDTH:int = 200; public static const PHOTO_HEIGHT:int = 120; // -------------------------------------------------- // Private members // -------------------------------------------------- private var _image:Sprite; private var _caption:TextField; // -------------------------------------------------- // Constructor // -------------------------------------------------- public function Photo():void { super(); drawFrame(); addEventListener(Event.ADDED_TO_STAGE, this.onInit); addEventListener(Event.REMOVED_FROM_STAGE, this.onUninit); } // -------------------------------------------------- // Init / uninit // -------------------------------------------------- protected function init():void { addEventListener(MouseEvent.MOUSE_DOWN, this.onDrag); } protected function uninit():void { removeEventListener(MouseEvent.MOUSE_DOWN, this.onDrag); removeEventListener(Event.ADDED_TO_STAGE, this.onInit); removeEventListener(Event.REMOVED_FROM_STAGE, this.onUninit); } // -------------------------------------------------- // Private methods // -------------------------------------------------- private function drawFrame():void { graphics.lineStyle(3, 0xCCCCCC, 1, true); graphics.beginFill(0xFFFFFF, 1); graphics.drawRect(-(PHOTO_WIDTH/2), -(PHOTO_HEIGHT/2), PHOTO_WIDTH, PHOTO_HEIGHT); graphics.endFill(); } private function photoDrag():void { startDrag(false); stage.addEventListener(MouseEvent.MOUSE_UP, this.onDrop); } private function photoDrop():void { stage.removeEventListener(MouseEvent.MOUSE_UP, this.onDrop); stopDrag(); } // -------------------------------------------------- // Event handlers // -------------------------------------------------- private function onDrag(evt:Event):void { photoDrag(); } private function onDrop(evt:Event):void { photoDrop(); } private function onInit(evt:Event):void { init(); } private function onUninit(evt:Event):void { uninit(); } } } Paste that into a new AS file and save it in your portfolio class path as "Photo.as". Then, create a new FLA in your project root and put the following actions on Frame 1: import com.carmstrong.portfolio.Photo; var photo:Photo = new Photo(); addChild(photo); You'll get a box that you can drag around. Yea! But seriously, this is the basic framework of your photo object... all the nifty animation is just glitz built ontop of this sort of thing. The script extends the Sprite class, then calls the super constructor within it's constructor. That will tell Sprite to build its self normally, then this will build ontop of it. The constructor draws the frame, then adds listeners for when the sprite is added and removed from stage. These become the initializer and uninitializers of the Photo. The rest is just simple functions and even handlers... Note that the event handlers are broken out and just call other methods. This is a good habit to get into so that other methods besides just an event call tap into the event's functionality.

fatbuoy1- 04-08-2008

Thanks! I think it will take me a while to get it completely sorted out in my head but Id say after trying it a few times it will start to make sense! So, what do you think I need seperate classes for? Im thinking I need: LoadXML = to load the XML file and put it into an array CreateMenu = to read the array and make the appropriate buttons MenuButtons = should these have a class of their own? Image = to load the appropriate URL from the array and add the image to the Photo object PercentLoader = to be plugged in anywhere theres images loading Have I missed anything?

bigmac- 04-08-2008

Sounds about right.

fatbuoy1- 04-08-2008

Thanks. Are the constructors only needed when theres an actual visible object to be created? Like do I need one for my XML loader class?

bigmac- 04-08-2008

Hmmm... interesting question, and a difficult one to answer clearly. In simplest terms, you need a constructor for any class of object is that instanced (and DisplayObject descendants certainly aren't the only object classes that need to get instanced).So, think of it like this: are you creating an instance of this class using "var obj = new MyClass();"...? If so, then the object needs a constructor. If you're just working with methods and members of a static class that never needs to be instanced, then you can nix the constructor... or make it into a Singleton (but we can get into that later).

fatbuoy1- 04-08-2008

Hmm.. ok well i'm trying to put together the LoadXML class, heres what I have so far package com.carmstrong.portfolio{ import flash.events.Event; import flash.net.URLLoader; import flash.net.URLRequest; public var portfolioData:Array=new Array ; public var externalXML:XML; public var uldr:URLLoader=new URLLoader ; public var request:URLRequest=new URLRequest("portfolio.xml"); uldr.load(request); uldr.addEventListener(Event.COMPLETE,onComplete); public function onComplete(event:Event):void { trace("XML loaded"); var i:Number=0; //Load list of example images var xmlData=new XML(evt.target.data); // specify a node name to read as a list var projectList:XMLList=xmlData.project; // Iterate through the list of image nodes for each (var projectNode:XML in projectList) { // extract each node's data var t:String=projectNode.title; var d:String=projectNode.description; var slidesList:XMLList=projectNode.slides.slide; var slidesData:Array=new Array ; for each (var slidesNode:XML in slidesList) { var u:String=slidesNode.url; var st:String=slidesNode.title; var c:String=slidesNode.caption; slidesData.push({url:u,title:st,caption:c}); } // Add data elements as a new Flash object in array portfolioData.push({title:t,description:d,slides:slidesData}); } } } Im guessing thats full of mistakes... I havnt put in a constructor because I'm still unsure how I would go about it for this one, like should I put uldr.load(request); inside the constructor, like public function LoadXML():void { uldr.load(request); uldr.addEventListener(Event.COMPLETE,onComplete); }?

bigmac- 04-08-2008

Don't get ahead of yourself... when you copy a mass amount of script into a fresh class right off the bat, you introduce more errors than you know what to do... especially if you're not familiar with how to read the error console. So, take it one step at a time: build a class framework then layer in methods. If you take that approach, you'll realize dumb errors as you go. For example, in the above script you've forgotten to include a class declaration... you just started dropping code into a package block. So, I'll talk you through this first one (building an XMLService object). First off: Start simple. Build a raw, basic class structure. For reasons that I'll explain later, make this class extend from EventDispatcher. Look at my previous class example as a model for how to extend a class. Step 1 is getting your basic extended class to compile into your document and to successfully create an instance of it. Once you can do that, set up a new URLLoader within the class constructor that will load the specified XML document. Wire up its event listeners and get to the point where you are successfully importing the data... you've done all that, so just do the same thing within an isolated structure. We'll proceed from there. Again... just don't get ahead of yourself.

fatbuoy1- 04-08-2008

Ok thanks :) You're right, its a lot neater and clearer when I start with that structure you gave me and build from there. However, i'm getting an error when I try and import the class into the main timeline: 1017: The definition of base class EventDispatcher was not found. Heres my la-*test*-('") attempt... I THINK it's pretty much right, but maybe you'll see some glaring mistakes. package com.carmstrong.portfolio{ import flash.events.Event; import flash.net.URLLoader; import flash.net.URLRequest; public class LoadXML extends EventDispatcher { public var _portfolioData:Array = new Array; // -------------------------------------------------- // Constructor // -------------------------------------------------- public function LoadXML():void { var _externalXML:XML; var _loadURL:URLLoader = new URLLoader; var _request:URLRequest = new URLRequest("portfolio.xml");//could instead reference a variable in main flash timeline? _loadURL.load(_request); uldr.addEventListener(Event.COMPLETE, onXMLLoaded); } // -------------------------------------------------- // Private methods // -------------------------------------------------- // // SHOULD I HAVE ALL THE ELEMENTS CONTAINED BELOW IN // onXMLLoaded() IN A PRIVATE METHOD HERE INSTEAD, // AND JUST USE onXMLLoaded() PURELY AS AN EVENT // HANDLER FUNCTION? // -------------------------------------------------- // Event handlers // -------------------------------------------------- private function onXMLLoaded(evt:Event) { trace("XML Loaded"); var i:Number=0; //Load list of example images var xmlData=new XML(evt.target.data); // specify a node name to read as a list var projectList:XMLList=xmlData.project; // Iterate through the list of image nodes for each (var projectNode:XML in projectList) { // extract each node's data var t:String=projectNode.title; var d:String=projectNode.description; var slidesList:XMLList=projectNode.slides.slide; var slidesData:Array=new Array; for each (var slidesNode:XML in slidesList) { var u:String=slidesNode.url; var st:String=slidesNode.title; var c:String=slidesNode.caption; slidesData.push({url:u,title:st,caption:c}); } // Add data elements as a new Flash object in array _portfolioData.push({title:t,description:d,slides:slidesData}); } } } } :D

fatbuoy1- 04-08-2008

Oh and am I extending this one from the EventDispatcher class so that it inherits EventDispatching properties, and can for example dispatch an event that will call my CreateMenu class?

bigmac- 04-09-2008

Yep, exactly. EventDispatcher is one of the most common and useful classes to extend utility objects from because it has the ability to subscribe listeners. K, as for your error. #1017 means that you didn't import a class that you've referenced. It even tells you which class you didn't import... in this case, EventDispatcher. So, look at your import statements at the top of the package block. See what you're missing? import flash.events.EventDispatcher; Looking through your code, it looks like you're getting ahead of yourself again. Get one thing working before moving on to the next. I'm seeing malformed statements that will cause errors... For example: public var _portfolioData:Array = new Array; or this... the variable is not previously defined uldr.addEventListener(Event.COMPLETE, onXMLLoaded); Also, this class as it stands will not work as an even dispatcher because you've never run the super constructor. Remember, you have to tell the super class to build in order to have all its fun features. So, add this as the first line of your constructor: super(); Few other notes... when naming object properties, public properties should NOT start with an underscore. While this is not technically wrong, its bad form. The leading underscore is an indicator of a reserved private property that is confined to use within the class. Also, lets cover the difference between properties and variables. A variable exists within a function only when a function runs. Once a function finishes running, all variables that were created during the function are purged, UNLESS they are stored to the class. In the case of your constructor, you're setting up a bunch of objects that you want to reference at a later time, but they are being configured as variables, not class properties. So, you're constructor should look more like this: public class LoadXML extends EventDispatcher { public var portfolioData:Array = new Array(); private var _externalXML:XML; private var _loadURL:URLLoader; // -------------------------------------------------- // Constructor // -------------------------------------------------- public function LoadXML(xmlPath:String):void { var req:URLRequest = new URLRequest(xmlPath); // << Pass this in _loadURL = new URLLoader(); _loadURL.load(req); _loadURL.addEventListener(Event.COMPLETE, onXMLLoaded); } } Also note that in RE to you comment about pulling the XML path from the root timeline...? NO. It defeats the purpose of an OOP architecture when you continue creating timeline dependencies. Just pass the XML path in through the constructor as a parameter. So, when you import this class and instance it, you'd use... var loadxml:LoadXML = new LoadXML("myData.xml");

fatbuoy1- 04-09-2008

Ok, I WILL get this! :D Still, with every mistake I learn like 10 new things. I wondered what the underscores were for right enough, I figured it was just what you did with variables within a class but I get it now. One thing though, whats the difference between a constructor and a super constructor? Anyways, I have that all working fine now I think, and have imported it into my main timeline. How do I go about reading from the portfolioData array within the LoadXML class? I've tried var title_txt:String = LoadXML.portfolioData[0].title; trace (title_txt) but it comes up with this error 1119: Access of possibly undefined property portfolioData through a reference with static type Class. Thanks for your patience. :)

bigmac- 04-09-2008

NP on the patience... I'm getting some weird sense of peace out of providing the lessons that I never got during college. So, error #1119 means that you're trying to reference an instance property through a reference to the class as a whole. This gets back to that discussion of static versus instance properties. Static properties are properties of the class, so you can reference them as "MyClass.someStaticProp". However, instance properties only exists within a specific instance of a class, so you cannot pull the property from the class as a whole... it's like trying to get the hair color of the human race. While every human HAS a hair color, you have to look at individual people to assess what it is. So, you can do one of two things. You could make the portfolioData property static and reference it the way you are. While that WOULD work, it would mean that you cannot reuse the class. If you load a second XML doc with that class, then it's loaded data will replace the single (static) class data value. And that's bad. So, the better option is to just reference the data as a property of the instance. The class doesn't need to change, you you can use this script as many times as you want since all loaded data will be stored and managed locally with the instance. As for super constructors... Hmm. You've seen the classic movie "Back to the Future", right? Well, in it Doc Brown builds a time machine out a Dalorien. In an OOP architecture we could think of this as: public class TimeMachine extends Dalorien { public function TimeMachine():void { // we now have a time machine } } Well, that technically works... but we skipped a step. In the above example we've built a TimeMachine out of the PARTS of a Dalorien. While our TimeMachine has tires and headlights and an engine, they're all just sitting in a pile in the center of the room. Just because we've strapped a Flux Capacitor onto a gull-wing door does NOT mean that we have a working TimeMachine. We have to build the Dalorien first by running its constructor, which gives us a working automobile; on top of which we can start adding the elements that will send up back to the future. :P

Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.