insertAt and removeAt vector methods missing from cs4 but present in documentation - actionscript-3

I seem to be having some trouble with the vector methods removeAt and insertAt, they are both present in the documentation for as3:
"https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Vector.html#insertAt()"
And yet in adobe flash cs4 they are undefined and throw up errors. Does cs4 not have these methods or is the documentation poor?

Well, there's an option other then upgrading to newest version of Flash Player and SDK. It is not a better option, not very elegant, yet simpler. Unless you are running some huge datasets, performance of the VPlus.insertAt(...) implementation is not an issue too.
Implementation:
package
{
public class VPlus
{
static public function deleteAt(V:*, index:int):void
{
// The method cuts a portion of Vector and returns it.
// We need just the "cut" part, yet it suffices.
V.splice(index, 1);
}
static public function insertAt(V:*, index:int, element:*):void
{
// Fix for from-the-end-and-backwards indexing.
if (index < 0)
{
index = V.length - index;
}
// Add one more element to the end of the given Vector.
V.push(null);
// Shift the Vector's elements from index and on.
for (var i:int = V.length - 2; i >= index; i--)
{
V[i+1] = V[i];
}
// Put the new element to its designated place.
V[index] = element;
}
}
}
Usage:
// myVec.deleteAt(10);
VPlus.deleteAt(myVec, 10);
// myVec.insertAt(15, "Hello World!");
VPlus.insertAt(myVec, 15, "Hello World!");

Related

as3 - Detect if object is moved to another object using timer

I was creating a shooting game that the target is appear and disappear any seconds. I don't know how use the codes and I don't know how to detect the object to object when using if statement.
Here's my codes:
import flash.utils.Timer;
var dummySX: Number = dummyS.x;
var dummySY: Number = dummyS.y;
var targetTimeStart: Timer = new Timer(1000);
targetTimeStart.start();
targetTimeStart.addEventListener(TimerEvent.TIMER, targetTimeStartNow);
function targetTimeStartNow(e: TimerEvent): void {
target.x = dummySX;
target.y = dummySY;
targetTimeStart.stop();
}
function detect(): void {
if ((target.x == dummySX) && (target.y == dummySY)) {
trace("DETECTED");
}
}
or
function detect(): void {
if (target.hitTestObject(dummyS)==true) {
trace("DETECTED");
}
}
Thanks!!
There are several ways to detect hit between objects.
Let's say you have 2 display objects (do1 and do2)
First of all there is the do1.hitTestObject(do2). This method is very fast and works well for rectangular objects. You can get some visually "false" results if the rectangular objects are rotated or you use it with other than rectangular objects.
Next there is the do1.hitTestPoint(do2.x, do2.y, shapeFlag). This method is slower but more accurate, especially when you set the shapeFlag to true. It tests the hit against a single point (x & y coordinates).
There is a third method (hitTest) that implies you use BitmapData objects and that is even more precise and is specific the the BitmapData class, but much harder to process (being able to ignore transparent pixels).
A fourth option would be to do a custom implementation of the hit detection, but it seems a bit off to detail that here.
Going over your code, I see you create a 1 second Timer object and start it, after which you add a listener with the targetTimeStartNow function. In that function you move the target object to the same position of the dummyS object and after that you stop the targetTimeStart Timer object. That means that you have only 1 entry in that function.
The detect function seems that is never called from your code, although both calls should trace DETECTED.
The first detect function that you've written mimics the hitTestPoint version.
function detect(): void {
if ((target.x == dummySX) && (target.y == dummySY)) {
trace("DETECTED");
}
}
This is the same with:
function detect():void {
if(target.hitTestPoint(dummySX, dummySY, false)) {
trace("DETECTED");
}
}
It'd be better to use this variant (in order to use the shape of the object, and not their bounding box):
function detect():void {
if(target.hitTestPoint(dummySX, dummySY, true)) {
trace("DETECTED");
}
}
The second detect function uses the hitTestObject and it's ok. You could use it without explicitly == true:
function detect(): void {
if(target.hitTestObject(dummyS)) {
trace("DETECTED");
}
}
The only thing is to call it in code in order to get it executed. So somewhere after the target object was moved just add:
detect();
Depending on your needs, you could add it to the targetTimeStartNow method (or add an EnterFrame listener, or create another Timer object):
function targetTimeStartNow(e: TimerEvent): void {
target.x = dummySX;
target.y = dummySY;
targetTimeStart.stop();
detect();
}

Haxe Map Memory Cleanup Issue

