Adding shape to stage as3 - actionscript-3

I'm not sure if I'm over or under thinking this however I've got this scenario. I wish to be able to add (for now) a triangle to the page using multiple classes. The first one being adding actionscript to a frame in flash the second an actual class. Now, can I do this? Or am I silly thinking I can? I wish to do this so I can create my background as a dynamically created area where thinks I can interact with are placed on as instances of a class.
On frame
import flash.display.Stage;
var sides:Sides=new Sides();
stage.addChild(sides);
this.addChild(sides);
On class
package {
import flash.display.Shape;
public class Sides extends Shape {
public function Sides() {
var triangleHeight:uint = 100;
var triangle:Shape = new Shape();
// red triangle, starting at point 0, 0
triangle.graphics.beginFill(0xFF0000);
triangle.graphics.moveTo(triangleHeight / 2, 0);
triangle.graphics.lineTo(triangleHeight, triangleHeight);
triangle.graphics.lineTo(0, triangleHeight);
triangle.graphics.lineTo(triangleHeight / 2, 0);
triangle.graphics.endFill();
trace("Into construct");
}
}
}
The issue I have is that the actual triangle does not appear on the screen it's blank. I know the constructor is ran, however I get no actual output as such.
I hope I made myself clear. If anyone can suggest a better solution I would love to hear it. My scenario is this.
I wish to create a world that other movie-clips can interact with. I will be creating lines to represent them. Now is it better to do it dynamically generated or is there a way to have some sort of base class that all of the other ones run off where that allows me to have random width. Hope this is clear.

you create an instance of a Shape within your Sides constructor to which you draw the triangle however this shape is never added to a display list, instead you add your instance of Sides (which itself has nothing drawn) to a display list.
Because your Sides class is extending Shape you don't need another instance of a Shape, your instance of Sides itself is a Shape and you can draw directly to it like so:
package {
import flash.display.Shape;
public class Sides extends Shape {
public function Sides() {
var triangleHeight:uint = 100;
// red triangle, starting at point 0, 0
this.graphics.beginFill(0xFF0000);
this.graphics.moveTo(triangleHeight / 2, 0);
this.graphics.lineTo(triangleHeight, triangleHeight);
this.graphics.lineTo(0, triangleHeight);
this.graphics.lineTo(triangleHeight / 2, 0);
this.graphics.endFill();
trace("Into construct");
}
}
}

Related

How to remove and add a Sprite type of data to the scene?

I have a Sprite type of variable:
var can: Sprite;
can= new Sprite();
addChild(can);
can.x = 5;
can.y = 5;
This Sprite is making a grid in my scene as shows below:
How it makes the grid?
I will pass it to a class named "Grid" to make the whole grid.
When I am going to go to another scene, I need to remove all child in current scene. So, I use the function:
function clearAllTut(): void {
//trace(numChildren);
while (numChildren > 0) {
removeChildAt(0);
}
}
when I will come back to this scene again, all the other child are demonstrated except "can".
The problem is with the removing function? (then why all the other child will be demonstrated again except "can")
or I need to change the method of programming for a Sprite type of variable?

Using an instance more than once when creating a MovieClip through composition

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?
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.

Having trouble getting calls to addChild() on nested children in vanilla ActionScript 3 to do anything

