A question on arrays… (Solved my problem)

Hey Monkeys! I’m having a little trouble with arrays… So, I have this array called ballsArray, which can hold 100 RigidBodyControls. (I’m using this to hold my… err, they’re kind of like bullets, more like canonballs I guess… But in the game you’re chucking around them around). I’m using the integer numBalls to hold the number of balls. Whenever I “summon” a ball, it goes up. Then, in the simpleUpdate() method, I run a for() loop to check to see if each ball is 100 units away from the character. If yes, then remove them from the rootNode and the PhysicsSpace. However, this is not quite working… Depending on the order of the balls exiting the 100u zone around the character, it either functions correctly or it doesn’t. If the balls summoned last exit first, it’s fine. But if the balls summoned first exit first, then the rest just continue on their way.



My code:

[java]for(int i=0; i<numBalls; i++){

float newDistance = character.getPhysicsLocation().distance(ballsArray.getPhysicsLocation());

//System.out.println(newDistance);

if(newDistance>100){

getPhysicsSpace().remove(ballsArray);

rootNode.detachChildNamed(“ball”+(i+1));

numBalls–;



}

}[/java]



My guess is that it’s because I lower the numBalls there in the loop, so when it runs it again the i stops before it should. To correct this I tried having another int, int numBallsSub, and having that go up (in place of the numBalls–), and then subtracting that from the numBalls after the for loop… That didn’t have any effect, which confused me…



That code:

[java]for(int i=0; i<numBalls; i++){

float newDistance = character.getPhysicsLocation().distance(ballsArray.getPhysicsLocation());

//System.out.println(newDistance);

if(newDistance>100){

getPhysicsSpace().remove(ballsArray);

rootNode.detachChildNamed(“ball”+(i+1));

numBallsSub++;



}

}

numBalls-=numBallsSub;

numBallsSub=0;

[/java]



So, do you guys have any idea as to how I could fix this? In fact, I’m kind of confused as to why this is happening… Shouldn’t the subtraction be called after the for loop is? Anyways, thanks for any help!

before I start, the first ball is named ball1? not ball0?



For the first code the logic is inherently flawed, because if for instance numBalls = 100 at the start, then decreasing it to 99 after 1 ball is removed, means that the ball with name “ball100” can never be removed if it needs to be. For every ball you remove, you in fact decrease the number of balls which can be removed by 1, as “i” increases and “numBalls” decreases (hope that made sense).



For the second one, i would expect that to work fine.



I would advise using Collections and iterators though, as you declare an array of size 100, but it might not all be used and hence a waste of memory. The type you use depends on what you do with the data

1 Like

If you are only ever iterating through and removing/adding at (effectively) random points in the list then that’s a classic case for using LinkedList. Just so long as you don’t need random access…



As wezrule said your current algorithm is fundamentally flawed. Just sketch out on paper what happens with an array of size 4 as you add/remove things and you should quickly see why.

1 Like

Haha, sorry, I forgot to add in that bit… The Spatial’s name starts with ball1 (makes it more organized-looking, I guess. Kind of silly, looking back, but it doesn’t affect things as I added in the -1 part when searching for the name).

Also, numBallls starts at 0, then once a ball is added it goes up, once a ball is taken away it goes down. The array just has the size of 100. It lets me keep up with how many balls there are in the array… Here’s the code that I add a ball with (it’s a method that I call when I press a button):



[java]numBalls++;

//no specific reason why it’s called mooseBall, lol, just needed something to call it that I would remember.

//Also, balll is the original ball Spatial which I already defined

Spatial mooseBall = balll.clone();

mooseBall.setName(“ball”+numBalls);

mooseBall.setShadowMode(ShadowMode.Cast);



RigidBodyControl moose = new RigidBodyControl(CollisionShapeFactory.createDynamicMeshShape(mooseBall), 100f);

mooseBall.addControl(moose);

ballsArray[numBalls-1]=moose;

rootNode.attachChild(mooseBall);

getPhysicsSpace().add(moose);

[/java]



But the last one (in my first post) should work. I don’t know why it doesn’t.

