【问题标题】:AS3 shuffling movieclipsAS3 洗牌影片剪辑
【发布时间】:2015-07-30 08:46:44
【问题描述】:

我已经添加了基本目标并为我的拼图应用了拖放功能,现在我在制作洗牌方面遇到了麻烦。如在玩家完成或打开fla后,每次都会在舞台的随机位置开始拼图。我了解使用数组以某种方式进行改组,但我不确定如何实现这一点。我已经将 19 个拼图的实例存储在数组中,但现在我不知道如何处理这个数组。其他教程有点超出我的范围,让我摸不着头脑。

刚开始为 flash 专业人士编写代码,是的,非常感谢任何有关 shuffle 电影剪辑(即拼图片段)的帮助。

这是我的代码,我没有发布整个内容,因为从 P1 到 P19 基本上是复制粘贴:

import flash.events.Event;

stage.addEventListener(Event.ENTER_FRAME, EntFrame)
function EntFrame(e: Event) : void
{

    P1.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
    function fl_ClickToDrag(event:MouseEvent):void
    {
        P1.startDrag();
    }
    stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
    function fl_ReleaseToDrop(event:MouseEvent):void
    {
        P1.stopDrag();
    }
    if (T1.hitTestObject(P1.Tar1))
    {
        P1.x = 313.15;
        P1.y = 242.75;
    }

    P19.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag_19);
    function fl_ClickToDrag_19(event:MouseEvent):void
    {
        P19.startDrag();
    }
    stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop_19);
    function fl_ReleaseToDrop_19(event:MouseEvent):void
    {
        P19.stopDrag();
    }
    if (T19.hitTestObject(P19.Tar19))
    {
        P19.x = 624.35;
        P19.y = 455.60;
    }
}

【问题讨论】:

  • 您的应用程序崩溃了吗?您的代码有大量内存泄漏的可能性,所有这些内联函数都被创建并附加到每个帧的侦听器。

标签: actionscript-3 flash


【解决方案1】:

这是我希望更全面的答案。

首先,抛弃那些内联函数。现在,您创建了一个 ENTER_FRAME 侦听器,并在该函数中定义了内联函数。这意味着每帧滴答声(与您的帧速率相关,而不是与主时间轴相关),这些函数将被再次创建,并且由于您将它们添加为侦听器的处理程序,它们将永远留在内存中。

这是一种编码方式,展示了减少冗余和消除内存泄漏的方法。这假设如下:

  1. 舞台上有 19 个对象,名为 T1 - T19,它们代表了棋子可以去的可能位置。

  2. 舞台上有 19 件作品,名为 P1 - P19,根据作品的正确位置,数字与 T 位置相关。

    //let's create a function to randomize the piece location
    function seedPieces() {
        //create an array consisting of the integers 1 - 19
        var unusedSpaces:Vector.<int> = new Vector.<int>;
        var i:int;
        for (i = 1; i <= 19; i++) {
            //populate that array
            unusedSpaces.push(i);
        }
    
        var curLocation:DisplayObject; //helper var for the loop below
        var curPiece:Sprite; //helper var for the loop below
    
        //loop 19 times (from 1 - 19) - one iteration for each piece
        for (i = 1; i <= 19; i++) {
            curPiece = this["P" + i] as Sprite; //you can get the piece this way, or use an array if you've made one, like `pieces[i];`
            trace(curPiece.name);
            //splice removes and returns the item at the specified index (in this case a random number between 0 and arrays length less 1) - the second parameter is amount of items to remove (just 1 for this case)
            curLocation = this["T" + unusedSpaces.splice(int(Math.random() * unusedSpaces.length), 1)] as DisplayObject; 
            trace("  ",curLocation.name);
            //move the piece to the random location:
            curPiece.x = curLocation.x;
            curPiece.y = curLocation.y;
        }
    }
    
    //NOW, as an aside, you should use a loop to add all your listeners for the sake of sanity - if you have them in an array, loop through that, or use the sloppy way like this:
    for (var i:int = 1; i <= 19; i++) {
        Sprite(this["P" + i]).addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
    }
    
    //create a var to hold any piece that is currently being dragged, so you know which piece to stop drag on later
    var currentDraggingItem:Sprite;
    seedPieces();
    
    
    
    function fl_ClickToDrag(event:MouseEvent):void
    {
    
        //assign this clicked item to the currentDraggingItem var
        currentDraggingItem = event.currentTarget as Sprite;
    
        //bring this one to the front
        currentDraggingItem.parent.addChild(currentDraggingItem);
    
        //you can use this one click handler for all pieces
        //the piece that was actually clicked, is referenced by event.currentTarget
        currentDraggingItem.startDrag();
    
    
        //add the mouse up listener now that the mouse is currently DOWN
        stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
    
        //listen every frame while dragging
        stage.addEventListener(Event.ENTER_FRAME, EntFrame);
    }
    
    function fl_ReleaseToDrop(event:MouseEvent):void
    {
        //if currentDraggingItem has a value, stop drag it
        if (currentDraggingItem) {
            currentDraggingItem.stopDrag();
            //send to the back
            currentDraggingItem.parent.addChildAt(currentDraggingItem,0);
        }
        //remove the mouse up and enter frame listener now that the mouse is UP
        stage.removeEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
        stage.removeEventListener(Event.ENTER_FRAME, EntFrame);
    
        if(checkComplete()){
            //game over, do something
        }
    }
    
    function EntFrame(e: Event) : void
    {
        //this will snap the peice to the correct spot when the mouse is touching the correct spot
        if(currentDraggingItem){
            if (this[currentDraggingItem.name.replace("P","T")].hitTestPoint(mouseX,mouseY))
            {
                currentDraggingItem.x = this[currentDraggingItem.name.replace("P","T")].x;
                currentDraggingItem.y = this[currentDraggingItem.name.replace("P","T")].y;
            }
        }
    }
    
    function checkComplete():Boolean {
        //use a loop to go through all your pieces and check if they are in the right spot. Again, you could have them in an array, or do it the lazy way
        for (var i:int = 1; i <= 19; i++) {
            if (!this["T"+i].hitTestObject(this["P"+i]))
            {
                return false;
            }
        }
        return true;
    }
    

