0
votes

FURTHER EDIT: Added second parameter to clarify that TreeGenerator is using pre-created parts from the Sprites passed through the parameter, not generating them.

EDIT: I've attempted to change the code away from using "shapes" and "MovieClips" as that was kind of confusing and obscuring the issue I was having.

I'm trying to create a Sprite by using that parts of other Sprites. I've posted some code that illustrates what I'm trying to do:

public class TreeGenerator extends Sprite 
{
    private var _leaf:Sprite
    private var _branch:Sprite
    private var _trunk:Sprite
    //these are separately drawn and instantiated in other sprites,
    //one of which will be passed through in the parameters

    public var thumbnail:Sprite

    public function TreeGenerator($preCreatedTreeOne:Sprite, $preCreatedTreeTwo:Sprite) 
    {
        _leaf = $preCreatedTreeOne.leaf;
        _branch = $preCreatedTreeTwo.branch;
        _trunk = $preCreatedTreeOne.trunk;

        thumbnail = $preCreatedTreeOne.leaf;
        //just uses the leaf for this example

        this.addchild(_leaf);
        _leaf.y = 30;
        this.addchild(_branch);
        _branch.y = 20;
        this.addchild(_trunk);
        _trunk.y = 10;
        //this "puts together" the tree image (though very
        //simply with just y for example purposes)

        this.addchild(thumbnail);
        thumbnail.y = 40;
        //this thumbnail is supposed to be a separate object that can also
        //be interacted with but this example neglects the event listeners.
        //the important thing here is the setting of the y to 40, which 
        //overwrites the y of 30 for _leaf.
    }
}

I'm passing through two Sprites already instantiated to $preCreatedTreeOne and $preCreatedTreeTwo that were created through an assortment of tree parts to choose from (large green leaf, small red leaf, thin branch, thick branch, etc.). Those sprites are drawn images, not images generated in code (say from a .swc library). When the user clicks a button after clicking on two trees on the stage, TreeGenerator will create another image of a tree, complete with leaf, branch, and trunk but this time using the parts from the two pre-created trees (and it would be dynamic, one click would generate a tree with green leaves from tree one, thick branches from tree two, and a thin trunk from tree one, whichever combination of two trees chosen as "one" or "two"). There would also be a separate thumbnail that could be interacted with independently (though that code is omitted in the example).

However, when I run the code, I see that the y coordinate value for _leaf gets overridden by thumbnail, because I now realize that both are now $preCreatedTreeOne.leaf.

How do I "take" additional instances (or copies) of $preCreatedTreeOne.leaf from $preCreatedTreeOne so that I can independently manipulate them when I store them in different variables?

1
Why do you pass in a MovieClip as a parameter? Where do these sets of shapes come from? You say the user chooses them: how does he do that? - null
You use MovieClip everywhere but which are really MovieClip? For example NewShape is definitely not one so what else is not a MovieClip? (has no timeline) - BotMaster
I guess you could just use "Sprite" instead. I'm not an advanced writer with Actionscript 3 (or programming in general). However, you still get the same problem even with sprites. Changing the x, y, scaleX, etc. of the thumbnail also affects _circle (note: the "shapes" are not important, more generally, I'm trying to use drawn images that are then put together as one image in this class, dynamically, say whenever the user clicks a button for example). I need to be able to manipulate _circle and thumbnail separately. - UltraVires

1 Answers

0
votes

IGraphicsData

You can create objects that correspond to calls to methods of the drawing API. They all implement the above interface. You can then group them in a Vector.<IGraphicsData> and shove them into drawGraphicsData() to get your stuff drawn in a Graphics object.

You are not passing around the meal, but its recipe. You can then cook as many meals according to the recipe as you like.

Since FP 11.6 you can also query Vector.<IGraphicsData> from a Graphics object via readGraphicsData()

disclaimer: I hacked together a modified version of your example code in wonder.fl because I don't have a compiler installed, please implement this properly with separate class files and not internal classes.

My Flash Player is from back in the day when it was still cool to have it and thus a little old (11.2), which means I couldn't actually test the code with readGraphicsData(), which is why I pass the triangle list to all 3 parameters.

package 
{
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.IGraphicsData;
    import flash.display.GraphicsPath;
    import flash.display.GraphicsSolidFill;
    
    import flash.display.GraphicsEndFill;
    
    public class Main extends Sprite 
    {
        public function Main() 
        {
            
            // assemble Vector.<IGraphicsData> manually for triangle
            var triangle:GraphicsPath = new GraphicsPath();
            var triangleHeight:uint = 30; 
            triangle.moveTo(triangleHeight / 2, 0); 
            triangle.lineTo(triangleHeight, triangleHeight); 
            triangle.lineTo(0, triangleHeight); 
            triangle.lineTo(triangleHeight / 2, 0);
            
            var commands:Vector.<IGraphicsData> = new <IGraphicsData>[new GraphicsSolidFill(0xff0000), triangle, new GraphicsEndFill()];

            addChild(new ShapeSet(commands, commands, commands));
            
            // since FP 11.6 the following is also possible
            
            // assemble Vector.<IGraphicsData> from existing Graphics object in Shape
            var square:Shape = new Shape();
            square.graphics.beginFill(0xff00);
            square.graphics.drawRect(0, 0, 30, 30);
            square.graphics.endFill();
            
             addChild(new ShapeSet(square.graphics.readGraphicsData(), commands, commands));
        }
    }
}
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.IGraphicsData;

internal class ShapeSet extends Sprite
{
    private var _square:Shape;
    private var _triangle:Shape;    
    private var _thumbnail:Shape;

    public function ShapeSet(square:Vector.<IGraphicsData>, triangle:Vector.<IGraphicsData>,  thumbnail:Vector.<IGraphicsData>) 
    {
        _square = new Shape();
        _triangle = new Shape();
        _thumbnail = new Shape();

        addChild(_square);
        _square.x = 10;
        addChild(_triangle);
        _triangle.x = 60;
        addChild(_thumbnail);
        _thumbnail.x = 90;
        
        _square.graphics.drawGraphicsData(square);
        _triangle.graphics.drawGraphicsData(triangle);
        _thumbnail.graphics.drawGraphicsData(thumbnail);
    }
}

If you want to pass only triangles to triangles, you should write a triangle class that encapsulates a Vector.<IGraphicsData> and ensures that it only contains data that represents a triangle. How to do this is out of the scope of this question.