commit 048575c14cb23267b94a3c9159b909c440000f20 Author: Jens Date: Sat Mar 21 15:45:24 2026 +0100 init diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..1a7df27 --- /dev/null +++ b/.clang-format @@ -0,0 +1,9 @@ +--- +BasedOnStyle: Google + +IndentWidth: 4 +BreakBeforeBraces: Linux +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +BinPackArguments: false +BinPackParameters: false diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f7c83c8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*] +root = true +indent_style = space +indent_size = 4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a2d95df --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Xmake cache +.xmake/ +build/ +.cache + +# MacOS Cache +.DS_Store + + + diff --git a/assets/ball.aseprite b/assets/ball.aseprite new file mode 100644 index 0000000..540d179 Binary files /dev/null and b/assets/ball.aseprite differ diff --git a/assets/ball.png b/assets/ball.png new file mode 100644 index 0000000..b717db9 Binary files /dev/null and b/assets/ball.png differ diff --git a/assets/block.aseprite b/assets/block.aseprite new file mode 100644 index 0000000..560e374 Binary files /dev/null and b/assets/block.aseprite differ diff --git a/assets/block.png b/assets/block.png new file mode 100644 index 0000000..e695545 Binary files /dev/null and b/assets/block.png differ diff --git a/compile_commands.json b/compile_commands.json new file mode 100644 index 0000000..9241b06 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1,31 @@ +[ +{ + "directory": "/home/jens/Development/cex/colossus_march", + "arguments": ["/usr/bin/gcc", "-c", "-m64", "-g", "-O0", "-std=c23", "-Isrc", "-Isrc/screens", "-I", "/home/jens/.xmake/packages/r/raylib/5.5/efaf75c5cc7042868d9f9fc4196a080a/include", "-I", "/home/jens/.xmake/packages/b/box2d/v3.1.1/2aecaa50772341c7b9eb7c79ee9859aa/include", "-o", "build/.objs/colossus_march/linux/x86_64/debug/src/screens/intro.c.o", "src/screens/intro.c"], + "file": "src/screens/intro.c" +}, +{ + "directory": "/home/jens/Development/cex/colossus_march", + "arguments": ["/usr/bin/gcc", "-c", "-m64", "-g", "-O0", "-std=c23", "-Isrc", "-Isrc/screens", "-I", "/home/jens/.xmake/packages/r/raylib/5.5/efaf75c5cc7042868d9f9fc4196a080a/include", "-I", "/home/jens/.xmake/packages/b/box2d/v3.1.1/2aecaa50772341c7b9eb7c79ee9859aa/include", "-o", "build/.objs/colossus_march/linux/x86_64/debug/src/screens/menu.c.o", "src/screens/menu.c"], + "file": "src/screens/menu.c" +}, +{ + "directory": "/home/jens/Development/cex/colossus_march", + "arguments": ["/usr/bin/gcc", "-c", "-m64", "-g", "-O0", "-std=c23", "-Isrc", "-Isrc/screens", "-I", "/home/jens/.xmake/packages/r/raylib/5.5/efaf75c5cc7042868d9f9fc4196a080a/include", "-I", "/home/jens/.xmake/packages/b/box2d/v3.1.1/2aecaa50772341c7b9eb7c79ee9859aa/include", "-o", "build/.objs/colossus_march/linux/x86_64/debug/src/screens/game.c.o", "src/screens/game.c"], + "file": "src/screens/game.c" +}, +{ + "directory": "/home/jens/Development/cex/colossus_march", + "arguments": ["/usr/bin/gcc", "-c", "-m64", "-g", "-O0", "-std=c23", "-Isrc", "-Isrc/screens", "-I", "/home/jens/.xmake/packages/r/raylib/5.5/efaf75c5cc7042868d9f9fc4196a080a/include", "-I", "/home/jens/.xmake/packages/b/box2d/v3.1.1/2aecaa50772341c7b9eb7c79ee9859aa/include", "-o", "build/.objs/colossus_march/linux/x86_64/debug/src/sprite.c.o", "src/sprite.c"], + "file": "src/sprite.c" +}, +{ + "directory": "/home/jens/Development/cex/colossus_march", + "arguments": ["/usr/bin/gcc", "-c", "-m64", "-g", "-O0", "-std=c23", "-Isrc", "-Isrc/screens", "-I", "/home/jens/.xmake/packages/r/raylib/5.5/efaf75c5cc7042868d9f9fc4196a080a/include", "-I", "/home/jens/.xmake/packages/b/box2d/v3.1.1/2aecaa50772341c7b9eb7c79ee9859aa/include", "-o", "build/.objs/colossus_march/linux/x86_64/debug/src/main.c.o", "src/main.c"], + "file": "src/main.c" +}, +{ + "directory": "/home/jens/Development/cex/colossus_march", + "arguments": ["/usr/bin/gcc", "-c", "-m64", "-g", "-O0", "-std=c23", "-Isrc", "-Isrc/screens", "-I", "/home/jens/.xmake/packages/r/raylib/5.5/efaf75c5cc7042868d9f9fc4196a080a/include", "-I", "/home/jens/.xmake/packages/b/box2d/v3.1.1/2aecaa50772341c7b9eb7c79ee9859aa/include", "-o", "build/.objs/colossus_march/linux/x86_64/debug/src/screens.c.o", "src/screens.c"], + "file": "src/screens.c" +}] diff --git a/screenshot000.png b/screenshot000.png new file mode 100644 index 0000000..9c18905 Binary files /dev/null and b/screenshot000.png differ diff --git a/src/defs.h b/src/defs.h new file mode 100644 index 0000000..2640895 --- /dev/null +++ b/src/defs.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include "raylib.h" + +#define GAME_NAME "Colossus March" + +#define BG CLITERAL(Color){243, 223, 162, 255} +#define BALL CLITERAL(Color){126, 189, 194, 255} +#define BLOCK CLITERAL(Color){187, 68, 48, 255} + +#define length(a) (sizeof(a) / sizeof(*a)) + +#define append(a, i) \ + { \ + a.data[a.len] = i; \ + a.len++; \ + } + +typedef size_t size; + +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef struct GameContext { + bool exit; +} GameContext; + +extern GameContext g_ctx; diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..82bee5b --- /dev/null +++ b/src/main.c @@ -0,0 +1,30 @@ +#include + +#include "defs.h" +#include "raylib.h" +#include "screens.h" + +GameContext g_ctx = {0}; + +int main(void) +{ + SetConfigFlags(FLAG_WINDOW_RESIZABLE); + InitWindow(800, 600, "flappu"); + SetTargetFPS(144); + SetExitKey(KEY_F12); + + while (!WindowShouldClose() && !g_ctx.exit) { + screen_update(); + + BeginDrawing(); + ClearBackground(BG); + + screen_draw(); + + EndDrawing(); + } + + CloseWindow(); + + return 0; +} diff --git a/src/screens.c b/src/screens.c new file mode 100644 index 0000000..6fa105b --- /dev/null +++ b/src/screens.c @@ -0,0 +1,65 @@ +#include "screens.h" + +#include "game.h" +#include "intro.h" +#include "menu.h" + +static Screen active_screen = Intro; + +void screen_switch_to(Screen screen) +{ + if (screen != active_screen) { + switch (active_screen) { + case Intro: + intro_screen_cleanup(); + break; + case Menu: + menu_screen_cleanup(); + break; + case Game: + game_screen_cleanup(); + break; + } + + active_screen = screen; + + switch (active_screen) { + case Intro: + case Menu: + break; + case Game: + game_screen_init(); + break; + } + } +} + +void screen_update() +{ + switch (active_screen) { + case Intro: { + intro_screen_update(); + } break; + case Menu: { + menu_screen_update(); + } break; + case Game: { + game_screen_update(); + } break; + } +} + +void screen_draw() +{ + switch (active_screen) { + case Intro: { + intro_screen_draw(); + } break; + case Menu: { + menu_screen_draw(); + } break; + case Game: { + game_screen_draw(); + } break; + } +} diff --git a/src/screens.h b/src/screens.h new file mode 100644 index 0000000..138a768 --- /dev/null +++ b/src/screens.h @@ -0,0 +1,11 @@ +#pragma once + +typedef enum Screen { + Intro, + Menu, + Game +} Screen; + +void screen_switch_to(Screen screen); +void screen_update(); +void screen_draw(); diff --git a/src/screens/game.c b/src/screens/game.c new file mode 100644 index 0000000..23b5025 --- /dev/null +++ b/src/screens/game.c @@ -0,0 +1,89 @@ +#include "game.h" + +#include +#include + +#include "raylib.h" +#include "raymath.h" +#include "screens.h" +#include "sprite.h" + +static Player player; +static Camera2D cam; + +static bool paused = false; +static bool game_over = false; + +void process_input() +{ + if (IsKeyPressed(KEY_P)) { + paused = true; + } + + if (IsKeyPressed(KEY_F10)) { + screen_switch_to(Menu); + } +} + +void game_screen_init() +{ + paused = 0; + game_over = 0; + + Sprite* player_sprite = sprite_new("assets/ball.png", + &(Vector2){100, 400}, + NULL, + &(Rectangle){0, 0, 32, 32}, + &BALL); + + Animation* anim = malloc(sizeof(Animation)); + if (!anim) abort(); + + *anim = (Animation){ + .current_frame = 0, .frame_count = 3, .current_time = 0, .fps = 4}; + player_sprite->animation = anim; + player = (Player){player_sprite}; + + cam = (Camera2D){{200, GetScreenHeight() / 2.0f}, player.sprite->pos, 0, 2}; +} + +void game_screen_update() +{ + if (game_over) { + if (IsKeyPressed(KEY_SPACE)) { + game_over = false; + game_screen_cleanup(); + game_screen_init(); + } + return; + } + + if (paused) return; + + float dt = GetFrameTime(); + + process_input(); + + // Update Camera + cam.target = Vector2Lerp(cam.target, player.sprite->pos, 0.1); + + // Update Animation + // TODO: make it scalable + animation_update(player.sprite->animation); +}; + +void game_screen_draw() +{ + BeginMode2D(cam); + + // Draw Stuff + sprite_draw(player.sprite); + + EndMode2D(); +} + +void game_screen_cleanup() +{ + // free player + sprite_free(player.sprite); +}; diff --git a/src/screens/game.h b/src/screens/game.h new file mode 100644 index 0000000..47a751b --- /dev/null +++ b/src/screens/game.h @@ -0,0 +1,12 @@ +#pragma once + +#include "sprite.h" + +typedef struct Player { + Sprite* sprite; +} Player; + +void game_screen_init(); +void game_screen_update(); +void game_screen_draw(); +void game_screen_cleanup(); diff --git a/src/screens/intro.c b/src/screens/intro.c new file mode 100644 index 0000000..4f00980 --- /dev/null +++ b/src/screens/intro.c @@ -0,0 +1,21 @@ +#include "intro.h" + +#include "defs.h" +#include "raylib.h" +#include "screens.h" + +void intro_screen_update() +{ + if (IsKeyPressed(KEY_ENTER)) { + screen_switch_to(Menu); + } +} + +void intro_screen_draw() +{ + DrawText(GAME_NAME, 120, 100, 120, WHITE); +} + +void intro_screen_cleanup() +{ +} diff --git a/src/screens/intro.h b/src/screens/intro.h new file mode 100644 index 0000000..2e626d9 --- /dev/null +++ b/src/screens/intro.h @@ -0,0 +1,5 @@ +#pragma once + +void intro_screen_update(); +void intro_screen_draw(); +void intro_screen_cleanup(); diff --git a/src/screens/menu.c b/src/screens/menu.c new file mode 100644 index 0000000..0b15d23 --- /dev/null +++ b/src/screens/menu.c @@ -0,0 +1,63 @@ +#include "menu.h" + +#include +#include + +#include "defs.h" +#include "raylib.h" +#include "screens.h" + +typedef enum Option { + Start, + Settings, + Quit +} Option; + +static const Option menu_options[] = {Start, Settings, Quit}; +size_t selected = Start; + +void menu_screen_update() +{ + if (IsKeyPressed(KEY_ENTER)) { + switch (menu_options[selected]) { + case Start: + screen_switch_to(Game); + break; + case Settings: + break; + case Quit: + g_ctx.exit = true; + break; + } + } + + if (IsKeyPressed(KEY_DOWN)) { + selected += 1; + } + if (IsKeyPressed(KEY_UP)) { + selected -= 1; + } + + if (selected <= 0) selected = 0; + if (selected >= length(menu_options)) selected = length(menu_options) - 1; +}; + +void menu_screen_draw() +{ + for (size_t i = 0; i < length(menu_options); i++) { + Color color = selected == i ? GREEN : WHITE; + + switch ((Option)menu_options[i]) { + case Start: + DrawText("Start", 20, 100 * i + 100, 64, color); + break; + case Settings: + DrawText("Settings", 20, 100 * i + 100, 64, color); + break; + case Quit: + DrawText("Quit", 20, 100 * i + 100, 64, color); + break; + } + } +} +void menu_screen_cleanup() {}; diff --git a/src/screens/menu.h b/src/screens/menu.h new file mode 100644 index 0000000..b321ffd --- /dev/null +++ b/src/screens/menu.h @@ -0,0 +1,5 @@ +#pragma once + +void menu_screen_update(); +void menu_screen_draw(); +void menu_screen_cleanup(); diff --git a/src/sprite.c b/src/sprite.c new file mode 100644 index 0000000..145d5f9 --- /dev/null +++ b/src/sprite.c @@ -0,0 +1,84 @@ +#include "sprite.h" + +#include +#include +#include + +#include "raylib.h" +#include "raymath.h" + +void* xmalloc(size_t size) +{ + void* p = malloc(size); + if (!p) abort(); + return p; +} + +Sprite* sprite_new(const char* path, + Vector2* pos, + Vector2* anchor, + Rectangle* source, + Color* color) +{ + assert(path && "path must not be empty"); + + Sprite* sprite = xmalloc(sizeof(Sprite)); + if (!sprite) abort(); + + sprite->tex = LoadTexture(path); + + sprite->pos = pos != NULL ? *pos : (Vector2){0, 0}; + + sprite->source = + source != NULL + ? *source + : (Rectangle){0, 0, sprite->tex.width, sprite->tex.height}; + + sprite->anchor = anchor != NULL ? *anchor + : (Vector2){sprite->source.width / 2.0f, + sprite->source.height / 2.0f}; + + sprite->color = color != NULL ? *color : (Color){26, 164, 98, 255}; + + sprite->animation = NULL; + + return sprite; +} + +void sprite_draw(Sprite* s) +{ + Rectangle source = s->source; + + // update source rect if sprite has animation + if (s->animation) { + source.x = source.width * (float)s->animation->current_frame; + } + + DrawTextureRec( + s->tex, source, Vector2Subtract(s->pos, s->anchor), s->color); +} + +void sprite_free(Sprite* s) +{ + if (s->animation) free(s->animation); + UnloadTexture(s->tex); + free(s); +} + +// +// Animation System +// +void animation_update(Animation* a) +{ + float dt = GetFrameTime(); + a->current_time += dt; + + if (a->current_time >= 1.0f / a->fps) { + a->current_time = 0; + a->current_frame++; + + if (a->current_frame >= a->frame_count) { + a->current_frame = 0; + } + } +} diff --git a/src/sprite.h b/src/sprite.h new file mode 100644 index 0000000..8f742c3 --- /dev/null +++ b/src/sprite.h @@ -0,0 +1,32 @@ +#pragma once + +#include "defs.h" +#include "raylib.h" + +typedef struct Animation { + u8 frame_count; + u8 current_frame; + u8 fps; + float current_time; +} Animation; + +typedef struct Sprite { + Texture2D tex; + Vector2 pos; + Vector2 anchor; + Rectangle source; + Color color; + Animation* animation; +} Sprite; + +Sprite* sprite_new(const char* path, + Vector2* pos, + Vector2* anchor, + Rectangle* source, + Color* color); + +void sprite_draw(Sprite* sprite); + +void sprite_free(Sprite* sprite); + +void animation_update(Animation* a); diff --git a/xmake.lua b/xmake.lua new file mode 100644 index 0000000..af40b17 --- /dev/null +++ b/xmake.lua @@ -0,0 +1,80 @@ +add_rules("mode.debug", "mode.release") + +add_requires("raylib", "box2d") + +target("colossus_march") +set_languages("c23") +set_kind("binary") +add_files("src/**.c") +add_packages("raylib", "box2d") +add_includedirs("src", os.dirs("src/**")) +set_rundir("$(projectdir)") + +-- +-- If you want to known more usage about xmake, please see https://xmake.io +-- +-- ## FAQ +-- +-- You can enter the project directory firstly before building project. +-- +-- $ cd projectdir +-- +-- 1. How to build project? +-- +-- $ xmake +-- +-- 2. How to configure project? +-- +-- $ xmake f -p [macosx|linux|iphoneos ..] -a [x86_64|i386|arm64 ..] -m [debug|release] +-- +-- 3. Where is the build output directory? +-- +-- The default output directory is `./build` and you can configure the output directory. +-- +-- $ xmake f -o outputdir +-- $ xmake +-- +-- 4. How to run and debug target after building project? +-- +-- $ xmake run [targetname] +-- $ xmake run -d [targetname] +-- +-- 5. How to install target to the system directory or other output directory? +-- +-- $ xmake install +-- $ xmake install -o installdir +-- +-- 6. Add some frequently-used compilation flags in xmake.lua +-- +-- @code +-- -- add debug and release modes +-- add_rules("mode.debug", "mode.release") +-- +-- -- add macro definition +-- add_defines("NDEBUG", "_GNU_SOURCE=1") +-- +-- -- set warning all as error +-- set_warnings("all", "error") +-- +-- -- set language: c99, c++11 +-- set_languages("c99", "c++11") +-- +-- -- set optimization: none, faster, fastest, smallest +-- set_optimize("fastest") +-- +-- -- add include search directories +-- add_includedirs("/usr/include", "/usr/local/include") +-- +-- -- add link libraries and search directories +-- add_links("tbox") +-- add_linkdirs("/usr/local/lib", "/usr/lib") +-- +-- -- add system link libraries +-- add_syslinks("z", "pthread") +-- +-- -- add compilation and link flags +-- add_cxflags("-stdnolib", "-fno-strict-aliasing") +-- add_ldflags("-L/usr/local/lib", "-lpthread", {force = true}) +-- +-- @endcode +--