Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using two Arrays in C/Gameboy programming

For a game in Gameboy programming, I am using four arrays called top, oldTop, bottom and oldBottom:

struct Point { int x, y; };
struct Rect  { struct Point xx, yy; };

Rect top[size], oldTop[size];
Rect bottom[size], oldBottom[i];

where Rect is a struct made of two Struct Points, the top-left and the bottom right corner points.

The idea of the game is to have random-heighted blocks top-down from the ceiling and bottom-up from the floor. It is similar to the copter-classic game. In my infinite while loop, I shift all of the rectangles down by one pixel using the following code

while (1)
{
    for (int i = 0; i < size; i++)
    {
        //in Struct Rect, xx is the top-left corner point, and yy is the bottom right
        top[i].xx.x--;
        top[i].yy.x--;
        bottom[i].xx.x--;
        bottom[i].yy.x--;

        if (top[i].xx.x < 0)
        {
            top[i].xx.x += 240;
            top[i].yy.x += 240;
        }

        if (bottom[i].xx.x < 0)
        {
            bottom[i].xx.x += 240;
            bottom[i].yy.x += 240;
        }
    }

    for (int i = 0; i < size; i++)
    {
        drawRect(oldTop[i], colorBlack);
        drawRect(oldBottom[i], colorBlack);
    }

    /*call delay function that wait for Vertical Blank*/
    for(int i = 0; i < size; i++)
    {
        drawRect(top[i], colorGreen);
        drawRect(bottom[i], colorGreen);
        oldTop[i] = top[i];
        oldBottom[i] = bottom[i];
    }
}

The drawRect method uses DMA to draw the rectangle.

with this code, the code should display the rectangles like this: (drew this up in paint) enter image description here

But the result I get is

enter image description here

What is odd is that if I don't draw the bottom row at all, then the top row draws fine. The result only messes up when I draw both. This is really weird because I think that the code should be working fine, and the code is not very complicated. Is there a specific reason this is happening, and is there a way to remedy this?

Thanks.

The code that I use to draw the rectangle looks like this:

void drawRect(int row, int col, int width, int height){
    int i;
for (i=0; i<height; i++)
{
    DMA[3].src = &color;
        DMA[3].dst = videoBuffer + (row+r)*240 +  col);
    DMA[3].cnt = DMA_ON | DMA_FIXED_SOURCE | width;
}
}
like image 936
sparkonhdfs Avatar asked Oct 04 '22 13:10

sparkonhdfs


1 Answers

Here's a debugging SSCCE (Short, Self-Contained, Correct Example) based on your code. There are assertions in this code that fire; it runs, but is known not to be correct. I've renamed bottom to btm and oldBottom to oldBtm so that the names are symmetric; it makes the code layout more systematic (but is otherwise immaterial).

#include <assert.h>
#include <stdio.h>

typedef struct Point { int x, y; } Point;
typedef struct Rect  { struct Point xx, yy; } Rect;
enum { size = 2 };
typedef enum { colourGreen = 0, colourBlack = 1 } Colour;

/*ARGSUSED*/
static void drawRect(Rect r, Colour c)
{
    printf(" (%3d)(%3d)", r.xx.x, r.yy.x);
}

int main(void)
{
    Rect top[size], oldTop[size];
    Rect btm[size], oldBtm[size];
    int counter = 0;

    for (int i = 0; i < size; i++)
    {
        top[i].xx.x = 240 -  4 * i;
        top[i].xx.y =   0 + 10 + i;
        top[i].yy.x = 240 - 14 * i;
        top[i].yy.y =   0 + 20 + i;
        btm[i].xx.x =   0 + 72 * i;
        btm[i].xx.y =   0 + 10 * i;
        btm[i].yy.x =   0 + 12 * i;
        btm[i].yy.y =   0 + 20 * i;
        oldTop[i] = top[i];
        oldBtm[i] = btm[i];
    }

    while (1)
    {
        if (counter++ > 480)  // Limit amount of output!
            break;
        for (int i = 0; i < size; i++)
        {
            //in Struct Rect, xx is the top-left corner point, and yy is the bottom right
            top[i].xx.x--;
            top[i].yy.x--;
            btm[i].xx.x--;
            btm[i].yy.x--;

            if (top[i].xx.x < 0)
            {
                top[i].xx.x += 240;
                top[i].yy.x += 240;
            }

            if (btm[i].xx.x < 0)
            {
                btm[i].xx.x += 240;
                btm[i].yy.x += 240;
            }
        }

        for (int i = 0; i < size; i++)
        {
            assert(top[i].xx.x >= 0 && top[i].yy.x >= 0);
            assert(btm[i].xx.x >= 0 && btm[i].yy.x >= 0);
        }

        for (int i = 0; i < size; i++)
        {
            drawRect(oldTop[i], colourBlack);
            drawRect(oldBtm[i], colourBlack);
        }

        /*call delay function that wait for Vertical Blank*/
        for(int i = 0; i < size; i++)
        {
            drawRect(top[i], colourGreen);
            drawRect(btm[i], colourGreen);
            oldTop[i] = top[i];
            oldBtm[i] = btm[i];
        }
        putchar('\n');
    }
    return(0);
}