Assume the following code:
package
{
import somenamespace.Button;
import flash.display.*;
import flash.events.Event;
import flash.text.TextField;
public final class Main extends Sprite
{
public function Main()
{
stage ? init() : addEventListener(Event.ADDED_TO_STAGE, init);
function init(pEvent:Event = null):void {
// support autoOrients
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
removeEventListener(Event.ADDED_TO_STAGE, init);
/*var btn:Button = new Button(0, 0, 400, 400)
addChild(btn);*/
var sprite:Sprite = new Sprite();
sprite.width = 400;
sprite.height = 400;
addChild(sprite);
var label2:TextField = createCustomTextField(sprite, 0, 50, 200, 20);
label2.text = "Drag to select some of this text.";
}
}
private function createCustomTextField(sprite:Sprite, x:Number, y:Number, width:Number, height:Number):TextField {
var result:TextField = new TextField();
result.x = x; result.y = y;
result.width = width; result.height = height;
sprite.addChild(result);
return result;
}
}
}
I'm having trouble getting nested children to show their own children on the screen. addChild() presumably adds the child, but nothing happens on the screen. I don't understand why. I'm used to using Flex and Starling and stuff like that, but the idiom seems to have changed a bit on even this basic point when going to straight vanilla.
You can see where I've commented out a bit of code where I was designing a custom button class, and I was having a lot of the same trouble with it; however I was able to get it to finally draw a blue rectangle on the screen, once I stopped trying to add a sprite to that effect to the button, and once I started to use the button's own graphics property to draw the rectangle instead (Button extends Sprite), along with using some awkward timing and such when manipulating its width and height.
Earlier I was trying to add the TextField directly to the Button, originally within its own constructor, but even adding it to a regular Sprite in the Main class isn't working. Replacing sprite.addChild(result); with addChild(result); makes it show up fine though.
In general, what's wrong with this type of design? I'm not just asking about this particular example, but in general, how do you get children to add children that add children and so on? Thanks!
UPDATE
Well, as it turns out, setting the width and height on a Sprite is what's causing the problem. Take that out, and you're fine. You can even make that nested Sprite's graphic property draw a rectangle of a certain width and height, and then add children to that Sprite, as long as you are not actually setting those particular properties. Obey this one rule, and everything works great. Disobey, and it's the end of the world!!!
...Or is it? I mean, those properties are probably there for a valid reason; it's just hard to tell why they would be linked to causing issues like preventing children from showing up on the screen, for no other reason than the simple fact that you touched them. As I experimented, I usually made sure the values provided for a size that was plenty big enough for any of the Sprite's children, and that their x and y properties were also set appropriately, so they shouldn't have just been moved offscreen or even off the Sprite itself. Anybody got an idea?
EDIT
One other thing to note is that, once I got the Button class to draw a blue rectangle, I was somehow able to adjust the size of the rectangle itself by setting the width and height properties of the Button; the Button's graphics property was having its size scaled to align with the Button's, and this was part of a built-in algorithm. However whether that actually worked or not depended on things being set up a certain way, and that setup itself seemed kind of random. At this point, I'm moving forward just fine without messing with Sprites' width and height properties, but there was something there that was kind of obscure.
Let's first find out what the documentation says about the width property:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#width
The width is calculated based on the bounds of the content of the display object.
There's no content in a newly created Sprite object. It is just an empty container.
Reading this value without content makes sense, the answer is 0. But writing a value to it that's different from 0 doesn't make too much sense.
How do you want to change the width of nothing?
Basically speaking, an empty DisplayObject should not have a writeable property width.
Maybe it should throw an error when you try to do it, but it doesn't really have to, because the operation isn't very logical.
There's a couple of things I'd suggest here - take a look at this:
package com.test
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.text.TextField;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
//Change the stage parameters
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//Adding a test Sprite
var sprite:Sprite = new Sprite();
this.addChild(sprite);
//Adding some color to the sprite so you can see ti
sprite.graphics.beginFill(0xff0000,1);
sprite.graphics.drawRect(0, 0, 100, 200);
sprite.graphics.endFill();
//Adding a text field
var textField:TextField = new TextField();
textField.text = "HELLO!";
this.addChild(textField);
}
}
}
Here's a similar example that'll hopefully show what's going on. First, your init function is being called in the constructor so I'm not sure if that'll work like it should, try pulling it out into its own function. Also - display objects when instantiated don't actually have anything in them so there's really no need to specify height and width. Let the contents determine the height and width unless you some need to define them explicitly.
You can modify the example so that the TextField is added to the sprite instead of the main Sprite by using:
sprite.addChild(textField);
Hopefully this helps!

Actionscript 3.0: Help Linking Document Class To And Audio Slider Class

