Improve function speed that uses remainder: - actionscript-3

Please have a look at this piece of code:
public static function getCharLocationById(id:int):Point {
var lx:int = id % 16;
var ly:int = id / 16;
return new Point(lx, ly);
}
It works perfectly but is very slow. Does anyone know of a way to make it much faster?
Thanks in advance!

If you create the objects beforehand for all possibilities, all you have to do is look them up in an array (with the id as index).
private static const _locationLookUpTable:Array = []; //or Vector, if you like
// fill the array somewhere, maybe like this
for (var i:uint = 0; i <= maximumId; ++i) _locationLookUpTable.push(i % 16, i / 16);
public static function getCharLocationById(id:int):Point {
return _locationLookUpTable[id];
}
If the number of ids is not limited or very large you can employ an object pool.
This requires a little more code as you should return the objects to the pool if they are not used any more.

Ignore the variable creations, only takes time to create, assign and then again read them to submit them to the Point constructor.
public static function getCharLocationById(id:int):Point
{
return new Point(id % 16, id / 16);
}
Also, considering that your input is an integer, you can use bitshifts for the division by 16 like this:
id = id >> 1; // div. by 2 = id/2
id = id >> 1; // div. by 2 = id/2/2 = id/4
id = id >> 1; // div. by 2 = id/2/2/2 = id/8
id = id >> 1; // div. by 2 = id/2/2/2/2 = id/16
Shortening that we get
id = id >> 4; // (1+1+1+1 = 4)
Keep in mind that the result will also be an integer, so 11 >> 1 will return 5 and not 5.5.

Related

Simplest way to prevent math.random form selecting the same number twice (AS3)

