ActionScript 3.0 Objects Null on Stage - actionscript-3

I'm creating a game where the user bakes a cake. If the user drags something (for example a jug of water) onto the next object (e.g saucepan) it should disappear from stage. The section of code in question is:
function mouseDownHandler(event:MouseEvent):void {
event.currentTarget.startDrag(true);
}
function mouseUpHandler(event:MouseEvent):void{
var obj = event.currentTarget;
var target = obj.dropTarget;
if (target != null){
test_match(target, obj);
}
obj.stopDrag();
trace(dropTarget);
}
function test_match(target, obj){
if (target == saucePan && obj == jug)
{
removeChild(obj);
}
}
The trace inside the mouseUpHandler function shows up "null" whenever I drop the jug on an object on the stage, hense why I don't think the code executes and removes the jug from stage.

obj.dropTarget vs. dropTarget
These are two different things.

Related

AS3 - How do you call previous currentTarget from within a different event?

I have a dropdown menu that lets you select an item to be placed on the stage. The item is drag and droppable so I use event.currentTarget.startDrag(); to start the drag. Ok, everything works fine so far.
However, I also need to be able to rotate the item while it is being dragged (using the spacebar).
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
function myKeyDown(e:KeyboardEvent):void{
if (e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
WHATGOESHERE?.gotoAndStop(rotate);
}
If I hardcode in an instance name of an object everything works fine - so the rotate function is working properly. The problem is, how can I reference event.currentTarget from the startDrag function while inside of the keyDown event?
My first thought was to set event.currentTarget to a variable and then calling the variable from within the keyDown event. However, targetHold = event.currentTarget; does not seem to record the instance name of the object being clicked...
public var targetHold:Object = new Object;
function ClickToDrag(event:MouseEvent):void {
event.currentTarget.startDrag();
targetHold = event.currentTarget;
trace ("targetHold " + targetHold);
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
function myKeyDown(e:KeyboardEvent):void{
if (e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
targetHold.gotoAndStop(rotate); //does not work
}
}
function ReleaseToDrop(event:MouseEvent):void {
event.currentTarget.stopDrag();
}
As you click the object, it should have focus. If you register the listener for the KeyboardEvent on the object and not on the stage, it will be .currentTarget.
Here's an example of what I have in mind. Right after starting the drag, add the listener to the same object instead of the stage.
event.currentTarget.startDrag();
event.currentTarget.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
The proper way of doing this would be to define all the functionality in a class. Within a self contained class, you would not need any .currentTarget.
Here is how I would do this: (well, actually I'd follow #null's advice and encapsulate it in a sub class that all your dragable objects would extend, but that is a little broad so this will do)
public var targetHold:MovieClip; //don't make a new object, just create the empty var
public function YourConstructor(){
//your other constructor code
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown); //don't add the listener in the click function
}
private function clickToDrag(event:MouseEvent):void {
if(targetHold) ReleaseToDrop(null); //safeguard in case flash lost the focus during the mouse up
targetHold = event.currentTarget as MovieClip; //assign the current target. Might as well cast it as MovieClip and get code completion benefits
targetHold.startDrag();
trace ("targetHold " + targetHold);
}
private function myKeyDown(e:KeyboardEvent):void{
//check if target hold exists
if (targetHold != null && e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
targetHold.gotoAndStop(rotate);
}
}
private function ReleaseToDrop(event:MouseEvent):void {
if(targetHold) targetHold.stopDrag();
targetHold = null;
}

Dragging movie clips in Action Script 3

Hi so recently I have been attempting to Drag a movie clip in AS3 but I'm having some trouble picking up with the hit tests anyone got any ideas? Just to clarify, the issue is that when the movieclips hit the drag test object, they're not executing the gotoframe() function.
initDrag() adds action listeners:
MOUSE_DOWN on the object
MOUSE_UP on the stage so it doesn’t matter if you are off the object
endDrag() removes the action listeners; call this (for each object) before you go to another frame
startADrag()create a rectangle within which the object can be dragged (in this case the stage)
call startDrag() on the object
stopADrag() call stopDrag() on the object from currentObject (but only if currentObject is not null).
var currentObject:MovieClip = null;
initDrag(block1);
initDrag(block2);
initDrag(block3);
initDrag(block4);
function initDrag(obj:MovieClip )
{
obj.addEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.addEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function endDrag(obj:MovieClip )
{
obj.removeEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.removeEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function startADrag(e:MouseEvent):void
{
currentObject = (MovieClip)(e.target);
var rect:Rectangle = new Rectangle(0,0,stage.stageWidth - currentObject.width,stage.stageHeight - currentObject.height + 100);
currentObject.startDrag(false,rect);
}
function stopADrag(e:MouseEvent):void
{
if (currentObject != null)
{
currentObject.stopDrag();
}
}
if(block1.hitTestObject(dragtest)){
gotoAndStop("lose");
}
if(block2.hitTestObject(dragtest)){
gotoAndStop(27);
}
if(block3.hitTestObject( dragtest)){
gotoAndStop("lose");
}
if(block4.hitTestObject( dragtest)){
gotoAndStop("lose");
}
thanks for any advice or answers.
The following code should work as expected. The problem is, as i already stated in my comment, that your calls to hitTestObject(obj) only get executed once, at the very beginning of your application. What you need to do though is to check it constantly.
Think about it, if your calls to hitTestObject-calls only get executed once at the beginning, when you didn't even have a chance to drag one of your objects, it will always return false, right? Because your objects are still in their initial position (outside of the dragtest objecti must assume).
With an event listener for Event.ENTER_FRAME you check it once per frame instead. So even if all the results for hitTestObject are false, it will check them all again on the next frame (if you are currently dragging, controlled through a simple boolean called dragging).
var currentObject:MovieClip = null;
var dragging:Boolean = false;
initDrag(block1);
initDrag(block2);
initDrag(block3);
initDrag(block4);
addEventListener(Event.ENTER_FRAME, checkForHit);
function checkForHit(e:Event):void{
if(dragging){
if(block1.hitTestObject(dragtest)){
gotoAndStop("lose");
}
if(block2.hitTestObject(dragtest)){
gotoAndStop(27);
}
if(block3.hitTestObject( dragtest)){
gotoAndStop("lose");
}
if(block4.hitTestObject( dragtest)){
gotoAndStop("lose");
}
}
}
function initDrag(obj:MovieClip )
{
obj.addEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.addEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function endDrag(obj:MovieClip )
{
obj.removeEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.removeEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function startADrag(e:MouseEvent):void
{
currentObject = (MovieClip)(e.target);
var rect:Rectangle = new Rectangle(0,0,stage.stageWidth - currentObject.width,stage.stageHeight - currentObject.height + 100);
currentObject.startDrag(false,rect);
dragging = true;
}
function stopADrag(e:MouseEvent):void
{
if (currentObject != null)
{
currentObject.stopDrag();
dragging = false;
}
}

Requesting value of property of a null object

I m currently converting my old game project which is in AS2 into AS3 by myself. And there was a problem. In the AS2 version of my game I used to check for a movieclip's sub movieclip's property and use it for some calculations, using
if (mc1.mc2.prop == undefined){
//do something
}
and during somepoint of the game the mc1 or mc2 is removed.
but in AS3 this no longer works because I cannot access the prop after mc1 or mc2 is removed.
Anyhelp? thanks.
It's hard to give a more concise answer without knowing how your game actually works, but this function will allow you to check if a hierarchical value exists on an object:
function hasProp(target:Object, prop:String):Boolean
{
var tests:Array = prop.split('.');
var test:* = target;
for each(var p:String in tests)
{
if(test.hasOwnProperty(p))
{
test = test[p];
}
else return false;
}
return true;
}
Used like:
if( hasProp(mc1, "mc2.prop") )
{
// Property exists.
}

Drag and Drop error 1010 part of the time?

I have a working drag and drop game, but it's not perfect. All my movieclips drag and drop to their targets when you are exactly lined up with the target.
However, if you let go of the mouse up when dragging the mc outside of the target zones, it will sometimes, but not always, throw the 1010 term undefined error and will not snap the mc back to its original start x/y coordinates (it just leaves the mc in the spot it was during mouse up). I ran the debugger and it deals with this line in my drop function:
if (event.currentTarget.dropTarget != null && MovieClip(event.currentTarget.dropTarget.parent).allowed.indexOf(event.currentTarget) >= 0){
FYI, allowed is a set of target arrays since I wanted "zones" for targets and not specific targets for some of the movieclips.
Any ideas?
Updated Code Below:
if (event.currentTarget.dropTarget != null) {
var mc:MovieClip=event.currentTarget.dropTarget as MovieClip;
if (mc==null) { // typecast fails. Say there's a Sprite below
reply_txt.textColor = 0xEE1212
reply_txt.text = "Oops! Try Again!";
event.currentTarget.alpha = 1;
event.currentTarget.x = startX;
event.currentTarget.y = startY;
return; // nothing to do here
}
mc=mc.parent;
if (mc && mc.allowed) {
// this MC has "allowed" property not "undefined" - we're in the grid
// so now we can check indexOf() safely
if (mc.allowed.indexOf(event.currentTarget)>=0){
reply_txt.textColor = 0x33BC10
reply_txt.text = "Good Job!";
event.currentTarget.alpha = 1;
event.currentTarget.removeEventListener(MouseEvent.MOUSE_DOWN, pickUp);
event.currentTarget.removeEventListener(MouseEvent.MOUSE_UP, dropIt);
event.currentTarget.buttonMode = false;
event.currentTarget.x = MovieClip(event.currentTarget.dropTarget.parent).x;
event.currentTarget.y = MovieClip(event.currentTarget.dropTarget.parent).y;
stored.push(event.currentTarget);
startXarray.push(startX);
startYarray.push(startY);
counter++;
}
}
}
Yes, when you stopDrag an object, it checks what kind of a DisplayObject is below the cursor, and that one is returned as dropTarget property in your event. So, if your object is dropped onto another MC that does not have allowed property, your 1010 error is thrown. You need to check this situation in a nested if statement like this:
if (event.currentTarget.dropTarget != null) {
var mc:MovieClip=event.currentTarget.dropTarget as MovieClip;
if (mc==null) { // typecast fails. Say there's a Sprite below
returnThisBack();
return; // nothing to do here
}
mc=mc.parent;
if (mc && mc.allowed) {
// this MC has "allowed" property not "undefined" - we're in the grid
// so now we can check indexOf() safely
if (mc.allowed.indexOf(event.currentTarget)>=0) snapThisToGrid();
} else returnThisBack();
} else returnThisBack();

ActionScript 3: how do you compare if the object where you clicked on is that type of object

I have a red box called mc1_mc and every time when you drag on it you get a new little blue box added to the stage. Yhe idea is that you can drag those blue boxes too. however I dont know how to detect them.
this is the code:
var newBlok:Boolean;
var blokIndex:int = 0;
var blokje:blok;
var huidigBlok:DisplayObject;
var prullenBak:DisplayObject = getChildByName("groen_mc");
stage.addEventListener(MouseEvent.MOUSE_DOWN,pickUp);
stage.addEventListener(MouseEvent.MOUSE_UP,dropIt);
function pickUp(event:MouseEvent):void
{
trace(event.currentTarget);
trace(event.target);
trace(event.target.name);
if (event.target.name == "mc1_mc")
{
trace("hoi");
blokje = new blok;
blokje.name = "blokje" + blokIndex;
blokIndex++;
addChild(blokje);
blokje.startDrag(true);
}
if (event.target.type == blok)
{
trace("blok");
}
//blokjeVast = blokje;
}
function dropIt(event:MouseEvent):void
{
event.target.stopDrag();
}
he wont ever come to the line: trace("blok");
even when the object i clicked on gives:
[object Stage]
[object blok]
blokje0
for the lines.
trace(event.currentTarget);
trace(event.target);
trace(event.target.name);
does anyone know how to do check if its a object of type "blok"?
To check whether an object is of a certain type, you can use the is operator.
So, you should change this:
if (event.target.type == blok)
{
trace("blok");
}
To this:
if(event.target is blok)
{
trace("blok");
}
And if the target is of type blok, you should see the trace.
There's one caveat here. ìs tells you if an object is of a certain type. Since a class can extend other classes and implement interfaces, you should check for the most derived or specific one first (if you want to distinguish between, say, Sprite and MovieClip).
var mc:MovieClip = new MovieClip();
if(mc is MovieClip) {
trace("is MovieClip");
} else if(mc is Sprite) {
trace("is Sprite");
}
// even if mc is a MovieClip, your code will never get in the else block
if(mc is Sprite) {
trace("is Sprite");
} else if(mc is MovieClip) {
trace("is MovieClip");
}