How would one convert from 2x32bit uints to a Number and back (assume max value of 2^52)?
I believe the following would theoretically work (passing around as ByteArray for clarity, but an Array could work as storage as well), But it doesn't because bitwise operators evidently force Number into 32 bits :\
(see: Binary math on Number objects limited to 32 bits?):
public static function read64BitNumberFromBuffer(buffer:ByteArray):Number {
var ch1:uint = buffer.readUnsignedInt();
var ch2:uint = buffer.readUnsignedInt();
var num:Number = ((ch1 << 32) | ch2);
return(num);
}
public static function write64BitNumberToBuffer(num:Number):ByteArray {
var ch1:uint = uint((num & 0xFFFFFFFF00000000) >> 32);
var ch2:uint = uint(num & 0xFFFFFFFF);
var buffer:ByteArray = new ByteArray();
buffer.writeUnsignedInt(ch1);
buffer.writeUnsignedInt(ch2);
return(buffer);
}
One could use a library like as3crypto's BigInteger to handle this, but that seems like an awful lot of bloat for such a discrete need. Is there a robust bit of code that could be injected into the above functions to make them return the correct values?
Although I'd prefer a pure Actionscript solution, as a point of interest- are bitwise operators in Crossbridge also limited to 32 bits? (btw- I need 1500 reputation to create a tag "crossbridge", can someone do it on my behalf?)
EDIT: Tried readDouble()/writeDouble() as well but it seemed to want to switch to reverse the bytes for some reason under a more thorough test (tried playing with endian setting, to no avail other than it did affect output in the wrong way)
OK- this seems to work perfectly:
package
{
import flash.display.Sprite;
import flash.utils.ByteArray;
public class TEMP extends Sprite
{
public function TEMP()
{
var targetNumber:Number = 6697992365;
var buffer:ByteArray = new ByteArray();
var testNumber:Number;
write64BitNumberToBuffer(buffer, targetNumber);
buffer.position = 0;
testNumber = read64BitNumberFromBuffer(buffer);
if(targetNumber == testNumber) {
trace("Passed! Both numbers are", targetNumber);
} else {
trace("Failed! Test number is", testNumber, "When it should be", targetNumber);
}
}
public static function read64BitNumberFromBuffer(buffer:ByteArray):Number {
var finalNumber:Number;
var str:String = '';
var byte:uint;
var chr:String;
while(str.length < 16) {
byte = buffer.readUnsignedByte();
chr = byte.toString(16);
if(chr.length == 1) {
chr = '0' + chr;
}
str += chr;
}
finalNumber = Number('0x' + str);
return(finalNumber);
}
public static function write64BitNumberToBuffer(buffer:ByteArray, num:Number) {
var hexString:String = num.toString(16);
var idx:uint = 16 - hexString.length;
var byte:uint;
while(idx--) {
hexString = '0' + hexString;
}
for(idx = 0; idx < hexString.length; idx += 2) {
byte = uint('0x' + hexString.substr(idx, 2));
buffer.writeByte(byte);
}
}
}
}
Output: Passed! Both numbers are 6697992365
Related
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;
}
}
}
I want to get unique random numbers each time from nos 1-40 without using an array.Is there any optimised way to get this in action script 3.
No, you have to use permutation, as you have to record those numbers you've already generated. And using these numbers require a set of some kind, aka Array. It's possible to solve this issue by using other data types, but they will essentially narrow down to an array of some sort.
A simple permutation code looks like this:
class Permutation {
private var _a:Array; // or Vector.<int> if you like
private var n:int; // next element
public function Permutation() {
reset(1);
}
public function reset(size:int=100):void {
_a.length=0;
for (n=0;n<size;n++) _a.push(n);
for (n=0;n<size;n++) {
var x:int=Math.floor(size*Math.random());
if (x==n) continue;
var swap:int=_a[x];
_a[x]=_a[n];
_a[n]=swap;
}
n=0;
}
public function getNext():int {
if (n==_a.length) return -1; // or any error value
n++;
return _a[n-1];
}
}
No array.
var generatedNumberCount:int;
var generatedNumberRef:Object = {};
for(var i:int = 0; i < 150; i++)
{
var result:Number = generateRandomInt(50);
trace(result);
}
trace(generatedNumberCount)
function generateRandomInt(limit:int):Number
{
if(generatedNumberCount >= limit)
{
return NaN;
}
var output:int = Math.ceil(Math.random() * limit);
while(generatedNumberRef[output] != undefined)
{
output = Math.ceil(Math.random() * limit);
}
generatedNumberRef[output] = true;
generatedNumberCount++;
return output;
}
This is my quadtree class, but i haven't added the collision detection yet, in all the examples online they can get 500 + at 60 fps with collision detection but my one only running at 20 fps without collision detection.
I'm following this tutorial http://gamedevelopment.tutsplus.com/tutorials/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space--gamedev-374 which is java but im using as3
public class Quadtree extends Entity
{
private var Max_objects:int = 1;
private var Max_levels:int = 5;
private var level:int;
private var objects:Vector.<Rectangle>;
public var rectangle:Rectangle;
public var Quadtree_list:Vector.<Quadtree>;
public function Quadtree(tmp_level:int , tmp_rec:Rectangle)
{
level = tmp_level;
objects = new Vector.<Rectangle>();
rectangle = tmp_rec;
Quadtree_list = new Vector.<Quadtree>();
Quadtree_list.length = 3;
}
public function clear():void
{
objects.length = 0;
for (var i:Number = 0; i < Quadtree_list.length ; i++)
{
if (Quadtree_list[i] != null)
{
Quadtree_list[i].clear();
world.remove(Quadtree_list[i]);
Quadtree_list[i] = null;
}
}
}
public function split():void
{
var subWidth:int = rectangle.width / 2;
var subHeight:int = rectangle.height / 2;
var xx:int = rectangle.x;
var yy:int = rectangle.y;
Base._world.add(Quadtree_list[0] = new Quadtree(level + 1, new Rectangle(xx + subWidth, yy, subWidth, subHeight)));
Base._world.add(Quadtree_list[1] = new Quadtree(level+1,new Rectangle(xx ,yy,subWidth,subHeight)));
Base._world.add(Quadtree_list[2] = new Quadtree(level+1,new Rectangle(xx,yy + subHeight,subWidth,subHeight)));
Base._world.add(Quadtree_list[3] = new Quadtree(level+1,new Rectangle(xx + subWidth,yy + subHeight,subWidth,subHeight)));
}
/*
* Determine which node the object belongs to. -1 means
* object cannot completely fit within a child node and is part
* of the parent node
*/
public function get_index(tmp_rect:Rectangle):Number
{
var index:int = -1;
var verticalMidpoint:Number = rectangle.x + (rectangle.width / 2);
var horizontalMidpoint:Number = rectangle.y + (rectangle.height / 2);
// Object can completely fit within the top quadrants
var topQuadrant:Boolean = (tmp_rect.y < horizontalMidpoint && tmp_rect.y + tmp_rect.height < horizontalMidpoint);
// Object can completely fit within the bottom quadrants
var bottomQuadrant:Boolean = (tmp_rect.y > horizontalMidpoint);
// Object can completely fit within the left quadrants
if (tmp_rect.x < verticalMidpoint && tmp_rect.x + tmp_rect.width < verticalMidpoint)
{
if (topQuadrant)
{
index = 1;
}
else if (bottomQuadrant)
{
index = 2;
}
}
else
// Object can completely fit within the right quadrants
if (tmp_rect.x > verticalMidpoint)
{
if (topQuadrant)
{
index = 0;
}
else if (bottomQuadrant)
{
index = 3;
}
}
return index;
}
/*
* Insert the object into the quadtree. If the node
* exceeds the capacity, it will split and add all
* objects to their corresponding nodes.
*/
public function insert(tmp_rect:Rectangle):void
{
if (Quadtree_list[0] != null)
{
var index:int = get_index(tmp_rect);
if (index != -1)
{
Quadtree_list[index].insert(tmp_rect)
return;
}
}
objects.push(tmp_rect);
if (objects.length > Max_objects && level < Max_levels)
{
if (Quadtree_list[0] == null)
{
split();
}
var i:int = 0;
while (i < objects.length)
{
var indexx:int = get_index(objects[i]);
if (indexx != -1)
{
Quadtree_list[indexx].insert(objects[i]);
objects.splice(i, 1);
}
else
{
i++;
}
}
}
}
Can you see why it's not performing very well?
Hard to say for certain without seeing exactly how you're using it. Plus it extends Entity which could be doing ...anything :)
I'm not an expert on Quadtrees either, but if you're calling split() a lot, it looks like it could end up being taxing - lots of instantiation calls to new Quadtree and new Rectangle. If this is indeed a bottleneck, you could look into instantiating one rectangle instance that you just pass around. Same with Quadtree. Or use object pooling so you're at least recycling instead of creating new things like crazy.
I hope that helps :)
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.
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)
}
}
}
}
}