Wednesday, January 09, 2008

Oh yeah!

I was doing some more reading and I had a side thought about the last suggested block placement logic. The way it is currently set up the loop exits upon first collision, meaning that if the block were to intersect on the x axis while it was being placed, it would simply be projected away from the object it was colliding with and then the loop would exit leaving it possibly suspended in mid air, if the block was now no longer colliding with an object.











OOps, not what we want to happen. This is an easy fix though, we just have to
continue to move the object through the main do loop until both an x and y collision has happened, so that the Object is at rest. So, this will change the logic structure too..







int collide=0 //Change collide to an integer value
do
{
if(collide==0)
{
Move block along negative x and y axises by -0.005
}

else
{
Move block along negative y axis by -0.005
}

if( collision with block placement area)
{
determine the projection by seeing which axis is the shortest distant to
non collision
move block to new position.
collide +=1; //ADD ONE TO COLLIDE
if(collide==2)
{
break; //(SIMPLE IF ENCLOSER OF BREAK STATEMENT)
}


}

else
{
do
{
subtract a number from the current block to work down the list of previously
generated blocks

if(the current block to check is out of bounds)
{
subtract one from the current row of blocks to check and make the last
block in the row the first to check
}

if(the row is out of bounds)
{
no collision happened, so break this loop
}
if(collision with current block to check)
{
determine the projection by seeing which axis is the shortest distant to
non collision
move block to new position.
collide +=2
break;
}

}
while(there's still blocks to check)
}



}while( collide<2)>





This seems to fix our problem, but upon closer inspection we run across one more.
Using the current structure of logic the blocks at some point will begin to leave spaces due to the inability of the blocks to know about spaces between each other. This problem occurs no matter what point of origin is used for placing the blocks into the Block Placement area. This is due to the different sizes of the blocks and the random nature of their creation.














So.. Now what??

Well one solution is that through the use of reference counting, the blocks keeping track of the order in which they are created, that they should be able to share information with a management system. It will be the job of this management system to keep track of available space that needs to be filled as the blocks are generated.

For example :


The first row of blocks can be generated by keeping track of the translations of the blocks before them without running into the space problem. By simply knowing the boundaries of the block before it and knowing it's own boundaries the right origin for placing the block can be determined. Once the first row is filled, if we continued to rely on this system alone, the same problem would occur so an added element is needed.

Because of the nature of the growing complexity of placing these blocks, this is where a quad tree does indeed come in handy. By Subdividing the space we can know which blocks the next block placed in the new row can come into contact with, without having to cycle through all of the blocks.

It will be up to blocks to keep track of what sectors or branches of the subdivided space they are in so that when an initial collision occurs on the new row, by comparing sizes of the blocks, and knowing the dimensions of the each sizes bounding blocks, we can determine where the new block will fit without wasting space.




This sounds well and dandy in theory, and I'm glad that I took the time really analyze the problem before attempting to really code the solution again, even though this analysis took me a couple of hours, it probably ended up saving me a couple of days time. Following this model I will be structuring a new system for block placement. I will post screenshots of this implementation, even if it ends up that it doesn't work out. That will be available sometime later today.

Further analysis will be required as well if this implementation fails.

3 comments:

Anonymous said...

Surely if your blocks will be regular sizes, this is all *very* inefficient? From the looks of your diagrams it seems the sizes can be represented as multiples of a common value (32 or whatever). If that's the case, then it's just a matter of filling in grid squares, since you know you won't end up with a 1 pixel sliver of a gap, for example. This could be done by assigning a random colour to grid cells, then running through this and turning adjacent similarly coloured cells into blocks, after perhaps a cleanup step to prevent concave or too-large shapes.

Will C said...

Hey Ben,

thanks for the comment. I may be a bit slow, but I don't really get what it is you're saying here.

I get the part about using a grid that has cell sizes set to the common base(which is 40) for the sizes of the blocks, but I don't follow on the rest. Are you suggesting that 3 colors be used to represent the block sizes and to populate the grid with these colors randomly, in sizes proportional to the blocks, then make sure that the are within bounds(not too large), then set
the blocks based on this data?

Maybe I'm making things too complicated, but I've been trying to think about what you're suggesting for a while now and I'm just not sure.

Another approach that I did think of was using a grid and storing the space that is used in a multi-dim array, then check against that before placing newly generated blocks, but I really have gotten caught up in solving the problem using collision, this may not be the fastest or best solution, but it's still an interesting problem to try and solve and I probably won't end up implementing it that way in the game as it's not the fastest way.

I really would like to hear more about your suggestion though. If this is a common technique and you have a link to it I'd appreciate that as well.

Anonymous said...

I wouldn't have thought it's an existing technique, it's just what popped to mind :)

What I mean is that you presumably can generate blocks of a variety of sizes and colours. The sizes will all be multiples of 40, so you can represent this easily with a grid. To generate the blocks, first loop through all cells, assigning them one of the possible colours. Then performa another step, where you find groups of adjacent identical colours (say, three reds in a row) and generate a block from those, then mark those cells as used. Keep going until all the cells are used, and you'll have generated a full 'wall' of blocks.

You may have to do something clever to avoid making blocks that aren't rectangular (if there happen to be three red cells in an L shape, for example), and you may have to limit the length of blocks (from your pictures it doesn't look like you want any really long ones). Overall though this should be quite simple.

In any case though, generating blocks from some kind of grid is going to be a load faster than dropping blocks in using collisions, and I'd say very much more robust too. Good choice ditching the collision-based placement :)