【讨论】:

  • 天哪,这已经把我最后的代码缩短了这么多,谢谢!我实际上理解了至少 80% 的代码,以前从未使用过 Vectors。随机播放完美无缺,现在我目前的问题是碎片在中间而不是在拼图应该最终完成的区域周围。
  • Vector 基本上和数组完全一样,只是每个成员都必须是指定的类型。在几乎所有场景中,它们的执行速度都比使用 Array 快。关于您的新问题,请确保您的锚点都是一致的。我必须对您的 T1 - T19 对象是什么做出一些假设,我正确吗?
  • 啊,很酷,需要更多地阅读这些向量。我已经修复了中间生成的洗牌,它们都在拼图完成位置的右侧。也许,仍然掌握所有这些编码术语。如果我理解你的意思,T1-T19 对象是我认为是锚点的目标。如果我的拼图检测到目标,它将使用编码自动转到指定的拼图完成位置 if (Tnum.hitTestObject(Pnum.Tarnum)) { Pnum.x = 301.75; Pnum.y = 543.95; }
【解决方案2】:

嗯,一般来说你可以用下面的代码洗牌:

var shuffledVector:Vector.<someClass> = new Vector.<someClass>;
while (originalVector.length > 0) {
    shuffledVector.push(originalVector.splice(Math.random() * originalVector.length, 1)[0]);
}

更长的解释版本:

var shuffledVector:Vector.<someClass> = new Vector.<someClass>; //We will store our shuffled vector in here
var randomIndex:int;                                            //Random index from the originalVector
var resultVector:Vector.<someClass>;                            //result from the originalVector.splice(...) function
var randomElement:someClass;                                    //Random element from the originalVector

while (originalVector.length > 0) {                             //We will reduce the size of the originalVector until the originalVector is empty.
    randomIndex =  Math.random() * originalVector.length;       //Calculate a random index within the range of the originalVector from 0 to originalVector.lenght-1 (note that the range decreases by one on every loop)
    randomVector = originalVector.splice(randomIndex, 1);       //Use splice to remove one element at the randomly choosen index, we will receive a vector with the removed element...
    randomElement = randomVector[0];                            //...so we need to access the element
    shuffledVector.push(randomElement);                         //Add the randomly choosen element to our shuffled vector
}

我已经编写了向量的代码,因为我建议使用向量而不是数组,但是其背后的原理对于数组是相同的。

在您的情况下, originalVector 是一个填充了您的 P1-P19 影片剪辑的矢量,而 someClass 将是影片剪辑。 originalVector 最后是空的,可以用改组后的向量替换,当然,如果你把代码放在一个单独的函数中,这样会更有意义:

function Shuffle(originalVector:Vector.<someClass>) : void {
    var shuffledVector:Vector.<someClass> = new Vector.<someClass>;
    while (originalVector.length > 0) {
        shuffledVector.push(originalVector.splice(Math.random() * originalVector.length, 1)[0]);
    }
    originalVector = shuffledVector;
}

题外话,但对进一步编码很重要: 其他人已经提到,在每一帧上添加 EventListener 是不好的,因为它绝对没有必要。您只需要添加一次侦听器。您的代码非常重复,您应该使用一个接受 MovieClip、x 和 y 的函数,然后调用该函数 19 次。 例如:

function setUpMovieClip(MC:MovieClip, x:int, y:int) : {
    MC.addEventListener(MouseEvent.MOUSE_DOWN, clickToDrag);
    //more code...
}

在 clickToDrag 函数中,您可以访问通过 event.target 属性单击的 MovieClip:

function clickToDrag(e:MouseEvent) : {
    e.target.startDrag();
    //more code...
}

希望你能明白。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-22
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多