I have a random number variable defined as below
var rannum:Number = Math.floor(Math.random()*50+1);
Then I have a trigger that calls for a new random number everytime a button is clicked
ranbtn.addEventListener(MouseEvent.CLICK, reran);
function reran (event:MouseEvent):void
{
rannum = Math.floor(Math.random()*50+1);
}
I would like to prevent the same random number from being selected until all the numbers have been selected and then possibly start over?
I found a few threads like this one but none of them were specifically what I needed
You need to create an array of the possible values and each time you retrieve a random index from the array to use one of the values, you remove it from the array.Here you have an easy example with javascript.
var uniqueRandoms = [];
var numRandoms = 50;
function makeUniqueRandom() {
// refill the array if needed
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
// now remove that value from the array
uniqueRandoms.splice(index, 1);
return val;
}
I've found another option, You can declare an array of Integers:[1,2,3,4...50] and sort them randomly.
var sorted:Array = [];
for(var i:int = 0; i < 50; i++){
sorted.push(i);
}
//I'm making a copy of sorted in unsorted
var unsorted:Array = sorted.slice();
//Randomly sort
while(sorted.join() == unsorted.join()){
unsorted.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
If you get a selected num, you can add one until it is not selected.
Create a list of integers from 1 to 50.
Pick a random integer from the list and remove it.
When there are no more integers left (after 50 picks), repeat step 1.
Code:
function createRangeOfIntegers(from:int, to:int):Vector.<int> {
if (from >= to) throw new ArgumentError("Invalid arguments");
var integers:Vector.<int> = new <int>[];
for (var i:int = from; i <= to; i++) {
integers.push(i);
}
return integers;
}
function getRandomInteger(integers:Vector.<int>):int {
var index:int = Math.random() * integers.length;
var integer:int = integers.splice(index, 1)[0];
return integer;
}
Example:
// create all the possible integers
var integers:Vector.<int> = createRangeOfIntegers(1, 50);
// select a random integer
var random:int = getRandomInteger(integers);
// When you've selected all integers you can start over
if (integers.length == 0)
integers = createRangeOfIntegers(1, 50);

Box2D - FRIM (Frame Rate Independent Movement)

I've been trying to implement a FRIM system for my game for the last couple of days.I did some research and came upon this article - it seemed simple enough to implement so I got started.
Everything seems to work fine except I get some temporal aliasing (moving bodies seem to jump ahead a bit) - this happens when more Box2D steps are processed....I think.
private const FIXED_TIMESTEP:Number = 1 / 60;
private const velocityIterations:int = 8;
private const positionIterations:int = 3;
private var fixedTimestepAccumulator:Number = 0;
private var fixedTimestepAccumulatorRatio:Number = 0;
public function Step(dt:Number):void
{
//dt - time between frames - I'm passing the e.passedTime - from the enter frame event; using Starling
fixedTimestepAccumulator += dt;
var nSteps:uint = Math.floor(fixedTimestepAccumulator / FIXED_TIMESTEP);
if (nSteps > 0)
{
fixedTimestepAccumulator = fixedTimestepAccumulator - nSteps * FIXED_TIMESTEP;
}
fixedTimestepAccumulatorRatio = fixedTimestepAccumulator / FIXED_TIMESTEP;
var nStepsClamped:int = Math.min(nSteps, MAX_STEPS);
for (var i:int = 0; i < nStepsClamped; ++i)
{
resetSmoothStates();
singleStep(FIXED_TIMESTEP);
}
world.ClearForces();
smoothStates();
}
private function resetSmoothStates():void
{
for (var bb:b2Body = world.GetBodyList(); bb; bb = bb.GetNext())
{
if (bb.GetUserData() is MyUserData && bb.GetType() != b2Body.b2_staticBody )
{
//each of my bodies have a reference to their sprite (actor) in userData
var _userdata:MyUserData=bb.GetUserData();
_userdata.x = _userdata.bodyPreviousX = bb.GetPosition().x * RATIO;
_userdata.y= _userdata.bodyPreviousY = - bb.GetPosition().y* RATIO;
_userdata.rotation = _userdata.bodypreviousRotation= _userdata.bodypreviousRotation = - bb.GetAngle();
}
}
}
private function smoothStates():void
{
var oneMinusRatio:Number = 1.0 - fixedTimestepAccumulatorRatio;
for (var bb:b2Body = world.GetBodyList(); bb; bb = bb.GetNext())
{
if (bb.GetUserData() is MyUserData && bb.GetType() != b2Body.b2_staticBody )
{
var userdata=bb.GetUserData();
userdata.x = (fixedTimestepAccumulatorRatio * bb.GetPosition().x * RATIO + oneMinusRatio * userdata.bodyPreviousX) ;
userdata.y = (- fixedTimestepAccumulatorRatio * bb.GetPosition().y * RATIO + oneMinusRatio * userdata.bodyPreviousY) ;
userdata.rotation = (- fixedTimestepAccumulatorRatio * bb.GetAngle() + oneMinusRatio * userdata.bodypreviousRotation);
}
}
}
private function singleStep(dt:Number):void
{
Input();
world.Step(dt, velocityIterations, positionIterations);
}
What am I doing wrong?
Any help, suggestions would be highly appreciated.
Thanks
I did this once in a game I was working on so that I could lockstep the game to a certain update rate (this was in iOS). This was based on the code in Daley's book (Learning iOS Game Programming), which was based on some other article in the web (I believe, it may be Allen Bishop's). The code looked like this:
void GameManager::UpdateGame()
{
const uint32 MAXIMUM_FRAME_RATE = Constants::DEFAULT_OBJECT_CYCLES_PER_SECOND();
const uint32 MINIMUM_FRAME_RATE = 10;
const uint32 MAXIMUM_CYCLES_PER_FRAME = (MAXIMUM_FRAME_RATE/MINIMUM_FRAME_RATE);
const double UPDATE_INTERVAL = (1.0/MAXIMUM_FRAME_RATE);
static double lastFrameTime = 0.0;
static double cyclesLeftOver = 0.0;
double currentTime;
double updateIterations;
currentTime = CACurrentMediaTime();
updateIterations = ((currentTime - lastFrameTime) + cyclesLeftOver);
if(updateIterations > (MAXIMUM_CYCLES_PER_FRAME*UPDATE_INTERVAL))
{
updateIterations = MAXIMUM_CYCLES_PER_FRAME*UPDATE_INTERVAL;
}
while (updateIterations >= UPDATE_INTERVAL)
{
// DebugLogCPP("Frame Running");
updateIterations -= UPDATE_INTERVAL;
// Set the random seed for this cycle.
RanNumGen::SetSeed(_cycleManager->GetObjectCycle());
// Dispatch messages.
_messageManager->SendMessages();
// Update all entities.
_entityManager->Update();
// Update the physics
_gameWorldManager->Update(Constants::DEFAULT_OBJECT_CYCLE_SECONDS());
// Advance the cycle clock.
_cycleManager->Update();
}
cyclesLeftOver = updateIterations;
lastFrameTime = currentTime;
}
I can't put my finger on the specific item that is wrong in yours. However, this part is suspicious:
var nStepsClamped:int = Math.min(nSteps, MAX_STEPS);
Before this, you updated your accumulator with:
fixedTimestepAccumulator = fixedTimestepAccumulator - nSteps * FIXED_TIMESTEP;
But now the actual number of steps you are going to execute may be different because of the clamping (nStepsClamped). So your time accumulation is different than the number of steps you actually execute.
Was this helpful?
I decided to go with another approach. I'm using filtered delta times for the physics (I know this can cause some problems).
Here's what I'm doing now:
//Play around with this filter value if things don't look right
var filter:Number=0.4;
filtered_dt= time_between_frames * filter + filtered_dt * (1 - filter);
//Poll imputs and apply forces
// I use velocityIterations =6, positionIterations=3
world.Step(filtered_dt, velocityIterations, positionIterations);
//move sprites here
world.ClearForces();
Another thing you have to do is to scale the forces you apply to your bodies using filtered_dt so things don't "explode" when the frame rate changes a lot.
Hope this helps some one else ... it's not the perfect solution but it works for me.
If you have slow moving bodies the interpolation method above should work fine too.

