Collision demo for the Gameduino

main.cpp

Committer:
TheChrisyd
Date:
2012-12-21
Revision:
1:614d0042c0d5
Parent:
0:deb284e70ca5

File content as of revision 1:614d0042c0d5:


#include "shield.h"
#include "mbed.h"
#include "GD.h"
SPI spimain(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk
GDClass GD(ARD_MOSI, ARD_MISO, ARD_SCK, ARD_D9, USBTX, USBRX) ;

void readn(int *dst, unsigned int addr, int c) {
    GD.__start(addr);
    while (c--)
        *dst++ = spimain.write(0);
    GD.__end();
}

#define NBALLS 80

static int coll[NBALLS];
static void load_coll() {
    while (GD.rd(VBLANK) == 0)  // Wait until vblank
        ;
    while (GD.rd(VBLANK) == 1)  // Wait until display
        ;
    while (GD.rd(VBLANK) == 0)  // Wait until vblank
        ;
    readn(coll, COLLISION, NBALLS);
}

struct ball {
    int x, y;
    signed char vx, vy;
    int lasthit;
};

static struct ball balls[NBALLS];

#include "stone_wall_texture.h" // texture from 3dmd.net project
#include "sphere.h"

static void plot_balls() {
    int i;
    for (i = 0; i < NBALLS; i++)
        GD.sprite(i, balls[i].x >> 4, balls[i].y >> 4, 0, 0, 0);
}

// Place all balls so that none collide.  Do this by placing all at
// random, then moving until there are no collisions

static int anycolliding() {
    plot_balls();
    load_coll();
    int i;
    for (i = 0; i < NBALLS; i++)
        if (coll[i] != 0xff)
            return 1;
    return 0;
}

static void place_balls() {
    int i;
    for (i = 0; i < NBALLS; i++) {
        balls[i].x = (2 + rand()%380) << 4;
        balls[i].y = (2 + rand()%280) << 4;
        balls[i].vx = (rand()%256)-128;
        balls[i].vy = (rand()%256)-128;
        balls[i].lasthit = 255;
    }
    while (anycolliding()) {
        for (i = 0; i < NBALLS; i++) {
            if (coll[i] != 0xff) {
                balls[i].x = (2 + (rand()%380)) << 4;
                balls[i].y = (2 + (rand()%280)) << 4;
            }
        }
    }
}

void setup() {
    int i;

    GD.begin();

    GD.wr(JK_MODE, 0);

    GD.copy(RAM_CHR, stone_wall_texture_chr, sizeof(stone_wall_texture_chr));
    GD.copy(RAM_PAL, stone_wall_texture_pal, sizeof(stone_wall_texture_pal));
    for (i = 0; i < 4096; i++)
        GD.wr(RAM_PIC + i, (i & 15) + ((i >> 6) << 4));

    GD.copy(RAM_SPRIMG, sphere_img, sizeof(sphere_img));
    GD.copy(RAM_SPRPAL, sphere_pal, sizeof(sphere_pal));

    for (i = 0; i < 256; i++)
        GD.sprite(i, 400, 400, 0, 0, 0);

    place_balls();
}


float dot(float x1, float y1, float x2, float y2) {
    return (x1 * x2) + (y1 * y2);
}

// Collide ball a with ball b, compute new velocities.
// Algorithm from
// http://stackoverflow.com/questions/345838/ball-to-ball-collision-detection-and-handling

void collide(struct ball *a, struct ball *b) {
    float collision_x, collision_y;

    collision_x = a->x - b->x;
    collision_y = a->y - b->y;
    float distance = sqrt(collision_x * collision_x + collision_y * collision_y);
    float rdistance = 1.0 / distance;
    collision_x *= rdistance;
    collision_y *= rdistance;
    float aci = dot(a->vx, a->vy, collision_x, collision_y);
    float bci = dot(b->vx, b->vy, collision_x, collision_y);
    float acf = bci;
    float bcf = aci;
    a->vx += int((acf - aci) * collision_x);
    a->vy += int((acf - aci) * collision_y);
    b->vx += int((bcf - bci) * collision_x);
    b->vy += int((bcf - bci) * collision_y);
}

#define LWALL (0 << 4)
#define RWALL (384 << 4)
#define TWALL (0 << 4)
#define BWALL (284 << 4)

static int timer;
int main() {
    setup();
    while (1) {
        int i;

        plot_balls();

        load_coll();

        struct ball *pb;

        for (i = NBALLS, pb = balls; i--; pb++, i) {
            if ((pb->x <= LWALL)) {
                pb->x = LWALL;
                pb->vx = -pb->vx;
            }
            if ((pb->x >= RWALL)) {
                pb->x = RWALL;
                pb->vx = -pb->vx;
            }
            if ((pb->y <= TWALL)) {
                pb->y = TWALL;
                pb->vy = -pb->vy;
            }
            if ((pb->y >= BWALL)) {
                pb->y = BWALL;
                pb->vy = -pb->vy;
            }
        }
        for (i = 1; i < NBALLS; i++) {
            int other = coll[i];
            if ((balls[i].lasthit != other) && other != 0xff) {
                collide(&balls[i], &balls[other]);
            }
            balls[i].lasthit = other;
        }
        for (i = NBALLS, pb = balls; i--; pb++, i) {
            pb->x += pb->vx;
            pb->y += pb->vy;
        }
        if (++timer == 2000) {
            place_balls();
            wait_ms(1000);
            timer = 0;
        }
    }
}