Instance-Generic Collision Detection in Actionscript - actionscript-3

I've tried using hitTestObject(), but that seems to require that I make the call using a specific instance, rendering it more or less useless unless I want to have dozens of objects making dozens of collision checks each frame, which just seems wasteful and annoying to implement.
Is there any way to do collision check based on class rather than instance?
Maybe Something equivalent to this:
http://docs.yoyogames.com/source/dadiospice/002_reference/movement%20and%20collisions/collisions/place_meeting.html
Alternatively, is there any function that returns whatever a list of objects that share overlapping coordinates with the one I'm checking?

If I'm understanding your question correctly, you have several objects of that same class that each need to check for collisions against each other?
Yes, you would have to go through each object and perform a collision check against the other objects. I suppose you could write a hitTestClass function yourself, but behind the scenes it would still be the same. As far as implementing it, it's not so bad:
for( var i:int = 0; i < asteroids.length -1; ++i )
{
var a:Asteroid = asteroids[ i ];
for( var j:int = i+1; j < asteroids.length; ++j )
{
var b:Asteroid = asteroids[ j ];
var isColliding:Boolean = a.hitTestObject( b );
//Code here to do whatever in the case of collision
}
}
If computational speed becomes a concern, then there are broad-phase collision detection techniques to chunk down the time. Quad trees are one example.

Related

Locating whether two instances of an array are in the same position

