This commit is contained in:
Tobias Berger 2021-11-29 16:43:21 +01:00
parent 1a1a73ea9f
commit 95f105fd96
9 changed files with 252 additions and 236 deletions

8
.vscode/tasks.json vendored
View file

@ -8,7 +8,7 @@
"type": "shell", "type": "shell",
"command": "gcc", "command": "gcc",
"args": [ "args": [
{ "value": "src/**.cpp", "quoting": "weak" }, { "value": "src/**.c", "quoting": "weak" },
{ "value": "-ooutput.exe", "quoting": "strong" }, { "value": "-ooutput.exe", "quoting": "strong" },
{ "value": "-Og", "quoting": "strong" }, { "value": "-Og", "quoting": "strong" },
{ "value": "-g", "quoting": "strong" }, { "value": "-g", "quoting": "strong" },
@ -16,7 +16,7 @@
{ "value": "-Iraylib/src", "quoting": "strong" }, { "value": "-Iraylib/src", "quoting": "strong" },
{ "value": "-Iraylib/src/extras", "quoting": "strong" }, { "value": "-Iraylib/src/extras", "quoting": "strong" },
{ "value": "-Llib", "quoting": "strong" }, { "value": "-Llib", "quoting": "strong" },
{ "value": "-std=c++2a", "quoting": "strong" }, { "value": "-std=c17", "quoting": "strong" },
{ "value": "-Werror", "quoting": "strong" }, { "value": "-Werror", "quoting": "strong" },
{ "value": "-Wall", "quoting": "strong" }, { "value": "-Wall", "quoting": "strong" },
{ "value": "-Wextra", "quoting": "strong" }, { "value": "-Wextra", "quoting": "strong" },
@ -42,7 +42,7 @@
"type": "shell", "type": "shell",
"command": "gcc", "command": "gcc",
"args": [ "args": [
{ "value": "src/**.cpp", "quoting": "weak" }, { "value": "src/**.c", "quoting": "weak" },
{ "value": "-ooutput.exe", "quoting": "strong" }, { "value": "-ooutput.exe", "quoting": "strong" },
{ "value": "-Ofast", "quoting": "strong" }, { "value": "-Ofast", "quoting": "strong" },
{ "value": "-Iinclude", "quoting": "strong" }, { "value": "-Iinclude", "quoting": "strong" },
@ -50,7 +50,7 @@
{ "value": "-Iraylib/src/extras", "quoting": "strong" }, { "value": "-Iraylib/src/extras", "quoting": "strong" },
{ "value": "-Llib", "quoting": "strong" }, { "value": "-Llib", "quoting": "strong" },
{ "value": "-std=c++2a", "quoting": "strong" }, { "value": "-std=c++2a", "quoting": "strong" },
{ "value": "-Werror", "quoting": "strong" }, { "value": "-Werro17 "quoting": "strong" },
{ "value": "-Wall", "quoting": "strong" }, { "value": "-Wall", "quoting": "strong" },
{ "value": "-Wextra", "quoting": "strong" }, { "value": "-Wextra", "quoting": "strong" },
{ "value": "-Wno-missing-field-initializers", "quoting": "strong" }, { "value": "-Wno-missing-field-initializers", "quoting": "strong" },

View file

@ -8,5 +8,14 @@
"recommendations": [ "recommendations": [
"ms-vscode.cpptools" "ms-vscode.cpptools"
] ]
},
"settings": {
"files.associations": {
"*.lock": "yarnlock",
"*.m": "cpp",
"cstdlib": "cpp",
"raylib.h": "c",
"math.h": "c"
}
} }
} }

33
include/rogue.h Normal file
View file

@ -0,0 +1,33 @@
#include "raylib.h"
typedef struct Vector2i
{
int x;
int y;
} Vector2i;
typedef struct Entity
{
Vector2i position;
Color color;
} Entity;
typedef struct Tile
{
bool walkable;
Color color;
} Tile;
Entity *createPlayer(Vector2i start_position);
Tile **createMapTiles();
void freeMapTiles(Tile **map_tiles);
void renderEverything(RenderTexture2D target);
void initGame();
void mainLoop();
void endGame();
extern unsigned int const MAP_HEIGHT;
extern unsigned int const MAP_WIDTH;
extern Entity *player;
extern Tile **map;

28
src/draw.c Normal file
View file

@ -0,0 +1,28 @@
#include "raylib.h"
#include "rogue.h"
void drawMap(Tile **map)
{
for (unsigned int x = 0; x < MAP_WIDTH; x++)
{
for (unsigned int y = 0; y < MAP_HEIGHT; y++)
{
DrawPixel(x, y, map[x][y].color);
}
}
}
void drawEntity(Entity *entity)
{
DrawPixel(entity->position.x, entity->position.y, entity->color);
}
void renderEverything(RenderTexture2D target)
{
BeginTextureMode(target);
{
drawMap(map);
drawEntity(player);
}
EndTextureMode();
}

118
src/engine.c Normal file
View file

@ -0,0 +1,118 @@
#include "raylib.h"
#include "rogue.h"
static int const PIXEL_SCALE = 10;
static int const VIRTUAL_SCREEN_WIDTH = 80;
static int const VIRTUAL_SCREEN_HEIGHT = 45;
const unsigned int MAP_HEIGHT = VIRTUAL_SCREEN_HEIGHT;
const unsigned int MAP_WIDTH = VIRTUAL_SCREEN_WIDTH;
static int const REAL_SCREEN_WIDTH = VIRTUAL_SCREEN_WIDTH * PIXEL_SCALE;
static int const REAL_SCREEN_HEIGHT = VIRTUAL_SCREEN_HEIGHT * PIXEL_SCALE;
static Rectangle const virtualScreenRect = {0.0f, 0.0f, (float)VIRTUAL_SCREEN_WIDTH, -(float)VIRTUAL_SCREEN_HEIGHT};
static Rectangle const realScreenRect = {0.0f, 0.0f, (float)REAL_SCREEN_WIDTH, (float)REAL_SCREEN_HEIGHT};
RenderTexture2D virtualScreen;
void initGame()
{
// Initialization
//--------------------------------------------------------------------------------------
#if defined(__DEBUG)
SetTraceLogLevel(LOG_ALL);
#else
SetTraceLogLevel(LOG_NONE);
#endif
SetConfigFlags(0);
InitWindow(REAL_SCREEN_WIDTH, REAL_SCREEN_HEIGHT, "TODO: Add a title");
virtualScreen = LoadRenderTexture(VIRTUAL_SCREEN_WIDTH, VIRTUAL_SCREEN_HEIGHT);
player = createPlayer((Vector2i){VIRTUAL_SCREEN_WIDTH / 2, VIRTUAL_SCREEN_HEIGHT / 2});
map = createMapTiles();
// SetTargetFPS(60); // Set our game to run at 60 frames-per-second
}
void update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_RIGHT))
{
player->position.x++;
}
if (IsKeyPressed(KEY_LEFT))
{
player->position.x--;
}
if (IsKeyPressed(KEY_UP))
{
player->position.y--;
}
if (IsKeyPressed(KEY_DOWN))
{
player->position.y++;
}
}
void draw()
{
// Draw
//----------------------------------------------------------------------------------
BeginTextureMode(virtualScreen);
{
ClearBackground(BLACK);
DrawPixel(player->position.x, player->position.y, player->color);
/*
for (unsigned int x = 0; x < VIRTUAL_SCREEN_WIDTH; x++)
{
for (unsigned int y = 0; y < VIRTUAL_SCREEN_HEIGHT; y++)
{
const unsigned char r = (unsigned char)floorf((float)x / (float)VIRTUAL_SCREEN_WIDTH * 255.0f);
const unsigned char b = (unsigned char)floorf((float)y / (float)VIRTUAL_SCREEN_HEIGHT * 255.0f);
const unsigned char g = 255 - (r + b) / 2;
const unsigned char a = 255;
DrawPixel(x, y, (Color){r, g, b, a});
}
}
*/
}
EndTextureMode();
BeginDrawing();
{
ClearBackground(BLACK);
// Draw rendered game texture
DrawTexturePro(virtualScreen.texture, virtualScreenRect, realScreenRect, (Vector2){0.0f, 0.0f}, 0.0f, WHITE);
// Draw GUI here
//--------------------------------------------------------------------------------------
#if __DEBUG
DrawFPS(0, 0);
#endif
}
EndDrawing();
}
void mainLoop()
{
update();
draw();
}
void endGame()
{
// De-Initialization
//--------------------------------------------------------------------------------------
MemFree(player);
freeMapTiles(map);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
}

