Visar inlägg med etikett as3. Visa alla inlägg
Visar inlägg med etikett as3. Visa alla inlägg

2012-12-10

Caching loaded images in AS3

Link to example project
Link to stack overflow

So, I read this question on StackOverflow about a guy who wanted to load images several times but didn't want to have them placed inside a swf-file or a swc-file (or rather wanted to have the swc created at runtime).

Storing images inside a cache in that way isn't super easy so I thought I would give it a try and see how a solution to that would work. I started out with a simple Static ImageManager but shortly found that it wasn't nearly as easy as I first thought it would be due to race conditions and as3 being rather limited to how you can work with loaded content, queuing loads etc.

I ended up creating two classes and an extra Main-class to provide as an example:

ImageManager (static class, keeps url as id for the image sand stores loaded images bitmapdata)
FileLoader (dynamic instances, does the actual load of objects and then notifies when it is done)

Since there is no easy way of storing files on this blog, I had to create some online storage service [chose Skybox today].

Anyways, here is the link to my example project, source code is "pasted" below for "completeness" if you just wanna see the files and don't wanna download the entire project.

Main.as - link to pastie
ImageManager.as - link to pastie
FileLoader.as - link to pastie

2012-09-04

Providing default values if null or empty

So, I was curious about wether there were a better way to do stuff like:


_parsedBetData["prizeLevel"] = params["prizeLevel"] == null ? "default" : params["prizeLevel"];
And posted my question on StackOverflow turns out this could be solved with the help of a regular ||=. 
So that specific code can be simplified as
_parsedBetData["prizeLevel"] = params["prizeLevel"] || "default";
If you are interested in providing a default value if _parsedBetData["prizeLevel"] is null or empty that can simply be done by:
_parsedBetData["prizeLevel"] ||= "default";
It's important to note that the check would return false for both and empty string and null.

2012-08-31

ActionScript Ascii Art

Yesterday I found this pretty awesome tool that lets you convert any image to ascii art. It's basically done through traversing each pixel in the picture and converting it into a grayscale value and then replacing that grayscale value with an appropriate ascii-character, which one depends on how much black that pixel is.

Most important code part:

rgbVal = _data.getPixel(x, y);
redVal = (rgbVal & 0xFF0000) >> 16;
greenVal = (rgbVal & 0x00FF00) >> 8;
blueVal = rgbVal & 0x0000FF;

/*
* Calculate the gray value of the pixel.
* The formula for grayscale conversion: (Y = gray): Y = 0.3*R + 0.59*G + 0.11*B
*/
grayVal = Math.floor(0.3 * redVal + 0.59 * greenVal + 0.11 * blueVal);

It then continues with checking that value against a white and black treshold and then checking up the final gray-value against a "palette" containing:

var palette:String = "@#$%&8BMW*mwqpdbkhaoQ0OZXYUJCLtfjzxnuvcr[]{}1()|/?Il!i><+_~-;,. ";

index = Math.floor(grayVal / 4);
result += palette.charAt(index);

End result:

Say hello to my collegue, transformed into Ascii





2012-08-30

Panning and scrolling movieclips

So, yesterday I started reading AS3 Developer's Guide. After reading through close to 200 pages I found something of interest that I think is worth sharing/saving for a later time.

It is related to clipping a movieclip and then scroll it without using the expensive masking-technique and something that I wish I had known earlier.

So how does it work?

Imagine that you have a large movieclip that contains info that would cover say 3-4 screen sizes. Personally I had this exact issue with an info screen inside a game that contained mixed texts and images. So what you should know is that each display object has an attribute called scrollRect that states which part of the image that is rendered. I think that this is similar to the "sourceRect"-parameter that can be found in DirectX and thus my guess is that only parts of the movieclip is sent to the GPU for rendering which would greatly increase performance in some cases.

Example code:

