How to avoid create new bitmapData object in loop in AS3? - actionscript-3

I want to store the bitmap data from _sampleTile in array, but I was wondering how to increase the performance. If I do it like this:
var _sampleTile:BitmapData;
var _arrayLenght:int = _tileClipArray.length;
for(var i:int = 0; i < _arrayLenght; ++i){
_sampleTile = new BitmapData(65, 65, false);
_sampleTile.draw(_tileClipArray[int(i)]);
_tileBitmapDataArray[i] = _sampleTile;
}
Then it would do too much constructing job in the loop, right? But if I do as bellow:
var _sampleTile:BitmapData = new BitmapData(65, 65, false);
var _arrayLenght:int = _tileClipArray.length;
for(var i:int = 0; i < _arrayLenght; ++i){
_sampleTile.fillRect(_sourceRectangle, 0x00FFFFFF);
_sampleTile.draw(_tileClipArray[int(i)]);
_tileBitmapDataArray[i] = _sampleTile.clone();
}
The .clone() returns a new BitmapData object so basically the result is the same, right?
In the second example if we replace the _sampleTile.clone() with _sampleTile - is it somehow possible to not store in array a reference to _sampleTile, but get the actual bitmapData from the _simpleTile?

No, you need to create a new BitmapData each iteration... either with clone() or new.
I see a couple alternatives though:
Make your creation asynchronous. Do just a few each frame, till you finish the whole batch.
Create a big BitmapData, draw all tiles in there and use references for the position of each tile. If the tiles are always the same, then you could eventually save the final BitmapData + positions and load them instead of creating them each time you run the application.

Related

How to Adjust Volume in an Audio loop?

How would someone change sound levels of a music playing in a loop? For example, I'm making a game and at a certain frame I want the music level (music.wav) to be decreased to half of its volume.
How could someone do this in AS3?
You are using the word "loop" in a confusing way. In programming, a loop usually refers to one of the "for" loops that looks like this:
for (var i:int = 0; i < 10; i++)
{
//do stuff 10 times
}
I surmise that this is not what you mean by loop, but rather that you would like a MovieClip or the main timeline to decrease the volume of a Sound object at the end of n frames. Or do you just mean the music itself is looping? Hopefully you see the value of asking well written questions. That being said..
Mind you, I haven't tried this, but according to my reference book (ActionScript 3.0 Cookbook by Lott, Schall & Peters) you need to use a SoundTransform object which specifies the volume at which you want the sound to be set. Try this:
var _sound:Sound = new Sound(music.wav); // creates a Sound object which has no internal volume control
var channel:SoundChannel = _sound.play(); // creates a SoundChannel which has a soundTransform property
var transform:SoundTransform = new SoundTransform(); // SoundTransform objects have a property called "volume". This is what you need to change volume.
Now in your loop (or on the frame event that you are using) do this:
transform.volume *= 0.9; // or whatever factor you want to have it decrease
//transform.volume /= 1.1; // or this if you prefer.
channel.soundTransform = transform; //
So anytime you want the volume to decrease by this incremental amount, run this bit of code. Of course, you need to make sure that any variables you set are accessible in the code that is referencing them. One way that comes to mind to do this is with a function.
private function soundDiminish(st:SoundTransform, c:SoundChannel, factor:Number = 0.9):void
{
st.volume *= factor;
c.soundTransform = st;
}
Now, whenever you want to diminish the volume just call the soundDiminish function.
Maybe your frame event looks like this:
function onLoadFrame(fe:Event):void
{
soundDiminish(transform, channel); // 3rd parameter optional
}
If you only want this function to be called every 20 frames then:
function onLoadFrame(fe:Event):void
{
// this is a counter that will count up each time this frame event happens
frameCount ++;
if (frameCount >= 20)
{
soundDiminish(transform, channel); // 3rd parameter optional
frameCount = 0; // reset the frame counter
}
}

In Actionscript 3, how do I create movieclips through a looping statement?

