Best way to save data from flash - actionscript-3

I have an AS3 document with roughly 200 individual elements I'm trying to save to the database. I just need to saved information about their physical properties on the stage.
There are many ways to do this, but what is the recommended approach?
The backend is PHP/MySQL and it's not a two-way exchange. Save it, done.

apart from the server side, a good way to store / assign position/rotation/scale is to use the DisplayObjects' transformation matrices:
shape.transform.matrix
sprite.transform.matrix
it is rather compact ; need to store 6 Numbers per object.
rounding the scale/rotation values down to 5 decimals ( 0.12345 instead of 0.123456789123456 ) and the translation to 1 decimal ( 0.1 instead of 0.123456 ) works pretty well to spare some Ko.
for example this method:
private function storeMatrix( displayObject:DisplayObject, decimals:int = 5 ):String
{
var str:String = '';
var m:Matrix = displayObject.transform.matrix;
str += m.a.toFixed( decimals ) + ':';
str += m.b.toFixed( decimals ) + ':';
str += m.c.toFixed( decimals ) + ':';
str += m.d.toFixed( decimals ) + ':';
str += m.tx.toFixed( 1 ) + ':';
str += m.ty.toFixed( 1 );
return str;
}
will return something like:
-0.95119:-0.30550:0.30550:-0.95119:110.0:110.0
and this method sets the position/rotation/scale from the string:
private function assignMatrix( str:String, _do:DisplayObject ):void
{
var values:Array = str.split( ':' );
var m:Matrix = new Matrix();
m.a = values[ 0 ];
m.b = values[ 1 ];
m.c = values[ 2 ];
m.d = values[ 3 ];
m.tx = values[ 4 ];
m.ty = values[ 5 ];
_do.transform.matrix = m;
}
once you've collected all the object's matrices, you can serialize them with AMF and store to database. last time I did that, I used FZIP to compress the data even further ( 500Ko->20Ko). I don't think it'll help in your case, just wanted to point it out :)
NB: if needed, you can also store the transform.ColorTransform properties of an object in the very same way.

I would check out flash remoting/AMFPHP: http://amfphp.sourceforge.net/
It's pretty straightforwad, and really easy to implement.
Hope this helps.

Related

Flash Builder 4.6 | mx:DataGrid | Decimal to Fraction...or Fraction to Decimal Formatting

My datagrid has a depth-dimensions column that shows fractions (one dimension used for example is 24 3/8). I have the ability to choose the text (fraction or decimal), but essentially I would need to be able to convert back and forth from 24 3/8 to 24.375.
Why the Decimal format is needed:
I have checkboxes to filter the depth-dimensions column, so I'll need decimal form for that logic (e.g. checkbox to see filter depth-dimensions between 20 and 26).
Why the fraction format is needed: I'll need the fraction format because that depth-dimension data will be referenced as a string in another part of the application. The filter doesn't work when in this format is used in the dataGrid, because it won't recognize 24 3/8 as a number/int.
So basically I'm looking for a way to convert between the two formats, 24 3/8 to 24.375 and 24.375 to 24 3/8.
Again, my apologies for the confusion - I'm able to re-edit and/or add more details if needed.
Thanks in advance!
--moe
Why the fraction format is needed: I'll need the fraction format
because that depth-dimension data will be referenced as a string in
another part of the application.
Your reason for needing the fraction format seems odd. Do you understand that you can use a Number data type in a String by casting it?
var decimalNum:Number = 3.14;
//concatenating a Number with a String automatically casts it
var autoCastString:String = "I want to eat some " + decimalNum;
trace(autoCastString);
// cast as String type
var decimalString:String = String(decimalNum);
trace("Mmmm! I like", decimalString);
Output:
I want to eat some 3.14
Mmmm! I like 3.14
But perhaps you have other reasons. The code below is from this link: Decimal to Fraction. I haven't tested it.
package com.lookmum.util
{
public class Fraction
{
private static var it :Number = 0;
public static var iterationLimit:Number = 10000;
public static var accuracy :Number = 0.00001;
public function Fraction()
{
}
private static function resetIt():void
{
it = 0;
}
private static function addIt():Boolean
{
it++;
if (it == iterationLimit)
{
trace('error : too many iterations');
return true;
}
else
{
return false;
}
}
public function getFractionString(num:Number):String
{
var fracString:String;
var fracArray:Array = getFraction(num);
switch (fracArray.length)
{
case 1 :
fracString = num.toString();
break;
case 2 :
fracString = fracArray[0].toString() + '/' + fracArray[1].toString();
break;
case 3 :
fracString = fracArray[0].toString() + ' ' + fracArray[1].toString() + '/' + fracArray[2].toString();
break;
}
return fracString;
}
public function getFraction(num:Number):Array
{
var fracArray:Array = new Array();
var hasWhole:Boolean = false;
if (num >= 1)
{
hasWhole = true;
fracArray.push(Math.floor(num));
}
if (num - Math.floor(num) == 0)
{
return fracArray;
}
if (hasWhole)
{
num = num - Math.floor(num);
}
var a:Number = num - int(num);
var p:Number = 0;
var q:Number = a;
resetIt();
while (Math.abs(q - Math.round(q)) > accuracy)
{
addIt();
p++;
q = p / a;
}
fracArray.push(Math.round(q * num));
fracArray.push(Math.round(q));
return fracArray;
}
}
}