So I have been using Haxe for a while and it has occurred to me recently that I don't really get what happens on some other the non-flash targets as far as memory cleanup. I mean 'new'ing everything and dumping it by setting references to null gives me this feeling that there are memory leakages, but I can't seem to find the documentation I'm looking for.
Specifically I use dictionaries/maps a decent amount. Like this:
var items:Map<String, MyObject> = new Map();
items.set("someKey", new MyObject(args...));
// Later
items["someKey"].doSomething();
items["someKey"].setVal(2);
...
// When Finished
items.remove("someKey");
The last line there just dumps my object somewhere into oblivion and hopefully gets garbage collected (at least on the Flash target).
I put together a little program just to see the cleanup in action on Flash/Neko and then change it for other targets, but I am failing to even see the cleanup on the Flash Neko target. Here is the project code:
package;
import openfl.display.Sprite;
import openfl.events.Event;
import haxe.ds.StringMap;
import openfl.events.KeyboardEvent;
import openfl.ui.Keyboard;
class Main extends Sprite
{
private var keypressID:Int;
private var itemID:Int;
private var dict:StringMap<Sprite>; // Using this since I read Map<String, T> just compiles to StringMap<T>.
public function new()
{
super();
addEventListener(Event.ENTER_FRAME, init);
}
private function init(event:Dynamic):Void
{
removeEventListener(Event.ENTER_FRAME, init);
// Entry point.
keypressID = 0;
itemID = 0;
dict = new StringMap();
stage.addEventListener(KeyboardEvent.KEY_UP, keyPress);
}
private function keyPress(event:Dynamic):Void
{
if (Std.is(event, KeyboardEvent) && cast(event, KeyboardEvent).keyCode == Keyboard.A)
{
trace('ID: $keypressID - Adding Item');
keypressID += 1;
for (i in 0...10000)
{
itemID += 1;
dict.set('$itemID', new Sprite());
}
}
else if (Std.is(event, KeyboardEvent) && cast(event, KeyboardEvent).keyCode == Keyboard.R)
{
trace('ID: $keypressID - Removing Items');
keypressID += 1;
removeItems();
}
// Force garbage collector to run.
else if (Std.is(event, KeyboardEvent) && cast(event, KeyboardEvent).keyCode == Keyboard.C)
{
trace('ID: $keypressID > Starting GC');
keypressID += 1;
forceGarbageCollection();
}
}
private function removeItems()
{
trace('ID: $keypressID > Remove All Item');
for (val in dict.keys())
{
dict.remove(val);
}
dict = new StringMap();
}
private function forceGarbageCollection():Void
{
neko.vm.Gc.run(true); // This does not work.
}
}
I run this on Windows and under task manager, my neko process only grows and never shrinks. Its gets up to 500MB quick when hitting 'A'. I then 'R' to remove all references to the items, but they never get collected it seems even when I force the GC.
I also tried storing openfl.util.Timer objects with event listeners attached to them to do traces and they never seem to get collected either. They just keep tracing. Now I suspect that may be because of the event listener reference, but am sure I have seen that trick in other AS3 memory leak tracking code.
Am I missing something or doing something wrong?
Edit:
I have modified the above question to reflect this, but I was mistaken about Flash player. I did get the memory to be reclaimed when running in the Flash player using flash.system.System.gc(); It seems the problem may be specific to neko which my question still addressed.

Clearing tiles in tile based as3 game