The statement for takes a triple as an argument
(initial value of i, condition to cease looping, i increment)
I want to create a different movie clip each time the loop goes on.
So, I tried:
for (i = 0; i < 9; i++){
var Unit+i:MovieClip = new MovieClip()
}
But, this triggers the following error:
1086: Syntax error: expecting semicolon before plus"
What's the correct syntax, then?
To address the issue. You cannot create a var dynamically by using the var keyword. So doing var Unit+i will give you a syntax error.
You can create an array ahead of time and put your objects in that (as per #Panzercrisis's answer which is perfectly acceptable).
Other ways you can do this:
If you current context is dynamic (like if this is timeline code or part of a dynamic class like MovieClip), you do something like this:
this["Unit"+i] = new MovieClip();
From a compile time checking and code maintenance perspective, this is a little sloppy in my opinion, but for quick timeline projects it's certainly acceptable.
You could also just not store the clip anywhere but the display list:
for(var i:int=0;i<9;i++){
var mc:MovieClip = new MovieClip();
//do whatever you need to do to the clip
//like draw something for instance
mc.graphics.beginFill(0xFF0000);
mc.graphics.drawRect(0,0,100,100);
addChild(mc); //add to the display list so you can see it
}
If you never need to remove this clip, this way is great.
Or, you could add them to a container display object
var clipContainer:Sprite = new Sprite(); //Sprite is the same as movie clip but without the timeline stuff
addChild(clipContainer);
for(var i:int=0;i<9;i++){
var mc:MovieClip = new MovieClip();
//do whatever you need to do to the clip
//like draw something for instance
mc.graphics.beginFill(0xFF0000);
mc.graphics.drawRect(0,0,100,100);
clipContainer.addChild(mc);
}
The clipContainer would then act the same as an array, where you can access all it's children. Also, moving/scalling the container would in turn move/scale all it's children
Basically this is what you want to do:
var arrMovieClips:Array = new Array(9);
for (var i:int = 0; i < arrMovieClips.length; i++)
{
arrMovieClips[i] = new MovieClip();
}
This will create an array with nine elements, so you essentially have nine variables in a row:
arrMovieClips[0]
arrMovieClips[1]
arrMovieClips[2]
...
arrMovieClips[8]
Then it will go through and loop 0, 1, 2, etc. When it gets to the length of arrMovieClips, which is 9, then it'll stop. As it goes through 0-8, it'll create a new MovieClip and store it in each spot.

As3 - Get Movieclips That The Name Start With A Specific String

I'm making a tile based game where ta_*(number)* and ca_*(number)* acts like bins. You drag things towards it and drop. But the level may put several these tiles.
I am not going to make something like:
if (my_mc.hitTestObject(ta_0) || my_mc.hitTestObject(ta_1) || my_mc.hitTestObject(ta_2).........)
Because some may not exist and throw an error at me, and I don't want to make like hundreds of them.
Is there a way to find movieclips on stage that start with the name "ta_" and "ca_"?
So that I can get: ta_1, ta_2.....?
No, you can't. Unless you loop on getChildAt() and check all children's names.
But, why don't you add your bins to an array when creating them?
(I assume you create them dynamically)
var myBinArray:Array = new Array(10);
for (var i:int = 0; i < myBinArray.length; i++)
{
var myBin = new Bin();
myBinArray[i] = myBin;
}
Then you simply loop on your array:
for (var i:int = 0; i < myBinArray.length; i++)
{
if (mybinArray[i] != null)
if (my_mc.hitTestObject(mybinArray[i])
{
// statements
// and here I assume you want to break for loop
}
}

Which one executes faster: hitTestObject or Point.distance?

I am trying to optimize my collision detection alghorithm written in AS3.
I am wondering if there is any improvements in performance if I use
Point.distance(pointObject1, pointObject2);
between two objects instead of using
object1.hitTestObject(object2);
My objects are all more or less convex so the border doesn't really matter.
Point.distance is much more faster (4 and more times!) if your test objects are complicated containers with several children inside. If you use simple Sprite's it'll be only near 25% difference in functions execution time.
It's so, because Point.distance is just counting a hypotenuse from Pythagoras' theorem. So, we've got only 2 subtractions, 1 addition and 3 involutions to count. Many modern processors have involution instruction, so it's fast. If we use hitTest, there are much more actions to be performed. And the number of these actions will grow with the complexity of hitTest'ing Sprite (because it's harder to count it's bounds).
I've just made some tests. The result confirmed that I was right.
var ar:Vector.<Sprite> = Vector.<Sprite>([]); //Sprites for hitTest
for(var i:int = 0; i < 100000; i++) {
var sp:Sprite = new Sprite(); //!The results will be other, is case of use a huge container with come objects here!
sp.graphics.drawCircle(0, 0, randomIntBetween(1, 200)); //add some shapes
sp.graphics.drawRect(0, 0, randomIntBetween(1, 200), randomIntBetween(1, 200));
sp.x = randomIntBetween(-800, 800);
sp.y = randomIntBetween(-800, 600);
sp.rotation = randomIntBetween(-360, 360); //rotate and scale in random way
sp.scaleX = sp.scaleY = Math.random();
ar.push(sp);
}
var tim:Number = new Date().time;
for each(var spr:Sprite in ar) {
ar[0].hitTestObject(spr);
}
tim = new Date().time - tim;
trace(tim);
var pn:Vector.<Point> = Vector.<Point>([]); //Points for Point.distance
for(i = 0; i < 100000; i++) {
var point:Point = new Point(randomIntBetween(-800, 800), randomIntBetween(-800, 800));
pn.push(point);
}
tim = new Date().time;
for each(var pnt:Point in pn) {
Point.distance(pn[0], pnt);
}
tim = new Date().time - tim;
trace(tim);
Actually, you can't compare those two with each other. If all your objects are single-pixel bitmaps the distance test would work fine. But I imagine that is not the case.
hitTestObject essentially checks the bounding rectangles of the objects, so it's pretty fast.
You could always check the distance to see if they're close enough before doing a pixel level check, because it's more expensive and you don't want to do it too much.
The distance check is great for when you set up circular bounds around an object and determining that two such circles do not intersect. If they do intersect then you have to do another check with hitTestObject to ensure the two object shapes actually overlap. So essentially you would use both, the distance check as a first pass check and hitTestObject as a follow up for accuracy.

AS3: How can I construct this Linkage problem?

I want to do something like this with AS3, but I'm new to AS3 and I'm not sure how to go about the coding.
What I need to do is I have 1 x blank MC called all_mc, inside that I need to have 200 x empty_mc all lined up one after another on the x axis.
Each empty_mc is 100px wide and load from a Linkage in the library called panelClass (which is a MovieClip).
The empty_mc itself is called emptyClass in the library.
I need the all_mc to display on the stage from start. It should look like this image. The I need 200 of these red squares.
I know instead of adding all 200 MCs manually, I should be making a loop? But I can not get my head around it for the life of me. Can someone please kindly help me out?
Just make a loop and dynamically create your MovieClips:
var mcWidth:Number = 100; // Using hardcoded value because MovieClip.width is not always reliable (if the MovieClip contains shapes with strokes, etc.)
for (var i:int = 0; i < 200; i++) {
var mc:panelClass = new panelClass();
all_mc.addChild(mc);
mc.name = "empty_mc" + i; // set a name so that it can be accessed later on
mc.x = mcWidth * i;
}