0
votes

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.

2

2 Answers

5
votes

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.

enter image description here

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.

3
votes

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();