Get global coordinate of a dynamically created nested component? - actionscript-3

In the code below, I have created 4 sprites (picn) inside a sprite (noteholder). How can I get the absolute values of the picn instances that I create? I know about the localToGlobal function, but I can't figure out how to use that in this case. At this point, I think I need the container because I need to be able to move the sprites after creation. Any help is greatly appreciated. Thanks!
package
{
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import Main;
public class Notes extends Sprite
{
private var speed:int = 14;
[Embed(source="../lib/Dodgethis.jpg")]
private var picn:Class;
private var noteholder:Sprite = new Sprite();
public function appear() {
trace ("appear ran")
var arr1:Array = new Array;
var numnotes:Number = 4;
Main.StageRef.addChild(noteholder);
trace (noteholder.x, noteholder.y);
for (var i = 0; i < numnotes; i++)
{
//trace (i);
var nbm:Bitmap = new picn;
noteholder.addChild(nbm);
nbm.y = i * 50;
arr1.push(nbm);

You need to hold a reference to the display objects you dynamically create — you don't need a "name" which is just an abstraction of instance variables when creating visual assets in the Flash IDE.
I've updated your code to demonstrate the concept:
package
{
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.Stage; // added this
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle; // added this (see below)
import Main;
public class Notes extends Sprite
{
private var speed:int = 14;
[Embed(source="../lib/Dodgethis.jpg")]
private var NoteBMP:Class;
private var display:Sprite = new Sprite();
private var notes:Array = []; // make notes an instance variable, so it's accessible throughout the class
// I renamed appear to 'build' because I'm a pedantic moron
public function build():void
{
trace ("build ran");
var noteCount:int = 4;
Main.StageRef.addChild(display);
for (var i:int = 0; i < noteCount; i++)
{
var nbm:Bitmap = new NoteBMP;
display.addChild(nbm);
nbm.y = i * 50;
notes.push(nbm); // by adding the display objects to an array you can reference them later
then at some later point in the Notes class you can reference your bitmaps by looping through the notes array
// initialize variables outside the loop
var localPos:Point
var globalPos:Point;
var bounds:Rectangle;
var n:DisplayObject;
var stage:Stage = Main.StageRef;
for (var i:int = 0; i < notes.length; i++)
{
trace( 'note' + i );
n = notes[i] as DisplayObject; // cast during assignment since array items have ambiguous type
// getBounds() returns a Rectangle representing the bounding box of the display object
bounds = n.getBounds(stage);
trace(
'getBounds:',
bounds.top, bounds.left, bounds.bottom, bounds.right
);
// localToGlobal() returns a Point which is just the position
localPos = new Point( n.x, n.y );
globalPos = display.localToGlobal(localPos)
trace(
'localToGlobal:',
globalPos.x, globalPos.y
);
}
A few points:
I refactored some names to make the intention more clear
I wonder why your Notes class extends Sprite, since it adds display (what you called "noteholder") to the stage. Assuming that's correct just make Notes a generic object i.e. doesn't seem to need to extend another class.

You can use getBounds about getBounds
// call this after added to stage
if (stage) {
var r:Rectangle = nbm.getBounds(stage);// r's x and y is the global pos
}
And I think localToGlobal should work in your case. Move the sprites don't have effect on localToGlobal

Related

Accessing timers within a actionscript class

I recently started programming in as3, and lately, I've started to learn object oriented programming. My problem is to access functions within a class. I guess that the "main" code is not very suitable for doing so, but I'm pretty much just asking for advice for every part of the code.
Main Code:
import flash.utils.Timer;
import flash.events.TimerEvent;
stage.addEventListener(MouseEvent.CLICK, makeCircle);
function makeCircle(event:MouseEvent):void
{
var s = new Circle();
addChild(s);
s.x = mouseX;
s.y = mouseY;
}
Class code (connected to a MovieClip circle with a MovieClip fill inside):
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
public class Circle extends MovieClip
{
private var t:Timer = new Timer(30,1000);
var time:Number = 0;
var size:Number;
var bf = new BlurFilter();
var ct:ColorTransform = new ColorTransform();
public function Circle()
{
// constructor code
t.addEventListener(TimerEvent.TIMER, updateCircle);
t.start();
ct.color = 0xffffff * Math.random();
fill.transform.colorTransform = ct;
fill.blendMode = "hardlight";
}
public function updateCircle(event:TimerEvent):void
{
time = t.currentCount / 10;
size = Math.pow(Math.E, - time) * Math.sin(5 * time) * (Math.log(time));
width = (size * 20 + 100 - time * 5) * 2;
height = (size * 20 + 100 - time * 5) * 2;
bf.blurX = time;
bf.blurY = time;
filters = [bf];
alpha = 1 - time / 20;
}
}
}
What I want to do is to remove the child of s (main code) when the t.currentCount (class code) is a set value (when the alpha value is 0).
Thanks in advance.
whay you want to do is do create either an even inside the Circle class that triggers when your timer completes (alpha == 0). The custom event would have to be caught in your main class.
To put a custom event listener in your main class write:
s.addEventListener("RemoveChild", removeChild)
add the handler function
function removeChild(e:Event)
{
removeChild(s);
}
in your circle class you can add the event when you want to trigger it:
this.dispatchEvent(new Event("RemoveChild");
Alternatively you control the Alpha value from your main class by placing the loop there and call removeChild(s); directly.
An easy way to get your custom events working is by using the AS3Signals framework.
Hope that helps

How can I use a document class in a single AS3 movie clip?

I have a confetti generator that I am tyring to add to a single movie clip within my flash file. The clip is masked and I want to have some graphics and text appear above the confetti (which will be above a background layer as well).
I purchased a decent script and have modified it to work with some original confetti artwork but I can't figure out how to use this class (or change it for use) in just the one movie clip. Pasting the class below. I've been stressing about this for a couple of hours now, any help would be greatly appreciated.
package com.pixeljunkyard
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import caurina.transitions.*;
import fl.motion.Color;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
public class Main extends Sprite
{
//Create Heart Instance
private var hearts:Heart;
//Amount of hearts
private var totalHearts:Number = 30;
//Falling Speed
private var speed:Number = 1.5;
//Constructor
public function Main()
{
//Align top left for screen aspect ratio
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//Loop through the amount of heart to be created
for (var i = 0; i < totalHearts; i++)
{
//Create new heart
var heart = new Heart();
//Set Random value
var randScale:Number = randRange(50, 100);
var randRotation:Number = randRange( -180, 180);
var randRotationY:Number = randRange( -360, 360);
//Random position and scale
heart.x = randRange(0, stage.stageWidth);
heart.y = randRange( -stage.stageHeight, stage.stageHeight);
heart.scaleX = randScale/100;
heart.scaleY = randScale/100;
//Name each heart with the number of creation
heart.name = "heart" + i;
var Low : int = 1;
var High : int = 8;
var myRandomNumber:int = Math.floor(Math.random()*(1+High-Low))+Low;
heart.gotoAndStop(myRandomNumber);
//Add eventlisteners for interactions
heart.addEventListener(MouseEvent.ROLL_OVER, hit_heart);
heart.addEventListener(Event.ENTER_FRAME, change_shade);
//Initial Animation
Tweener.addTween(heart, {time:randRange(1,5)/speed, rotation:randRotation,rotationY:randRotationY,y:stage.stageHeight+(heart.height/2)+20, transition:"linear", onComplete:rebirth,onCompleteParams:[heart]} );
//Add to Stage
addChildAt(heart, i);
}
}
//Change shade to give lighting effect
private function change_shade(e:Event):void
{
//New color instance
var c:Color = new Color();
//Set properties
c.brightness = e.target.rotation / 300;
//Apply color to heart
e.target.transform.colorTransform = c;
}
//Random Function
private function randRange(min:Number, max:Number):Number
{
var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}
//Interactive animation
private function hit_heart(e:Event):void
{
Tweener.addTween(e.target, { time:randRange(1,3), rotationY:e.target.rotationY+180 } );
}
//Reset heart to top of the screen once fallen
private function rebirth($heart:Heart):void
{
$heart.x = randRange(0, stage.stageWidth);
$heart.y = -$heart.height;
Tweener.addTween($heart, {time:randRange(1,5)/speed, rotation:randRange(-180,180),y:stage.stageHeight+($heart.height/2)+20, transition:"linear", onComplete:rebirth,onCompleteParams:[$heart]} );
}
}
}
Now I understand your problem.
First of all, I suggest to never write code on the timeline, except simple stuff like stop() or gotoAndPlay("loop").
The easiest way to achieve what you want is to do the following:
Make a blank MovieClip in Flash IDE Ctrl + F8
Give it a linkage like this:
Then click the edit button (marked with a red rectangle)
Open in Flash Professional if asked
Save the file in your .FLA directory and copy the contents of your Main.as file into this file
Remove the package name ("com.pixeljunkyard")
Change the public class Main extends Sprite to public class ConfettiContainer extends MovieClip and import flash.display.MovieClip
Now you have a class ConfettiContainer which does the same stuff that you Main.as file did. Don't forget to copy anything that this Main.as class uses from stage to your ConfettiContainer MovieClip.
You can now create and use it like this:
var confetti:ConfettiContainer = new ConfettiContainer();
addChild(confetti);
P.S. If you can't see Export for Actionscript option when creating a Symbol in Flash, click Advanced.

Papervision3D cube face orientation

I have a question about Papervision3D, or perhaps bitmapData, I am unsure where the problem is. I have constructed a program that takes 4 banners and splits them into pieces and then applies those pieces to cubes so that I can make a banner rotator. So after I run my program I have 10 cubes with a piece of a banner on 4 faces(front, top, back, bottom) of each cube. The problem is that some of the faces are oriented incorrectly(spun 180 degrees). Is there a way in Papervision3D to spin a cube face? The other place I think the problem may be is when I create the bitmapData that will be applied to the cube faces. Is there some way to explicitly define orientation during bitmapData creation? Any help or ideas would be greatly appreciated. Thanks!
-------Edit----------
Here is the code for my CubeMaker.as class. This is the class that takes the image pieces and applies them to the cubes.
package {
import away3d.events.MaterialEvent;
import away3d.materials.BitmapMaterial;
import away3d.materials.ColorMaterial;
import away3d.materials.TransformBitmapMaterial;
import away3d.primitives.Cube;
import away3d.primitives.data.CubeMaterialsData;
import CubeEvent;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
public class CubeMaker extends Sprite {
private var _colorMaterial:ColorMaterial = new ColorMaterial(0x000000);
private var _dcRef;
private var _banners:Array;
private var _cubeArray:Array = [];
private var _cubeCoung:int = 0;
private var _numberOfPieces:int;
private var _width:Number;
private var _depth:Number;
private var _height:Number;
public function CubeMaker(banners:Array, numberOfPieces:int) {
_dcRef = DocumentClass._base;
_banners = banners;
_numberOfPieces = numberOfPieces;
}
public function makeCubes() {
//loop through the cubes
for (var i = 0; i < _numberOfPieces; i++) {
var faceBitmapArray:Array;
//fill array with four faces for current cube
faceBitmapArray = fillFace(i);
//get width and height from a piece instance
var width:Number;
var height:Number;
var tempArray:Array;
tempArray = _banners[0];
_width = tempArray[0].width;
_height = tempArray[0].height;
_depth = tempArray[0].height;
//create four materials from bitmapData
var myFront:TransformBitmapMaterial = new TransformBitmapMaterial(faceBitmapArray[0], {rotation:0} );
var myTop:TransformBitmapMaterial = new TransformBitmapMaterial(faceBitmapArray[1], {rotation:0.5} );
var myBack:TransformBitmapMaterial = new TransformBitmapMaterial(faceBitmapArray[2], {rotation:0} );
var myBottom:TransformBitmapMaterial = new TransformBitmapMaterial(faceBitmapArray[3], {rotation:0} );
//create two materians from color
var myLeft:ColorMaterial = new ColorMaterial(0x000000);
var myRight:ColorMaterial = new ColorMaterial(0x000000);
//create a CubeMatrialsData from the materials created above
var myMaterials:CubeMaterialsData = new CubeMaterialsData( { front:myFront, back:myBack, top:myTop, bottom:myBottom, left:myLeft, right:myRight} );
//listen for material change
myMaterials.addOnMaterialChange(materialChanged);
//create a new cube with the CubeMaterialsData created earlier
var _cube = new Cube({width:_width, height:_height, depth:_depth, cubeMaterials:myMaterials});
//the created cube is put into the _cubeArray
_cubeArray[i] = _cube;
if (i == (_numberOfPieces - 1)) cubesMade();
}
}
private function fillFace(i:int):Array {
var faceBitmapArray:Array = [];
for (var j = 0; j < 4; j++) {
//tempBannerArray filled with one banner in pieces
var tempBannerArray:Array = _banners[j];
//batmapData created and sized to current banner piece
var bitmapData:BitmapData = new BitmapData(tempBannerArray[i].width, tempBannerArray[i].height);
//bitmapData filled with current banner piece bitmap data
bitmapData = tempBannerArray[i].bitmapData;
bitmapData.lock();
//array is filled with bitmap data
faceBitmapArray[j] = bitmapData;
}
return faceBitmapArray;
}
private function cubesMade() {
//dispatch event to notify of cube making completion
dispatchEvent(new CubeEvent(CubeEvent.CUBES_MADE, _cubeArray.length));
}
private function materialChanged(e:MaterialEvent):void {
trace("Warning! Warning! Material changed!");
}
public function get cubes():Array {
return _cubeArray;
}
public function get cubeWidth():Number {
return _width;
}
public function get cubeHeight():Number {
return _height;
}
public function get cubeDepth():Number {
return _depth;
}
}
}
Preface: Papervision3D is close to unsupported / closed as a library, so I highly recommend using Away3D or another actionscript 3D library. Though the work done on PV3D was groundbreaking and incredible from a flash perspective so if you're looking to build a 3D experience with it, it's quite good. Just know from the get-go that future dev + support are unlikely.
Preface aside, take a look at the "Cube" primitive class in the library. You can create Materials and attach them to the MaterialsList instance that will be added to the cube instance. Assuming you're using BitmapMaterial, it has a "rotation" property, that you can set. Just determine which materials are upside-down and make their rotation = 180. Pros: quick; Cons: hard-coded.
The other option is to hit the problem on the "asset" end and flip your images. Pros: quick; Cons: non-scalable or puts the issue on the designer.
The best option, when loading the data / assets, is to have a "rotate" property that you can use to set which images should be flipped. It's a cube, so like Ender says, up is relative.

AS3 > Starting class on certain frame?

I created an AS file and used it as a class, inside it I called buttons and slideshow images.
After that I decided to create an intro by moving the timeline. My problem is that all the objects are displayed from the very first frame, is there a way to make the entire class start after certain frame?
Code for reference:
package {
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.MovieClip;
public class play extends MovieClip {
private var loader:Loader = new Loader();
private var images:Array = ["img/Layer_1.jpg", "img/Layer_2.jpg", "img/Layer_3.jpg", "img/Layer_4.jpg", "img/Layer_5.jpg", "img/Layer_6.jpg", "img/Layer_7.jpg", "img/Layer_9.jpg", "img/Layer_10.jpg", "img/Layer_11.jpg", "img/Layer_12.jpg", "img/Layer_13.jpg", "img/Layer_14.jpg"];
private var triangleButton:triangle = new triangle;
private var squareButton:square = new square;
private var crossButton:cross = new cross;
private var circleButton:circle = new circle;
public function play() {
loadNextImage();
addChild(loader);
loader.x = 137;
loader.y = 65;
//Buttons
addChild(triangleButton);
triangleButton.width = 28;
triangleButton.scaleY = triangleButton.scaleX;
triangleButton.x = 804;
triangleButton.y = 107;
triangleButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(circleButton);
circleButton.width = 28;
circleButton.scaleY = circleButton.scaleX;
circleButton.x = 825;
circleButton.y = 130;
circleButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(crossButton);
crossButton.width = 28;
crossButton.scaleY = crossButton.scaleX;
crossButton.x = 804;
crossButton.y = 155;
crossButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(squareButton);
squareButton.width = 28;
squareButton.scaleY = squareButton.scaleX;
squareButton.x = 780;
squareButton.y = 130;
squareButton.addEventListener(MouseEvent.CLICK, slideGames);
}
public function slideGames(event:MouseEvent):void {
loadNextImage();
}
public function loadNextImage() : void {
// Increment the image
_imageIndex++;
// If we've reached the end of the array, start over
if (_imageIndex >= images.length) {
_imageIndex = 0;
}
// Now get the image source from the array and tell the loader to load it
var imageSource : String = images[_imageIndex] as String;
loader.load(new URLRequest(imageSource));
}
// Next image to display
protected var _imageIndex : int = -1;
}
}
Yes, instead of initializing everything in the constructor of your class (play()), you can move it to another function, and call that from the timeline. I am assuming you are using the play class as the document class.
So instead of
public function play() {
you would rename it to
public function play_start() {
Create an empty constructor named play() at this point if you want to.
In the flash IDE, select the frame where you want the items to appear, then create a keyframe there.
Select the keyframe and go to the Actions panel (F9) and enter the following code:
this.play_start();
once the playhead is at the keyframe, your code should be executed.

PaperVision3D and Flash CS4

I need to develop a cube that contain 10 little cubes and manipulate everyone like an object..Somebody have any idea or some tutorial for do this on PaperVision3d and Flash CS4..Thanks Folks!!
I think what you actually want is Papervision3d as I know of nothing called "PaperViewer". If that is the case, please update your question.
This should give you an idea of how to start. It creates 10 cubes and stores them in an array. You can access them using boxes[index] to alter their scale, postion and rotation.
package
{
import flash.display.Sprite;
import flash.events.Event;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.view.BasicView;
public class Boxes3d extends Sprite
{
private static const NUM_BOXES:int = 10;
private var world:BasicView;
private var boxes:Array;
public function Boxes3d()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
private function addedToStage(event:Event):void
{
// create the world and add it to the stage
world = new BasicView();
addChild(world);
// create a set of boxes
boxes = [];
var box:Cube;
var materials:MaterialsList;
for(var boxIndex:int = 0; boxIndex < NUM_BOXES; boxIndex++)
{
// create a material to cover the cube
materials = new MaterialsList({
all: new ColorMaterial(Math.random()*0xFFFFFF) });
// make a cube
box = new Cube(materials, 100, 100, 100);
// spread it out in space
box.x = Math.random()*500 - 250;
box.y = Math.random()*500 - 250;
box.z = Math.random()*500 - 250;
// add it to the scene
world.scene.addChild(box);
}
// get the world to render each frame
world.startRendering();
addEventListener(Event.ENTER_FRAME, positionCamera);
}
private function positionCamera(event:Event):void
{
var camera:Camera3D = world.cameraAsCamera3D;
camera.x = -(stage.width/2 - mouseX) * 2;
camera.y = (stage.height/2 - mouseY) * 2;
}
}
}