Whats a better way to remove an old image or an image that is not there at all?
I am working with this XML slideshow and I have tweaked it the way I want, except the first image that loads doesn't disappear. How can I make this statement better? I've tried if (previous || imgHolder.numChildren > 0 ) as well and didn't work. Any help?
package
{
import flash.display.MovieClip;
import com.greensock.*;
import com.greensock.loading.*;
import com.greensock.events.LoaderEvent;
import com.greensock.loading.display.*;
public class Main extends MovieClip
{
var xml:XMLLoader;
var images:Array;
var current:int = 0;
var previous:Number;
public function Main()
{
init();
}
private function init()
{
LoaderMax.activate([ImageLoader]);
xml = new XMLLoader("xml/gallery.xml",{name:"loader",onComplete:onXmlLoaded});
xml.load();
}
function onXmlLoaded(e:LoaderEvent)
{
images = LoaderMax.getContent("loader");
nextImage(); //nextImage can use image var
}
private function nextImage()
{
TweenLite.from(images[current],1,{alpha:0, onStart:currentImage, onComplete: updateImage});
}
private function currentImage():void
{
imgHolder.addChild(images[current]);
}
private function updateImage()
{
if (previous)
{
imgHolder.removeChild(images[previous]);
}
previous = current;
if (current < images.length - 1)
{
current++;
} else
{
current = 0;
}
TweenLite.delayedCall(2, nextImage);
}
}
}
You could manipulate the contents of the Array to keep track of your current and previous slide index. The first in the Array is your current slide and the last is the previous slide. Like you suggested a numChildren check on your imgHolder is a good way to check if there is something to remove.
private function nextImage() : void
{
TweenLite.from(images[0], 1 , {alpha:0, onStart:currentImage, onComplete:updateImage});
}
private function currentImage():void
{
imgHolder.addChild(images[0]);
}
private function updateImage() : void
{
if(imgHolder.numChildren > 1)
{
imgHolder.removeChild(images[images.length-1]);
}
images.push(images.shift());
TweenLite.delayedCall(2, nextImage);
}
Related
all of these functions are getting this error. The setuplayer, the makeBalloons and the makeBalloon. I copied and pasted this code from my teacher. So I don't know what it could been stuck on trying to get these ballons to spawn in a game. Before I added the touch layer it would run but no balloons spawned. So I decided to add a touch layer and then I got these errors.
private function setupTouchLayer(evt: Event): void {
touchLayer.graphics.beginFill(0x000000, 0);
touchLayer.graphics.drawRect(0, 0,stage.stageWidth, stage.stageHeight);
touchLayer.graphics.endFill();
}
private function makeBalloons(): void {
balloonSpawnCounter++;
if (balloonSpawnCounter > balloonSpawnDelay) {
balloonSpawnCounter = 0;
balloonSpawnDelay -= difficultyRate;
difficulty += difficultyRate;
makeBalloon();
}
}
private function makeBalloon(): void {
var i: int;
for (i = 0; i < Math.floor(difficulty); i++) {
var newBalloon: Balloon = new MouseBalloon();
newBalloon.x = 1050;
newBalloon.y = Math.random() * 300 + 150;
newBalloon.xVel = (-Math.random() * difficulty) - 5;
newBalloon.sinMeter = Math.random() * 10;
newBalloon.bobValue = Math.random() * difficulty;
newBalloon.addEventListener(Particle.PURGE_EVENT, purgeBalloonHandler);
balloonsLayer.addChild(newBalloon);
balloons.push(newBalloon);
}
}
private function purgeBalloonHandler(evt: Event): void {
var targetBalloon: Particle = Particle(evt.target);
purgeBalloon(targetBalloon);
}
private function purgeBalloon(targetBalloon: Particle): void {
targetBalloon.removeEventListener(Particle.PURGE_EVENT, purgeBalloonHandler);
try {
var i: int;
for (i = 0; i < balloons.length; i++) {
if (balloons[i].name == targetBalloon.name) {
balloons.splice(i, 1);
balloonsLayer.removeChild(targetBalloon);
i = balloons.length;
}
}
} catch (e: Error)
{
trace("Failed to delete arrow!", e);
}
}
private function hitTest(shark: Particle): void {
for each(var balloon: Balloon in balloons) {
if (balloon.status != "Dead" && balloon.hitTestPoint(shark.x, shark.y)) {
balloon.destroy();
}
}
}
private function update(evt: Event): void {
for each(var balloon: Particle in balloons) {
balloon.update();
}
makeBalloons();
}
}
}
}
If you are copying and pasting code from a class file, into a timeline, you have to remove any package or class blocks, and any scope keywords like private,public,protected, final etc.
For example, if you had the following .as file:
package com.mystuff {
public class ExampleClass extends Object {
public function ExampleClass(){
trace("Hello World!");
}
private function doSomething():void {
trace("Doing something...");
}
}
}
To put that on a timeline keyframe, you'd have to change it to:
trace("Hello World");
function doSomething():void {
trace("Doing Something...");
}
The function that has the same name as the class name, you want to be by itself at the top of the code. All other functions, just remove the public and private keywords.
Now, if you'd like to use that code in an actual class file (which is good), you would do the following: (assuming you just have the code and not a file, and are using Animate/FlashPro as your IDE).
In AnimateCC, go to file -> new and choose ActionScript 3.0 Class. Give it the class name that matches what you see in the code.
Paste your code.
Save the file in the same directory as your .fla, assuming the code starts with package {. If the code starts with something like package com.mystuff, the file should saved in a subfolder called mystuff that is inside another folder called com which is in the same directory as your .fla.
To use that class file in the timeline (or another class file), you'd have to instantiate it like so:
import com.mystuff.ExampleClass;
var ec:ExampleClass = new ExampleClass();
ec.dosomething();
If you are using a class file, but are getting that error, it probably means you've accidentally closed your class block, like the following:
package {
public class ExampleClass {
}//if you put an extra one of these closing curly braces in your code, it will end your class, or if you on purpose do it like this example.
private function dosomething():void {
//will error because this function needs to live inside the class block
}
}
I am working on a game that creates three circles" red, green, and blue who have 3,2,1 health respectively. They get removed from the stage after their health reaches 0 and it is decremented by 1 per click. I am using a Main.mxml file then I have a Target.as file, as well as RedTarget.as, GreenTarget.as, and BlueTarget.as. My question is that I would like to set everything up in my Target.as file, then push the details such as color, health, and if they are dead or not through those functions. I am having trouble doing that though because I am not sure what I would need in the Target.as and then what I would need to code in each of the colored target files.
Here is my Target.as file:
package com.multiClicker {
//import the needed classes
import flash.display.Shape;
import flash.events.MouseEvent;
import spark.components.Image;
public class Target extends Image {
public function Target() {
//add event listeners
this.addEventListener(MouseEvent.CLICK, onClick);
}
//sets the hp of the target
public function hp():Number {
return hp;
}
//get function that returns false if alpha is <= 0
public function dead():Boolean {
if(alpha <= 0){
return false;
}
return true;
}
//subtracts one from targets HP when clicked
public function onClick(e:MouseEvent = null):void {
//subtracts one from hp each click
hp --;
if(hp <=0) {
this.addEventListener(onEnterFrame);
}
}
//subtracts .1 from the classes alpha
public function onEnterFrame():void{
this.alpha =- .1;
}
//draws the target
public function drawTarget(color):void {
var circle:Shape = new Shape();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(0,0,30);
}
}
}
and then my RedTarget.as file, which is the same as blue and green, except for that they are labeled as such in the variables:
package com.multiClicker {
import flash.events.MouseEvent;
public class RedTarget extends Target{
private var redHP:Number = 3;
private var redDead:Boolean = false;
private var redColor:String = "red";
public function RedTarget()
{
redHP = hp;
redDead = dead;
redColor = color;
//include the super function
super();
}
//subtracts one from targets HP when clicked
override public function onClick(e:MouseEvent=null):void {
super.onClick(e);
//push all to super
}
}
}
Any help on the issue would be great. I have been trying to figure it out throughout the day but have not figured it out.
Are you just asking how to pass variables in when you create the Target object?
public class Target extends Image {
public function Target(hp:Number, dead:Boolean, color:String) {
this.hp = hp;
this.dead = dead;
this.color = color;
}
}
Then you instantiate each target like this:
var redTarget:Target = new Target(3, false, "red");
var greenTarget:Target = new Target(2, false, "green");
etc...
I have this class ('Scheduler.as'):
package
{
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Scheduler
{
private var m_tmr:Timer = null;
private var m_the_this:* = null;
private var m_function:Function = null;
private var m_args:Array = null;
public function Scheduler(the_this:*, f:Function, interval:int, args:Array = null)
{
this.m_the_this = the_this;
this.m_function = f;
this.m_args = args;
if (this.m_args.length == 0)
this.m_args = null;
this.m_tmr = new Timer(interval, 1);
this.m_tmr.addEventListener(TimerEvent.TIMER, on_timer);
this.m_tmr.start();
}
private function on_timer(e:TimerEvent):void
{
if (this.m_args == null)
this.m_function.call(this.m_the_this);
else
this.m_function.call(this.m_the_this, this.m_args);
}
public static function schedule_call(the_this:*, f:Function, interval:int, ...args):Scheduler
{
return new Scheduler(the_this, f, interval, args);
}
}
}
And here's an AS3 FlashDevelop app that uses it ('Main.as'):
package
{
import flash.display.Sprite;
import flash.events.Event;
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);
// entry point
Scheduler.schedule_call(this, this.test_func_NO_PARAMS, 0);
Scheduler.schedule_call(this, this.test_func_ONE_PARAM, 0, 123);
Scheduler.schedule_call(this, this.test_func_TWO_PARAMS, 0, "HELLO", "WORLD");
}
private function test_func_NO_PARAMS():void
{
trace("No params was called successfully!");
}
private function test_func_ONE_PARAM(some_number:int):void
{
trace("One param was called successfully! 'some_number' = " + some_number);
}
private function test_func_TWO_PARAMS(stringA:String, stringB:String):void
{
trace("Two params was called successfully! 'stringA' = " + stringA + ", 'stringB' = " + stringB);
}
}
}
So as you see in your test-run the first two calls work fine, the one that calls a function that takes no parameters and the one that takes one parameter.
The problem is when I need to pass more than one parameter!
Solving the issue:
Well, I know it'd be solved if I could simply retain the ...args as is, and pass it on to the this.m_function.call call.
Another way, maybe is to have some sort of a foreach loop which would feed the designated ...args when the time comes, yet again, how would I refer/pass it?
There must be a nice trick here to make it work, you're welcome to sweat with me on this one!
Try changing this line:
this.m_function.call(this.m_the_this, this.m_args);
to this:
this.m_function.apply(this.m_the_this, this.m_args);
apply passes the parameters to the applied function as a list instead of a single array (the same effect as if you wrote the_function(arg[0],arg[1],arg[N])).
Edit:
Maybe I'm not understanding your problem, but this simplified sample of your code works fine (I'm not using a Timer and I'm not building any instance but I think the main thing here is how apply works; taking an array of parameters and passing them as a list of variable parameters to the invoked function):
private function arg0():void {
trace("arg0");
}
private function arg1(a:*):void {
trace("arg1");
}
private function arg2(a:*,b:*):void {
trace("arg2");
}
private function arg3(a:*,b:*,c:*):void {
trace("arg3");
}
private function test():void {
schedule_call(this,arg0,10);
schedule_call(this,arg1,10,1);
schedule_call(this,arg2,10,1,2);
schedule_call(this,arg3,10,1,2,3);
}
public function schedule_call(the_this:*, f:Function, interval:int, ...args):void
{
var m_args:Array = args;
f.apply(the_this, m_args);
}
up until now, the way i've been needing to handle my own custom events is by adding an event listener to the object that was dispatching the custom event. while this method of event handling works just fine, i've come to the point where i would like my custom events to be globally accessible, where the listening object does not need to be the same object that is dispatching the event.
in this example, my main Controller class is instantiating and adding to the display list 2 sprite classes: Square and Triangle. the 4th and final class is a custom event called ColorChangeEvent.
i'm attempting to dispatch a new ColorChangeEvent from the Square class, which uses a timer to dispatch a new random color once every second, while Triangle will listen for the dispatched event and change its fill color to the color that was dispatched by Square.
Controller.as:
package
{
import flash.display.Sprite;
public class Controller extends Sprite
{
public function Controller()
{
var sq:Square = new Square();
sq.x = sq.y = 100;
var tr:Triangle = new Triangle();
tr.x = tr.y = 250;
addChild(sq);
addChild(tr);
}
}
}
Square.as:
package
{
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Square extends Sprite
{
public function Square()
{
graphics.beginFill(0x999999);
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
var myTimer:Timer = new Timer(1000);
myTimer.addEventListener(TimerEvent.TIMER, dispatchNewColor);
myTimer.start();
}
private function dispatchNewColor(evt:TimerEvent):void
{
var randomColor:Number = Math.random() * 0xFFFFFF;
trace("Square Class Dispatched: " + randomColor);
dispatchEvent(new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor));
}
}
}
Triangle.as:
package
{
import flash.display.Sprite;
import flash.geom.ColorTransform;
public class Triangle extends Sprite
{
public function Triangle()
{
graphics.beginFill(0x999999);
graphics.moveTo(0, 0);
graphics.lineTo(100, 50);
graphics.lineTo(-50, 150);
graphics.endFill();
addEventListener(ColorChangeEvent.CHANGE, changeColor);
}
private function changeColor(evt:ColorChangeEvent):void
{
var ct:ColorTransform = new ColorTransform;
ct.color = evt.color;
transform.colorTransform = ct;
trace("Triangle Class Received: " + evt.color);
}
}
}
ColorChangeEvent.as:
package
{
import flash.events.Event;
public class ColorChangeEvent extends Event
{
public static const CHANGE:String = "change";
public var color:Number;
public function ColorChangeEvent(type:String, color:Number)
{
super(type);
this.color = color;
}
override public function clone():Event
{
return new ColorChangeEvent(type, color);
}
}
}
needless to say, this isn't working.
of course, i could add the event listener to the Square instance in the Controller class, who's event handler could pass that value to Triangle via a public function to change the color, but this is exactly the kind of limitation i'm trying to avoid.
it's not always easy to access and pass a value to a class from where the custom event is dispatched, which is why i'm looking for an actual global solution to handling custom events.
I have been using this class for some time now. To use it you would do this in square:
data.EventManager.instance.publish("someName", randomColor);
and then in your Triangle:
data.EventManager.instance.subscribe("someName", handleColorChange);
private function handleColorChange(color:Number):void {
// implementation here
}
You can even pass the ColorChangeEvent instead of just the color.
data.EventManager.instance.publish(ColorChangeEvent.CHANGE, new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor);
And then
data.EventManager.instance.subscribe(ColorChangeEvent.CHANGE, handleColorChange);
private function handleColorChange(colorChangeEvent:ColorChangeEvent):void {
// implement here
}
I removed a lot of code that is specific to my projects, so I am not 100% it is usable exactly as-is. But, you should be able to modify it to get it working correctly. If not, let me know and I can try to work it out with you.
This class handles additional things that I will not go into, though you are free to explore. Be aware, however, that anything that subscribes for event notification has a strong reference by the EventManager. That means that if you want to destroy something for garbage collection, you need to call EventManager.instance.cancel(ColorChangeEvent.CHANGE, handleColorChange) before the Triangle instances can be collected.
package data {
import flash.utils.*;
public class EventManager extends Object {
private var _subscribers:Dictionary;
private var _calls:Dictionary;
private var _feeds:Dictionary;
private var _requests:Dictionary;
private var _notify:Dictionary;
private var _services:Dictionary;
private static var __instance:EventManager;
public function EventManager() {
if (__instance) {
trace("EventManager is a Singleton class which should only be accessed via getInstance()");
}
_feeds = new Dictionary(true);
_subscribers = new Dictionary(true);
_requests = new Dictionary(true);
_services = new Dictionary(true);
_notify = new Dictionary(true);
}
public function getFeedData($name:String) {
if (_feeds[$name]) {
return _feeds[$name];
}
return undefined;
}
public function unpublish($name:String) {
var _post:* = _feeds[$name];
delete _feeds[$name];
return _post;
}
public function cancel($name:String, $subscriberFunc:Function, ...args): void {
var _cnt:Number;
var _subscriberArray:Array;
if (_subscribers[$name]) {
for (_cnt = 0; _cnt < _subscribers[$name].length; _cnt++) {
if (_subscribers[$name][_cnt] == $subscriberFunc) {
_subscribers[$name].splice(_cnt, 1);
}
}
}
if (_requests[$name]) {
_subscriberArray = _requests[$name];
_cnt = _subscriberArray.length;
while (_cnt > 0) {
if (_subscriberArray[_cnt] == $subscriberFunc) {
_subscriberArray.splice(_cnt, 1);
}
_cnt--;
}
}
}
public function subscribe($name:String, $subscriber:Function, ...args): void {
var _funcArray:Array;
var _func:Function;
if (_feeds[$name]) {
$subscriber(_feeds[$name]);
}
if (! _subscribers[$name]) {
_subscribers[$name] = new Array();
}
_subscribers[$name].push($subscriber);
if (_notify[$name]) {
_funcArray = _notify[$name];
for each (_func in _funcArray) {
_func();
}
delete _notify[$name];
}
}
public function request($name:String, $feedFunction:Function): void {
var _requestArray:Array;
var _request:Function;
if (! _feeds[$name]) {
if (! _requests[$name]) {
_requests[$name] = new Array();
}
_requests[$name].push($feedFunction);
} else {
$feedFunction(_feeds[$name]);
}
if (_notify[$name]) {
_requestArray = _notify[$name];
for each (_request in _requestArray) {
_request();
}
delete _notify[$name];
}
}
public function publish($name:String, $data:*, $args:Object = null): void {
var _subscriberArray:Array;
var _func:Function;
var cnt:Number = 0;
_feeds[$name] = $data;
if (_subscribers[$name] != undefined) {
_subscriberArray = _subscribers[$name].slice();
_cnt = 0;
while (_cnt < _subscriberArray.length) {
_func = _subscriberArray[_cnt] as Function;
if ($args) {
_func($data, $args);
}else {
_func($data);
}
_cnt++;
}
}
if (_requests[$name]) {
_subscriberArray = _requests[$name].slice();
delete _requests[$name];
_cnt = 0;
while (_cnt < _subscriberArray.length) {
if (_subscriberArray[_cnt] != null) {
_subscriberArray[_cnt]($data);
}
_cnt++;
}
}
}
public function notify($name:String, $subscriber:Function): void {
if (_requests[$name] || _subscribers[$name]) {
$subscriber();
}else {
if (! _notify[$name]) {
_notify[$name] = new Array();
}
_notify[$name].push($subscriber);
}
}
public static function getInstance(): EventManager {
if (! __instance) {
__instance = new EventManager();
}
return __instance;
}
public static function get instance(): EventManager {
return getInstance();
}
}
}
I got this to work by creating a singleton: EventDispatchSingleton that extends EventDispatcher. It's basically an empty singleton that provides the dispatchEvent and add/removeEventListener methods (these are automatically provided by extending EventDispatcher).
Anywhere I want to dispatch an event I import EventDispatchSingleton and then call EventDispatchSingleton.instance.dispatchEvent(<someEvent>);.
Then, wherever I want to listen to that event, I just import EventDispatchSingleton and call EventDispatchSingleton.instance.addEventListener(eventName, callback);
You should look into event bubbling, specificly I think you will find the Capturing phase of the event propagation useful. Take a read of Event propagation from Adobe LiveDocs. It's in the Flex docs, but it is about AS3 Events.
Also Senocular has a good post on Flash Event Bubbling.
I'm new to flash in general and have been writing a program with two classes that extend MovieClip (Stems and Star).
I need to create a new Stems object as a child of the scene when the user stops dragging a Star object, but do not know how to reference the scene from within the Star class's code.
I've tried passing the scene into the constructor of the Star and doing sometihng like:
this.scene.addChild (new Stems ());
But apparently that's not how to do it... Below is the code for Stems and Stars, any advice would be appreciated greatly.
package {
import flash.display.MovieClip;
import flash.events.*;
import flash.utils.Timer;
public class Stems extends MovieClip {
public const centreX=1026/2;
public const centreY=600/2;
public var isFlowing:Boolean;
public var flowerType:Number;
public const outerLimit=210;
public const innerLimit=100;
public function Stems(fType:Number) {
this.isFlowing=false;
this.scaleX=this.scaleY= .0007* distanceFromCentre(this.x, this.y);
this.setXY();
trace(distanceFromCentre(this.x, this.y));
if (fType==2) {
gotoAndStop("Aplant");
}
}
public function distanceFromCentre(X:Number, Y:Number):int {
return (Math.sqrt((X-centreX)*(X-centreX)+(Y-centreY)*(Y-centreY)));
}
public function rotateAwayFromCentre():void {
var theX:int=centreX-this.x;
var theY:int = (centreY - this.y) * -1;
var angle = Math.atan(theY/theX)/(Math.PI/180);
if (theX<0) {
angle+=180;
}
if (theX>=0&&theY<0) {
angle+=360;
}
this.rotation = ((angle*-1) + 90)+180;
}
public function setXY() {
do {
var tempX=Math.random()*centreX*2;
var tempY=Math.random()*centreY*2;
} while (distanceFromCentre (tempX, tempY)>this.outerLimit ||
distanceFromCentre (tempX, tempY)<this.innerLimit);
this.x=tempX;
this.y=tempY;
rotateAwayFromCentre();
}
public function getFlowerType():Number {
return this.flowerType;
}
}
}
package {
import flash.display.MovieClip;
import flash.events.*;
import flash.utils.Timer;
public class Star extends MovieClip {
public const sWide=1026;
public const sTall=600;
public var startingX:Number;
public var startingY:Number;
public var starColor:Number;
public var flicker:Timer;
public var canUpdatePos:Boolean=true;
public const innerLimit=280;
public function Star(color:Number, basefl:Number, factorial:Number) {
this.setXY();
this.starColor=color;
this.flicker = new Timer (basefl + factorial * (Math.ceil(100* Math.random ())));
this.flicker.addEventListener(TimerEvent.TIMER, this.tick);
this.addEventListener(MouseEvent.MOUSE_OVER, this.hover);
this.addEventListener(MouseEvent.MOUSE_UP, this.drop);
this.addEventListener(MouseEvent.MOUSE_DOWN, this.drag);
this.addChild (new Stems (2));
this.flicker.start();
this.updateAnimation(0, false);
}
public function distanceOK(X:Number, Y:Number):Boolean {
if (Math.sqrt((X-(sWide/2))*(X-(sWide/2))+(Y-(sTall/2))*(Y-(sTall/2)))>innerLimit) {
return true;
} else {
return false;
}
}
public function setXY() {
do {
var tempX=this.x=Math.random()*sWide;
var tempY=this.y=Math.random()*sTall;
} while (distanceOK (tempX, tempY)==false);
this.startingX=tempX;
this.startingY=tempY;
}
public function tick(event:TimerEvent) {
if (this.canUpdatePos) {
this.setXY();
}
this.updateAnimation(0, false);
this.updateAnimation(this.starColor, false);
}
public function updateAnimation(color:Number, bright:Boolean) {
var brightStr:String;
if (bright) {
brightStr="bright";
} else {
brightStr="low";
}
switch (color) {
case 0 :
this.gotoAndStop("none");
break;
case 1 :
this.gotoAndStop("N" + brightStr);
break;
case 2 :
this.gotoAndStop("A" + brightStr);
break;
case 3 :
this.gotoAndStop("F" + brightStr);
break;
case 4 :
this.gotoAndStop("E" + brightStr);
break;
case 5 :
this.gotoAndStop("S" + brightStr);
break;
}
}
public function hover(event:MouseEvent):void {
this.updateAnimation(this.starColor, true);
this.canUpdatePos=false;
}
public function drop(event:MouseEvent):void {
this.stopDrag();
this.x=this.startingX;
this.y=this.startingY;
this.updateAnimation(0, false);
this.canUpdatePos=true;
}
public function drag(event:MouseEvent):void {
this.startDrag(false);
this.canUpdatePos=false;
}
}
}
The fastest way would be to use the parent variable which references the DisplayObject parent.
var stem:Stems = new Stems(2);
stem.x = x; //optional: set stem coordinates to that of Star
stem.y = y;
parent.addChild(stem);
If you want to add the Stems object to the stage every time a star-drag action stops you need to put the above code inside your drop function.