Pairing a draggable object to a target object in AS3

142 views Asked by At

I'm currently stuck with my approach below. I'm not entirely sure if using "hitTestObject" method is appropriate in pairing the pieces to their respective place. I was able to at least match the chess piece to their respective location (that's the best I can do and I feel i'm doing it wrong) but I'm now stuck in counting how many pieces are actually in their correct places. e.g. when I move the pawn to a different tile, it will still count as one, I also want to avoid duplicate counting, example, If pawn is already in the correct location, it will just count as 1, and if it was moved, then that count will be removed. Only count the pieces that are in the correct tile.

My goal here is to be able to make all the chess pieces draggable and determine if they're in their respective location. If ALL the chess pieces are in their location, it will trace or call a function.

Thank you!

import flash.events.Event;
import flash.display.MovieClip;
import flash.events.MouseEvent;

/* Declaring an X and Y variable to be used as a reset container */ 
var xPos: int, yPos: int;

/* Attaching event listeners for each chess piece */
addListeners(
    king, queen, bishop_1, bishop_2, knight_1, knight_2, rook_1, rook_2,
    pawn_1, pawn_2, pawn_3, pawn_4, pawn_5, pawn_6, pawn_7, pawn_8);


/* Getting the original x and y postion to be used as a reset */
function getPosition(currentTarget: Object): void {
    xPos = currentTarget.x;
    yPos = currentTarget.y;
}

/* Function to get the suffix value of an object. example, I need to get the value 4 from "pawn_4" */
function getLastCharInString($s: String, $pos: Number): String {
    return $s.substr($s.length - $pos, $s.length);
}

/* A simple function that rotates the chess piece */
function lift(object: Object, rot: Number) {
    object.rotation = rot;
}

function dragObject(e: MouseEvent): void {
    getPosition(e.currentTarget);
    lift(e.currentTarget, -10);

    getChildByName(e.currentTarget.name + "_hs").alpha = 1;


    e.currentTarget.startDrag();
}

/* This variable is supposed to hold the value of each piece that is correctly placed in each tile. 
The total score should be 16 as there are 16 pieces. Only correcly placed piece should be added in the total score. */
var counter:int;

function stopDragObject(e: MouseEvent): void {


    var curretTarget = e.currentTarget.name;

    lift(e.currentTarget, 0);

         /* Hide active hotspots  */
    getChildByName(e.currentTarget.name + "_hs").alpha = 0;

    var multiplePieceSufix = Number(getLastCharInString(curretTarget, 1));

    if (multiplePieceSufix >= 1) {


        /* Boolean variables that checks whether the current piece is active*/
        var isPawn: Boolean = false,
            isBishop: Boolean = false,
            isKnight: Boolean = false,
            isRook: Boolean = false,
            currentTargeName;

        var widthDiff = getChildByName(e.currentTarget.name + "_hs").width - getChildByName(e.currentTarget.name).width / 2;
        var heightDiff = getChildByName(e.currentTarget.name + "_hs").height - getChildByName(e.currentTarget.name).height / 2;

        if (curretTarget.substr(0, 4) == "pawn") {
            isPawn = true;
        } else if (curretTarget.substr(0, 6) == "bishop") {
            isBishop = true;
        } else if (curretTarget.substr(0, 6) == "knight") {
            isKnight = true;
        } else if (curretTarget.substr(0, 4) == "rook") {
            isRook = true;
        }


        if (isPawn == true) {

            /* there are total of 8 pieces of pawn */
            for (var w = 1; w < 9; w++) {

                currentTargeName = this["pawn_" + w + "_hs"];

                if (e.target.hitTestObject(currentTargeName)) {

                    /* For some reason the chess pieces are not aligning with their "_hs" version, I already checked their registry point and it seem to be normal.
                     so to fix, I had to manually add some hard coded values to adjust their location. */
                    e.currentTarget.x = currentTargeName.x - 8;
                    e.currentTarget.y = currentTargeName.y + currentTargeName.height;

                }
            }

        } else if (isBishop == true) {

            for (var x = 1; x < 3; x++) {

                currentTargeName = this["bishop_" + x + "_hs"];

                if (e.target.hitTestObject(currentTargeName)) {

                    e.currentTarget.x = currentTargeName.x - 9;
                    e.currentTarget.y = currentTargeName.y + currentTargeName.height - 18;

                }
            }

        } else if (isKnight == true) {

            for (var y = 1; y < 3; y++) {

                currentTargeName = this["knight_" + y + "_hs"];

                if (e.target.hitTestObject(currentTargeName)) {

                    e.currentTarget.x = currentTargeName.x - 8;
                    e.currentTarget.y = currentTargeName.y + currentTargeName.height;

                }
            }

        } else if (isRook == true) {

            for (var z = 1; z < 3; z++) {

                currentTargeName = this["rook_" + z + "_hs"];

                if (e.target.hitTestObject(currentTargeName)) {

                    e.currentTarget.x = currentTargeName.x - 8;
                    e.currentTarget.y = currentTargeName.y + 62;

                }
            }

        }


    } else {


        if (e.target.hitTestObject(getChildByName(e.currentTarget.name + "_hs"))) {

            /* Again, I'm not sure why the pieces are not aligning as intended.
            modX and modY is a holder for the adjustment value. I'm not comfortable
            seeing this approach myself, but I also run out of ideas how to fix it. */ 

            var modX: Number, modY: Number;

            if (e.currentTarget.name == "king") {
                modX = 11;
                modY = 53;
            } else {
                modX = 11;
                modY = 29;
            }

            e.currentTarget.x = getChildByName(e.currentTarget.name + "_hs").x - modX;
            e.currentTarget.y = getChildByName(e.currentTarget.name + "_hs").y + getChildByName(e.currentTarget.name + "_hs").height - modY;

        }

    }

    /* This is supposed to add to the total score or count of how many pieces are placed correctly.
    Thie problem with thi scounter, as it also counts any piece that is places to any "_hs" */
    counter++;

    trace(counter);

    e.currentTarget.stopDrag();
}