There isn’t any problem whatsoever with the numbers matching up and removing things, as this properly removes them:

[java]for(int i=0; i<numBalls; i++){

float newDistance = character.getPhysicsLocation().distance(ballsArray.getPhysicsLocation());

//System.out.println(newDistance);

if(newDistance>100){

getPhysicsSpace().remove(ballsArray);

rootNode.detachChildNamed(“ball”+(i+1));

//numBalls–;

//^ commenting out the subtracting bit

}

}[/java]



It’s that when numBalls decreases, the for loop never reaches the later elements (if the first one leads things off with exiting the zone). Which is why I thought that subtracting everything after the for loop would give me what I wanted. But I guess simpleUpdate() doesn’t work like that? Which wouldn’t make sense, 'cause Java finishes the method before it runs it again… sigh



Now, I have no idea what collections are, and I guess I should check into that… I was trying to do things with ArrayList, but that just got more jumbled up than I wanted it to and I guess I just plain old didn’t understand them enough, 'cause that kept glitching and not working right… Anyways, hope that cleared things up a bit.



EDIT: also zarch, I’m not randomly accessing them… Not yet, at least, and I don’t expect that I will be…

Learn Java Collections. It’s probably the single most important API in the Java language…



In the meantime trace through in paper with a “virtual” array of 3 items and think specifically about what happens as you add/remove things…and things at different positions in the array.



It’s nothing to do with update() and everything to do with how you are mangling the array…

I did that, everything looked fine. But obviously something’s not fine, so I will check again…

Array

0 | 1 | 2


X1 | X2 | X3

numEntries = 3

Trying to remove X2, what do you do?

This is really fundamental basic programming skills...and without them you really won't get far in trying to create a 3d game.
@nomnom said:
EDIT: also zarch, I'm not randomly accessing them... Not yet, at least, and I don't expect that I will be...


definitely use a LinkedList as Zarch suggests. Compared with an ArrayList (stores as an array underneath), LinkedLists are cheap to append objects to the end, and to remove them from the middle while iterating, and doesn't waste any extra memory with unused array locations. But it is slow in other areas, so thats why you must decide what operations you'll need to do with it, and find a balance which will define what collection to use to be the most efficient.

@zarch it’s never removed from the array, it’s replaced, as shown in the code. I know that that’s not the best way to go with things, but I was just testing to see if I could get something to work. I’m going to abandon that I guess and check up on LinkedList, then report back. Thanks.

@nomnom said:
@zarch it's never removed from the array, it's replaced, as shown in the code. I know that that's not the best way to go with things, but I was just testing to see if I could get something to work. I'm going to abandon that I guess and check up on LinkedList, then report back. Thanks.


In the code I saw... you reduced the number of balls after handling the entry... thus if you "removed" element 3 then you'd never get to element 4 because numBalls is now smaller. I never saw any swapping.
1 Like

Hmm, what do you mean by swapping? Moving the other elements down?



Anyways, I did what I should’ve done first, create a ball class that holds all the stuff I need (the RigidBodyControl, Spatial, etc) that I can call getSpatial or whatever method needed to return what I need… So now I can just call the rootNode.detachChild(x.getSpatial) and physicsSpace.remove(x.getRigidBodyControl), instead of trying to guess it with the array (the big problem I was having in my attempts at this was trying to figure out the name to take it out of the rootNode, but with this I can just take out the Spatial). Also, I switched to LinkedList (wonderful, just what I needed!)

So everything works splendidly now. My framerate also went up to top it off^^



Thanks guys! I’ll share my “game” once I polish it off a bit…

Don’t just blindly use LinkedList, it’s correct for this use but very bad for others.



You need to read and properly understand the collections API. In particular the difference between Set/List/Map and between ArrayList and LinkedList and between HashSet and SortedSet.



(There are lots more subtleties too but those are the absolute minimum).



There are plenty of good tutorials online.

@zarch said:
Don't just blindly use LinkedList, it's correct for this use but very bad for others.

Well, no, of course not... Research first, it'll save a lot of time. I'm going into more collections, but LinkedList was perfect for this situation. I didn't even know about all of these before (just ArrayList), so thanks again!