259 lines
5.8 KiB
C
259 lines
5.8 KiB
C
|
/* bricks.c - provided by briks <briks@riseup.net> */
|
||
|
|
||
|
#include "basic/basic.h"
|
||
|
#include "usetable.h"
|
||
|
|
||
|
#define SCREEN_WIDTH 96
|
||
|
#define SCREEN_HEIGHT 67
|
||
|
#define FIELD_WIDTH 8
|
||
|
#define FIELD_HEIGHT 7
|
||
|
#define BRICK_WIDTH 11
|
||
|
#define BRICK_HEIGHT 4
|
||
|
#define BRICK_SPACING 1
|
||
|
|
||
|
#define PADDLE_WIDTH 20
|
||
|
#define PADDLE_Y 66
|
||
|
#define PADDLE_SPEED 3
|
||
|
|
||
|
#define PAUSE_INITIAL 30
|
||
|
|
||
|
#define LIVES_INITIAL 5
|
||
|
|
||
|
#define LEVELS 3
|
||
|
|
||
|
int levels[LEVELS][FIELD_HEIGHT][FIELD_WIDTH] = {
|
||
|
{
|
||
|
{0,0,0,0,0,0,0,0},
|
||
|
{0,1,1,0,0,1,1,0},
|
||
|
{0,1,1,0,0,1,1,0},
|
||
|
{0,0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0,0},
|
||
|
{0,1,0,0,0,0,1,0},
|
||
|
{0,0,1,1,1,1,0,0}
|
||
|
},
|
||
|
{
|
||
|
{0,1,0,1,0,1,0,1},
|
||
|
{1,0,1,0,1,0,1,0},
|
||
|
{0,1,0,1,0,1,0,1},
|
||
|
{1,0,1,0,1,0,1,0},
|
||
|
{0,1,0,1,0,1,0,1},
|
||
|
{1,0,1,0,1,0,1,0},
|
||
|
{0,0,0,0,0,0,0,0}
|
||
|
},
|
||
|
{
|
||
|
{1,1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1,1},
|
||
|
{0,0,0,0,0,0,0,0}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
int playLevel(int levelNo, int pause);
|
||
|
void drawBricks(int bricks[FIELD_HEIGHT][FIELD_WIDTH]);
|
||
|
void drawPxChk(int x, int y, int color);
|
||
|
void drawBall(int ball[2], int color);
|
||
|
void drawPaddle(int paddleX, int color);
|
||
|
int fieldIsCleared(int bricks[FIELD_HEIGHT][FIELD_WIDTH]);
|
||
|
int abs(int x);
|
||
|
|
||
|
void ram(void) {
|
||
|
|
||
|
lcdClear();
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln(" BRICKS");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln(" by briks");
|
||
|
lcdRefresh();
|
||
|
delayms(1000);
|
||
|
|
||
|
int pause = PAUSE_INITIAL;
|
||
|
for (int i = 1; true; i++) {
|
||
|
lcdClear();
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln(" Level");
|
||
|
lcdPrintln("");
|
||
|
lcdPrint(" ");
|
||
|
lcdPrintln(IntToStr(i, 2, 0));
|
||
|
lcdRefresh();
|
||
|
delayms(1000);
|
||
|
if (playLevel(i % LEVELS, pause) == 0) {
|
||
|
return;
|
||
|
}
|
||
|
pause = pause - (pause / 4); // shorten pause (increases speed)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int playLevel(int levelNo, int pause) {
|
||
|
|
||
|
lcdClear();
|
||
|
|
||
|
// load level
|
||
|
int bricks[FIELD_HEIGHT][FIELD_WIDTH];
|
||
|
memcpy(bricks, levels[levelNo], sizeof(bricks));
|
||
|
|
||
|
// initialisation
|
||
|
int ball[2] = {SCREEN_WIDTH / 2, FIELD_HEIGHT * (BRICK_HEIGHT + BRICK_SPACING) + 1};
|
||
|
int direction[2] = {1,1};
|
||
|
int paddleX = SCREEN_WIDTH / 2 - PADDLE_WIDTH / 2;
|
||
|
int lives = LIVES_INITIAL;
|
||
|
|
||
|
drawBricks(bricks);
|
||
|
|
||
|
while ( 1 ) {
|
||
|
|
||
|
// ball
|
||
|
drawBall(ball, 0);
|
||
|
ball[0] += direction[0];
|
||
|
ball[1] += direction[1];
|
||
|
|
||
|
// paddle / user input
|
||
|
drawPaddle(paddleX, 0);
|
||
|
int key = getInputRaw();
|
||
|
switch (key) {
|
||
|
case BTN_ENTER:
|
||
|
// exit
|
||
|
return 0;
|
||
|
case BTN_LEFT:
|
||
|
paddleX -= PADDLE_SPEED;
|
||
|
if (paddleX < 0)
|
||
|
paddleX = 0;
|
||
|
break;
|
||
|
case BTN_RIGHT:
|
||
|
paddleX += PADDLE_SPEED;
|
||
|
if (paddleX + PADDLE_WIDTH > SCREEN_WIDTH)
|
||
|
paddleX = SCREEN_WIDTH - PADDLE_WIDTH;
|
||
|
break;
|
||
|
}
|
||
|
drawPaddle(paddleX, 1);
|
||
|
|
||
|
// collisions
|
||
|
|
||
|
// bricks
|
||
|
int x = ball[0] / ((BRICK_WIDTH + BRICK_SPACING));
|
||
|
int y = ball[1] / ((BRICK_HEIGHT + BRICK_SPACING));
|
||
|
if (0 <= x && x < FIELD_WIDTH && 0 <= y && y < FIELD_HEIGHT) {
|
||
|
if (bricks[y][x] == 1) {
|
||
|
// collision with brick
|
||
|
int xRel = ball[0] - x * (BRICK_WIDTH + BRICK_SPACING);
|
||
|
int yRel = ball[1] - y * (BRICK_HEIGHT + BRICK_SPACING);
|
||
|
if (xRel == 0 || xRel == BRICK_WIDTH)
|
||
|
direction[0] *= -1; // hit top or bottom
|
||
|
if (yRel == 0 || yRel == BRICK_HEIGHT)
|
||
|
direction[1] *= -1; // hit left or right
|
||
|
bricks[y][x] = 0;
|
||
|
if (fieldIsCleared(bricks))
|
||
|
return 1; // next level
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// paddle / bottom
|
||
|
if (direction[1] > 0) {
|
||
|
// moving to the bottom
|
||
|
if (ball[1] >= PADDLE_Y) {
|
||
|
if (paddleX <= ball[0] && ball[0] <= paddleX + PADDLE_WIDTH) {
|
||
|
// collision with paddle
|
||
|
direction[1] = - abs(direction[1]);
|
||
|
if (key == BTN_LEFT)
|
||
|
direction[0] = -2;
|
||
|
else if (key == BTN_RIGHT)
|
||
|
direction[0] = 2;
|
||
|
else
|
||
|
direction[0] = (direction[0] > 0) ? 1 : -1;
|
||
|
}
|
||
|
else {
|
||
|
// ball lost
|
||
|
lives--;
|
||
|
if (lives == 0) {
|
||
|
lcdClear();
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln("");
|
||
|
lcdPrintln(" GAME OVER");
|
||
|
lcdRefresh();
|
||
|
delayms(2000);
|
||
|
return 0;
|
||
|
}
|
||
|
ball[0] = SCREEN_WIDTH / 2;
|
||
|
ball[1] = FIELD_HEIGHT * (BRICK_HEIGHT + BRICK_SPACING) + 1;
|
||
|
direction[0] = (paddleX + PADDLE_WIDTH / 2 < ball[0]) ? -1 : 1;
|
||
|
direction[1] = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// walls
|
||
|
|
||
|
if (ball[1] <= 0)
|
||
|
direction[1] = abs(direction[1]);
|
||
|
if (ball[0] <= 0)
|
||
|
direction[0] = abs(direction[0]);
|
||
|
else if (ball[0] >= SCREEN_WIDTH - 1)
|
||
|
direction[0] = - abs(direction[0]);
|
||
|
|
||
|
drawBricks(bricks);
|
||
|
drawBall(ball, 1);
|
||
|
|
||
|
lcdRefresh();
|
||
|
delayms(pause);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void drawBricks(int bricks[FIELD_HEIGHT][FIELD_WIDTH]) {
|
||
|
for (int x = 0; x < FIELD_WIDTH; x++)
|
||
|
for (int y = 0; y < FIELD_HEIGHT; y++)
|
||
|
for (int i = 0; i < BRICK_WIDTH; i++)
|
||
|
for (int j = 0; j < BRICK_HEIGHT; j++)
|
||
|
lcdSetPixel(x * (BRICK_WIDTH + BRICK_SPACING) + i, y * (BRICK_HEIGHT + BRICK_SPACING) + j, bricks[y][x]);
|
||
|
}
|
||
|
|
||
|
void drawPxChk(int x, int y, int color) {
|
||
|
if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT)
|
||
|
return;
|
||
|
lcdSetPixel(x, y, color);
|
||
|
}
|
||
|
|
||
|
void drawBall(int ball[2], int color) {
|
||
|
drawPxChk(ball[0] - 1, ball[1] - 1, color);
|
||
|
drawPxChk(ball[0], ball[1] - 1, color);
|
||
|
drawPxChk(ball[0] + 1, ball[1] - 1, color);
|
||
|
drawPxChk(ball[0] - 1, ball[1], color);
|
||
|
drawPxChk(ball[0], ball[1], color);
|
||
|
drawPxChk(ball[0] + 1, ball[1], color);
|
||
|
drawPxChk(ball[0] - 1, ball[1] + 1, color);
|
||
|
drawPxChk(ball[0], ball[1] + 1, color);
|
||
|
drawPxChk(ball[0] + 1, ball[1] + 1, color);
|
||
|
}
|
||
|
|
||
|
void drawPaddle(int paddleX, int color) {
|
||
|
for (int x = 0; x < PADDLE_WIDTH; x++) {
|
||
|
lcdSetPixel(paddleX + x, PADDLE_Y, color);
|
||
|
lcdSetPixel(paddleX + x, PADDLE_Y + 1, color);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int fieldIsCleared(int bricks[FIELD_HEIGHT][FIELD_WIDTH]) {
|
||
|
for (int x = 0; x < FIELD_WIDTH; x++)
|
||
|
for (int y = 0; y < FIELD_HEIGHT; y++)
|
||
|
if (bricks[y][x] == 1)
|
||
|
return 0;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int abs(int x) {
|
||
|
if (x < 0)
|
||
|
return x * -1;
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
|