Here's the code in its present stage. Not organised at all. Everything happens in setup() while loop() is empty. Just a few functions so far. Most of the stuff I will put in separate functions to get a more readable code. I invite you to test it and comment.
#include <Arduino_MKRIoTCarrier.h>
MKRIoTCarrier carrier;
float p = 3.1415926;
#define EVEN1 65042
#define EVEN2 33284
#define ODD1 65430
#define ODD2 64781
#define ODD3 45831
#define ODD4 6177
#define NOFITEMS 61 // should be 61
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define ORANGE 0b1111101111100000
#define BROWN 0b0111100111100000
#define PINK 0b1111100100000100
// Function prototypes
void newBall(void);
void newGame(void);
// Globals
GFXcanvas16 centre(44, 40);
int ox, oy;
float ballx, bally, oballx, obally;
float vx, vy;
float x, y, z;
int timex, timey, otimex, otimey, otime, newtime;
float a, h, h2, aold, delta;
int lx1, ly1, lx2, ly2;
int lox1, loy1, lox2, loy2;
uint32_t dist2;
float dist;
uint16_t quarantene = 10;
int8_t itemCount;
unsigned long icTime = -1;
unsigned long gameTime;
void setup(void) {
CARRIER_CASE = false;
carrier.begin();
newGame();
otimex = 0;
otimey = 0;
// Initialize the ball going straight down first time
ballx = 128;
bally = 150;
oballx = 128;
obally = 150;
vx = 0.;
vy = 0.76;
// Seed the RNG with tilt values from the accelerometer.
// RNG is used for each new ball direction in newBall()
while (!carrier.IMUmodule.accelerationAvailable());
carrier.IMUmodule.readAcceleration(x, y, z);
randomSeed(10000 * (x + y + z));
ox = carrier.display.width() / 2;
oy = carrier.display.height() / 2;
carrier.display.drawRGBBitmap(ox - 21, oy - 19, centre.getBuffer(), 44, 40);
quarantene = 10;
lox1=0; loy1=0; lox2=1; loy2=1;
aold = 0;
carrier.display.setTextSize(2);
do // main loop
{
if (carrier.IMUmodule.accelerationAvailable())
{
carrier.IMUmodule.readAcceleration(x, y, z);
h2 = x*x + y*y;
if (h2 > 0.000001)
{
a = atan2(y, x);
delta = a - aold;
if (delta < -3.1415926536) delta += 6.28318530718;
if (delta > 3.1415926536) delta -= 6.28318530718;
h = sqrt(h2);
if (h > 1) h = 1;
aold += h*delta;
//carrier.display.fillScreen(0);
// carrier.display.drawCircle(ox+cos(aold)*110, oy-sin(aold)*110, 5, WHITE);
// calculate bat
lx1 = ox+cos(aold-0.2)*110;
ly1 = oy-sin(aold-0.2)*110;
lx2 = ox+cos(aold+0.2)*110;
ly2 = oy-sin(aold+0.2)*110;
// Draw bat by first drawing over the old bat
carrier.display.drawLine(lox1, loy1, lox2, loy2, BLACK);
carrier.display.drawLine(lx1, ly1, lx2, ly2, WHITE);
lox1 = lx1;
loy1 = ly1;
lox2 = lx2;
loy2 = ly2;
// calculate ball
ballx += vx;
bally += vy;
quarantene++;
dist2 = (ballx - 128)*(ballx - 128)+(bally - 128)*(bally - 128);
dist = sqrt(dist2);
if (dist > 129)
{
newBall();
}
// check ball vs. bat
if ( (quarantene > 5) && (lx1 - ballx)*(ly2 - bally) - (ly1 - bally)*(lx2 - ballx) > 0) // cross product
{
// if cross product is positive, we've crossed the bat line
// if (dist > 128) // just check if we're farther than the screen
if ((lx1 - ballx)*(lx2 - ballx) + (ly1 - bally)*(ly2 - bally) > 0) // if dot product > 0 you missed the bat
{
// reset
newBall();
}
else // You hit the bat
{
float nx, ny, l, dotp;
ny = lx2 - lx1;
nx = ly1 - ly2;
l = sqrt(nx * nx + ny * ny);
nx /= l;
ny /= l;
dotp = 2. * (vx * nx + vy * ny);
nx *= dotp;
ny *= dotp;
vx -= nx;
vy -= ny;
quarantene = 0; // Put ball in quarantene for 5 game loops to avoid stucking
}
}
else // Ball is still at centre side of bat line. Check for collision with hex comb.
{
uint8_t checkX, checkY; // corner point to check for collision
float colx, coly; // mean coordinate for 1 or 2 items the ball colides with
uint8_t nOfCols;
if ((ballx > ox - 21) && (ballx < ox + 23) &&
(bally > oy - 20) && (bally < oy + 20))
{
checkX = ballx - ox + 21;
checkY = bally - oy + 20;
// collisionCheck() returns true if no collision!
// If false, increase nOfCols and add coordinate of collided item to colX, colY
// and erase item with black rect
colx = 0;
coly = 0;
nOfCols = 0;
if (collisionCheck(checkX - 1, checkY - 1, &colx, &coly, &nOfCols))
{
if (collisionCheck(checkX - 1, checkY + 1, &colx, &coly, &nOfCols))
{
if (collisionCheck(checkX + 1, checkY - 1, &colx, &coly, &nOfCols))
{
collisionCheck(checkX + 1, checkY + 1, &colx, &coly, &nOfCols);
}
}
}
if (nOfCols) // We have a collision with item
{
// Check if all items (61 of them) have been hit
if (!itemCount)
{
delay(1000);
carrier.display.fillScreen(BLACK);
carrier.display.setTextColor(PINK);
carrier.display.setCursor(20, 80);
carrier.display.setTextSize(3);
carrier.display.print(" Game\ncompleted\n in ");
carrier.display.print(newtime);
carrier.display.print(" s");
delay(3000);
carrier.display.fillScreen(BLACK);
newGame();
newBall();
}
else
{
if (nOfCols == 2)
{
colx /= 2;
coly /= 2;
}
// Now we have a collision between ball and coordinate colX, colY.
// Do the same as with colliding bat
float nx, ny, l, dotp;
ny = coly - bally;
nx = colx - ballx;
l = sqrt(nx * nx + ny * ny);
nx /= l;
ny /= l;
dotp = 2. * (vx * nx + vy * ny);
nx *= dotp;
ny *= dotp;
vx -= nx;
vy -= ny;
carrier.display.drawRGBBitmap(ox - 21, oy - 19, centre.getBuffer(), 44, 40);
}
} // End of collision with item
} // End of checking for collision in centre
}// End of checking if ball inside centre
// Erase old ball
carrier.display.fillRect(oballx-1, obally-1, 3, 3, BLACK);
// Draw new ball
carrier.display.drawPixel(ballx, bally, WHITE);
carrier.display.drawPixel(ballx+1, bally-1, 23275);
carrier.display.drawPixel(ballx+1, bally+1, 23275);
carrier.display.drawPixel(ballx-1, bally-1, 23275);
carrier.display.drawPixel(ballx-1, bally+1, 23275);
carrier.display.drawPixel(ballx-1, bally, 33808);
carrier.display.drawPixel(ballx+1, bally, 33808);
carrier.display.drawPixel(ballx, bally-1, 33808);
carrier.display.drawPixel(ballx, bally-1, 33808);
// Restore ball coordinates
oballx = ballx;
obally = bally;
// write time
newtime = (millis() - gameTime) / 1000;
timex = 118 - (ballx - 128) * 60 / dist;
timey = 120 - (bally - 128) * 60 / dist;
carrier.display.setTextSize(2);
carrier.display.setTextColor(BLACK);
carrier.display.setCursor(otimex, otimey);
carrier.display.print(otime);
carrier.display.setTextColor(WHITE);
carrier.display.setCursor(timex, timey);
carrier.display.print(newtime);
otimex = timex;
otimey = timey;
otime = newtime;
}
}
if (millis() - icTime > 500)
{
carrier.display.setTextColor(BLACK);
carrier.display.setTextSize(3);
carrier.display.setCursor(112, 35);
carrier.display.print(int(itemCount));
icTime = -1;
}
}
while(1);
}
bool collisionCheck(uint8_t x, uint8_t y, float *colx, float *coly, uint8_t *nOfCols)
{
uint8_t fx, fy, mfx, mfy;
float addx, addy;
if (centre.getPixel(x, y) == 0)
return true;
(*nOfCols)++;
itemCount--;
carrier.display.setTextColor(BLACK);
carrier.display.setTextSize(3);
carrier.display.setCursor(112, 35);
carrier.display.print(int(itemCount+1));
carrier.display.setTextColor(CYAN);
carrier.display.setTextSize(3);
carrier.display.setCursor(112, 35);
carrier.display.print(int(itemCount));
icTime = millis();
fy = y / 9;
mfy = y % 9;
if (mfy < 4)
{
fx = x / 5;
*coly += 9 * fy + 1.5;
*colx += 5 * fx + 1.5;
centre.fillRect(5 * fx, 9 * fy, 4, 4, BLACK);
}
else
{
fx = (x - 2) / 5;
*coly += 9 * fy + 6;
*colx += 5 * fx + 4;
centre.fillRect(5 * fx + 2, 9 * fy + 4, 5, 5, BLACK);
}
return false;
}
void newBall(void)
{
carrier.display.setTextSize(2);
carrier.display.setTextColor(BLACK);
carrier.display.setCursor(otimex, otimey);
carrier.display.print(otime);
carrier.display.setTextSize(3);
carrier.display.setTextColor(ORANGE);
carrier.display.setCursor(60, 60);
carrier.display.print("new ball");
delay(1000);
carrier.display.setCursor(60, 60);
carrier.display.setTextColor(BLACK);
carrier.display.print("new ball");
carrier.display.fillRect(oballx-1, obally-1, 3, 3, BLACK);
carrier.display.drawLine(lox1, loy1, lox2, loy2, BLACK);
#define TIMERX 112
#define TIMERY 35
for (int8_t i = 3; i > 0; i--)
{
carrier.display.setCursor(TIMERX, TIMERY);
carrier.display.setTextColor(BLACK);
carrier.display.print(i+1);
carrier.display.setCursor(TIMERX, TIMERY);
carrier.display.setTextColor(RED);
carrier.display.print(i);
delay(1000);
}
carrier.display.setCursor(TIMERX, TIMERY);
carrier.display.setTextColor(BLACK);
carrier.display.print(1);
carrier.display.setCursor(TIMERX, TIMERY);
carrier.display.setTextColor(RED);
carrier.display.print(0);
delay(150);
carrier.display.setCursor(TIMERX, TIMERY);
carrier.display.setTextColor(BLACK);
carrier.display.print(0);
ballx = 128;
bally = 150;
dist = 22.;
vx = float(random(100)) / 100. - 0.5;
vy = sqrt(0.5776 - vx * vx);
quarantene = 5;
carrier.display.setTextSize(2);
}
void newGame(void)
{
centre.fillScreen(0);
// Create the honeycomb graphic
for (int i = 0; i < 5; i++)
{
int x0, y0;
int margin = 2 - i;
if (margin < 0) margin = -margin;
for (int j = margin; j < 9-margin; j++)
{
x0 = 5*j;
y0 = 9*i;
centre.drawPixel(x0 + 1, y0, EVEN2);
centre.drawPixel(x0 + 2, y0, EVEN2);
centre.drawPixel(x0 + 1, y0+3, EVEN2);
centre.drawPixel(x0 + 2, y0+3, EVEN2);
centre.drawPixel(x0, y0+1, EVEN2);
centre.drawPixel(x0, y0+2, EVEN2);
centre.drawPixel(x0 + 3, y0+1, EVEN2);
centre.drawPixel(x0 + 3, y0+2, EVEN2);
centre.drawPixel(x0+1, y0+1, EVEN1);
centre.drawPixel(x0+1, y0+2, EVEN1);
centre.drawPixel(x0+2, y0+1, EVEN1);
centre.drawPixel(x0+2, y0+2, EVEN1);
}
}
for (int i = 0; i < 4; i++)
{
int x0, y0, margin;
if (i == 0 || i == 3)
margin = 1;
else
margin = 0;
for (int j = margin; j < 8-margin; j++)
{
x0 = 5*j+3;
y0 = 9*i+5;
centre.drawPixel(x0 + 1, y0 - 1, ODD4);
centre.drawPixel(x0 - 1, y0 + 1, ODD4);
centre.drawPixel(x0 + 3, y0 + 1, ODD4);
centre.drawPixel(x0 + 1, y0 + 3, ODD4);
centre.drawPixel(x0, y0, ODD3);
centre.drawPixel(x0+2, y0, ODD3);
centre.drawPixel(x0, y0+2, ODD3);
centre.drawPixel(x0+2, y0+2, ODD3);
centre.drawPixel(x0+1, y0, ODD2);
centre.drawPixel(x0+1, y0+2, ODD2);
centre.drawPixel(x0, y0+1, ODD2);
centre.drawPixel(x0+2, y0+1, ODD2);
centre.drawPixel(x0+1, y0+1, ODD1);
}
}
// Honeycomb graphic ready
itemCount = NOFITEMS;
carrier.display.drawRGBBitmap(ox - 21, oy - 19, centre.getBuffer(), 44, 40);
gameTime = millis();
oballx = 0;
obally = 0;
}
void loop()
{
}