ORIGINAL_HEIGHT = _infoScreen.height; //store the original size in a variable
_infoScreen.cacheAsBitmap = true;
_infoScreen.scrollRect = new Rectangle(0,0,_infoScreen.width, 300); //visible part of the movieclip


_up.addEventListener(MouseEvent.CLICK, function(e:Event):void {
    var r:Rectangle = _infoScreen.scrollRect;
    r.y -= 20;
    _infoScreen.scrollRect = r;
});


_down.addEventListener(MouseEvent.CLICK, function(e:Event):void {
    var r:Rectangle = _infoScreen.scrollRect;
    r.y += 20;
    _infoScreen.scrollRect = r;
});

Ugly picture as example:

As you can see only the specified scrollRect is shown and in the picture I have scrolled down a couple of times.

Good thing to know is that you will only experience a performance gain if you cache your movieclip as bitmap.

If you are interested in reading in more detail about it, you can do so inside the developers guide. When this was written that could be found in chapter 10 on page 178.

2012-06-20

Mouse interaction and custom cursor

Recently I've been working quite a bit with replacing the mouse cursor with custom graphics. And usually there are a lot of custom behaviour to it, similar to, play some animation when LMB is pressed, the custom cursor should be disabled while over a specific area (buttons). And last but not least, something specific should happen when user presses LMB inside a specific area for example attaching new movie clips while LMB is down etc.

In the above scenario, this is the best solution I've come up with this far. Imagine you have a "container" that encapsulates every movie clip that you will be using, you then listen to mouse-press and starts listening to enter-frame messages:

function init:
_container.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_container.addEventListener(Event.ENTER_FRAME, onEnterFrame);
_cursor.visible = true;
_cursor.startDrag(true);
Mouse.hide();

then inside the function onMouseDown (observe the stage-reference):
_isMouseDown = true;
_container.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_container.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);

and inside the function onMouseUp

_isMouseDown = false;
_container.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_container.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);

and finally the onEnterFrame-function, using a hitbox (subpart of "container" where the mouse-cursor should be replaced with custom-cursor) (if you are curious about the hitTestMouse-function please see my previous post):
{
if (hitTestMouse(_hitbox)) { 
    _cursor.visible = true;
    Mouse.hide();
} else { 
    _cursor.visible = false;
    Mouse.show();
    return; //outside of bounds

if(_isMouseDown == false) 
     return; 
}

/* depending on your solution, you could either create an awesome shape for hit test (_hitBox), or you could use a simple rectangle and then do more escape routes here in code with something similar to if(hitTestMouse(_button2)) useCustomCursor(false) and then return;
*/

//create and attach your custom movieclip here
var mc:MovieClip = new _eraserDef();

mc.x = _container.mouseX;

mc.y = _container.mouseY;

_container.foo.addChild(mc);
}

This will make it possible to replace mouse cursor with custom graphics while over a specific area (hitbox) and then restore regular cursor while hovering above buttons or outside hitbox and "place symbols" or "draw" while inside the hitbox. 

Don't remember to kill all event-listeners, stopdrag on _cursor, and to restore mouse when you're done with what you're gonna do.

Proper hitTest in AS3



After many ugly attempts at handling hit tests in AS3 I finally managed to solve what I was looking for. The thing I forgot to consider was to use the global mouse-coordinates.

public function hitTestMouse(hitarea:DisplayObject):Boolean {
    return hitarea.hitTestPoint(hitarea.stage.mouseX, hitarea.stage.mouseY, true);
}


The last parameter (shapeFlag) would decide if the hit test are checked any actual shapes inside the hitarea that the mouse is hovering above.

Take the picture below as an example, say that the two buttons "autoskrap" and "vinstkontroll" are inside a movie clip (marked as the grayish box) if the shapeFlag is set to false (default) the hitTestMouse-function would return true whenever the mouse were somewhere inside the gray box. If the shapeFlag is set to true it would only return true if the mouse were over the actual buttons.