diff options
| author | Oskari Timperi <oskari.timperi@iki.fi> | 2016-09-07 18:22:41 +0300 |
|---|---|---|
| committer | Oskari Timperi <oskari.timperi@iki.fi> | 2016-09-07 18:22:41 +0300 |
| commit | 7a080b6d053fd0965641ee38dcd55fb7f015ebba (patch) | |
| tree | 2b2e8a784cc729649b4bf2107305b3b788980618 | |
| download | breakout-master.tar.gz breakout-master.zip | |
| -rw-r--r-- | Makefile | 16 | ||||
| -rw-r--r-- | Makefile.mingw | 15 | ||||
| -rw-r--r-- | main.c | 274 | ||||
| -rw-r--r-- | timer.c | 48 | ||||
| -rw-r--r-- | timer.h | 16 |
5 files changed, 369 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..35c00a4 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +CC = gcc +RAYLIB = ../raylib +INCDIR = -I$(RAYLIB)/src +CFLAGS += -Wall $(INCDIR) +LDFLAGS += $(LIBDIR) +LIBRAYLIB = $(RAYLIB)/release/linux/libraylib.a +LIBGLFW3 = $(RAYLIB)/src/external/glfw3/lib/linux/libglfw3.a +LDLIBS += $(LIBRAYLIB) $(LIBGLFW3) -lm -ldl -lpthread -lX11 -lXrandr \ + -lXinerama -lXi -lXxf86vm -lXcursor + +breakout: main.c timer.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean +clean: + rm -f breakout diff --git a/Makefile.mingw b/Makefile.mingw new file mode 100644 index 0000000..dd4c833 --- /dev/null +++ b/Makefile.mingw @@ -0,0 +1,15 @@ +CC = i686-w64-mingw32-gcc +RAYLIB = ../raylib +INCDIR = -I$(RAYLIB)/src +CFLAGS += -Wall $(INCDIR) +LDFLAGS += $(LIBDIR) +LIBRAYLIB = $(RAYLIB)/release/win32/mingw32/libraylib.a +LIBGLFW3 = $(RAYLIB)/src/external/glfw3/lib/win32/libglfw3.a +LDLIBS += $(LIBRAYLIB) $(LIBGLFW3) -lgdi32 + +breakout.exe: main.c timer.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean +clean: + rm -f breakout @@ -0,0 +1,274 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <time.h> + +#include "raylib.h" + +#include "timer.h" + +#define screenWidth (800) +#define screenHeight (600) +#define tileCountX (7) +#define tileCountY (5) +#define xMargin (10) +#define yMargin (10) +#define levelYOffset (20) +#define ballRadius (5) +#define tileWidth ((screenWidth - xMargin*2) / tileCountX) +#define tileHeight ((screenHeight / 2 - yMargin - levelYOffset) / tileCountY) +static const Color tileColor[5] = { RED, GREEN, BLUE }; + +typedef struct Game +{ + Rectangle paddle; + Vector2 ball; + Vector2 ballVelocity; + Timer movementTimer; + int tiles[tileCountX][tileCountY]; + bool started; + int score; + bool gameOver; +} Game; + +bool CheckBallCollisionRec(Vector2 center, float radius, Rectangle rec, + Vector2 *velocity) +{ + if (CheckCollisionCircleRec(center, radius, rec)) + { + if (rec.x >= center.x) + { + velocity->x = -velocity->x; + } + else if (rec.x+rec.width <= center.x) + { + velocity->x = -velocity->x; + } + else if (rec.y >= center.y) + { + velocity->y = -velocity->y; + } + else if (rec.y+rec.height <= center.y) + { + velocity->y = -velocity->y; + } + + return true; + } + + return false; +} + +void GameInitialize(Game *game) +{ + memset(game, 0, sizeof(*game)); + + game->paddle.width = 50; + game->paddle.height = 10; + game->paddle.x = screenWidth / 2 - game->paddle.width / 2; + game->paddle.y = screenHeight - yMargin - game->paddle.height; + + game->ball.x = screenWidth / 2; + game->ball.y = screenHeight - screenHeight / 4; + + game->ballVelocity.x = 100; + game->ballVelocity.y = -100; + + TimerStart(&game->movementTimer); + + for (int i = 0; i < tileCountX; ++i) + { + for (int j = 0; j < tileCountY; ++j) + { + game->tiles[i][j] = GetRandomValue(1, 3); + } + } +} + +Rectangle GetTileRect(int tx, int ty) +{ + Rectangle tile; + + tile.x = xMargin + tx * tileWidth; + tile.y = yMargin + levelYOffset + ty * tileHeight; + tile.width = tileWidth; + tile.height = tileHeight; + + return tile; +} + +void GameHandleKeys(Game *game, int64_t elapsed) +{ + if (!game->gameOver) + { + if (IsKeyDown(KEY_RIGHT)) + { + game->paddle.x += 160 * elapsed / 1000 / 1000; + if (!game->started) + game->started = true; + } + else if (IsKeyDown(KEY_LEFT)) + { + game->paddle.x -= 160 * elapsed / 1000 / 1000; + if (!game->started) + game->started = true; + } + + if (game->paddle.x < 0) + game->paddle.x = 0; + else if (game->paddle.x > screenWidth - game->paddle.width) + game->paddle.x = screenWidth - game->paddle.width; + } + else + { + if (IsKeyPressed(KEY_SPACE)) + { + GameInitialize(game); + } + } +} + +void GameHandleBallTileCollisions(Game *game) +{ + for (int i = 0; i < tileCountX; ++i) + { + for (int j = 0; j < tileCountY; ++j) + { + Rectangle tileRect = GetTileRect(i, j); + + if (!game->tiles[i][j]) + continue; + + if (CheckBallCollisionRec(game->ball, 5, tileRect, + &game->ballVelocity)) + { + game->tiles[i][j] -= 1; + game->score++; + if (game->tiles[i][j] == 0) + game->score++; + return; + } + } + } +} + +void GameHandleBallPaddleCollision(Game *game) +{ + CheckBallCollisionRec(game->ball, 5, game->paddle, &game->ballVelocity); +} + +void GameHandleBallScreenCollision(Game *game) +{ + if (game->ball.x+5 >= screenWidth) + { + game->ball.x = screenWidth-5; + game->ballVelocity.x = -game->ballVelocity.x; + } + else if (game->ball.x-5 <= 0) + { + game->ball.x = 5; + game->ballVelocity.x = -game->ballVelocity.x; + } + + if (game->ball.y-5 <= 0) + { + game->ball.y = 5; + game->ballVelocity.y = -game->ballVelocity.y; + } + else if (game->ball.y+5 >= screenHeight) + { + game->gameOver = true; + } +} + +void GameUpdate(Game *game) +{ + int64_t elapsed = TimerElapsedMicro(&game->movementTimer); + + GameHandleKeys(game, elapsed); + + if (!game->gameOver) + { + if (game->started) + { + game->ball.x += game->ballVelocity.x * elapsed / 1000 / 1000; + game->ball.y += game->ballVelocity.y * elapsed / 1000 / 1000; + + GameHandleBallScreenCollision(game); + GameHandleBallPaddleCollision(game); + GameHandleBallTileCollisions(game); + } + } + + TimerStart(&game->movementTimer); +} + +void DrawTextCentered(const char *text, int width, int y, int size, Color color) +{ + int textWidth = MeasureText(text, size); + DrawText(text, width/2 - textWidth/2, y, size, color); +} + +void GameDraw(Game *game) +{ + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawRectangleRec(game->paddle, BLACK); + + DrawCircle(game->ball.x, game->ball.y, 5, BLACK); + + for (int i = 0; i < tileCountX; ++i) + { + for (int j = 0; j < tileCountY; ++j) + { + Rectangle tileRect = GetTileRect(i, j); + Color color = tileColor[game->tiles[i][j]-1]; + DrawRectangleRec(tileRect, color); + } + } + + DrawText(FormatText("SCORE: %i", game->score), xMargin, yMargin, 20, + MAROON); + + if (!game->started) + { + DrawTextCentered("START!", screenWidth, screenHeight/2, 40, BLACK); + } + + if (game->gameOver) + { + DrawTextCentered("GAME OVER!", screenWidth, screenHeight/2, 40, BLACK); + DrawTextCentered("Press SPACE to try again.", screenWidth, + screenHeight/2 + 40, 20, BLACK); + } + + EndDrawing(); +} + +int main(int argc, char **argv) +{ + Game game; + + srand(time(0)); + + TimerInit(); + + GameInitialize(&game); + + InitWindow(screenWidth, screenHeight, "Breakout"); + + SetTargetFPS(60); + + while (!WindowShouldClose()) + { + GameUpdate(&game); + GameDraw(&game); + } + + CloseWindow(); + + return 0; +} @@ -0,0 +1,48 @@ +#include "timer.h" + +#include <time.h> + +#if defined(_WIN32) +#include <windows.h> +int64_t frequency; +#endif + +void TimerInit() +{ +#if defined(_WIN32) + QueryPerformanceFrequency((LARGE_INTEGER *) &frequency); +#endif +} + +int64_t TimerGetTimeMicro() +{ +#if defined(_WIN32) + int64_t value; + QueryPerformanceCounter((LARGE_INTEGER *) &value); + value = value * 1000LL*1000LL; + return value / frequency; +#else + struct timespec tp; + if (clock_gettime(CLOCK_MONOTONIC, &tp)) + { + return 0; + } + return (((int64_t) tp.tv_sec) * 1000LL*1000LL*1000LL + ((int64_t) tp.tv_nsec)) / 1000LL; +#endif +} + +void TimerStart(Timer *timer) +{ + *timer = TimerGetTimeMicro(); +} + +int64_t TimerElapsedMicro(Timer *timer) +{ + int64_t now = TimerGetTimeMicro(timer); + return now - *timer; +} + +int64_t TimerElapsedMilli(Timer *timer) +{ + return TimerElapsedMicro(timer) / 1000LL; +} @@ -0,0 +1,16 @@ +#ifndef TIMER_H +#define TIMER_H + +#include <stdint.h> + +typedef int64_t Timer; + +void TimerInit(); + +void TimerStart(Timer *timer); + +int64_t TimerElapsedMicro(Timer *timer); + +int64_t TimerElapsedMilli(Timer *timer); + +#endif |
