How to scale objects to a certain size? - actionscript-3

I have a question about scaling objects. I have a function that calculates the target scale of a group of objects. The scale is dependant on the amount of objects. At the same time I want the objects to have a maximum scale. I want the objects to be no bigger than 55 pixels wide. So I divide the 55 by the object width to get the maximum scale. So I came up with the following function:
private function setScale():Number
{
//The 6 is just a random number I chose.
scale = 6/amountObjects;
if (scale >= 55/averageObjectWidth)
{
scale = 55/averageObjectWidth;
}
return scale;
}
The problem I have is that when I perform this function multiple times I eventually get the wrong scale. I'll illustrate this in the following example:
I have ten objects, so the scale would be 0.6.
The average object width is 138, so the maximum scale is about 0.4.
So I would then scale the objects with this scale factor. The new width would be then 55.
Then when the amount of objects changes I run this function again. Now there are 9 objects, the new scale based on the amount of objects becomes about 0.7. Here is the pickle now, since the new object width is 55 when I do scale = 55/averageObjectWidth... I get 1! Meaning that it will skip the if statement and return me a scale of 0.7.
All I want to do is have this class return me a scale based on the amount of objects, that is still under the width of 55.
I hope I was clear enough and thank you for your time.

Would I be right in assuming that these objects are Sprites?
In which case when you set the scale/width/height of the sprite you are setting its scale. So to get the 'true'/unscaled width you could use sprite.width / sprite.scaleX (or set the scale back to 1, but you'd have to set it back again, that may cause weird graphical glitches)

Related

Actionscript 3, What is the difference is between scale and dimension

I'd like to know if I change the scale value, what happened to the object? I'm using flash air system.
I draw a movie clip box with 1000 x 1000px dimension.
I might change the size with 2 ways :
1st : Control of dimension with mc.with or mc.height
2nd : Control of dimension with mc.scaleX or mc.scaleY
Once I try to change the object with 500 x 500px,
Which one do you prefer : mc.width = mc.height = 500 vs mc.scaleX = mc.scaleY = 0.5
What is the benefit of using scale method?
Some good reading in the documentation here.
Basically they do exactly the same thing. It just depends on the case which one is easier for the developer to define in that case. If you know you need the result to be as wide as 212 pixels or the same width as object1 it makes sense to say
object2.width = 212;
or
object2.width = object1.width;
Let's assume you prefer to keep object2's dimensions proportional. You could then say
object2.scaleY = object2.scaleX;
without even knowing how many pixels that is or having another object of that same height to set it to.
The final note is this: if you change scale, dimension changes, and when you change dimension, scale also does change. In other words, setting scaleX to 1 will also set it back to its original width. Use them interchangeably. Use the one that is simpler for you in that instance.

HTML5 Canvas save() and restore() performance

So the issue that I'm having is that in developing an HTML5 canvas app I need to use a lot of transformations (i.e. translate, rotate, scale) and therefore a lot of calls being made to context.save() and context.restore(). The performance drops very quickly even with drawing very little (because the save() and restore() are being called as many times as possible in the loop). Is there an alternative to using these methods but still be able to use the transformations? Thank you!
Animation and Game performance tips.
Avoid save restore
Use setTransform as that will negate the need for save and restore.
There are many reasons that save an restore will slow things down and these are dependent on the current GPU && 2D context state. If you have the current fill and/or stroke styles set to a large pattern, or you have a complex font / gradient, or you are using filters (if available) then the save and restore process can take longer than rendering the image.
When writing for animations and games performance is everything, for me it is about sprite counts. The more sprites I can draw per frame (60th second) the more FX I can add, the more detailed the environment, and the better the game.
I leave the state open ended, that is I do not keep a detailed track of the current 2D context state. This way I never have to use save and restore.
ctx.setTransform rather than ctx.transform
Because the transforms functions transform, rotate, scale, translate multiply the current transform, they are seldom used, as i do not know what the transform state is.
To deal with the unknown I use setTransform that completely replaces the current transformation matrix. This also allows me to set the scale and translation in one call without needing to know what the current state is.
ctx.setTransform(scaleX,0,0,scaleY,posX,posY); // scale and translate in one call
I could also add the rotation but the javascript code to find the x,y axis vectors (the first 4 numbers in setTransform) is slower than rotate.
Sprites and rendering them
Below is an expanded sprite function. It draws a sprite from a sprite sheet, the sprite has x & y scale, position, and center, and as I always use alpha so set alpha as well
// image is the image. Must have an array of sprites
// image.sprites = [{x:0,y:0,w:10,h:10},{x:20,y:0,w:30,h:40},....]
// where the position and size of each sprite is kept
// spriteInd is the index of the sprite
// x,y position on sprite center
// cx,cy location of sprite center (I also have that in the sprite list for some situations)
// sx,sy x and y scales
// r rotation in radians
// a alpha value
function drawSprite(image, spriteInd, x, y, cx, cy, sx, sy, r, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(sx,0,0,sy,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,-cx,-cy,w,h); // render the subimage
}
On just an average machine you can render 1000 +sprites at full frame rate with that function. On Firefox (at time of writing) I am getting 2000+ for that function (sprites are randomly selected sprites from a 1024 by 2048 sprite sheet) max sprite size 256 * 256
But I have well over 15 such functions, each with the minimum functionality to do what I want. If it is never rotated, or scaled (ie for UI) then
function drawSprite(image, spriteInd, x, y, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(1,0,0,1,x,y); // set scale and position
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,0,0,w,h); // render the subimage
}
Or the simplest play sprite, particle, bullets, etc
function drawSprite(image, spriteInd, x, y,s,r,a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(s,0,0,s,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,-w/2,-h/2,w,h); // render the subimage
}
if it is a background image
function drawSprite(image){
var s = Math.max(image.width / canvasWidth, image.height / canvasHeight); // canvasWidth and height are globals
ctx.setTransform(s,0,0,s,0,0); // set scale and position
ctx.globalAlpha = 1;
ctx.drawImage(image,0,0); // render the subimage
}
It is common that the playfield can be zoomed, panned, and rotated. For this I maintain a closure transform state (all globals above are closed over variables and part of the render object)
// all coords are relative to the global transfrom
function drawGlobalSprite(image, spriteInd, x, y, cx, cy, sx, sy, r, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
// m1 to m6 are the global transform
ctx.setTransform(m1,m2,m3,m4,m5,m6); // set playfield
ctx.transform(sx,0,0,sy,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a * globalAlpha; (a real global alpha)
ctx.drawImage(image,spr.x,spr.y,w,h,-cx,-cy,w,h); // render the subimage
}
All the above are about as fast as you can get for practical game sprite rendering.
General tips
Never use any of the vector type rendering methods (unless you have the spare frame time) like, fill, stroke, filltext, arc, rect, moveTo, lineTo as they are an instant slowdown. If you need to render text create a offscreen canvas, render once to that, and display as a sprite or image.
Image sizes and GPU RAM
When creating content, always use the power rule for image sizes. GPU handle images in sizes that are powers of 2. (2,4,8,16,32,64,128....) so the width and height have to be a power of two. ie 1024 by 512, or 2048 by 128 are good sizes.
When you do not use these sizes the 2D context does not care, what it does is expand the image to fit the closest power. So if I have an image that is 300 by 300 to fit that on the GPU the image has to be expanded to the closest power, which is 512 by 512. So the actual memory footprint is over 2.5 times greater than the pixels you are able to display. When the GPU runs out of local memory it will start switching memory from mainboard RAM, when this happens your frame rate drops to unusable.
Ensuring that you size images so that you do not waste RAM will mean you can pack a lot more into you game before you hit the RAM wall (which for smaller devices is not much at all).
GC is a major frame theef
One last optimisation is to make sure that the GC (garbage collector) has little to nothing to do. With in the main loop, avoid using new (reuse and object rather than dereference it and create another), avoid pushing and popping from arrays (keep their lengths from falling) keep a separate count of active items. Create a custom iterator and push functions that are item context aware (know if an array item is active or not). When you push you don't push a new item unless there are no inactive items, when an item becomes inactive, leave it in the array and use it later if one is needed.
There is a simple strategy that I call a fast stack that is beyond the scope of this answer but can handle 1000s of transient (short lived) gameobjects with ZERO GC load. Some of the better game engines use a similar approch (pool arrays that provide a pool of inactive items).
GC should be less than 5% of your game activity, if not you need to find where you are needlessly creating and dereferencing.

How to fix the map layer scale size in mapserver(ms4w)

Sample layer map file is:
LAYER
NAME "abc"
STATUS OFF
CONNECTIONTYPE POSTGIS
CONNECTION ""
DATA ""
TYPE polygon
TRANSPARENCY 100
MINSCALEDENOM 1
MAXSCALEDENOM 4000
METADATA
"fields" "layer"
END
CLASS
NAME 'abc'
MINSCALEDENOM 1000
MAXSCALEDENOM 4000
STYLE
OUTLINECOLOR 21 58 224
COLOR 151 219 242
END
END
END
How to fix the map layer scale size of 1:4000 ratio In map file of map script mode in Map Server(ms4w)
can any body help me ?
It is doable but requires a lot of effort to do so.
It is challenging because the scale is the default parameter for WMS getMap operation. The generic WMS getmap operation with a bbox with two coordiantes comes with a width and height as the output parameter. Without knowing what the output width and height will be, it will be hard to simply
The bbox of two pairs of coordinates and the width and height are the parameters decided what is the scale of the output image.
Imagine we have an interest area and a fixed scale at 1:4000.
So in some part of the system we need to get the height and width of the output in a situation like a window in a front end application or a print map extend. we will need to calculate the center point of the area/shape for the output, then recalculate the bbox coordinates based on pixels to the center point in width and height. Then use the new two pairs of coordinates and the height and weight to do the wms getmap request.
In this way the center part is still remain in the middle and the bbox may changed to make sure the scale is fixed as expected.This is complicated at server side using mapserver alone but can be easily managed by using other applications/APIs like OL3,leaflet,ArcGIS Javascript API etc. which has the function to force the output to be in a fixed scale.

Proper using of scene2d's Stage in a game with a huge world

If the whole "game world" is thousands of times wider than a viewport, and if I want to use scene2d to manage game objects as Actors, should I create Stage object as wide as the whole world, or should the Stage be some area around current viewport but not the whole world?
In other words, does a Stage with greater width and height consume more memory itself, even if I render objects only on a small viewport-sized part of it?
I think you misunderstood what exactly a Stage is. A Stage doesn't really have a size itself. You don't specify a width or height or the Stage, you only specify the width and height of the viewport. The viewport is like a window, which shows only a part of your world, aka scene. A Stage is a 2D scene graph and it "grows" with your Actors. The more Actors you have, the bigger (memory wise) your Stage is, but it doesn't depend on how far spreaded your Actors actually are. If they are very far spreaded and you only display a very small part of your whole Stage, it will be handled very efficient, because a scene graph sub-divides this huge space to be able to very quickly decide whether to ignore a certain Actor, or draw it on the Screen.
That means a Stage is actually exactly what you need for this kind of situation and you should probably not have any problems, FPS and memory wise. But of course if your Stage is 1000s of times the size of your viewport and you know yourself that certain Actors aren't displayed soon, then it might make sense to not add them to the Stage yet.
A stage is only a root node that will hold all the actors. It's role is to call methods for its children (like draw and act); thus only the number and complexity of actor have an impact on memory and frame rate.
For your situation a culling method is certainly required. The simplest one would be to check if an actor is in the viewport and if not skip drawing him. Create a custom actor and add this code: source
public void draw (SpriteBatch batch, float parentAlpha) {
// if this actor is not within the view of the camera we don't draw it.
if (isCulled()) return;
// otherwise we draw via the super class method
super.draw(batch, parentAlpha);
}
Rectangle actorRect = new Rectangle();
Rectangle camRect = new Rectangle();
boolean visible;
private boolean isCulled() {
// we start by setting the stage coordinates to this
// actors coordinates which are relative to its parent
// Group.
float stageX = getX();
float stageY = getY();
// now we go up the hierarchy and add all the parents'
// coordinates to this actors coordinates. Note that
// this assumes that neither this actor nor any of its
// parents are rotated or scaled!
Actor parent = this.getParent();
while (parent != null) {
stageX += parent.getX();
stageY += parent.getY();
parent = parent.getParent();
}
// now we check if the rectangle of this actor in screen
// coordinates is in the rectangle spanned by the camera's
// view. This assumes that the camera has no zoom and is
// not rotated!
actorRect.set(stageX, stageY, getWidth(), getHeight());
camRect.set(camera.position.x - camera.viewportWidth / 2.0f,
camera.position.y - camera.viewportHeight / 2.0f,
camera.viewportWidth, camera.viewportHeight);
visible = (camRect.overlaps(actorRect));
return !visible;
}
If you need to improve performance even further you can switch to manually deciding what is visible and what not (ex when moving the camera). This would be faster because all those culling calculations are executed at EVERY frame, for EVERY actor. So although it's a lot faster to do some math instead of drawing, a big number of actors would give a huge amount of unwanted calls.

Comparing two bitmaps against each other for match as3

I'm trying to position an image on top of another image based upon the make-up of the smaller image. The smaller image is a cut-out of a larger image and I need it to be positioned exactly on the larger image to make it look like a single image, but allow for separate filters and alphas to be applied. As the images are not simple rectangles or circles, but complex satellite images, I cannot simply redraw them in code. I have quite a few images and therefore do not feel like manually finding the position of each image every and hard setting them manually in actionscript. Is there any way for me to sample a small 5-10 sq. pixel area against the larger image and set the x and y values of the smaller image if a perfect match is found? All the images are in an array and iterating through them has already been set, I just need a way to sample and match pixels. My first guess was to loop the images pixel by pixel right and down, covering the whole bitmap and moving to the next child in the array once a match was found, leaving the matched child where it was when the perfect match was found.
I hope I understood your question correctly.
There may be an option that uses copypixels to achieve what you want. You can use the bitmapdata.rect value to determine the size of the sample you want, and loop through the bigger bitmap using thet rectangle and a moving point. Let's see if I can code this out...
function findBitmapInBitmap(tinyimg:BitmapData, largeimg:BitmapData):Point {
var rect:Rectangle = tinyimg.rect;
var xbound:uint = largeimg.rect.width;
var ybound:uint = largeimg.rect.height;
var imgtest:BitmapData = new BitmapData(tinyimg.rect.width, tinyimg.rect.height);
for (var ypos:uint = 0, y <= ybound, y++) {
for (var xpos:uint = 0, x <= xbound, x++) {
imgtest.copyPixels(largeimg, rect, new Point(xpos, ypos);
if (imgtest.compare(tinyimg) == 0) return new Point(xpos, ypos);
}
}
return new Point(-1,-1); // Dummy value, indicating no match.
}
Something along those lines should work - I'm sure there's room for code elegance and possible optimization. However, it seems like something like this method would be very slow, since you'd have to check each pixel for a match.
There is a better way. Split your big image into layers, and use the blitting technique to composite them at runtime. In your case, you could create a ground texture without satellites, and then create the satellites separately, and use the copyPixels method to place them whereever you want. Google "blitting in as3" to find some good tutorials. I'm currently working on a game project that uses this technique and it's a very good method.
Good luck!
Edit: Forgot to code in a default return statement. Using this method, you'd have to return an invalid point (like (-1,-1)) and check for it outside the function. Alternatively, you could just copy your small bitmap to the big one within the function, which would be much more logical, but I don't know your requirements.
You need to find pixel sequence in the big image. BitmapData.getPixel gives you pixel value. So get first pixel from small image, find it in big image, then continue comparing until you find full match. If you have trouble to code that, feel free to ask.
For the actual comparison, there's BitmapData.compare which returns the number 0 if the BitmapData objects are equivalent.