An alternative to bitmapdata with less memory usage?

Im using a very big BitmapData as a pathing map for my platformer game, however I only use pixels for 4 particular values, instead of, well 4294967295.
Would converting this Bitmapdata as 2 2D Vectors of Boolean save me some memory ?
And if it does, what about performance, would it be faster or slower to do something like:
MapGetPixel(x:int, y:int):int
{
return MapBoolFirst[x][y] + MapBoolSecond[x][y]*2;
}
instead of the bitmapdata class getPixel32(x:int, y:int):uint ?
In short im looking for a way to reduce the size and/or optimize my 4 colors bitmapdata.
Edit :
Using my boolean method apparently consumes 2 times more memory than the bitmapdata one.
I guess a boolean takes more than one bit in memory, else that would be too easy. So im thinking about bitshifting ints and thus have an int store the value for several pixels, but im not sure about this…
Edit 2 :
Using int bitshifts I can manage the data of 16 pixels into a single int, this trick should work to save some memory, even if it'll probably hit performance a bit.
Bitshifting will be the most memory-optimized way of handling it. Performance wise, that shouldn't be too big of an issue unless you need to poll a lot of asks each frame. The issue with AS is that booleans are 4bits :(
As I see it you can handle it in different cases:
1) Create a lower res texture for the hit detections, usually it is okay to shrink it 4 times (256x256 --> 64x64)
2) Use some kind of technique of saving that data into some kind of storage (bool is easiest, but if that is too big, then you need to find another solution for it)
3) Do the integer-solution (I haven't worked with bit-shifting before, so I thought it would be a fun challenge, here's the result of that)
And that solution is way smaller than the one used for boolean, and also way harder to understand :/
public class Foobar extends MovieClip {
const MAX_X:int = 32;
const MAX_Y:int = 16;
var _itemPixels:Vector.<int> = new Vector.<int>(Math.ceil(MAX_X * MAX_Y / 32));
public function Foobar() {
var pre:Number = System.totalMemory;
init();
trace("size=" + _itemPixels.length);
for (var i = 0; i < MAX_Y; ++i) {
for (var j = 0; j < MAX_X; ++j) {
trace("item=" + (i*MAX_X+j) + "=" + isWalkablePixel(j, i));
}
}
trace("memory preInit=" + pre);
trace("memory postInit=" + System.totalMemory);
}
public function init() {
var MAX_SIZE:int = MAX_X * MAX_Y;
var id:int = 0;
var val:int = 0;
var b:Number = 0;
for(var y=0; y < MAX_Y; ++y) {
for (var x = 0; x < MAX_X; ++x) {
b = Math.round(Math.random()); //lookup the pixel from some kind of texture or however you expose the items
if (b == 1) {
id = Math.floor((y * MAX_X + x) / 32);
val = _itemPixels[id];
var it:uint = (y * MAX_X + x) % 32;
b = b << it;
val |= b;
_itemPixels[id] = val;
}
}
}
}
public function isWalkablePixel(x, y):Boolean {
var val:int = _itemPixels[Math.floor((y * MAX_X + x) / 32)];
var it:uint = 1 << (y * MAX_X + x) % 32;
return (val & it) != 0;
}
}
One simple improvement is to use a ByteArray instead of BitmapData. That means each "pixel" only takes up 1 byte instead of 4. This is still a bit wasteful since you're only needing 2 bits per pixel and not 8, but it's a lot less than using BitmapData. It also gives you some "room to grow" without having to change anything significant later if you need to store more than 4 values per pixel.
ByteArray.readByte()/ByteArray.writeByte() works with integers, so it's really convenient to use. Of course, only the low 8 bits of the integer is written when calling writeByte().
You set ByteArray.position to the point (0-based index) where you want the next read or write to start from.
To sum up: Think of the ByteArray as a one dimensional Array of integers valued 0-255.
Here are the results, I was using an imported 8 bit colored .png by the way, not sure if it changes anything when he gets converted into a
BitmapData.
Memory usage :
BitmapData : 100%
Double Boolean vectors : 200%
Int Bitshifting : 12%
So int bitshifting win hands down, it works pretty much the same way as hexadecimal color components, however in that case I store 16 components (pixel values in 2 bits) not the 4 ARGB:
var pixels:int = -1;// in binary full of 1
for (var i:int = 0; i < 16; i++)
trace("pixel " + (i + 1) +" value : " + (pixels >> i * 2 & 3));
outputs as expected :
"pixel i value : 3"

