5

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;
}
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
sparkonhdfs
  • 1,313
  • 2
  • 17
  • 31
  • 1
    "if I don't draw the bottom row at all, than the top row draws fine" <-- This makes it sound like it's something in the `drawRect` function. Is that something you wrote, and if so could you include it in the question? – SeKa Mar 31 '13 at 10:14
  • I have added the code I am using to draw Rectangles to my post. I do not see anything that could be wrong with this, altough it is possible it may be the flaw. – sparkonhdfs Mar 31 '13 at 14:50
  • 1
    When the bottom coordinate goes negative, you wrap it by adding 240. That leaves you with a rectangle with its top at, say, +50 and its 'bottom' at +239. Do you need to change your code to limit the bottom to 0? `if (top[i].xx.x > 0) top[i].xx.x--; if (bottom[i].xx.x > 0) bottom[i].xx.x--;` etc? – Jonathan Leffler Mar 31 '13 at 15:47
  • I have tested that earlier. I also tried to make the lower limit of the bottom rectangles 140, so that if an overflow occurred, it wouldn't flow to the top, but to the next line, but that also does not work. – sparkonhdfs Mar 31 '13 at 18:33
  • 1
    Have you printed (to a log file) the coordinates of the rectangles that you're displaying and redisplaying? Have you made sure that the `old` arrays are properly initialized (and the new ones, come to that)? – Jonathan Leffler Mar 31 '13 at 18:50
  • I had been using that, but since this is an infinite while loop and runs verry fast because of DMA, the data makes very little sense. I removed some of my code to test some other areas, and after I incorrectly pasted the top[i] decrement statements, it worked. This makes no sense at all. I speculate that the two arrays share some location in memory and accessing them at the same time causes a collision. thank you for the help. – sparkonhdfs Mar 31 '13 at 22:54
  • 1
    The `drawRect()` function you show bears no resemblance to the function that is called in the code. The shown function expects discrete values for the position instead of a `struct Rect` and it doesn't take a colour value. You mention that 'the two arrays share some location in memory'...if you write the array declarations as shown — 4 separate arrays — then they cannot share memory. They must be distinct. – Jonathan Leffler Mar 31 '13 at 22:55
  • The method that I have posted is a helper method. The actual method takes in a Struct Rect and calls that function with the appropriate values. I did not post that method because it's very simple – sparkonhdfs Mar 31 '13 at 22:56
  • I was compiling the code and I think your problem is likely in the definition of `oldBottom`: `Rect bottom[size], oldBottom[i];`. What is `i` set to? Is it the same as `size` at the time when the variables are defined? If not, then you're likely writing out of bounds of your `oldBottom` array, which leads to havoc being wrought on your display. – Jonathan Leffler Mar 31 '13 at 23:13

1 Answers1

4

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278