AS3: How do I automate declaring multiple objects

I am trying to initialize and populate multiple objects along with their related properies automatically.
Basically I have a 32x32 grid and for each position on the grid I would like to assign an object with multiple properties that can be referenced later.
A 32x32 grid has 1024 positions on it and I really don't want to have to write up that many variable declarations manually. I have the array set up in a separate class file which allows me to assign a variable to a grid position: gridPos.put(x, y, object.property);
I have also set up a pair of for loops which will populate the objects with default starting data.
Now what I need to do is get it to declare the objects for me with unique names and then populate them all with the starting data. These objects need to be accessible from other parts of the code (I tried to declare them as public var gridPosTile[h] : Object = new Object; but declaring it as 'public' it gave me an error saying it "1114: The public attribute can only be used inside a package.")
*Also, I know [h] is not right but it was kinda how I saw it working in my head... please illuminate me :)
Many Thanks
public function gridPosTilePopulate():void
{
var g: int = 40;
var h: int = 1;
for(var i:int = 0; i < 32; i++)
{
var v: int = 40;
g += 40;
for(var q:int = 0; q < 32; q++)
{
var gridPosTile[h] : Object = new Object;
gridPos.put(i, q, gridPosTile[h]);
gridPosTile[h].xPos = (v + 40));
gridPosTile[h].yPos = (g + 40));
gridPosTile[h].p1Set = false);
gridPosTile[h].p2Set = false);
gridPosTile[h].m1Set = false);
gridPosTile[h].m2Set = false);
gridPosTile[h].m3Set = false);
gridPosTile[h].m4Set = false);
gridPosTile[h].coinSet = false);
gridPosTile[h].powerupSet = false);
v += 40;
h++;
}
}
}
You didn't post your full class so I can not tell you why you got the 1114 error.
I would start with adding a a property to your class to store the gridPosTitle objects.
You should use an array collection or a vector. In my example I will use an arrayCollection.
This storage collection will allow you easy reference to all of the tiles you have created.
To add a dynamic name property all you need to do is use bracket notation.
And lastly remove all reference to "h" since it is not needed except to name the object.
package com.example{
public class SomeClassName{
// storage var for future use.
public var tileStorage:ArrayColelction
public function gridPosTilePopulate():void
{
tileStorage = new ArrayCollection()
var g: int = 40;
var h: int = 1;
for(var i:int = 0; i < 32; i++)
{
var v: int = 40;
g += 40;
for(var q:int = 0; q < 32; q++)
{
var gridPosTile : Object = new Object;
gridPos.put(i, q, gridPosTile);
gridPosTile.xPos = (v + 40));
gridPosTile.yPos = (g + 40));
gridPosTile.p1Set = false);
gridPosTile.p2Set = false);
gridPosTile.m1Set = false);
gridPosTile.m2Set = false);
gridPosTile.m3Set = false);
gridPosTile.m4Set = false);
gridPosTile.coinSet = false);
gridPosTile.powerupSet = false);
v += 40;
h++;
// here we add the name property
// try to never use keywords on dynamic classes since sometimes they may already be used
gridPosTile.myName = "tile_" + h;
tileStorage.additem(gridPosTile)
}
}
}
}
}

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)).

Loop through array, set property of each element?

Okay, very simple: there is an array containing 3 objects. Each object has a unique property called "ID" with values of either 1, 2, or 3.
One of the objects gets deleted.
The objective now is to update the ID property of each object corresponding to the new array.length value.
So for example, the object with ID of 2 got deleted. The remaining objects in the array would each have ID values of 1 and 3 respectively.
So the objective is to loop through the array and update the ID properties to 1, and 2 (instead of 1 and 3).
So I guess the question is how to write a loop to update a common property of each element in an array. Thanks.
You can use a for-loop to go through the array, as in walkietokyo's answer, or you can use a method closure:
myArray.forEach ( function ( item:*, i:int, arr:Array) : void { item.ID = i; } );
or a while-loop:
var i:int = -1;
while (++i < myArray.length) myArray[i].ID = i;
for (var i:uint = 1; i <= myArray.length; i++) {
myArray[i].ID = i;
}
General info on loops:
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7fcf.html
var i:uint; // for speed keep out of the loop
var arrayLength = myArray.length // for speed keep out of the loop
for (i = 0; i < arrayLength; i++) {
myArray[i].ID = i;
}