From 048575c14cb23267b94a3c9159b909c440000f20 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 21 Mar 2026 15:45:24 +0100 Subject: [PATCH] init --- .clang-format | 9 +++++ .editorconfig | 4 ++ .gitignore | 10 +++++ assets/ball.aseprite | Bin 0 -> 929 bytes assets/ball.png | Bin 0 -> 484 bytes assets/block.aseprite | Bin 0 -> 389 bytes assets/block.png | Bin 0 -> 147 bytes compile_commands.json | 31 +++++++++++++++ screenshot000.png | Bin 0 -> 95749 bytes src/defs.h | 38 ++++++++++++++++++ src/main.c | 30 ++++++++++++++ src/screens.c | 65 ++++++++++++++++++++++++++++++ src/screens.h | 11 ++++++ src/screens/game.c | 89 ++++++++++++++++++++++++++++++++++++++++++ src/screens/game.h | 12 ++++++ src/screens/intro.c | 21 ++++++++++ src/screens/intro.h | 5 +++ src/screens/menu.c | 63 ++++++++++++++++++++++++++++++ src/screens/menu.h | 5 +++ src/sprite.c | 84 +++++++++++++++++++++++++++++++++++++++ src/sprite.h | 32 +++++++++++++++ xmake.lua | 80 +++++++++++++++++++++++++++++++++++++ 22 files changed, 589 insertions(+) create mode 100644 .clang-format create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 assets/ball.aseprite create mode 100644 assets/ball.png create mode 100644 assets/block.aseprite create mode 100644 assets/block.png create mode 100644 compile_commands.json create mode 100644 screenshot000.png create mode 100644 src/defs.h create mode 100644 src/main.c create mode 100644 src/screens.c create mode 100644 src/screens.h create mode 100644 src/screens/game.c create mode 100644 src/screens/game.h create mode 100644 src/screens/intro.c create mode 100644 src/screens/intro.h create mode 100644 src/screens/menu.c create mode 100644 src/screens/menu.h create mode 100644 src/sprite.c create mode 100644 src/sprite.h create mode 100644 xmake.lua 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 0000000000000000000000000000000000000000..540d1794a5c9ecaf3af7f6511da0cfd7b741c72a GIT binary patch literal 929 zcmZ3;%)szqDGP%F7&0<2Fr)x60w^#rf&>`^fRGlz326GSk1SwYS%4OZ0WrG**h(bp zvVd$B2B4?{kfEet;;LbjW@*?TW_`a@#`U3+F$R%BREnN!yqBcq$)$=9oQ^-uTe z$~TY)*`xpr6gc<~WU({&Bvz&tDHu)$a#$4@fKFj#_|F7WBgY`iP%-E2)j+NW10LoJ z_x@k{rF$dIcedY*#@bWfZ7XKZ=9Y1tu=2$OQ|l_5dEYPHNj#}j(vYX>Is2AZS;qZY zA5x)- zhpl(KULS6(KPJp#JbPK^Qn#;HB=f4|s$Zl!?{XJ=*j_1pTgmo8+w2p%o6i`XK2x+g z|6RBB|AX~ul6nTtcaG{UtWL7tyY%#}CG2VKk=uovzqPx$o=HSORA_DMi^(ECUAzhA@nD8d?0aEKDT~6wsS-?=(kiruv3D&M~lN zGMk1)G}Q749BueO83T-1V@582(U4{{FTGI~f}>F&FPDg+a|FVRKVfpuek8;Bn-p`y z2!w=hWJwu-28Q;aeuOmdy;IlAy1`9Zq~zW>>_XMnfLwx#w3Dt5 zV9%~mD`&vg4q&}@0E;yQV0^}N7cILvJp=g3s#B`oC|q(0S~&}=y{{BNde1eFhpR;f zkTnV}c7G{{q56Lgpc+ViW__)&GSrUBB}iG&_h+>?3W4hj8vwHN%9kNz8;Zknor2(B z2A=`IJ8vvL%MoEwGNe^qVppGv@a&JB#TPlOEJg-Mzb*c0FQ);;7dd7;fh}j&;3K`G zC*#ySfNNBqRhoKzhN4&^&BrrLKvv^`JS-`*58)44lRd^jNlYmJv@@#r*=W~_3uM>x a+w=#{n0{jE3E{E;0000)}PiDX?C zkj=sX6jcB+loU){HEhx>4g15a?-#1wT#)we@T}jT%w|3f$l7OMJ|)jPQ$NUC#mL6e z-oC^jp(#4=Ve;(%@n@f$zWwL_|NpbsZf~h;&&RMxDbTd5pdiAdU>0Vv= z2J#@A6qtb|4EzT&*cp5hD^rUU48wpNRt1REe;=bwN6Sz`yJ?ti-ec6(Ue1U_aC-aY`OCRm05 literal 0 HcmV?d00001 diff --git a/assets/block.png b/assets/block.png new file mode 100644 index 0000000000000000000000000000000000000000..e6955453e76346e3c468f21a20cde7ed689db7a3 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}zMd|QArY-_ zuN(3)DDp5L{QCF*`GpT!T2?5YUDg>?`9v?#@1n71vIRqYx`o5Py-_Q6MSDzoo0IR* qz`)4F!XcmlX8hspzyG21AH%VY99Eq-6I*}=GkCiCxvXrlRwl<*xeE$YW8JQN?U%R$dqqy6Z|m`3LQ;H*=F5~pHhZdsruv(ZyGM0*(K=r=f1Caz1XPRZ&Fl9$6sM%HW62)_*^;x>W=B-WD* zDnTWvL}MkUa3~xKhr(g^sv4p=kbuO}BBK)F-a!Hq>qZJHK_#d}U12-Wl%;Se914fR z;m|_#EkFVi>sAgbK_#d}QZ13Wvyz+7>2-BpfM7Kw@puQ3)zRCF*h_8l18% zOyN*C6b^+$hF*1~BpOLHiarfUK%!0*9r%wr%q0{Kg+t*G1y;QVDI{UiK>`xdlmH1x z)VWi3^H2#YK_%o%gx3HGNUZG_DnTWvgkToIEcHN;V{);v1_?;4y#^{lC8$JQPDGzZ zwsI&O3Wvg>a0q6pj+8J3VG7Zw0SQRdiGpC3s0xsPgnWsxUmyXAu$v$OiM0bqC8z|I zkQ@;93nU=1cBH5Tm7o$LH$-mKqaF@G#l{*WAhGrus05Xu5_LHdeHtP+AQ2MbN!Kw|ARPzfqQCF*h_`ZThYL*Y<36b^;MvyfCr zN-&FjiRjaS1SIN2!GnK9Re%H}geipm0trZj-2@3ptQ|NiK_#e!PvlOif>L zeeAB_)9E@_FLmWF$!hdGZeFtk4S;rj#GKDU`kdeISVCa`i1LPv-P~j?@dDRrykPdydwj+isR*sK#Uo$UKhC#Uh?{Bmw%P`dy;0&Dxl`wwn@jxI@Bg@*MiM8KcJj>?UD{{=~xoe6kyEO3Q zpXH(P)ZXvII`Vfpk@5VlQ;5+}=RL*Uk&nDTxo(%uh^(MToFT~s&Tl{WwkNx|XY=`B zgVuJ#@9e6T-JcOE%(cBsPThF8r0MvMr1a#1e$8J53(cuer{)8J@E&G>=JvYnhBnLP zt#qa=OK9Kjz43!``1RDajhL@3&~;DDV;Y*Z+K`a4e!Zj zml~Tl&PjRpOwsDb786&6mK)iyI=tu4>*St4ygRQO@`7{nm6OR;+iDJ*+r&}-u@AX3 zruUtbFP}_)v1gq*dAnzQr^nt{6Y&nmqPIckGNzHtALRSMoct@D-p_k1*z~5y*ZP&? z#5|peVDj?FW_ps&o1$}~&;}wT$Olf!b+4R1;eeWyKlG*5~(=oEBB)S=u8(9j6!ns=??asic z1eKtY_GeKFN7M&MKw>>*pb}JqO71j$yIq&ppBOrg?Cg;ywy({>0V)w^Bp?BabtDp% zpb}Klen_p|b(+GVa3~xKhbIH5R+Vs%XyAYZB-TAGRDw!SiMpJ~<9SqqN>B;E*hjTr zJU>EoD?kDg(We0kNYuHr&1sqtNcdlwO9U5?fP}e(xr8XNaHJpsiM2^bC8z|IkfG;y z9jPbj#oh!XeS9I#PmJL~cZ%1|%R+CknD^ zqAEZF5{}7*{Q?O{gxv%QNUR+=DnTWvgyev*UmyXAwIf9(s05V|xgm0+9`$elDmK<2 z0g1KOKqaUIm8i>!=+h9n0g0F>Kmro-CE|<}Bp?xe8jyg*x^;z0PzfsG@ldKGC2}LY z21r0+ZNE?nDnTXcaw5BVs05Xu67nU&et`re){YdFpb}IQZ1o`s}3Qi56JOGKXrBp^{I3Lg9;ssbb+Axt6c7f3)N z>?TM+V(q|D2`WJ)BnO230tra09Vse7C8&hR4Urr5sD}ekv9SgTNUXgEDnTWvL|slq tpN7Z{NW??|5|EHD5oe_TCnSc^^2dhqNgwU|)-eA}pO%yP>D2sp{{gH4s=xpM literal 0 HcmV?d00001 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 +--