I'm trying to work out a way for my game to recognise when two instances of this array have the same x or y position as another and if so to move re randomize the position of one of the instances.:
for(i=0;i<8;i++) {
PlatformInstance[i] =new Platform();
PlatformInstance[i].y= Math.random()*900;
PlatformInstance[i].x= Math.random() *1500;
stage.addChild(PlatformInstance[i]);
}
the problem i have is that the code i try detects that one platform instance has the same position as the SAME platform instance, and will constantly re randomize the position.
is there a way to differentiate between different instances?
thanks very much in advance.
EDIT
The only code i could think of was running an if statement in a loop to see whether
If (PlatformInstance[i].y == PlatformInstance[i].y)
Obviously this wouldnt work and thinking of it i know it wouldn't however i was wondering if there was a way to do:
If (Platforminstance[i].y == "other" Platforminstance[i].y
or some other words to that effect
You don't seem to have a clear understanding of how arrays work, I recommend looking into that. Something like this should work
i=0;
j=0;
while( i < PlatformInstance.length -1) {
j++;
if (j == PlatformInstance.length) {
i++;
j=i+1;
}
if( (Math.abs(PlatformInstance[i].x - PlatformInstance[j].x) < platformWidth)
|| (Math.abs(PlatformInstance[i].y - PlatformInstance[j].y) < platformHeight) ) {
PlatformInstance[j].y= Math.random()*900;
PlatformInstance[j].x= Math.random() *1500;
//Now you'll have start checking at the beginning again since you moved one
i=0;
j=0;
continue;
}
}
Also as it was previously mentioned, PlatformInstance is not a good name for an array. Only Class names should start with a capital letter. And an array of platforms should not be called an "instance". I would recommend changing it to simply platforms

AS3 math: nearest neighbour in array

So let's say i have T, T = 1200. I also have A, A is an array that contains 1000s of entries and these are numerical entries that range from 1000-2000 but does not include an entry for 1200.
What's the fastest way of finding the nearest neighbour (closest value), let's say we ceil it, so it'll match 1201, not 1199 in A.
Note: this will be run on ENTER_FRAME.
Also note: A is static.
It is also very fast to use Vector.<int>instead of Arrayand do a simple for-loop:
var vector:Vector.<int> = new <int>[ 0,1,2, /*....*/ 2000];
function seekNextLower( searchNumber:int ) : int {
for (var i:int = vector.length-1; i >= 0; i--) {
if (vector[i] <= searchNumber) return vector[i];
}
}
function seekNextHigher( searchNumber:int ) : int {
for (var i:int = 0; i < vector.length; i++) {
if (vector[i] >= searchNumber) return vector[i];
}
}
Using any array methods will be more costly than iterating over Vector.<int> - it was optimized for exactly this kind of operation.
If you're looking to run this on every ENTER_FRAME event, you'll probably benefit from some extra optimization.
If you keep track of the entries when they are written to the array, you don't have to sort them.
For example, you'd have an array where T is the index, and it would have an object with an array with all the indexes of the A array that hold that value. you could also put the closest value's index as part of that object, so when you're retrieving this every frame, you only need to access that value, rather than search.
Of course this would only help if you read a lot more than you write, because recreating the object is quite expensive, so it really depends on use.
You might also want to look into linked lists, for certain operations they are quite a bit faster (slower on sort though)
You have to read each value, so the complexity will be linear. It's pretty much like finding the smallest int in an array.
var closestIndex:uint;
var closestDistance:uint = uint.MAX_VALUE;
var currentDistance:uint;
var arrayLength:uint = A.length;
for (var index:int = 0; index<arrayLength; index++)
{
currentDistance = Math.abs(T - A[index]);
if (currentDistance < closestDistance ||
(currentDistance == closestDistance && A[index] > T)) //between two values with the same distance, prefers the one larger than T
{
closestDistance = currentDistance;
closestIndex = index;
}
}
return T[closestIndex];
Since your array is sorted you could adapt a straightforward binary search (such as explained in this answer) to find the 'pivot' where the left-subdivision and the right-subdivision at a recursive step bracket the value you are 'searching' for.
Just a thought I had... Sort A (since its static you can just sort it once before you start), and then take a guess of what index to start guessing at (say A is length 100, you want 1200, 100*(200/1000) = 20) so guess starting at that guess, and then if A[guess] is higher than 1200, check the value at A[guess-1]. If it is still higher, keep going down until you find one that is higher and one that is lower. Once you find that determine what is closer. if your initial guess was too low, keep going up.
This won't be great and might not be the best performance wise, but it would be a lot better than checking every single value, and will work quite well if A is evenly spaced between 1000 and 2000.
Good luck!
public function nearestNumber(value:Number,list:Array):Number{
var currentNumber:Number = list[0];
for (var i:int = 0; i < list.length; i++) {
if (Math.abs(value - list[i]) < Math.abs(value - currentNumber)){
currentNumber = list[i];
}
}
return currentNumber;
}

How to make smooth moving using as3?

I have loaded some images through XML and attached into dynamically created MovieClips named mc0,mc1,mc2...etc.
_loader.removeEventListener(ProgressEvent.PROGRESS, onLoadingAction);
count++;
var img:Bitmap = Bitmap(e.target.content);
img.cacheAsBitmap = true;
img.smoothing = true;
img.alpha = 0;
TweenLite.to(MovieClip(my_mc.getChildByName("mc"+count)).addChild(img),1, {alpha:1,ease:Quint.easeIn});
and within ENTER_FRAME handler
for (i=0; i < mc.numChildren; i++)
{
my_mc.getChildAt(i).x -= Math.round((mouseX-stage.stageWidth/2)*.006);
}
Everthing works fine. But it is shaking so that it was not looking good.
How do I achieve smooth movement?
One solution I've used is to round the (x,y) position to the closest integer. No matter that you've added smoothing to your bitmap and cached it, rounding could make it feel less choppy and way smoother.
Another thing you need to be careful is the dimensions of the images. Images that have an odd dimension won't be smoothed the same way as images with even dimensions. Check how to workaround this in my blog post Flash Smoothing Issue.
Since Flash has a variable frame rate (in the sense that it will drop frames), one shouldn't depend on the entering of a frame as a unit of action. Rather, it would be wiser to calculate the elapsed time explicitly.
For instance, in the enter frame handler:
var currentTime:Number = (new Date()).time;
for (i=0; i < mc.numChildren; i++)
{
my_mc.getChildAt(i).x -= speed * (currentTime - lastTime); // speed is in px/ms
}
lastTime = currentTime;
where you have the variable lastTime declared somewhere in a persistent scope:
var lastTime:Number = (new Date()).time;
I don't know if this addresses what you are calling "shaking", but it's at least something to consider.

AS3: How to refer an object by his properties

Well, I'm doing a checkers game and I need to refer a piece by its position (x and y, both) and remove it from the screen (no problem with this).
I've been traying combinations with "this." but nothing.
How would you do that?
this.x and this.y are functional from the scope of your checkers pieces object; however, if you're accessing a piece outside of their scope, you must use a piece's instance name. Although not optimal, you could loop through children DisplayObjects.
// create a collection of your checker pieces
var checkers:Array = [];
// create a checker piece, whatever your DisplayObject class is.
var checker:Checker;
checkers.push(checker);
// add it to the stage, probably your game board
addChild(checker);
checker.x = 100;
checker.y = 100;
// loop through the children (from your game board)
for (var i:uint = 0; i < numChildren; i++)
{
var checker:DisplayObject = getChildAt(i);
trace(checker.x);
trace(checker.y);
}
Using coordinates to reference a piece may not be optimal for game play. You might want to consider a row / column or approach it from how your game board works.
If this is not clear, you should specify some code or expand your question with more detail.

For-loop variable scope confusion

I have noticed a weird behavior of the variables in for loops. It's not really a problem, but it disturbs me a lot.
Actually I've created two loops this way:
for (var i:uint; i<19; i++) SomeFunction (i);
for (var i:uint; i<26; i++) SomeOtherFunction (i);
What I received was a compilation warning:
Warning: Duplicate variable definition.
This warning really surprised me. Nothing like that ever happened to me in other languages.
It seems that the i variable gets into the scope that is higher in the hierarchy and becomes available out of the loop's block. I've also tried to embrace the loop block in a curly brace, but it didn't change anything.
Why does it happen? Is it normal? Is it possible to avoid it? For now I've just set different names for both of the variables, but that's not a real solution I think. I'd really like to use the i-named variable in most of my for-loops.
yes, the loop increment variable is in the scope of the loops parent, not inside the loop itself. This is intentional, for examples like this:
public function getPositionOfValue ( value:String ) : int
{
for ( var i:int = 0; i < someArray; i++ )
{
if (someArray[i] == value )
{
break;
}
}
return i;
}
this allows you to access the value of i once the loop is over. There are lots of cases where this is very useful.
What you should do in the cases where you have multiple loops inside the same scope is var the i outside of the loops:
public function getPositionOfValue ( value:String ) : int
{
var i:int;
for ( i = 0; i < 15; i++ )
{
//do something
}
for ( i = 0; i < 29; i++ )
{
//do something else
}
return i;
}
then you get rid of your warning. The other thing to consider is to name your loop increment variables something more descriptive.
Update: Two other things to consider:
1) you shouldn't use uints except for things like colors and places where Flex expects a uint. They are slower than int's to use. Source]1 Update: it looks like this may no longer be the case in newer versions of the flash player: source
2) when you var a loop increment variable inside of a loop declaration, you want to make sure you set it to the proper initialization value, usually 0. You can get some hard to track down bugs if you dont.
As mentioned here, as3 has global and local scope and that's about it.
It does not do block-level scoping (or for-level either). With hoisting, you can even write to variables before you define them. That's the bit that would do my head in :-)
Early versions of Visual C had this bug, leading to all sorts of wonderful funky macro workarounds but this is not a bug in as3, it's working as designed. You can either restrict your code to having the declaration in the first for only or move the declaration outside all the for statements.
Either way, it's a matter of accepting that the language works one way, even though you may think that's a bad way :-)
Declare the variable i outside the loops to avoid this. As long as you reset it (i=0) you can still use it in all loops.
var i : uint;
for (i=0; i<19; i++) SomeFunction(i);
for (i=0; i<26; i++) SomeOtherFunction(i);