deleting items from 2d arrays

Jarrett Billingsley jarrett.billingsley at gmail.com
Thu Aug 13 20:52:50 PDT 2009


On Thu, Aug 13, 2009 at 10:59 PM, Michael P.<baseball.mjp at gmail.com> wrote:
> Okay, so I'm making a breakout type game in D. Using Derelict.
> I have a 2d array of Block type variables(not important what's in them) declared like this:
> Block[][] level;
> and later load into like this:
> level = loadLevel( "levels.txt", levelNumber );
> Anyways, what I want to do is that when the ball hits one of the blocks in the array, I remove it. When a line no longer has any blocks in it, I remove that line/row. When there are no more lines, I load the next level.
> Any ideas on how I could achieve this?
>
> foreach( Block[] ba; level )
> {
>        foreach( Block b; ba )
>        {
>                if( checkCollision( ball, b.p ) )
>                {
>                        //remove the block??
>                }
>        }
> }
>
> The level array has 12 lines of 'x' amount of bricks. x can be as great as 10.

Okay.  First you need a remove function to take lines out of the
array.  Here's a general one:

import std.c.string; // phobos
import tango.stdc.string; // tango

void remove(T)(ref T[] arr, size_t idx)
{
    assert(arr.length > 0);

    if(idx == 0)
        arr = arr[1 .. $];
    else if(idx == arr.length - 1)
        arr = arr[0 .. $ - 1];

    memmove(&arr[idx], &arr[idx + 1], T.sizeof * (arr.length - idx - 1));
    arr = arr[0 .. $ - 1];
}

You use it like arr.remove(idx) (or alternately, remove(arr, idx)) and
the given element will be removed, everything after it will be shifted
down a slot, and the length of the array will be reduced by one.

Now you need to do collision with the blocks.  If Block is a class, we
can use 'null' in the array to indicate that there is not block there;
if it's a struct, you'll have to keep an 'active' member in the struct
or somesuch.  Either way, a quadratic algorithm for detecting
collision probably isn't necessary.  You can calculate which blocks
the ball is near with a little math.

const BlockHeight = 24; // fill these in
const BlockWidth = 60; // with whatever you're using

void checkRemoveLine(int row)
{
    foreach(ref b; level[row])
        if(b.active)
            return;

    // none of the blocks were active
    level.remove(row);
}

void removeBlock(int row, int col)
{
    level[row][col].active = false;
    checkRemoveLine(row);
}

void collidePoint(int x, int y)
{
    auto row = y / BlockHeight;
    auto col = x / BlockWidth;

    // assuming Block is a struct..
    if(row < level.length && level[row][col].active)
        removeBlock(row, col);
}

const BallDiam = 10; // this makes the ball 10 pixels across
const HalfBallDiam = BallDiam / 2;

void collide(Ball ball)
{
    // collide all four corners of the ball's colbox
    collidePoint(ball.x + HalfBallDiam, ball. y + HalfBallDiam);
    collidePoint(ball.x - HalfBallDiam, ball. y + HalfBallDiam);
    collidePoint(ball.x - HalfBallDiam, ball. y - HalfBallDiam);
    collidePoint(ball.x + HalfBallDiam, ball. y - HalfBallDiam);
}

Your main game loop would probably look something like this:

foreach(levelFile; levelFiles)
{
    level = loadLevel(levelFile); // load the level array

    // while there are still lines..
    while(level.length > 0)
    {
        getUserInput();
        updateStuff();
        doCollision(); // ball runs into things yay
        drawGraphics();
    }
}

Well this has ended up being a bit long ;)


More information about the Digitalmars-d-learn mailing list