Converting alpha percent to RGBA hex in AS3?

Say I have the following setup in my AS code:
var color:String = "#0000FF"; //blue
var alpha:Number = 42; //42% or 42/100
How would I combine those into a #RRGGBBAA hex color? I've been Googling around and trying to figure out hexadecimal conversion and notation without luck.
There are two ways you could do this.
One is a bit hacky using int's toString() method and passing 16 as the radix/base:
var rgb:int = (int)("#0000FF".replace("#","0x"));//convert the string to a int (note you can type hex ints starting with 0x (e.g. 0x0000FF)
var a:int = 42;
var rgba:int = int("0x"+rgb.toString(16) + a.toString(16));
or the less hacky and probably faster computationally method using bitwise operators:
var rgb:uint = (uint)("#0000FF".replace("#","0x"));
//extract components using bit shifting (>>) and masking (0xFF)
var r:uint = rgb >> 16 & 0xFF;
var g:uint = rgb >> 8 & 0xFF;
var b:uint = rgb >> 0 & 0xFF;//same as rgb >> 0xFF, just added >> 0 to make the shift obvious
var a:uint = 42;
var rgba:uint = r << 24 | g << 16 | b << 8 | a;
var argb:uint = a << 24 | r << 16 | g << 8 | b;
//test
trace(rgba.toString(16));
trace(argb.toString(16));
Note that using toString(16) in the trace above is to make it useful to us humans,
you'd use the actual uint value when working with hex color values.
Also note that you might want to use ARGB in as3 sometimes, for example when working with BitmapData:
addChild(new BitmapData(100,100,true,0x2a0000ff));//add a 42% transparent blue box (100x100 px)
UPDATE
The above bitshift code snippet actually explains rgb extraction in detail which helps understand things better, but you already have rgb, so it's a matter of adding the alpha component. Also you mentioned 42% which is not the same as on a 0 to 255 scale. Therefore bellow lies your answer:
var rgb:uint = (uint)("#0000FF".replace("#","0x"));
var a:uint = (uint)((42 * .01) * 255);//map 42 from 0<>100 to 0<>255 ( *.01 is the same as / 100 but faster
var rgba:uint = rgb << 8 | a;
var argb:uint = a << 24 | rgb;
Regarding speed, if I run the two different conversion methods a million times here are execution times:
using strings (var rgba:int = int("0x"+rgb.toString(16) + a.toString(16));) takes 851 ms
using bitwise ops (var rgba:uint = rgb << 8| a;) takes 3 ms
As you can the bitwise version is much faster and for your case even less verbose than the string version. Also, now that you understand bitwise operators probably it's easier to read/understand.
In conclusion:
var color:String = "#0000FF"; //blue
var alpha:Number = 42; //42% or 42/100
var rgb:uint = (uint)(color.replace("#","0x"));
var a:uint = (uint)((alpha * .01) * 255);
var rgba:uint = rgb << 8 | a;
trace("hex: #",rgba.toString(16),"test",0x0000ff6b.toString(16));
Also, it's funny you mentioned Google, because you can use the search to convert to hex.
Update:
There seems to be a bit of confusion so I've split the 3 steps into functions:
converting a hex string to an int
converting a alpha percentage (0-100) to a 0-255 int
concatenating the above
Which would be:
function getHex(hexStr:String):uint{
return (uint)(hexStr.replace("#","0x"));
}
function getHexAlpha(alpha:uint):uint{
return (uint)((alpha * .01) * 255);
}
function rgbaConcat(rgb:uint,a:uint):uint{
return rgb << 8 | a;
}
trace("test",rgbaConcat(getHex("#FF9900"),getHexAlpha(50)).toString(16));
or all in one go:
function rgbaConcat(hexStr:String,alpha:uint):uint{
var rgb:uint = (uint)(hexStr.replace("#","0x"));
var a:uint = (uint)((alpha * .01) * 255);
return (rgb << 8 | a);
}
trace("test",rgbaConcat("#123456",100).toString(16));
I'm not sure if sprintf or something similar is available in action script, but you would use something like:
var alpha_2:int = Math.round(255*alpha/100);
var rgba:String = sprintf("%s%2x", color, alpha_2);
By the way, be sure to check whether it is supposed to be #RRGGBBAA or #AARRGGBB
So apparently sprintf is not available, you can use some substitute as mentioned in Is there something like printf in Action Script 3?
If you do not like to use a printf like function you can use:
function hex_char(value:int) {
if (value < 0)
return "X";
if (value < 10)
return String.fromCharCode("0".charCodeAt(0)+value);
if (value < 16)
return String.fromCharCode("A".charCodeAt(0)+value-10);
return "X";
}
var alpha_2:int = Math.round(255*alpha/100);
var rgba:String = color + hex_char(alpha_2/16) + hex_char(alpha_2%16);
alternatively you coulde use the following definition for hex_char which (I assume) will give you an exception/error for any value under 0 or over 15 instead of "X"
function hex_char(value:int) {
return "0123456789ABCDEF".charAt(value);
}

