Skip to content

Instantly share code, notes, and snippets.

@theshaneobrien

theshaneobrien/main.c Secret

Last active Dec 8, 2019
Embed
What would you like to do?
MegaDrive Breakout
#include <genesis.h>
#include <resources.h>
#include <string.h>
#include <tools.h>
//Edge of the playing field / screen
const int LEFT_EDGE = 0;
const int RIGHT_EDGE = 320;
const int TOP_EDGE = 0;
const int BOTTOM_EDGE = 224;
Sprite* ball;
Sprite* player;
//Ball vars
int ballPosX = 100;
int ballPosY = 100;
int ballVelX = 1;
int ballVelY = 1;
int ballWidth = 8;
int ballHeight = 8;
int ballReleased = FALSE;
//Brick vars
struct Brick
{
Sprite* brickSprite;
int brickPosX;
int brickPosY;
};
struct Brick bricksArray[24];
int maxBricks = 24;
int currentBricksHit = 0;
const int BRICK_WIDTH = 32;
const int BRICK_HEIGHT = 16;
//Player vars
int playerPosX = 144;
const int PLAYER_POS_Y = 200;
int playerVelX = 0;
const int PLAYER_WIDTH = 32;
const int PLAYER_HEIGHT = 8;
//Score vars
int score = 0;
char labelScore[6] = "SCORE\0";
char strScore[3] = "0";
//UI vars
int gameOn = FALSE;
char msgStart[22] = "Press Start to Begin!\0";
char msgReset[37] = "Game Over! Press Start to play Again.";
char msgComplete[43] = "Congratulations! Start to play Again.";
//Juice
int flasing = FALSE;
int frames = 0;
int ball_color = 0;
int playerVelDirection()
{
int x = random();
if (x > 32767)
{
return -1;
}
else if (x < 32767)
{
return 1;
}
}
int sign(int x)
{
return (x > 0) - (x < 0);
}
void showText(char s[])
{
VDP_drawText(s, 20 - strlen(s) / 2, 15);
}
void updateScoreDisplay()
{
sprintf(strScore, "%d", score);
//This clears the tiles where the text was too
VDP_clearText(1, 2, 3);
//Add the tiles behind the text again
VDP_fillTileMapRect(PLAN_B, TILE_ATTR_FULL(PAL1, 0, FALSE, FALSE, 1), 0, 0, 40, 30);
VDP_drawText(strScore, 1, 2);
}
void startGame()
{
makeBrickField();
score = 0;
updateScoreDisplay();
ballPosX = playerPosX + 16;
ballPosY = PLAYER_POS_Y - 10;
ballVelX = playerVelDirection();
ballVelY = -1;
//Clear the text from the screen
VDP_clearTextArea(0, 10, 40, 10);
//Replace the tiles we've cleared
VDP_fillTileMapRect(PLAN_B, TILE_ATTR_FULL(PAL1, 0, FALSE, FALSE, 1), 0, 10, 40, 10);
gameOn = TRUE;
}
void endGame()
{
XGM_setPCM(65, &gameOver, 17408);
XGM_startPlayPCM(65, 1, SOUND_PCM_CH2);
//SND_startPlay_4PCM(&gameOver, 39424, SOUND_PCM_CH1, 0);
showText(msgReset);
gameOn = FALSE;
}
void winGame()
{
XGM_setPCM(65, &win, 36352);
XGM_startPlayPCM(65, 1, SOUND_PCM_CH2);
showText(msgComplete);
gameOn = FALSE;
}
//AABB Collision
void paddleBallCollision()
{
//Check if the left edge of the ball is to the left of the right edfe of the paddle
//Check if the right edge of the ball is to the right of the left edge of the paddle
if (ballPosX < playerPosX + PLAYER_WIDTH && ballPosX + ballWidth > playerPosX)
{
//Check if we are inside the vertical bounds of the player paddle
if (ballPosY < PLAYER_POS_Y + PLAYER_HEIGHT && ballPosY + ballHeight >= PLAYER_POS_Y)
{
XGM_setPCM(65, &hit, 4352);
XGM_startPlayPCM(65, 1, SOUND_PCM_CH2);
//SND_startPlay_4PCM(&hit, 9728, SOUND_PCM_CH1, SOUND_PCM_CH3);
//A collision is happening!
ballPosY = PLAYER_POS_Y - ballHeight - 1;
ballVelY = -ballVelY;
flasing = TRUE;
}
}
}
void ballCollisionAction(int brickIndex)
{
XGM_setPCM(66, &hitBrick, 4608);
XGM_startPlayPCM(66, 1, SOUND_PCM_CH2);
//Destroy Brick
SPR_releaseSprite(bricksArray[brickIndex].brickSprite);
bricksArray[brickIndex].brickPosX = -BRICK_WIDTH;
bricksArray[brickIndex].brickPosY = -BRICK_HEIGHT;
flasing = TRUE;
score++;
updateScoreDisplay();
if (score % 10 == 0)
{
ballVelX += sign(ballVelX);
ballVelY += sign(ballVelY);
}
currentBricksHit++;
checkWin();
}
void ballBrickCollision()
{
for (int i = 0; i < maxBricks; i++)
{
//Check Bottom brick collision
if (ballPosX < bricksArray[i].brickPosX + BRICK_WIDTH - 2 && ballPosX + ballWidth > bricksArray[i].brickPosX + 2)
{
if (ballPosY < bricksArray[i].brickPosY + BRICK_HEIGHT && ballPosY + ballHeight >= bricksArray[i].brickPosY + 20)
{
ballCollisionAction(i);
ballVelY = -ballVelY;
}
}
//Check Top BrickCollision
if (ballPosX < bricksArray[i].brickPosX + BRICK_WIDTH - 2 && ballPosX + ballWidth > bricksArray[i].brickPosX + 2)
{
if (ballPosY < bricksArray[i].brickPosY + BRICK_HEIGHT - 20 && ballPosY + ballHeight >= bricksArray[i].brickPosY)
{
ballCollisionAction(i);
ballVelY = -ballVelY;
}
}
//Check Left Side
if (ballPosX < bricksArray[i].brickPosX + BRICK_WIDTH -28 && ballPosX + ballWidth > bricksArray[i].brickPosX)
{
if (ballPosY < bricksArray[i].brickPosY + BRICK_HEIGHT - 4 && ballPosY + ballHeight >= bricksArray[i].brickPosY + 4)
{
ballCollisionAction(i);
ballVelX = -ballVelX
;
}
}
//Check Right Side
if (ballPosX < bricksArray[i].brickPosX + BRICK_WIDTH && ballPosX + ballWidth > bricksArray[i].brickPosX + 28)
{
if (ballPosY < bricksArray[i].brickPosY + BRICK_HEIGHT - 4 && ballPosY + ballHeight >= bricksArray[i].brickPosY + 4)
{
ballCollisionAction(i);
ballVelX = -ballVelX;
}
}
}
}
void moveBall()
{
if(ballReleased == TRUE)
{
//Check horizontal bounds
if(ballPosX < LEFT_EDGE){
ballPosX = LEFT_EDGE;
ballVelX = -ballVelX;
XGM_setPCM(65, &wall, 6400);
XGM_startPlayPCM(65, 1, SOUND_PCM_CH2);
}
else if (ballPosX + ballWidth > RIGHT_EDGE)
{
ballPosX = RIGHT_EDGE - ballWidth;
ballVelX = -ballVelX;
XGM_setPCM(65, &wall, 6400);
XGM_startPlayPCM(65, 1, SOUND_PCM_CH2);
}
//Check vertical bounds
if(ballPosY < TOP_EDGE)
{
ballPosY = TOP_EDGE;
ballVelY = -ballVelY;
XGM_setPCM(65, &wall, 6400);
XGM_startPlayPCM(65, 1, SOUND_PCM_CH2);
}
else if (ballPosY + ballHeight > BOTTOM_EDGE)
{
endGame();
}
paddleBallCollision();
ballBrickCollision();
//Ball Movement Logic here
ballPosX += ballVelX;
ballPosY += ballVelY;
}
else if (ballReleased == FALSE)
{
ballPosX = (playerPosX + 1) + (PLAYER_WIDTH / 2) - (ballWidth / 2);
ballPosY = PLAYER_POS_Y - 10;
}
//Update the Sprites Pos
SPR_setPosition(ball, ballPosX,ballPosY);
}
void flashBall()
{
if (flasing == TRUE)
{
//Flashing code goes here
frames++;
if (frames % 4 == 0)
{
VDP_setPaletteColor(22, ball_color);
}
else if (frames % 2 == 0)
{
VDP_setPaletteColor(22, RGB24_TO_VDPCOLOR(0xffffff));
}
if (frames > 12)
{
flasing = FALSE;
frames = 0;
VDP_setPaletteColor(22, ball_color);
}
}
}
void positionPlayer()
{
//Add the player's velocity to its position
playerPosX += playerVelX;
//Keep the player within the bounds of the screen
if(playerPosX < LEFT_EDGE)
{
playerPosX = LEFT_EDGE;
}
if(playerPosX + PLAYER_WIDTH > RIGHT_EDGE)
{
playerPosX = RIGHT_EDGE - PLAYER_WIDTH;
}
//Tell the sprite engine to position the sprite
SPR_setPosition(player, playerPosX, PLAYER_POS_Y);
}
void makeBrickField()
{
int x = 1;
int y = 1;
for (int i = 0; i < maxBricks; i++)
{
bricksArray[i].brickSprite = SPR_addSprite(&bricks, x * 32, y*30, TILE_ATTR(PAL1, 0, FALSE, FALSE));
bricksArray[i].brickPosX = x * 32;
bricksArray[i].brickPosY = y * 30;
x++;
if(x > 8)
{
y++;
x = 1;
}
}
}
void resetGame()
{
//Remove all existing sprites
for (int i = 0; i < maxBricks; i++)
{
SPR_releaseSprite(bricksArray[i].brickSprite);
}
gameOn = FALSE;
ballReleased = FALSE;
playerPosX = 144;
currentBricksHit = 0;
}
void checkWin()
{
if(currentBricksHit >= maxBricks)
{
winGame();
}
}
void myJoyHandler(u16 joy, u16 changed, u16 state)
{
//If the player 1 port Joypad was firing an event
if (joy == JOY_1)
{
if (state & BUTTON_START)
{
if (!gameOn)
{
resetGame();
startGame();
}
}
if (state & BUTTON_A || state & BUTTON_B || state & BUTTON_C)
{
if (ballReleased == FALSE)
{
ballReleased = TRUE;
}
}
//Set the player velocity if the left or right dpad are pressed;
//Set velocity to 0 if no direction is pressed
//State = This will be 1 if the button is currently pressed and 0 if it isn’t.
if (state & BUTTON_RIGHT)
{
playerVelX = 3;
}
else if (state & BUTTON_LEFT)
{
playerVelX = -3;
}
else
{
//changed = This tells us whether the state of a button has changed over the last frame.
//If the current state is different from the state in the previous frame, this will be 1 (otherwise 0).
if ((changed & BUTTON_RIGHT) | (changed & BUTTON_LEFT))
{
playerVelX = 0;
}
}
}
}
int main()
{
//init game
resetGame();
//Play a sound effect and some chill beats
XGM_setLoopNumber(10);
XGM_setPCM(65, &start, 17664);
XGM_startPlayPCM(65, 1, SOUND_PCM_CH2);
XGM_startPlay(&music);
//Init the Joypad
JOY_init();
//Defines a function for joystick callbacks
JOY_setEventHandler(&myJoyHandler);
//Load our tileset
VDP_loadTileSet(bgtile.tileset, 1, DMA);
//Set the current pallet
VDP_setPalette(PAL1, bgtile.palette->data);
//Fill the screen
VDP_fillTileMapRect(PLAN_B, TILE_ATTR_FULL(PAL1, 0, FALSE, FALSE, 1), 0, 0, 40, 30);
//Draw the UI on Plane A
VDP_setTextPlan(PLAN_A);
VDP_drawText(labelScore, 1, 1);
//Draw the UI on Plane B
VDP_setTextPlan(PLAN_B);
VDP_drawText(labelScore, 1, 1);
updateScoreDisplay();
showText(msgStart);
//Initiate Sprite Engine
SPR_init(0,0,0);
//Assign our Sprite
ball = SPR_addSprite(&imgball, (playerPosX + 1) + (PLAYER_WIDTH / 2) - (ballWidth / 2), PLAYER_POS_Y - 10,TILE_ATTR(PAL1,0,FALSE,FALSE));
player = SPR_addSprite(&paddle, playerPosX, PLAYER_POS_Y, TILE_ATTR(PAL1, 0, FALSE, FALSE));
ball_color = VDP_getPaletteColor(22);
//Update + waitVsync = do stuff per frame
while (1)
{
if(gameOn)
{
moveBall();
positionPlayer();
flashBall();
//Handle flashing of the ball
}
//Update the Sprite drawing
SPR_update();
VDP_waitVSync();
}
return(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.