I am making a Falling Sand style game in Java, and I'm having weird issues with an if-else block that I have. In my doGravity() method, I have an various blocks of conditions that will cause different things to happen, and for some odd reason, 开发者_高级运维one block is NEVER getting hit.
When I have this block count how many times each condition is hit, the left and right blocks are hit almost evenly:
else if(world[x][y+1]==EMPTY && (x-1 >= 0) && world[x-1][y+1] == EMPTY && (x+1 < world.length) && world[x+1][y+1]==EMPTY) {
int r = rand.nextInt(50);
if(r == 0) {
world[x-1][y+1] = world[x][y];
//System.out.println("GO: right");
countRight++;
}
else if(r == 1) {
world[x+1][y+1] = world[x][y];
//System.out.println("GO: left");
countLeft++;
}
else {
world[x][y+1] = world[x][y];
countCenter++;
}
world[x][y] = EMPTY;
}
Next comes this condition, which also equally distributes left and right.
else if((x-1 >= 0) && world[x-1][y+1] == EMPTY && (x+1 < world.length) && world[x+1][y+1]==EMPTY) {
if(rand.nextBoolean()) {
world[x-1][y+1] = world[x][y];
//countLeft++;
}
else {
world[x+1][y+1] = world[x][y];
//countRight++;
}
world[x][y] = EMPTY;
}
But when I count these blocks, the left block NEVER gets hit, even when the space to the left is open. I feel like its probably just some stupid typo that I can't see for some reason.
else if((x-1 >= 0) && world[x-1][y+1] == EMPTY) {
world[x-1][y+1] = world[x][y];
world[x][y] = EMPTY;
countLeft++;
System.out.println("Hit Left");
}
else if((x+1 < world.length) && world[x+1][y+1] == EMPTY) {
world[x+1][y+1] = world[x][y];
world[x][y] = EMPTY;
countRight++;
System.out.println("Hit Right");
}
UPDATE: If I remark out the left
block at the end, absolutely nothing changes. The sand acts exactly the same. If I remark out the right
block at the end, it acts the same as if I remark out both blocks. I cannot figure this out. It should work... but it doesn't.
UPDATE: Here's the full source code. I have no idea what this could possibly be. It will, in fact, drive me insane. http://pastebin.com/mXCbCvmb
Your pastebin code does show "Hit left", you just need to change the creation of world (line 65 pastebin) to
world = new Color[worldWidth][worldHeight+1];
Because of the y+1 part i would suppose. Other than that it grows both to the left and to the right.
EDIT: http://pastebin.com/GVmSzN4z I twiddled a little with your doGravity to make the drops a little more symmetric.
I dont see anything strange in the posted code... however the "else" at the beginning of the second block makes me think that probably the above condition is being executed in cases that insted you would like to be handled by the "left" case.
What is the condition in the if
before that part?
EDIT
After checking your full source code I finally found where the problem is. Your doGravity
update function always goes left->right and this introduces the asymmetry. By changing it so that the update direction is alternating between left->right and right->left for odd/even scanlines the asymmetry disappears.
private void doGravity() {
for(int i = worldHeight - 1; i >= 0; i--) {
if (i % 2 == 0)
{
for(int j = 0; j < worldWidth; j++) {
if(world[j][i] != EMPTY) {
if(hasGravity(world[j][i])) {
dropParticle(j, i);
}
}
}
}
else
{
for(int j = worldWidth-1; j >= 0; --j) {
if(world[j][i] != EMPTY) {
if(hasGravity(world[j][i])) {
dropParticle(j, i);
}
}
}
}
}
}
I downloaded your code from paste bin the first thing I did was extract this method and use it instead of all the embedded array cell checking so I could set a break point and see what the values for x
and y
and what the contents of that indexed cell was.
private boolean isEmpty(final int x, final int y)
{
return world[x][y] == EMPTY;
}
I would extract all the EMPTY
checks to something more readable, such as isLeftEmpty(x,y)
and isRightEmpty(x,y)
and isNextLeftEmpty(x,y)
it will help you reason about the correctness of your logic in your code.
I would also extract the (x + 1 < world.length)
to isNextXOutsideWorld(x)
, this will help document your intentions and help with reasoning about the logic you intend as well.
This also has a side effect of simplifying the logic in the if/elseif/else
statements.
I did some brief debugging and I let it run for a few minutes and came to the conclusion that the following line matches always and supersedes the next else if
statement.
else if ((x + 1 < world.length) && isEmpty(x + 1, y + 1) &&
(x - 1 >= 0) && isEmpty(x - 1,y + 1))
is always true when I run it, so it never reaches the next statement
else if ((x - 1 >= 0) && isEmpty(x - 1,y + 1))
I would try and break each of the else/if
statements out to method calls with descriptive names and just all them all in order using a Strategy
pattern since they are all mutually exclusive. That large of a method is definitely a code smell, compounded with all those else/if
blocks, the stinky factor is high.
It is very hard to extrapolate what your intended behavior is from all the noise in the if/elseif/else
blocks.
精彩评论