Trouble creating a spectrogram

I know it was asked a thousand times before, but I still can't find a solution.
Searching SO, I indeed found the algorithm for it, but lacking the mathematical knowledge required to truly understand it, I am helplessly lost!
To start with the beginning, my goal is to compute an entire spectrogram and save it to an image in order to use it for a visualizer.
I tried using Sound.computeSpectrum, but this requires to play the sound and wait for it to end, I want to compute the spectrogram in a way shorter time than that will require to listen all the song. And I have 2 hours long mp3s.
What I am doing now is to read the bytes from a Sound object, the separate into two Vectors(.); Then using a timer, at each 100 ms I call a function (step1) where I have the implementation of the algorithm, as follows:
for each vector (each for a channel) I apply the hann function to the elements;
for each vector I nullify the imaginary part (I have a secondary vector for that)
for each vector I apply FFT
for each vector I find the magnitude for the first N / 2 elements
for each vector I convert squared magnitude to dB scale
end.
But I get only negative values, and only 30 percent of the results might be useful (in the way that the rest are identical)
I will post the code for only one channel to get rid off the "for each vector" part.
private var N:Number = 512;
private function step1() : void
{
var xReLeft:Vector.<Number> = new Vector.<Number>(N);
var xImLeft:Vector.<Number> = new Vector.<Number>(N);
var leftA:Vector.<Number> = new Vector.<Number>(N);
// getting sample range
leftA = this.channels.left.slice(step * N, step * (N) + (N));
if (leftA.length < N)
{
stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
return;
}
else if (leftA.length == 0)
{
stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
return;
}
var i:int;
// hann window function init
m_win = new Vector.<Number>(N);
for ( var i:int = 0; i < N; i++ )
m_win[i] = (4.0 / N) * 0.5 * (1 - Math.cos(2 * Math.PI * i / N));
// applying hann window function
for ( i = 0; i < N; i++ )
{
xReLeft[i] = m_win[i]*leftA[i];
//xReRight[i] = m_win[i]*rightA[i];
}
// nullify the imaginary part
for ( i = 0; i < N; i++ )
{
xImLeft[i] = 0.0;
//xImRight[i] = 0.0;
}
var magnitutel:Vector.<Number> = new Vector.<Number>(N);
fftl.run( xReLeft, xImLeft );
current = xReLeft;
currf = xImLeft;
for ( i = 0; i < N / 2; i++ )
{
var re:Number = xReLeft[i];
var im:Number = xImLeft[i];
magnitutel[i] = Math.sqrt(re * re + im * im);
}
const SCALE:Number = 20 / Math.LN10;
var l:uint = this.total.length;
for ( i = 0; i < N / 2; i++ )
{
magnitutel[i] = SCALE * Math.log( magnitutel[i] + Number.MIN_VALUE );
}
var bufferl:Vector.<Number> = new Vector.<Number>();
for (i = 0; i < N / 2 ; i++)
{
bufferl[i] = magnitutel[i];
}
var complete:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
complete[0] = bufferl;
this.total[step] = complete;
this.step++;
}
This function is executed in the event dispatched by the timer (stepper).
Obviously I do something wrong, as I said I have only negative values and further more values range between 1 and 7000 (at least).
I want to thank you in advance for any help.
With respect,
Paul
Negative dB values are OK. Just add a constant (representing your volume control) until the number of points you want to color become positive. The remaining values that stay negative are usually just displayed or colored as black in a spectrogram. No matter how negative (as they might just be the FFT's numerical noise, which can be a huge negative dB number or even NaN or -Inf for log(0)).

actionscript 3 trace returns a blank function rather than a number

I have a simple code that seems to be giving strange results.
var startPoint:Point = new Point(x, y); // a point
var r:Number = path[i].row + (-Math.floor((length * 2 + 2) / 2)); // just some math
trace(r); // the math checks out and gives a 3
var tey = startPoint.y + r; //this gives a really strange return....
trace(startPoint.y + r, tey); // this works, and then gives the strange return.
the return is
3
10 7function Function() {}
as
var tey:Number = startPoint.y + r;
trace(startPoint.y + r, tey);
the return is
10 NaN
IDE is FlashDevelop if you feel that information is important.
Additional Info/Testing:
trace(startPoint.y);
traces as
7
:Number
var tey:Number = startPoint.y + r;
trace(tey);
equals
NaN
Number()
var tey = Number(startPoint.y) + r;
trace(tey);
equals
7function Function() {}
(excuse my poor post layout, I'm still inexperienced with stackoverflow's editing system and am working on making this a little cleaner)
I can not reproduce your issue.
Your problem is with the X and Y values on this line, probably more so the Y value.
var startPoint:Point = new Point(x, y); // a point
Try hard coding the X and Y to 0
Here is some sample code I ran. This worked as expected, so I will assume its the vars X and Y or something related to the "i" when you access path[i].row
var startPoint:Point = new Point(0, 0); // a point
var r:Number = 3; // just some math
trace(r); // the math checks out and gives a 3
var tey = startPoint.y + r; //this gives a really strange return....
trace(startPoint.y + r, tey); // this works, and then gives the strange return.
I discovered the issue, it was with a part of the code that I appended out of my sample above.
var startPoint:Point = new Point(x, y); // a point
for ( /*for stuff*/ ){
var r:Number = path[i].row + (-Math.floor((length * 2 + 2) / 2)); // just some math
}
trace(r); // the math checks out and gives a 3
var tey = startPoint.y + r; //this gives a really strange return....
trace(startPoint.y + r, tey); // this works, and then gives the strange return.
being var'd inside of the for loop made it act oddly when used outside so I had to move the var assignment outside of the loop and use as normal. A strange occurrence, but I should have knew better.