function addListeners(...objects): void {
    for (var i: int = 0; i < objects.length; i++) {
        objects[i].addEventListener(MouseEvent.MOUSE_DOWN, dragObject);
        objects[i].addEventListener(MouseEvent.MOUSE_UP, stopDragObject);

        // hide hotspots
        getChildByName( objects[i].name + "_hs" ).alpha = 0;

    }
}

Source: Download the FLA here

--

Updates:

I have added comments in my code to clarify what I'm trying to accomplish.

I'm planning to do board game in flash which has similar function and behaviour to this. User can drag the object to a specified tile and check wether that object belongs there or not.

1

There are 1 answers

1
BadFeelingAboutThis On BEST ANSWER

After reviewing your code, your question is quite broad. I'm going pair it down to what seems to be your main concern - the score / counting correctly moved pieces.

Right now, you do the following every time an object is dragged:

counter++;

This means that the counter will increment no matter where you drag the object, and no matter how times you drag the object. (so even if the piece was already in the correct spot, if you dragged it a second time it will still increment your counter).

What you need to do, is associate a flag with each object to indicate whether it is in the correct location or not, and set that flag to the appropriate value every time that object is done dragging.

Something like this:

 //don't use target, use currentTarget
 if (e.currentTarget.hitTestObject(currentTargeName)) {
      e.currentTarget.correct = true; //since MovieClips are dynamic, you can just make up a property on them and assign a value to it.

      //to fix your alignment:
      e.currentTarget.x = currentTargeName.x + ((currentTargetName.width - e.currentTarget.width) * 0.5);
      e.currentTarget.y = currentTargeName.y + currentTargeName.height;
 }else{
      //if the hit test is false, mark it as NOT correct
      e.currentTarget.correct = false;
 }

Then, later to know the current count, iterate over all the pieces and check their correct value. This would be much easier if all your pieces were in an array.

var allPieces:Array = [king, queen, bishop_1, bishop_2, knight_1, knight_2, rook_1, rook_2,
pawn_1, pawn_2, pawn_3, pawn_4, pawn_5, pawn_6, pawn_7, pawn_8];

function countCorrect():Boolean {
    var ctr:int = 0;
    for(var i:int=0;i<allPieces.length;i++){
        if(allPieces[i].correct) ctr++;
    }
    return ctr;
}

trace(countCorrect() + " of " allPieces.length " are correct");

As an aside, this best way to do this would be with some custom class files. That would however require a complete refactoring of your code.

Also, you probably don't want to use hitTestObject, as even if a piece is mostly over a neighbor, it will still be true as long as 1 pixel of it's bound touch 1 pixel of the tile. Better would be to do a hitTestPoint on the tile, and pass in the center point of the piece (the the middle of the piece has to be touching the tile for it to count).

//a point that is the center of the events current target (the piece)
var point:Point = new Point();
point.x = e.currentTarget.x + (e.currentTarget.width * 0.5);
point.y = e.currentTarget.y - (e.currentTarget.height * 0.5);

if (currentTargetName.hitTestPoint(point)) {