action script 3 - "Error #1006: startDrag is not a function" - actionscript-3

I was writing code for dragging mechanism which invokes to wait for small period of time before starting the drag operation.
But I am getting this error message in the mouseDownHandler() function.
TypeError: Error #1006: startDrag is not a function.
at Function/<anonymous>()[C:\blahblah_8216\bobo\flex2\src\ui\map\WorldMap.as:105]
at Function/http://adobe.com/AS3/2006/builtin::apply()
at SetIntervalTimer/onTimer()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
I have found the solution by slightly changing the code by declaring a clone variable _me of this
private var _me:WorldMap;
Instantiate it in the constructor
public function WorldMap(){
_me = this;
}
Replacing this with _me in below code works without error
Code
public var dragInProgress:Boolean = false;
private var dragTime:int = 100;
private var dragInProgressInt:int;
private function mouseDownHandler(event:MouseEvent):void {
trace(this.name," mouse down ",getTimer());
dragInProgressInt = setTimeout(function():void
{
dragInProgress = true;
this.startDrag(false,new Rectangle(Config.GAME_SCREEN_WIDTH - Config.FULL_GAME_SCREEN_WIDTH,
Config.GAME_SCREEN_HEIGHT - Config.FULL_GAME_SCREEN_HEIGHT,
Config.FULL_GAME_SCREEN_WIDTH - Config.GAME_SCREEN_WIDTH,
Config.FULL_GAME_SCREEN_HEIGHT - Config.GAME_SCREEN_HEIGHT));
}, dragTime);
}
private function mouseUpHandler(event:MouseEvent):void {
clearTimeout(dragInProgressInt);
setTimeout(function():void
{
dragInProgress = false;
this.stopDrag();
}, 1);
Can anyone tell me why this is happening?

The reason startDrag is failing when you use 'this' is because you're calling it from within an 'anonymous function', which means the 'this' keyword will no longer reference the main class and instead references the function definition. An 'anonymous function' is basically a function that isn't bound to a specific class, read more here.
An alternate way to accomplish what you'd like to do is demonstrated below:
public var dragInProgress:Boolean = false;
private var dragTime:int = 100;
private var dragInProgressInt:int;
private function mouseDownHandler(event:MouseEvent):void {
trace(this.name," mouse down ",getTimer());
dragInProgressInt = setTimeout(mouseDownFinished, dragTime);
}
private function mouseUpHandler(event:MouseEvent):void {
clearTimeout(dragInProgressInt);
setTimeout(mouseUpFinished, 1);
}
private function mouseDownFinished():void
{
dragInProgress = true;
this.startDrag(false,new Rectangle(Config.GAME_SCREEN_WIDTH - Config.FULL_GAME_SCREEN_WIDTH,
Config.GAME_SCREEN_HEIGHT - Config.FULL_GAME_SCREEN_HEIGHT,
Config.FULL_GAME_SCREEN_WIDTH - Config.GAME_SCREEN_WIDTH,
Config.FULL_GAME_SCREEN_HEIGHT - Config.GAME_SCREEN_HEIGHT));
}
private function mouseUpFinished():void
{
dragInProgress = false;
this.stopDrag();
}
Notice the functions are now defined within the main class with 'setTimeout' passing a reference using the function name. Using 'this' within these functions will now reference the main class correctly.

Related

TypeError: Error #1009: Cannot access a property or method of a null object reference. at ColoringScreen/freezeColor()

hi I am once again asking for pointers on what I did wrong here the code works fine but when I test to play it the output message has this:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at ColoringScreen/freezeColor()
here's the code
public class ColoringScreen extends MovieClip {
var bitmapDt:BitmapData = new BitmapData (176.8, 176.8);
var ct:ColorTransform = new ColorTransform();
var hexaColor:*;
var myObject:Object;
public function ColoringScreen() {
// constructor code
chBackBtn.addEventListener(MouseEvent.CLICK, backtoMainScreen)
bitmapDt.draw(ColorPickerMc.spectrum);
ColorPickerMc.spectrum.addEventListener(MouseEvent.CLICK, freezeColor);
addEvents(oneMc, twoMc, threeMc, fourMc, fiveMc, sixMc, sevenMc, eightMc, nineMc, tenMc, elevenMc, twelveMc, thirteenMc, fourteenMc, fifteenMc, sixteenMc, seventeenMc, eighteenMc, ninteenMc, twentyMc, twentyoneMc, twentytwoMc, twentythreeMc, twentyfourMc, twentyfiveMc);
}
private function addEvents(...objects){
for(var i:Number=0; i<objects.lenght; i++){
objects[i].addEventListener(MouseEvent.CLICK, selectObject);
}
}
private function selectObject(e:MouseEvent){
myObject = e.target;
ColorPickerMc.spectrum.addEventListener(MouseEvent.MOUSE_MOVE, updateColor);
}
private function backtoMainScreen(e:MouseEvent) {
MovieClip(stage.getChildAt(0)).gotoAndStop("Intro");
}
private function updateColor(e:MouseEvent){
hexaColor = "0x"+bitmapDt.getPixel(ColorPickerMc.spectrum.mouseX, ColorPickerMc.spectrum.mouseY).toString(16);
ct.color = hexaColor;
myObject.transform.colorTransform = ct;
}
private function freezeColor(e:MouseEvent){
myObject.transform.colorTransform = ct;
ColorPickerMc.spectrum.removeEventListener(MouseEvent.MOUSE_MOVE, updateColor);
}
}
I know it's been asked a million times but I'm still scratching my head as to what property or method or what instance am I lacking cuz I checked it and all seem to be in place I named my instances and movie clip symbols all of it are in the same keyframe why does my freezeColor not work anymore? any help would be much appreciated

Actionscript 3 Call to a possibly undefined method

Here is the problem, the object is moved together with the clicked object. I want it to be moveable following the mouse pointer, but let the clicked object stays. so when an object is clicked, there will be 2 objects in the stage(the static and moving one).
I think I've figured it out by adding a new object to be moved. in function onClickHero I've tried movingHero = new heroes but it says "call to a possibly undefined method heroes". My question is there any other way how to make another clone of the clicked object since I made it in array? And why does movingHero = new heroes doesn't work?
I'm still amateur at classes. Sorry if it's messed up. Thanks for helping.
package {
import flash.display.MovieClip
import flash.events.MouseEvent
import flash.events.Event
import flash.display.Sprite
public class Hero {
private var heroesArray:Array;
private var heroContainer:Sprite = new Sprite;
private var hero1:MovieClip = new Hero1();
private var hero2:MovieClip = new Hero2();
private var moveHero:Boolean = false;
private var movingHero:MovieClip;
private var _money:Money = new Money();
private var _main:Main;
public function Hero(main:Main)
{ _main = main;
heroesArray = [hero1,hero2];
heroesArray.forEach(addHero);
}
public function addHero(heroes:MovieClip,index:int,array:Array):void
{
heroes.addEventListener(Event.ENTER_FRAME, playerMoving);
heroes.addEventListener(MouseEvent.CLICK, chooseHero);
}
public function playerMoving(e:Event):void
{
if (moveHero == true)
{
movingHero.x = _main.mouseX;
movingHero.y = _main.mouseY;
}
}
public function chooseHero(e:MouseEvent):void
{
var heroClicked:MovieClip = e.currentTarget as MovieClip;
var cost:int = _main._money.money ;
if(cost >= 10 && moveHero == false)
{
_main._money.money -= 10;
_main._money.addText(_main);
onClickHero(heroClicked);
moveHero = true;
}
}
public function onClickHero(heroes:MovieClip):void
{
movingHero = heroes;
heroContainer.addChild(movingHero);
}
public function displayHero(stage:Object):void
{
stage.addChild(heroContainer);
for (var i:int = 0; i<2;i++)
{
stage.addChild(heroesArray[i]);
heroesArray[i].x = 37;
heroesArray[i].y = 80+i*70;
heroesArray[i].width=60;
heroesArray[i].height=55;
heroesArray[i].buttonMode = true;
}
}
}
}
EDIT: I've tried to make movingHero = new Hero1(); but since I don't know which hero will be clicked so I can't just use Hero1 from library. and If I use movingHero = heroClicked I only get the value of hero1 which is a var from Hero1 movieclip. So, is there any way to call the movie clip from library the same as which hero was clicked in stage?
You seemingly want to clone an object while not knowing its type. If that object also containg game logic, it's not the best idea to say spawn new heroes of either type, this might make a mess of your code. But if not, you can get the exact class of the object given, and make an object of that class via the following code:
public function onClickHero(heroes:MovieClip):void
{
if (!heroes) {
trace('heroes is null!');
return;
}
var heroClass:Class = getDefinitionByName(getQualifiedClassName(heroes)) as Class;
movingHero = new heroClass(); // instantiate that class
heroContainer.addChild(movingHero);
// movingHero.startDrag(); if needed
}
Don't forget to clean up the movingHero once it's no longer needed.

actionscript 3 Timer class and callback problems

I have a timer class in actionscript that looks like this:
public class AGTimer {
public var myTimer:Timer ;
public var done:Boolean = false;
public var timer_disable:Boolean = false;
public var started:Boolean = false;
public function AGTimer(num:Number = 0) {
this.timer_disable = false;
if (num != 0 ) timerStart(num);
// constructor code
}
public function timerStart(num:Number):void {
myTimer = new Timer(num * 1000, 1);
myTimer.addEventListener(TimerEvent.TIMER, runOnce);
myTimer.start();
started = true;
done = false;
}
public function runOnce(e:TimerEvent):void {
done = true;
}
public function timerDone():Boolean {
if (done && ! timer_disable) return true;
else if (!started ) return true;
else return false;
}
}
I have several of these in an array. I reference them with their index number. sometimes I start a timer and let it go, then before I have a chance to check it, I delete it by calling 'new AGTimer()' and creating a new one. Could it happen that the callback from the actionscript Timer object is still called somehow after the timer itself is deleted? What would I do about it if it did happen? I am trying to find a bug and am considering this sort of problem. What kind of error would I see?
Yes, a timer will continue to run callbacks even if it is not referenced somewhere. You have to remove event listener for the timer for it in order to remove it.
Basically something like this:
private function destroyTimer():void {
if(myTimer) {
myTimer.removeEventListener(runOnce);
myTimer.stop();
myTimer = null;
}
}

Passing arguments into mouseEvent function

This seems simple in other languages, but I don't understand the error. I have 7 buttons that I would like to each take my gallery movieclip to a certain frame when you click on them.
Error: 1067: Implicit coercion of a value of type int to an unrelated type flash.events:MouseEvent.
Error: 1136: Incorrect number of arguments. Expected 2.
Error: 1067: Implicit coercion of a value of type void to an unrelated type Function.
Any help?
function gotoImage(event:MouseEvent, frameParam:int):void
{
MovieClip(this.root).gallery.gotoAndStop(frameParam);
}
t1.addEventListener(MouseEvent.CLICK, gotoImage(1));
t2.addEventListener(MouseEvent.CLICK, gotoImage(2));
t3.addEventListener(MouseEvent.CLICK, gotoImage(3));
t4.addEventListener(MouseEvent.CLICK, gotoImage(4));
t5.addEventListener(MouseEvent.CLICK, gotoImage(5));
t6.addEventListener(MouseEvent.CLICK, gotoImage(6));
t7.addEventListener(MouseEvent.CLICK, gotoImage(7));
You've got two things off with your code:
First, in ActionScript, event handlers always have the same signature:
function someHandler(e:Event):void { .. }
Sometimes the Event argument is a more specific subclass of Event, such as MouseEvent, but there is always just one argument.
The addEventListener method needs a function itself, not the result of invoking a function.
// Here's a function:
function multiply(i1:int, i2:int):int { return i1 * i2; }
// Here's assigning the result of **invoking** a function:
var result:int = multiply(2,3);
// Here's assigning a **function itself** to a variable:
var f:Function = multiply;
// You can invoke the function via the variable f in two different ways:
var result1 = f(2,3);
var result2 = f.apply(null, [2,3]);
So, you'll need to change your code to follow the above to points. You'll have to associate the buttons with jumping to a specific frame one of two ways:
Simple but repetitive: Use a separate handler for each button, with the frame hard coded into each handler.
1a. Named functions (most verbose):
function onT1Click(e:MouseEvent):void {
MovieClip(this.root).gallery.gotoAndStop(1);
}
t1.addEventListener(MouseEvent.CLICK, onT1Click);
// etc. etc.
1b. Anonymous functions:
t1.addEventListener(MouseEvent.CLICK, function(e:Event):void {
MovieClip(this.root).gallery.gotoAndStop(1);
});
// etc. etc.
More elegant: Use the same handler, and store the association between button and frame elsewhere, such as in a Dictionary. If you stick with your naming convention you could even fill the Dictionary in a for loop getting the buttons by name:
var buttonToFrame:Dictionary = new Dictionary();
for(var i:int = 1; i < 8; i++) {
var btn:Button = this["t" + i.toString()];
buttonToFrame[btn] = i;
btn.addEventListener(MouseEvent.CLICK, onClick);
}
function onClick(e:MouseEvent):void {
var btn:Button = Button(e.currentTarget);
var frameNum:int = buttonToFrame[btn];
MovieClip(this.root).gallery.gotoAndStop(frameNum);
}
Just change this
t1.addEventListener(MouseEvent.CLICK, function(me:MouseEvent):void{ gotoImage(me, 1)});
t2.addEventListener(MouseEvent.CLICK, function(me:MouseEvent):void{ gotoImage(me, 2)});
and so on...
This is possible with a roundabout approach. For the event handler, use a function that returns a nested anonymous function.
private var textFieldA:TextField = new TextField;
private var textFieldB:TextField = new TextField;
public function setParameterizedTextWhenTextFieldsAreClicked ():void {
addChild(textFieldA);
textFieldA.text = 'Text field A';
textFieldA.addEventListener(MouseEvent.CLICK, showCustomMessage("One"));
addChild(textFieldB);
textFieldB.text = 'Text field B';
textFieldB.y = 20;
textFieldB.addEventListener(MouseEvent.CLICK, showCustomMessage("Two"));
// NOTE: We must use strongly referenced listeners because weakly referenced
// listeners **will get garbage collected** because we're returning
// an anonymous function, which gets defined in the global namespace and
// thus, the garbage collector does not have anything pointing to it.
}
private function showCustomMessage (message:String):Function {
// NOTE: You can store the following function to a class variable
// to keep it in memory, which would let you use weakly referenced
// listeners when using this as an event handler. Many people
// would find that awkward. I would discourage that.
return function (e:MouseEvent):void {
var textField:TextField = e.target as TextField;
textField.text = message; // "message" argument is available because
// this function's scope is kept in memory.
}
}
Bear in mind, the use of anonymous functions and reliance on function scope being kept in memory seem to present garbage collection complications.

Why can't my class see an array on the timeline?

I have a class that controls an enemy. From within that class, it checks for collisions with an array on the main timeline. I've done it this way before and it works fine, so I have no idea what I've done wrong this time. It keeps giving me an
ReferenceError: Error #1069: Property
bulletArray not found on
flash.display.Stage and there is no
default value.
error from within the enemy class.
Here's my code (shortened to remove the unimportant parts):
On timeline:
var bulletArray:Array = new Array();
function shoot(e:TimerEvent)
{
var bullet:MovieClip = new Bullet(player.rotation);
bullet.x = player.x;
bullet.y = player.y;
bulletArray.push(bullet);
stage.addChild(bullet);
}
In class:
private var thisParent:*;
thisParent=event.currentTarget.parent;
private function updateBeingShot()
{
for (var i=0; i<thisParent.bulletArray.length; i++) {
if (this.hitTestObject(thisParent.bulletArray[i]) && thisParent.bulletArray[i] != null) {
health--;
thisParent.bulletArray[i].removeEventListener(Event.ENTER_FRAME, thisParent.bulletArray[i].enterFrameHandler);
thisParent.removeChild(thisParent.bulletArray[i]);
thisParent.bulletArray.splice(i,1);
}
}
Any help would be greatly appreciated! Thanks.
My guess is that event.currentTarget is the instance where you declared the bulletArray variable. Using event.currentTarget.parent will refer to stage outside your scope. I donĀ“t know how you declare the listeners. Try using event.target instead of event.currentTarget and see if you get the same error.
My advice is that you put all your code in a class.
If you are going to do it this way you need to pass in a reference to the timeline.
private var _timeline:Object;
// constructor
public function YourClass(timeline:Object) {
_timeline = timeline;
}
private function updateBeginShot() {
// ..
trace(_timeline.bulletArray); // outputs [array contents]
// ..
}