I was trying to implement custom google search in my course-ware that developed in flash. I define a class named 'Main' (Main.as) and put my search code there. But the problem is, that Main class has a conflict with the other codes containing in my course-ware (i've combo box & other basic navigation in course-ware). i have no idea how to resolve it. is there any way to put that code in timeline layer? help please.. thanks. here is my Main class:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.net.navigateToURL;
import flash.net.URLRequest;
public class Main extends Sprite
{
public function Main():void
{
searchButton.addEventListener(MouseEvent.MOUSE_UP, google);
addEventListener(KeyboardEvent.KEY_DOWN, google);
searchTerms.addEventListener(MouseEvent.MOUSE_DOWN, selectText);
}
private function google(e:*):void
{
if(e.type == "mouseUp")
{
navigateToURL(new URLRequest("http://www.google.com/search?q=" + searchTerms.text));
}
else if(e.keyCode == Keyboard.ENTER)
{
navigateToURL(new URLRequest("http://www.google.com/search?q=" + searchTerms.text));
}
}
private function selectText(e:MouseEvent):void
{
searchTerms.setSelection(0, searchTerms.length);
}
}
}
From what you shared & the messages here, I assume you are trying to add code through the flash IDE while at the same time having a document class called Main, for your application.
There are lots of ways you may get around this.
Assuming you want keep your timeline code unaltered while adding an instance of the Main class :
Add an empty movie clip to the library, say SearchClass.
Go to properties of the movie clip & click export for actionscript.
Set the class to Main. Do make sure where Main.as lies outside with respect to the fla.
Add this movieclip onto the stage, on any frame or layer.
Do remember to clear the document class field.
As a side note, You should also rename the class Main to something meaningful, like SearchClass.
If you wonder about setting the class vs base class,
We use base class only when you wish to extend the features of the class (by adding UI elements for eg).
You could also simply call the class directly from the timeline code as :
var main:Main = new Main();
addChild(main);
Just make sure the Main.as file lies next to the fla... ie make sure the path is available to compiler.
Related
I'm very new to AS3 and I'm trying to learn by experimenting in flash, by making a simple 2D farming game with very simple code.
I've made one crop field out of 6 that works, which is a movieclip with different frames for each fruit growing. For example, frame 1-5 is a strawberry growing where frame 5 is when it's ready to be picked, and then 6-10 is of carrots, etc
Is there a way for me to make it so that I don't have to write the exact same code for the next crop field, and instead change the variables in this code depending on which crop field you click on?
Here's an example of the code
if (field1.currentFrame == 1)
{
field1.nextFrame();
infoText.text = "You've watered the crop. Let's wait and see how it turns out!";
function plantStrawberry():void
{
field1.nextFrame();
if (field1.currentFrame == 5)
{
clearInterval(strawberryInterval);
}
}
var strawberryInterval = setInterval(plantStrawberry,5000);
}
pls no judgerino, as said, I'm very new to AS3, lol.
There are a few ways to go about being DRY (don't repeat yourself) with your code in this scenario. The best way, would be to learn to use classes. Classes are blueprints, and are made for these very scenarios.
Here is an example of a simple class to do what you'd like. In Flash/Animate, go to file, then new, then 'ActionScript 3.0 Class' - give it a name of Crop.
In the document that comes up, there should be some basic boilerplate code. Everything should wrapped in a package. The package tells flash where to find this class - so this example, leave it as is (just package {) and save this file in the same folder as your .fla. All functions need to be wrapped in a class declaration, this should be generated for you based off the name you put in (Crop). Next you'll see one function, that has the same name as the class. This is called a constructor, and this function runs whenever you create a new instance of this class. Since classes are blueprints, you create instances of them that are objects - those objects then get all the code you put in this class.
So, to start, you should have this:
package {
public class Crop {
public function Crop() {
// constructor code
}
}
}
Let's go ahead and put your code in. See the code comments for details:
package {
//imports should go here
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
//lets make this class extend MovieClip - that means it will be a MovieClip in addition to everything else you add below
public class Crop extends MovieClip {
//instead of setInterval, use a timer - it's easier to manage and cleanup
//in class files, variables and functions have access modifiers, that's what the public and private words are about
//private means only this class can ever use the var/function
private var timer:Timer;
public function Crop() {
//initialize the timer - have it tick every 5 seconds, and repeat 4 times (to move you from frame 1 - 5)
timer = new Timer(5000, 4);
//listen for the TIMER event (which is the tick) and call the function 'grow' when the timer ticks
timer.addEventListener(TimerEvent.TIMER, grow);
}
//a function that starts the timer ticking
public function startGrowing():void {
timer.start();
}
//this function is called every timer tick.
private function grow(e:Event):void {
this.nextFrame(); //go to the next frame of your crop
}
}
}
Save the file. Now that you have this class, you need to attach it to your library assets so they all get this functionality.
In the library panel, for each of your crop objects, right click (or ctrl+click on Mac) and go to properties. In the properties, click advanced, and give it a unique class name (for instance Strawberry). Then in the base class field, put Crop (the class we just made). Repeat for the others.
Now on your timeline, when you want a crop to start growing, you can do:
field1.startGrowing(); //assuming your instance `field1` is one of the crops that you assigned the base class `Crop` to
Hopefully this gives an entry point into the power of classes. You can add more functionality into this one and it automatically apply to all the crops you attached it to.
Although BFAT's tutorial is absolutely correct, it is not the only way to do things, moreover, if you ever move from Flash and AS3 to something else, or even try Starling (a framework that allows to build fast and non-laggy mobile applications in Flash/AS3), you'll find that concept not applicable. It is very Flash-y and I applause to it though.
Instead of making each field subclass the abstract (means, it is never instantiated by itself) Crop class, you can make the Crop class take 1 of these 6 fields as an argument on creation (or later). Basically, you tell "I want to make crop field with wheat graphics". So, let me redo that class a bit.
package
{
// Imports.
import flash.display.Sprite;
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.Event;
import flash.events.TimerEvent;
public class Crop extends Sprite
{
// I agree with the use of Timer.
private var timer:Timer;
// Visuals go here.
private var field:MovieClip;
// Class constructor.
public function Crop(FieldClass:Class)
{
// With "new" keyword you can omit ()
// if there are no mandatory arguments.
field = new FieldClass;
field.stop();
addChild(field);
}
// A function that starts the timer ticking.
public function startGrowing():void
{
timer = new Timer(5000, 4);
timer.addEventListener(TimerEvent.TIMER, grow);
timer.start();
}
// This function is called every timer tick.
private function grow(e:Event):void
{
// Command the graphics to go to the next frame.
field.nextFrame();
}
}
}
Then, the usage. When you create fields, you need to set AS3 classes to them to have access, leaving base class as is, Flash will automatically set it to non-specific MovieClip. Lessay, you have crops.Wheat field and crops.Barley field.
import Crop;
import crops.Wheat;
import crops.Barley;
var W:Crop = new Crop(Wheat);
var B:Crop = new Crop(Barley);
addChild(W);
addChild(B);
B.x = 100;
W.startGrowing();
B.startGrowing();
here is my problem. In my document class TowerDefenseGame.as, I defined a variable Turrent1Flag:
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.display.Sprite;
import flash.display.Shape;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldType;
public class TowerDefenseGame extends MovieClip
{
public var Turrent1Flag==0;
}
public function TowerDefenseGame()
{
......
}
Now, in another class Turrent1Button.as, I need to create a mouse click event, by which the Turrent1Flag is set to 1:
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.display.Sprite;
import TowerDefenseGame;
public class TurretButton1 extends MovieClip
{
public var ButtonBase:Sprite=new Sprite();
public var TurretBase:Sprite=new Sprite();
public var Gun:Sprite=new Sprite();
public function TurretButton1()
{
......
this.addEventListener(MouseEvent.CLICK, MouseClick);
}
public function MouseClick(event:MouseEvent):void
{
MovieClip(root).Turret1Flag = 1;
}
Well, this does not work. I am using Adobe flash cs6 and it says the value cannot be accessed. Someone know how to do this?
try this:
private static var _instance:TowerDefenseGame;
public static function get instance():TowerDefenseGame { return _instance; }
public function TowerDefenseGame()
{
_instance = this;
}
public function MouseClick(event:MouseEvent):void
{
TowerDefenseGame.instance.Turret1Flag = 1;
}
So, to start out, AS3 makes it difficult to so what you've been used to doing in AS2 on purpose, to allow for better Object Oriented practices. When you maintain high and tight walls between Classes, it becomes easier to change Class A without having any effect whatsoever on Class B. Class B only knows about the doors and windows that are the "official" ways into the house of Class A, so it doesn't matter if you move the couch. You also make it extremely easy to replace Class A with Class C that has similar doors and windows.
When you reach through the walls by introducing global state, you can't replace Class B with Class C without changing Class A, because Class A has a direct reference to Class B and knows exactly where the couch is.
One way to handle this is through Inversion of Control (IoC). So, for our house, the couch might be supplied from outside and whatever component supplied it might keep a reference to it, so it would be able to access the couch no matter where in the house it went. So, you might choose to create your TurretButton and pass that into whoever owns that, while your TowerDefenseGame keeps a reference to it and listens directly to it, changing its own flag in response to the click.
Looking at your code, you probably don't need to go that far, because I don't see any sign that your TurretButton is actually nested. In that case, you can listen directly to it, whether you're creating it on the stage or creating it through code (which I'm not a fan of). If you're using the stage in the IDE and it exists on the stage, then just create a public variable of type TurretButton (or you could probably use SimpleButton since you no longer have need for a special Class here based on the code you've shown). That instance will be available in the constructor of your TowerDefenseGame. Just add your event listener to it, and then the listener and the variable you want to change are in the same scope. Ergo, the problem you were trying to solve never existed--you were simply looking at the problem from a perspective that overcomplicated things.
If, in fact, your code is nested in a way that's not shown, you can use ActionScript 3's event system, which is fabulous, to handle the issue without introducing direct coupling and without having to create the button through code and push it down to where it's used. One way is to just listen for any mouse click (since that is a bubbling event) and look to see what was clicked. Another solution is to generate a custom event from the button that you can then listen to from the top level to change the flag. That would look something like:
package view.button {
public class TurretButton extends MovieClip {
public function TurretButton() {
super();
mouseChildren = false;
addEventListener(MouseEvent.CLICK, broadcastTurretEvent);
}
protected function broadcastTurretEvent(e:Event):void {
dispatchEvent(new Event('turretClicked', true));//the true parameter makes it bubble
}
}
}
Then your tower Class would look like
package {
public class TowerDefenseGame extends MovieClip {
//the fact that you're calling it Turret1Flag suggests you're going to have more than 1
protected var turretFlags:Array /*of Boolean*/ = [false, false];
//your turret button instances
//doesn't show nesting, this is just to indicate that
//these are named instances so you know how what they're called
//they could be nested at any level
public var turret1:TurretButton;
public var turret2:TurretButton;
//...etc.
public function TowerDefenseGame() {
super();
addEventListener('turretClicked', onTurretClicked);
}
protected function onTurretClicked(e:Event):void {
//you can also just extract the number and do the math
//to get the correct array index
switch(e.target.name) {
case 'turret1':
turretFlags[0] = !turretFlags[0];
break;
case 'turret2':
turretFlags[1] = !turretFlags[1];
break;
}
}
}
}
Note how well this scales. You don't have to have a different Class for each button to change each separate flag. It's also easy to add more buttons without a whole lot of code changes. You could take this solution further and create a custom event that has a property that says which button was clicked, and you could supply the value to use to that for the button through dependency injection, etc.
I also made the assumption in my code that flags should be boolean and that they're turning on with the first click and off with the second click, etc. You could take the same idea and change it to, for example, increment with every click. I suspect you don't actually want to do what your code was showing and just turn it on with the first click and just leave it on forever.
Another note is that if you think you might want to code in AS3 over the longer term, you should probably learn the coding conventions that are used in AS3. One of these is that Class names start with a capital letter, but properties and methods do not.
It's probably not a great habit to get into for everything, but a static variable looks like it would work here.
public class TowerDefenseGame extends MovieClip
{
public static var Turrent1Flag = 0;
}
In Turrent1Button.as:
public function MouseClick(event:MouseEvent):void
{
TowerDefenseGame.Turret1Flag = 1;
}
i am new in ActionScript 3/ Flash CS4, i am learning classes in ActionScript(OOP). I have in my folder two files - Pro.fla (my flash project) and .as (Pro.as). I created class in Pro.as:
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Pro extends MovieClip
{
private var button:my_button=new my_button(); // is the button from the library (MovieClip), which has been linkage Base class: Pro and class: my_button
public function Pro()
{
button.x+=2050;
}
}
}
when i ctrl+enter, i have a mistake: Error: Error #1023: Stack overflow,
What is the problem, can anyone help me with that? Thank you in advance!
It looks like you have a recursion issue. In your comment, you mentioned that "my_button" has a base class of "Pro". I'm guessing "Pro.as" is your Document class and not the base class of your button. Right now, because Pro is the base class of the button, and you're creating the button within Pro, it's creating an endless loop.
If you haven't created a base class for the button, you probably want to set it to "flash.display.Sprite" or "flash.display.MovieClip" to have it extend either Sprite or MovieClip.
The base class of the button should be flash.display.SimpleButton (or MovieClip)
I am relatively new to flash. I am trying to create a square grid and add it to the movie. When I open the actionscript panel by pressing F9 and when I type the following code,
var square:SquareClip = new SquareClip();
addChild(square);
Things are working fine (the squareclip is appearing in the movie).
Instead when I do this however, I deleted the above code and just create a new instance of Main,
new Main
and inside Main.as
package{
//----
//IMPORT
//
import flash.display.*;
import flash.events.*;
import flash.text.*;
//Class creation
public class Main extends MovieClip {
//PROPERTIES
public function Main():void {
layout_in_grid();
}
private function layout_in_grid():void{
trace("layout_in_grid");
//create a new Square
var square:SquareClip = new SquareClip();
addChild(square);
trace("Square added");
}
}
}
And when I run the code, my square is not coming. I am doing something wrong very basically. Please help me.
You need to add Main to the displaylist:
var myMain : Main = new Main();
addChild(myMain);
You could also set Main as your document class.
#Mattias is correct. But you should set this as the Document Class as he suggested - When you've selected the stage, in the properties there will be an input box allowing you to enter the name of the class.
If your file is in the same location as the FLA and called 'Main.as' you enter in the box:
Main
If the file is within a folder structure e.g. com/company/projects/Main.as - enter:
com.company.projects.Main
--
Kudos on learning the OOP way!
I'd like to access the stage of the main timeline from w/i a class that extends a movieclip. Basically, I have a button in the main timeline that makes a HUD appear. The HUD is an extended MovieClip class. When people click on a button in the HUD, I'd like to remove the object from the stage of the main MovieClip.
#curro: I think your confusion may come from the fact that I am running this code from a class definition file. Clicking on a button w/i this object should remove it from the DisplayList of the MainTimeline. Here's the code from the class definition file:
package classes {
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class Answers extends MovieClip {
public function Answers(){
listen();
}//constructor
//initiatlize variables
public var answersArray:Array = new Array();
private function listen():void {
submit_btn.addEventListener(MouseEvent.CLICK, function(e:MouseEvent){
answersArray.push(answer_txt.text);
e.currentTarget.parent.parent.stage.removeChild(this);
});//listen
}//listen
}//class Definition
}//package
trace(e.currentTarget.parent.parent) gets me the MainTimeline, and trace(e.currentTarget.parent.parent.stage) appears to return the main stage, but I cannot use removeChild w/o getting an error that I am trying to coerce the stage to be a DisplayObject (which it ought to be).
What's on the stage of the MainTimeline: A single button that, when clicked, adds an instance of the Answers class to the stage.
What's part of the Answers class that's not in the code?
I first created Answers as a MovieClip object in the main library. It has 3 parts:
a TextField named "answer_txt"
a "clear_btn" that clears the answer_txt
a "submit_btn" that submits the text of answer_txt and then removes the entire Answers object from the MainTimeline (at least, that's what I want it to do).
your class definition is really weird. Looks like a mixture of as2 and as3.
Try with this:
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.text.*;
import fl.controls.Button;
public class Answers extends MovieClip
{
public var answersArray:Array = new Array();
public function Answers()
{
submit_btn.addEventListener(MouseEvent.CLICK, remove);
}
private function remove(e:MouseEvent)
{
answersArray.push(answer_txt.text);
this.parent.removeChild(this);
}
}
}
This works on my computer. Your code doesn't. I think it has something to do with the listen method. The class isn't still instatiated and you are making it work.
Hey, I can't make head or tail from the code. Where does submit_btn come from? Is it a property of the class? What about answer_txt?
You don't need to access e.currentTarget... to remove "this" simply:
this.parent.removeChild(this);
If you add that movieclip to the stage then you can access the stage from that class as simple as in the document class
stage
Otherwise you can't access stage from that class. But you can access it by sending the stage as argument when instantiate the class.