i'm making a simple isometric city builder using action script 3.0.
the concept is like age of empires, so when I push a button a shape will be created and it will follow the cursor until i'll click again on the stage and in this way an house will be placed.
but I've some problems with the order of visualization when more house collide between them.
You want to sort the sprites from back to front when a new item is added, here is some sample code that does that.
private function sortItems():void
{
var sprites:Array = [];
for (var i:int = 0; i < map.numChildren; ++i) {
var c:DisplayObject = map.getChildAt(i);
sprites.push(c);
}
sortSprites(sprites);
}
private function sortSprites(sprites:Array):void
{
sprites.sort(sortCompare);
var index:int = 0;
for (var j:int = 0; j < sprites.length; j++) {
index = map.getChildIndex(sprites[j]);
if (index != j)
map.setChildIndex(sprites[j], j);
}
}
private function sortCompare(a:DisplayObject, b:DisplayObject):int
{
return ((a.y + a.height) - (b.y + b.height));
}
Related
The assignment is the spawn several light and dark feathers according to score points from a quiz. The light feathers symbolize the correct points (light_feather), and the dark feather are the incorrect points (dark_feather) (Each are being tracked). All the feathers are supposed to line up on one line, meaning first light feathers, followed by the dark feathers. I got the quiz dynamics figured out, and the function I have posted here is only for when they press end quiz.
var light_feather:LightFeather = new LightFeather();
var dark_feather:DarkFeather = new DarkFeather();
var good_answers:uint = 0;
var bad_answers:uint = 0;
function avsluttFunc (evt:MouseEvent)
{
var sum_LightFeatherX:Number = 0;
for (var i = 0; i < good_answers; i++) {
addChild(light_feather);
light_feather.x += 12 + (i*16);
light_feather.y = 0;
trace("Lys X-verdi: " + light_feather.x);
sum_LightFeatherX += Number(light_feather.x);
return sum_LightFeatherX;
}
trace(sum_LightFeatherX);
dark_feather.x += sum_LightFeatherX;
for (var j = 1; j <= bad_answers; j++) {
addChild(dark_feather);
dark_feather.x += 12 + (j*16);
dark_feather.y = 0;
trace("Mørk X-verdi: " + dark_feather.x);
}
/*
//Resetter poengsummen
good_answers = 0;
bad_answers = 0;
*/
}
You can do what you are looking for using only one for loop, take a look :
var good_answers:uint = 2;
var bad_answers:uint = 4;
function avsluttFunc(evt:MouseEvent)
{
for (var i:int = 0; i < good_answers + bad_answers; i++) {
var feather:DisplayObject = i < good_answers ? new LightFeather() : new DarkFeather();
feather.x += 12 + i * (feather.width + 1);
feather.y = 0;
addChild(feather);
}
}
This code example will create 4 DarkFeather instances next to 2 LightFeather ones.
Edit :
How to add your objects to an array ?
// feathers array should be accessible for both codes (adding and removing objects)
var feathers:Array = [];
for (var i:int = 0; i < good_answers + bad_answers; i++) {
var feather:DisplayObject = i < good_answers ? new LightFeather() : new DarkFeather();
addChild(feather);
feathers.push(feather);
}
then to remove them from the stage, you can do for example :
for (var i:int = 0; i < feathers.length; i++) {
var feather:DisplayObject = DisplayObject(feathers[i]);
feather.parent.removeChild(feather);
}
Hope that can help.
As I said: Is there any difference (in performance) between these two for loop?
Between this:
var n:int = displayObjects_.length;
for (var i:int = 0; i < n; i++)
{
var currentObject:DisplayObject = displayObjects_[i];
currentObject.width = newWidth;
}
and this:
var n:int = displayObjects_.length;
for (var i:int = 0; i < n; i++)
{
displayObjects_[i].width = newWidth;
}
I tested them before. The result said the first one was faster but I don't know if I did it right.
I know it's not really an answer to your question, but if you're looking for fastest way to iterate through this array you should do:
for each(var currentObject:DisplayObject in displayObjects_) {
currentObject.width = newWidth;
}
I tried this out on a bare-bones project using SDK 4.6. This is the code.
public class Main extends Sprite
{
public function Main()
{
var displayObjects_:Array = [];
for (var i:int = 0; i < 1000000; i++)
{
displayObjects_.push(new Sprite());
}
var start:int = getTimer();
for (i = 0; i < displayObjects_.length; i++)
{
var currentObject:Sprite = displayObjects_[i];
currentObject.width = 100;
}
var end:int = getTimer()
trace(end, start, end - start);
start = getTimer();
for (i = 0; i < displayObjects_.length; i++)
{
displayObjects_[i].width = 100;
}
end = getTimer()
trace(end, start, end - start);
}
}
These are the results.
Done(0)
[Starting debug session with FDB]
16703 16250 453
17141 16703 438
Like I said, it would be very surprising to see any difference between the two. You'll probably see more improvements through using Vector instead of Array. Otherwise, this stuff is too mundane to fuss over.
As I know, Actionscript compiler automatically moves variable definitions to the begin of the function. So, this loop doesn't declare variable each time, first sample the same that:
var currentObject:DisplayObject;
var n:int = displayObjects_.length;
for (var i:int = 0; i < n; i++)
{
currentObject = displayObjects_[i];
currentObject.width = newWidth;
}
So, I think the difference only in one additional variable declare and it willn't affects performance. But 3vilguy's example is better.
Im currently trying to make a road movement animation but cant figure how the road must not scale itself.
The whole code isn`t mine it is from a tutorial ,I just tried to modify it to my needs ,but I cant do the part that the road should move like if Im seeing it from above(bird view) ,at always same speed.
currently i have this swf file
http://www.stouchgames.com/APKs/Road.swf
I dont want it to be like little lines in the top and then in the bottom a big line that moves.I just want to be equally Big lines that move from top to bottom.
So far i have a simple movieClip with 2 frames and the frames have the graphics in this picture:
http://stouchgames.com/APKs/road.jpg
and this code :
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Main extends MovieClip {
//Depth of the visible road
private const roadLines:int = 320;
//Dimensions of the play area.
private const resX:int = 480;
private const resY:int = 320;
//Line of the player's car.
private const noScaleLine:int = 8;
//All the road lines will be accessed from an Array.
private var yMap:Array = [];
private var lines:Array = [];
private var halfWidth:Number;
private var lineDepth:int;
private const widthStep:Number = 0;
private var playerY:Number;
private var speed:int = 2;
private var texOffset:int = 100;
public function Main() {
//Populate the zMap with the depth of the road lines
for (var i:int = 0; i < roadLines; i++) {
yMap.push(1 / (i - resY));
}
playerY = 100 / yMap[noScaleLine];
for (i = 0; i < roadLines; i++) {
yMap[i] *= playerY;
}
//Make the line at the bottom to be in front of the rest,
//and add every line at the same position, bottom first.
lineDepth = numChildren;
for (i = 0; i < roadLines; i++) {
var line = new Road();
lines.push(line);
addChildAt(line, lineDepth);
line.x = resX / 2;
line.y = resY - i;
}
//Scaling the road lines according to their position
addEventListener(Event.ENTER_FRAME, race);
}
private function race(event:Event):void {
for (var i:int = 0; i < roadLines; i++) {
if ((yMap[i] + texOffset) % 100 > 50) {
lines[i].gotoAndStop(1);
} else {
lines[i].gotoAndStop(2);
}
}
texOffset = texOffset + speed;
while (texOffset >= 100) {
texOffset -= 100;
}
}
}
}
i did try to just make just 2 road movieClips with the different graphics ,then use a
for (var i:int = 0; i < 8; i++) {
if (((i % 2) == 0)) {
var line = new Road ;
lines.push(line);
addChildAt(line,lineDepth);
line.x = resX / 2;
line.y = resY - i * 50;
line.alpha = .2;
}
if (((i % 2) == 1)) {
var line = new Road2 ;
lines.push(line);
addChildAt(line,lineDepth);
line.x = resX / 2;
line.y = resY - i * 50;
line.alpha = .5;
}
but then when i get in the Event.EVERY frame function i cant make them move smoothly ... and decided it must be done by the 1st way cause of the much more detailed ending and cause in the end if i want to change the resolutions of the road i can do it much easier with it . Ofcourse i could be wrong cause i haven`t done such a thing like this before.
So can someone help ?
replace yMap[i] with i in race function:
for (var i:int = 0; i < roadLines; i++) {
if ((i + texOffset) % 100 > 50) {
lines[i].gotoAndStop(1);
} else {
lines[i].gotoAndStop(2);
}
}
I have a setupBoard(); and a setupBlocks(); in my function:
function init(e)
{
setupBoard();
removeEventListener(Event.ENTER_FRAME , init);
setupCat();
setupBlocks();
}
function setupBoard()
{
var columns:Array = new Array();
var i,j:int;
var _place:place;
for (i = 0; i < 11; i++)
{
columns = [];
for (j = 0; j < 11; j++)
{
_place = new place();
_place.thisX=i;
_place.thisY=j;
_place.thisDistance=Math.min(i+1,j+1,11-i,11-j)*11;
_place.y = 56 * i + 3;
_place.x = 5 + 71 * j + 35*(i%2);
_place.buttonMode=true;
_place.addEventListener(MouseEvent.CLICK, setBlock);
columns[j] = _place;
// SÆTTER TAL PÅ BRIKKERNE
_place.thisText.text = _place.thisDistance + " - " + _place.thisX + " : " + _place.thisY;
addChild(_place);
}
rows[i] = columns;
}
}
The "place" is the MovieClip
this function loads when the game launches and when the game is finish/completed..
the setupBoard, setup the board ofc, and the setupBlocks setup some movieclips, which contain some graphic.
Here's my question, how do I remove/reload all the blocks when the game enters that function again?
At the moment they are just placed upon each other, which I don't like at all.
If I understood correctly, what you want to do is remove all the previous blocks (from the last time you ran the setup function) when you run setup a second time.
To do that, you should create a function which loops your rows and columns Arrays, and for each Place object it find, it does the following: removes it from the stage, removes all Event Listeners, and finally sets it to null. Your function could look something like this (and you would call it just before calling setup again):
for (i = 0; i < rows.length; i++)
{
var column:Array = rows[i];
for (j = 0; j < column.length; j++)
{
var place:Place = column[j];
if (contains(place))
{
removeChild(place);
}
place.removeEventListener(MouseEvent.CLICK, setBlock);
place = null;
}
column = [];
}
row = [];
I just wrote that straight into the box, so it's not tested. But basically it does the three things necessary to get those objects removed from the view, and clears up anything that would stop them from being freed from memory by the garbage collector.
Hope that helps.
Debu
I'm looking for an efficient way to filter a specific color from a bitmapData object in ActionScript 3. Currently I use a loop with readByte32(). This takes about a second to process which is unacceptable. I have been trying to get paletteMap() to work but so far haven't been able to grasp its API (any truly useful links? Google has failed me...).
Here's my current logic, which I want to improve:
var n:int = bitmapData.width;
for (var i:int = 0; i < n; i++) {
var m:int = bitmapData.height;
for (var j:int = 0; j < m; j++) {
var color:int = bitmapData.getPixel(i, j);
if (color == 0xCACACA) {
bitmapData.setPixel32(i, j, 0x00000000);
}
}
}
I can get slightly better performance from using Vectors but it's only marginally better...
var v:Vector.<uint> = bitmapData.getVector(bitmapData.rect);
var n:int = bitmapData.width * bitmapData.height;
for (var i:int = 0; i < n; i++) {
var color:uint = v[i];
v[i] = color == 0xFFCACACA ? 0x00000000 : color;
}
bitmapData.setVector(bitmapData.rect, v);
I really think there must be a better way to do this that only takes a few 100 milliseconds. If anyone can unlock the mysteries of bitmapData for me, you will be the new leader of my people.
PS I am using bitmapData.lock() and unlock(); I just didn't post the boilerplate stuff.
An easy way is using the threshold method. It's a bit cumbersome at first, but it's pretty fast (as fast as you'll get, I think)
This will change every red pixel (considering red only a pixel whose value is exactly 0xffff0000) to blue (0xff0000ff).
var colorToReplace:uint = 0xffff0000;
var newColor:uint = 0xff0000ff;
var maskToUse:uint = 0xffffffff;
var rect:Rectangle = new Rectangle(0,0,bitmapData.width,bitmapData.height);
var p:Point = new Point(0,0);
bitmapData.threshold(bitmapData, rect, p, "==", colorToReplace,
newColor, maskToUse, true);
Flash has an API to a shader like language called pixel bender that may be of use to you in this case. Here is a tutorial from adobe on how to apply a pixel bender filter to an image in flash.
Otherwise you could processes rows at a time. (Note a slight error in your code was to re-get the height on each iteration of width):
private var currentRow:Number = 0;
private var timer:Timer;
public function processImage(event:Event=null):void
{
var m:int = bitmapData.height;
for (var j:int = 0; j < m; j++)
{
if (bitmapData.getPixel(currentRow, j) == 0xCACACA)
{
bitmapData.setPixel32(currentRow, j, 0x00000000);
}
}
currentRow++;
if(currentRow < bitmapData.width)
{
timer = new Timer(1, 500);
timer.addEventListener(TimerEvent.COMPLETE, processImage);
timer.start();
}
}
The processing will take a bit longer but at least your display won't be blocked.