As noted in a late comment, one big difference between this and your code is that oldBottom in your code is declared as:

Rect top[size], oldTop[size];
Rect bottom[size], oldBottom[i];

using the size i instead of size. This probably accounts for array overwriting issues you see.

There's a second problem though; the assertions in the loop in the middle fire:

 (240)(240) (  0)(  0) (236)(226) ( 72)( 12) (239)(239) (239)(239) (235)(225) ( 71)( 11)
 (239)(239) (239)(239) (235)(225) ( 71)( 11) (238)(238) (238)(238) (234)(224) ( 70)( 10)
 (238)(238) (238)(238) (234)(224) ( 70)( 10) (237)(237) (237)(237) (233)(223) ( 69)(  9)
 (237)(237) (237)(237) (233)(223) ( 69)(  9) (236)(236) (236)(236) (232)(222) ( 68)(  8)
 (236)(236) (236)(236) (232)(222) ( 68)(  8) (235)(235) (235)(235) (231)(221) ( 67)(  7)
 (235)(235) (235)(235) (231)(221) ( 67)(  7) (234)(234) (234)(234) (230)(220) ( 66)(  6)
 (234)(234) (234)(234) (230)(220) ( 66)(  6) (233)(233) (233)(233) (229)(219) ( 65)(  5)
 (233)(233) (233)(233) (229)(219) ( 65)(  5) (232)(232) (232)(232) (228)(218) ( 64)(  4)
 (232)(232) (232)(232) (228)(218) ( 64)(  4) (231)(231) (231)(231) (227)(217) ( 63)(  3)
 (231)(231) (231)(231) (227)(217) ( 63)(  3) (230)(230) (230)(230) (226)(216) ( 62)(  2)
 (230)(230) (230)(230) (226)(216) ( 62)(  2) (229)(229) (229)(229) (225)(215) ( 61)(  1)
 (229)(229) (229)(229) (225)(215) ( 61)(  1) (228)(228) (228)(228) (224)(214) ( 60)(  0)
Assertion failed: (btm[i].xx.x >= 0 && btm[i].yy.x >= 0), function main, file video.c, line 63.

I think your 'not negative' checks should be revised to:

            if (top[i].xx.x < 0)
                top[i].xx.x += 240;
            if (top[i].yy.x < 0)
                top[i].yy.x += 240;

            if (btm[i].xx.x < 0)
                btm[i].xx.x += 240;
            if (btm[i].yy.x < 0)
                btm[i].yy.x += 240;

This stops anything going negative. However, it is perfectly plausible that you should simply be checking on the bottom-right x-coordinate (instead of the top-left coordinate) using the original block. Or the wraparound may need to be more complex altogether. That's for you to decipher. But I think that the odd displays occur because you were providing negative values where you didn't intend to and weren't supposed to.

The key points to note here are:

  1. When you're debugging an algorithm, you don't have to use the normal display mechanisms.
  2. When you're debugging, reduce loop sizes where you can (size == 2).
  3. Printing just the relevant information (here, the x-coordinates) helped reduce the output.
  4. Putting the counter code to limit the amount of output simplifies things.
  5. If things are going wrong, look for patterns in what is going wrong early.

I had various versions of the drawRect() function before I got to the design shown, which works well on a wide screen (eg 120x65) terminal window.

like image 82
Jonathan Leffler Avatar answered Oct 10 '22 03:10

Jonathan Leffler