so I've been going at actionscript 3 for a couple weeks now but I'm still a complete newb. The most difficulty I've had is linking classes to my document class. For example, I'll have a nice great class that does things wonderfully (I could just insert it as the document class of another FLA and it would provide all the functionality I need for that specific function), but now when I have to insert it as a regular class...I guess "subclassing" the document class, all goes to hell.
I know you have to change variables and instantiate things to get it to work and I sort of understand that, but it sometimes it just gets way over my head and I feel like their should be a simple solution if I ALREADY HAVE a full working class. Seems that all too often there's a billion things I need to switch around.
Anyways, I have a specific example I'm hoping someone could help explain and walk me through a bit. I went online and found some code for a slider, then spent the last few hours editing it to contain the mp3 I want, loop it, etc. etc. Now it works great on a designated FLA...I just run it as the document class and up pops a designed audio slider that changes the volume, loops and everything. Now I want to add this slider into a simple game I've been working on, but just have NO idea where to start or what to do. For now I'll keep it simple though.
Say I just have my blank document class and my audio slider class. Now when I run my game, it runs the document class of course, and from there, I want it to run my audio slider class directly. I think if I just solve this I will be able to implement it into my game. So here is my blank document class and my audio slider class! Thanks for the help!
WHAT I'VE TRIED
I attempted to create public variables in the document class for the sprite and the slider, then create a new sprite/slider once the document class runs. I thought that to be on the right track, but then it started looking like I was going to have to do that for almost all the variables in the audio slider class. I also thought...well why can't I just run Volume() in the Document Class? Still confusing me a little why that doesn't work, but it doesn't.
Blank Document Class
package {
import flash.display.MovieClip;
import flash.display.Sprite;
public class ASDocumentClass extends MovieClip {
public function ASDocumentClass() {
}
}
}
and here is the audio slider class
package {
import flash.display.Sprite;
import flash.display.Graphics;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.net.URLRequest;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.geom.Rectangle;
public class Volume extends Sprite {
public var snd:Sound = new Sound();
public var channel:SoundChannel = new SoundChannel();
//URLRequest=new URLRequest("solitude.wav");
//Make sure you pass URLRequest an audio file on your computer.
public var req:BackgroundMusic = new BackgroundMusic();
public var boundary:Rectangle;
public var sprite:Sprite;
public var slider:Sprite;
public var xPos:Number=stage.stageWidth/2;
public var yPos:Number=stage.stageHeight/2;
public var vol:Number;
/*
Our request is loaded into the sound object and plays through
our channel. Volume is initially set at 50% and passed as a
transformation to our our channels soundTransform property
(a fancy way of saying volume). The init() function is called.
*/
public function Volume() {
channel=req.play();
channel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished,false,0,true );
vol=.5;
channel.soundTransform=new SoundTransform(vol);
init();
}
/*
The init function creates and draws a rectangle and circle
to the stage and centers them based on the height and
width of the stage. In addition, a rectangle object is
created to 'contain' the sliding circle, like an imaginary box.
We pass -100 as the x value because it is added relative
to our sprite. If we set its x value at 0, or the sprites default x
value,the boundary would stop and start at the slider sprite. Change
-100 to 0 in the rectangle object to get a better idea of its use.
*/
public function init():void {
sprite = new Sprite();
sprite.graphics.beginFill(0x999999);
sprite.graphics.drawRect(xPos,yPos,200,5);
sprite.graphics.endFill();
addChild(sprite);
sprite.x-=sprite.width/2;
slider = new Sprite();
slider.graphics.beginFill(0xFF0000);
slider.graphics.drawCircle(xPos,yPos, 20);
slider.graphics.endFill();
addChild(slider);
slider.addEventListener(MouseEvent.MOUSE_DOWN, dragSlider);
stage.addEventListener(MouseEvent.MOUSE_UP, stopSlider);
boundary=new Rectangle(-100,0,200,0);
}
/*
dragSlider runs when the use holds the mouse button down. A
startDrag method is used on our sprite where we specify boundary
as our dragging limits. A new event handler designed
to change the mouse volume is subsequenlty called per frame, where
the slider.x property determines volume.
*/
public function dragSlider(event:MouseEvent):void {
slider.startDrag(false,boundary);
slider.removeEventListener(MouseEvent.CLICK, dragSlider);
slider.addEventListener(Event.ENTER_FRAME, changeVolume);
}
/*
Stops dragging and removes the event listener to save on space. Again,
volume will be based on the sliders current x position, which is
constantly being recalculated per frame because we used an
ENTER_FRAME event.
*/
public function stopSlider(event:MouseEvent):void {
slider.stopDrag();
slider.removeEventListener(MouseEvent.MOUSE_UP, stopSlider);
}
/*
This function is constantly recalculating the vol variable
based on the sliders x position, relative to the length of
our rectangle. Creates a decimal range from 0 to 1, where 1
represents 100% volume and 0 represents mute. Anything exceeding
100% causes distortion.
*/
public function changeVolume(event:Event):void {
vol=.5+Math.round(slider.x)/200;
channel.soundTransform=new SoundTransform(vol);
}
public function onBackgroundMusicFinished(event:Event):void
{
channel = req.play();
channel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished );
}
}
}
It looks as though your Volume class is as you said, mostly complete and self-contained. This is good, as it will make instantiating a new instance of it within your document class easier.
Within the document, class, to instantiate a new class, you can do the following:
var new_volume:Volume = new Volume();
addChild(new_volume);
It's important to note that the stage does not come into scope within your Volume class until you have added it to the stage from within it's parent class (in this case, it's parent class is the document class).
So these two lines:
public var xPos:Number=stage.stageWidth/2;
public var yPos:Number=stage.stageHeight/2;
don't work, as the stage is undefined there. To wait until you get know stage is defined, you can use an Event.ADDED_TO_STAGE event listener. So you can re-write your Volume class a bit to look more like this:
package {
/* Imports here */
public class Volume extends Sprite {
/* Other vars here */
public var xPos:Number;
public var yPos:Number;
public function Volume(){
/* Other assignments that are not stage-dependant can go here */
this.addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event):void{
//We remove it immediately so that it doesn't get called multiple times
//As the instance is added to the display list tree
this.removeEventListener(Event.ADDED_TO_STAGE, onStage);
xPos = stage.stageWidth/2;
yPos = stage.stageHeight/2;
/* Now that we have a reference to the stage, let's go ahead and create our slider */
init();
}
from there you can go on with business as usual, and just alter your variable values as needed to get the class to work within the confines of your player environment/document class.

Flash ActionScript 3 - Draw static 3D cube

I'm trying to draw a 10x10 grid with Actionscript 3 with a vanishing point behind - so each square looks like it's coming towards the screen (each from its own relative perspective).
I've found many tutorials for 3D perspective cubes, but they all revolve around movement. Surely static shapes must be easier, but I'm yet to find any help regarding them.
Is there some way I can use PerspectiveProjection() in my case where it doesn't involve movement? It looks to be exactly what I want, yet seems reliant on movement.
Or are there any other methods for 3D perspective object creation?
I'd prefer to use internal AS3 functions if possible.
The closest I've got was this tutorial , which I could likely apply to my situation, but I want to make sure there's not an easier/cleaner way before attempting it.
Thanks.
Here's the fastest and probably most recommended way to achieve what you're after:
Download the Papervision3D library for AS3.
Once you've done this, create a document class and paste inside it this code that I've created for you to get you started:
package
{
import org.papervision3d.view.BasicView;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.materials.ColorMaterial;
/**
* Document class.
* #author Marty Wallace.
*/
public class Base extends BasicView
{
/**
* Constructor.
*/
public function Base()
{
// Create an array of faces for your cube.
var faces:Array = [
"front",
"back",
"left",
"right",
"top",
"bottom"
];
// Create a list of materials, which contains a material for each face of the cube.
var list:MaterialsList = new MaterialsList();
// Create a new material for each face.
for each(var i:String in faces)
{
// Define the material.
var material:ColorMaterial = new ColorMaterial(Math.random()*0xFFFFFF);
// Add your material to the face represented by i.
list.addMaterial(material, i);
}
// Create the Cube.
var cube:Cube = new Cube(list, 250, 250, 250);
// Rotate the cube to however required.
cube.rotationX = Math.random()*360;
cube.rotationY = Math.random()*360;
cube.rotationZ = Math.random()*360;
// Add the cube to the scene.
scene.addChild(cube);
// Render the cube.
startRendering();
}
}
}
The majority of the code is pretty self explanatory and there are uint.MAX_VALUE tutorials around for this particular framework.
Enjoy!