21
src/main.c Normal file
View file

@ -0,0 +1,21 @@
#include "raylib.h"
#include "math.h"
#include "rogue.h"
Entity *player;
Tile **map;
int main(void)
{
initGame();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
mainLoop();
}
endGame();
return 0;
}

View file

@ -1,232 +0,0 @@
#include "raylib.h"
#include "raymath.h"
#include "monogram.ttf.h"
enum class Player
{
NONE,
RED_PLAYER,
BLUE_PLAYER,
};
Player checkBoard(Player board[9])
{
// horizontal, vertical, and diagonal checks from first cell
if (board[0] != Player::NONE && ((board[0] == board[1] && board[0] == board[2]) || (board[0] == board[3] && board[0] == board[6]) || (board[0] == board[4] && board[0] == board[8])))
return board[0];
// vertical check from second cell
if (board[1] != Player::NONE && (board[1] == board[4] && board[1] == board[7]))
return board[1];
// vertical and diagonal checks from third cell
if (board[2] != Player::NONE && ((board[2] == board[5] && board[2] == board[8]) || (board[2] == board[4] && board[2] == board[6])))
return board[2];
// horizontal check from fourth cell
if (board[3] != Player::NONE && (board[3] == board[4] && board[3] == board[5]))
return board[3];
// horizontal check from seventh cell
if (board[6] != Player::NONE && (board[6] == board[7] && board[6] == board[8]))
return board[6];
return Player::NONE;
}
void resetBoard(Player board[9])
{
for (unsigned char i = 0; i < 9; i++)
{
board[i] = Player::NONE;
}
}
int main(void)
{
// Size of a gameboard pixel
static const int SCREEN_SCALE = 256;
static const int TOPBAR_HEIGHT = 40;
static const int VIRTUAL_SCREEN_SIZE = 3;
static const int SCREEN_SIZE = VIRTUAL_SCREEN_SIZE * SCREEN_SCALE;
static const float TEXT_SPACING = 2.0f;
// Initialization
//--------------------------------------------------------------------------------------
#if defined(__DEBUG)
SetTraceLogLevel(LOG_ALL);
#else
SetTraceLogLevel(LOG_NONE);
#endif
SetConfigFlags(0);
InitWindow(SCREEN_SIZE, SCREEN_SIZE + TOPBAR_HEIGHT, "Tic Tac Toe");
static const int fontChars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '};
Font monogramFont = LoadFontFromMemory(".ttf", monogramFontBytes, sizeof(monogramFontBytes), TOPBAR_HEIGHT, (int *)fontChars, sizeof(fontChars));
/* For drawing */
RenderTexture2D target = LoadRenderTexture(VIRTUAL_SCREEN_SIZE, VIRTUAL_SCREEN_SIZE);
Rectangle sourceRec = {0.0f,
0.0f,
(float)VIRTUAL_SCREEN_SIZE,
-(float)VIRTUAL_SCREEN_SIZE};
Rectangle destRec = {0.0f,
(float)(TOPBAR_HEIGHT),
SCREEN_SIZE,
SCREEN_SIZE};
/* For game logic */
Player board[9];
resetBoard(board);
Player currentPlayer = Player::RED_PLAYER;
unsigned char points[3] = {0, 0, 0};
unsigned char turn = 0;
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
//----------------------------------------------------------------------------------
// Update
//----------------------------------------------------------------------------------
// Toggle borderless
if (IsKeyPressed(KEY_F1))
{
if (IsWindowState(FLAG_WINDOW_UNDECORATED))
{
ClearWindowState(FLAG_WINDOW_UNDECORATED);
}
else
{
SetWindowState(FLAG_WINDOW_UNDECORATED);
}
}
Vector2 mousePos = GetMousePosition();
// Floor instead of trunc to check negative values for out-of-bounds check for cursor
char hovered = (char)floorf(mousePos.x / (float)SCREEN_SCALE) + 3 * (char)floorf((mousePos.y - ((float)TOPBAR_HEIGHT)) / (float)SCREEN_SCALE);
if (hovered < 0 || hovered >= 9 || board[(unsigned char)hovered] != Player::NONE)
{
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
}
else if (board[(unsigned char)hovered] == Player::NONE)
{
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
board[(unsigned char)hovered] = currentPlayer;
currentPlayer = (currentPlayer == Player::RED_PLAYER) ? Player::BLUE_PLAYER : Player::RED_PLAYER;
// Cursor doesn't really matter in this frame
Player winner = checkBoard(board);
// Game is over
if (winner != Player::NONE || (++turn) >= 9)
{
TraceLog(LOG_INFO, TextFormat("Winner: %d", winner));
points[(int)winner]++;
resetBoard(board);
turn = 0;
}
}
else
{
SetMouseCursor(MOUSE_CURSOR_POINTING_HAND);
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginTextureMode(target);
{
ClearBackground(WHITE);
for (unsigned char i = 0; i < 9; i++)
{
Color color;
switch (board[i])
{
case Player::RED_PLAYER:
color = RED;
break;
case Player::BLUE_PLAYER:
color = BLUE;
break;
case Player::NONE:
default:
color = WHITE;
break;
}
const unsigned char x = i % 3;
const unsigned char y = i / 3;
DrawPixel(x, y, color);
if (i == hovered)
{
DrawPixel(x, y, Color{255, 255, 255, 128});
}
}
}
EndTextureMode();
BeginDrawing();
{
ClearBackground(BLACK);
// Draw rendered game texture
DrawTexturePro(target.texture, sourceRec, destRec, Vector2{0.0f, 0.0f}, 0.0f, WHITE);
#if __DEBUG
DrawFPS(0, TOPBAR_HEIGHT);
#endif
// Draw Top Bar
// Current player in top-left corner
switch (currentPlayer)
{
case Player::RED_PLAYER:
DrawRectangle(0, 0, TOPBAR_HEIGHT, TOPBAR_HEIGHT, RED);
break;
case Player::BLUE_PLAYER:
DrawRectangle(0, 0, TOPBAR_HEIGHT, TOPBAR_HEIGHT, BLUE);
break;
default:
break;
}
// Scores in top-left, labelled with colored squares
const char *blueScore = TextFormat("%03u ", points[2]);
const int blueScoreWidth = (int)MeasureTextEx(monogramFont, blueScore, TOPBAR_HEIGHT, TEXT_SPACING).x;
const char *redScore = TextFormat("%03u %s", points[1], blueScore);
const int redScoreWidth = (int)MeasureTextEx(monogramFont, redScore, TOPBAR_HEIGHT, TEXT_SPACING).x;
const char *scoreboard = TextFormat("%03u %s", points[0], redScore);
const int scoreboardWidth = (int)MeasureTextEx(monogramFont, scoreboard, TOPBAR_HEIGHT, TEXT_SPACING).x;
DrawTextEx(monogramFont, scoreboard, Vector2{(float)SCREEN_SIZE - scoreboardWidth, 0}, TOPBAR_HEIGHT, TEXT_SPACING, WHITE);
DrawRectangle(SCREEN_SIZE - TOPBAR_HEIGHT - blueScoreWidth - 2, 0, TOPBAR_HEIGHT, TOPBAR_HEIGHT, BLUE);
DrawRectangle(SCREEN_SIZE - TOPBAR_HEIGHT - redScoreWidth - 2, 0, TOPBAR_HEIGHT, TOPBAR_HEIGHT, RED);
DrawRectangle(SCREEN_SIZE - TOPBAR_HEIGHT - scoreboardWidth - 2, 0, TOPBAR_HEIGHT, TOPBAR_HEIGHT, WHITE);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

27
src/map.c Normal file
View file

@ -0,0 +1,27 @@
#include "rogue.h"
Tile **createMapTiles()
{
Tile **tiles = MemAlloc(sizeof(Tile *) * MAP_WIDTH);
for (unsigned int x = 0; x < MAP_WIDTH; x++)
{
tiles[x] = MemAlloc(sizeof(Tile) * MAP_HEIGHT);
for (unsigned int y = 0; y < MAP_HEIGHT; y++)
{
tiles[x][y].color = WHITE;
tiles[x][y].walkable = false;
}
}
return tiles;
}
void freeMapTiles(Tile **map_tiles)
{
for (unsigned int x = 0; x < MAP_WIDTH; x++)
{
MemFree(map_tiles[x]);
}
MemFree(map_tiles);
}

12
src/player.c Normal file
View file

@ -0,0 +1,12 @@
#include "rogue.h"
#include "raylib.h"
Entity *createPlayer(Vector2i const start_position)
{
Entity *const newPlayer = MemAlloc(sizeof(Entity));
newPlayer->position = start_position;
newPlayer->color = DARKBLUE;
return newPlayer;
}