I been searching for a way to handle this for hours but have found nothing. In my BuildMap function, I instantiate new MovieClips (Tile) with the instance name cell. Their frame is based on my 2d array (protoMap). The problem is that the cells are instantiated in the function. I don't know how to access them outside of it. I want to removeChild(cell) but the only way I know how is within the function that it's instantiated in.
public function BuildMap()
{
for (var i:int=0; i < mapHeight; i++)
{
for (var u:int=0; u < mapWidth; u++)
{
var cell:MovieClip = new Tile();
cell.gotoAndStop(protoMap[i][u]+1);
cell.x = tileSide*u;
cell.y = tileSide*i;
addChild(cell);
var currCellLabel:String = cell.currentFrameLabel;
mapLabels[i].push(currCellLabel);
}
}
}
I want a function called ClearMap() that loops through again and does removeChild(cell). I thought about doing a clearTiles:Boolean and in BuildMap() do
if(clearTiles == false)
{
build the map;
}else{loop again and removeChild(cell)}
but that didn't work... so then I tried to pass cell as an argument to BuildMap() but when I tried to remove it, it wasn't an object of the caller... or something like that. I was also thinking to put cell into its own array, but I don't want to waste memory unnecessarily. Any solutions for the noob?
Create a class instead of using functions.
The point of a class is to isolate concerns.
In your case, you want to deal with all those tiles. (create them according to protoMap and be able to delete them all.
Extending a DisplayObjectContainer such as Sprite, will allow you to add all the tiles to the map object, then you can add and remove the map easily.
Your BuildMap function becomes the constructor.
Here's some non working pseudo code that illustrates the idea:
package
{
public class Map extends Sprite
{
public function Map (data, width, height)
{
for (var i:int=0; i < height; i++)
{
for (var u:int=0; u < width; u++)
{
var cell:MovieClip = new Tile();
cell.gotoAndStop(data[i][u]+1);
cell.x = tileSide*u;
cell.y = tileSide*i;
addChild(cell);
var currCellLabel:String = cell.currentFrameLabel;
mapLabels[i].push(currCellLabel);
}
}
}
public function clear():void
{
removeChildren();
}
}
}
The whole map is contained in that class. You'd have to add the labels, but you didn't specify what they are or what they do, so I left them out.
You can use it like so:
var awesomeMap:Map = new Map(protoMap, mapWidth, mapHeight);
addChild(awesomeMap);
//later
awesomeMap.clear();
//or
removeChild(awesomeMap);
I'd like to point out that building tile maps with MovieClips this way is a bad idea. MovieClips are horrible for performance, because they carry the overhead of their timeline.
Removing all children is very wasteful, too.
So if you have performance problems, try reusing objects and/or employing a technique called "blitting"
See this article: http://www.adobe.com/devnet/flash/articles/blitting_mc.html

As3 - Function with unlimited arguments as Movieclip?

I want to pass to a function an uncertain number of movieclips, sth like this
function Test(...args)
{
for(var item in args){
item.x = 100;
}
}
But using this method didn't work, any solution?
You're almost there, you just need to use a for each loop for your example to work correctly:
function Test(...args)
{
for each(var item:MovieClip in args)
// ^^^^
{
item.x = 100;
}
}
Better however would be to accept an Array or Vector holding the MovieClips. This will greatly improve readability of your code later on:
function Test(list:Vector.<MovieClip>)
{
for each(var item:MovieClip in list)
{
item.x = 100;
}
}
Use arguments; see the Adobe Reference docs (for AS3), the MDN (for JS) or this example jsfiddle (for a working example).
[NB: question originally tagged as JS, leaving javascript/jsfiddle in there for reference]

How can I check if an array contains another array?

At first sight it's very simple, but I'm having some problems to do this without using a lot of nested loops.
Example:
var father:Array = new Array(0,1,2,3,4,5);
var son:Array = new Array(3,4,5);
father.contains(son) // returns true or 4(the starting index if the contained array)
ActionScript 3 actually supports some slightly crazy stuff, due to the fact that, in the early days, Adobe/Macromedia were trying to make it compliant with Ecmascript.
So... you can do this:
var a1:Array = [1,2,3,4,5,6,7,8,9];
var a2:Array = [3,4,5];
// borrow String's indexOf function, and it magically works on Arrays
// but rename it because Array already has a different indexOf function
a1.indexOf2 = String.prototype.indexOf;
trace(a1.indexOf2(a2) > -1); // true
But you need to be a little bit careful because it will convert all the elements to Strings for the equality test. For primitives, it mostly won't matter but it will break badly with objects as they'll all be converted to "[object Object]" or to whatever their toString() returns.
Also, if you wanted to use the actual index for anything, rather than just checking it's not -1, you have to divide by two, as the number is double what you'd expect. I don't exactly know why this is :)
If you need something more general and reliable, you'd be better off writing a function to do an explicit search. This is a quick example, which I just wrote so could easily be bug-ridden:
public function find(haystack:Array, needle:Array):int
{
var index:int = -1;
while(index <= haystack.length - needle.length)
{
index++;
index = haystack.indexOf(needle[0], index);
for( var i:int = 1; i<needle.length; i++)
{
if(haystack[index+i] != needle[i])
{
continue;
}
}
if( i == needle.length)
{
return index;
}
}
return -1;
}
Try this for simplicity:
// Determines if an array contains en element (similar to the PHP function with the same name)
public function in_array(needle:*, haystack:Array):Boolean
{
for each (var element:* in haystack)
{
if (element == needle) {return true;}
}
return false;
}