admin管理员组

文章数量:1357678

So I found some old script in a Newgrounds forum that should allow me to shake the scene without having to animate the scene manually. The problem is I don't really understand how to make it work. Can anyone explain to me how this works and how I can get it to work?

var AMOUNT = 20; //adjust based on how much you want the movieclip to shake

function makeMcShake(which:MovieClip)
{
    which.defaultPos = {which.x, which.y};
    which.addEventListener(Event.EnterFrame, shake);
}

function stopMcShake(which:MovieClip)
{
    which.removeEventListener(Event.EnterFrame, shake);
    which.x = which.defaultPos.x;
    which.y = which.defaultPos.y;
}

function shake(e:Event)
{
    e.currentTarget.x = e.currentTarget.defaultPos.x + Math.rand() * AMOUNT - AMOUNT / 2;
    e.currentTarget.y = e.currentTarget.defaultPos.y + Math.rand() * AMOUNT - AMOUNT / 2;
}

So I found some old script in a Newgrounds forum that should allow me to shake the scene without having to animate the scene manually. The problem is I don't really understand how to make it work. Can anyone explain to me how this works and how I can get it to work?

var AMOUNT = 20; //adjust based on how much you want the movieclip to shake

function makeMcShake(which:MovieClip)
{
    which.defaultPos = {which.x, which.y};
    which.addEventListener(Event.EnterFrame, shake);
}

function stopMcShake(which:MovieClip)
{
    which.removeEventListener(Event.EnterFrame, shake);
    which.x = which.defaultPos.x;
    which.y = which.defaultPos.y;
}

function shake(e:Event)
{
    e.currentTarget.x = e.currentTarget.defaultPos.x + Math.rand() * AMOUNT - AMOUNT / 2;
    e.currentTarget.y = e.currentTarget.defaultPos.y + Math.rand() * AMOUNT - AMOUNT / 2;
}
Share Improve this question edited Mar 28 at 19:20 Organis 7,3462 gold badges14 silver badges15 bronze badges asked Mar 28 at 15:29 Johnson YanJohnson Yan 114 bronze badges 3
  • Ok, I formatted the script to readability, and there are problems: 1) which.defaultPos = ... line makes no sense as {a, b, c, ...} is not a valid AS3 statement. 2) The event name is wrong. It should be exactly Event.ENTER_FRAME and none other. Otherwise, the logic of it is simple: upon calling makeShake you save the initial position and then every frame shift the target to that very position with a random offset. – Organis Commented Mar 28 at 19:24
  • I see. It is an old script after all, so I guess this is just outdated. Or maybe it's useable for ActionScript 2 or 1. Do you know where I can find a source where I can make a scene shake? Or the very least the Movieclip? – Johnson Yan Commented Mar 28 at 22:25
  • No, it is absolutely usable, just has errors. I am going to compose a correct one now. – Organis Commented Mar 29 at 7:28
Add a comment  | 

2 Answers 2

Reset to default 0

So, while the logic of the provided code was correct, there were multiple AS3 / Flash Palyer errors that prevented it to execute.

1. Creation of the preset object. As I already mentioned, the {a, b, c, ...} record does not mean a thing, there's a meaningful record that looks pretty similar: the creation of the generic object:

var O:Object = {x: 10, y: 20, alpha: 0.5};

is essentially the same as

var O:Object = new Object;

O.x = 10;
O.y = 20;
O.alpha = 0.5;

but obviously shorter.

2. Class fields, methods, constants, they are case-sensitive and should be typed in EXACTLY as supposed, otherwise Flash Player just wouldn't understand your intent. I pretty much advise to always check things with the language reference: the Math class, the Event class.

These are wrong:

Event.EnterFrame
Math.rand()

These are correct:

Event.ENTER_FRAME
Math.random()

Now. I expect the script for the shaking was intended like the one below.

Please ⚠️ keep in mind ⚠️ that while most of the scripts I compose still work as is, it was still ages since I last used AS3 and I have no way to check it so I might just miss something.

// @param:
// which — target to shake
// power — how much you want it to shake
// count — how many times (omit if you want it to shake until stopped manually)
function shake(which:MovieClip, power:Number, count:int = -1):void
{
    // Sanity check.
    if (!which)
    {
        return;
    }

    // Just in case, stop it if it is already shaking.
    unshake(which);
    
    // Save the shake parameters. This creates a generic object with fields.
    which.preset = {x: which.x, y: which.y, power: power, count: count};
    
    // Subscribe to the event that fires each frame.
    which.addEventListener(Event.ENTER_FRAME, onShaking);
}

function unshake(which:MovieClip):void
{
    // Sanity check.
    if (!which)
    {
        return;
    }
    
    // Unsubscribe from the event.
    which.removeEventListener(Event.ENTER_FRAME, onShaking);
    
    // Ignore if there is no preset object.
    if (which.preset)
    {
        // Return the target to its initial position.
        which.x = which.preset.x;
        which.y = which.preset.y;
        
        // Remove the shake parameters object.
        which.preset = null;
    }
}

function onShaking(e:Event):void
{
    // Get the direct reference to the target object.
    var which:MovieClip = e.currentTarget as MovieClip;
    
    // Sanity check. If there's no parameter object — just stop it.
    if (!which.preset)
    {
        unshake(which);
        return;
    }
    
    // Check if the countdown is complete.
    var count:int = which.preset.count;
    
    if (count > 0)
    {
        count -= 1;
        
        // Stop shaking if it is indeed complete.
        if (count == 0)
        {
            unshake(which);
            return;
        }
        
        which.preset.count = count;
    }

    // Shaking itself.
    var power:Number = which.preset.power;
    
    which.x = which.preset.x + Math.random() * power - power / 2;
    which.y = which.preset.y + Math.random() * power - power / 2;
}

And so, the usage.

Since DisplayObject.root:DisplayObject won't be automatically cast to the required MovieClip (meaning that you know that your root is a MovieClip yet the compiler does not) you need to explicitly typecast it to be accepted as argument.

// Shake the root MovieClip a bit 10 times.
shake(root as MovieClip, 5, 10);

// Shake the root MovieClip a bit more for approximately 1 second.
shake(root as MovieClip, 10, stage.frameRate);

// Shake the root MovieClip a lot and indefinitely.
shake(root as MovieClip, 25);

Okay, so eventually the code that finally made a MovieClip to shake is the following.

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

function shake(which:MovieClip, power:Number, count:int = -1):void {
    if (!which) return;
    unshake(which);
    which.preset = {x: which.x, y: which.y, power: power, count: count};
    which.addEventListener(Event.ENTER_FRAME, onShaking);
}

function unshake(which:MovieClip):void {
    if (!which) return;
    which.removeEventListener(Event.ENTER_FRAME, onShaking);
    if (which.preset) {
        which.x = which.preset.x;
        which.y = which.preset.y;
        which.preset = null;
    }
}

function onShaking(e:Event):void {
    var which:MovieClip = e.currentTarget as MovieClip;
    if (!which.preset) {
        unshake(which);
        return;
    }
    var count:int = which.preset.count;
    if (count > 0) {
        count--;
        if (count == 0) {
            unshake(which);
            return;
        }
        which.preset.count = count;
    }
    var power:Number = which.preset.power;
    which.x = which.preset.x + Math.random() * power - power / 2;
    which.y = which.preset.y + Math.random() * power - power / 2;
}

//For insertNamehere, change it to the name of the MovieClip in the properties panel

shake(insertNamehere, 10, 100);

//Thanks again Organis, you are a great help!

本文标签: actionscript 3Trying to get makeMcShake script found in Newgrounds forum to workStack Overflow