aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorschererleander <leander@schererleander.de>2026-03-10 02:58:58 +0100
committerschererleander <leander@schererleander.de>2026-03-10 02:58:58 +0100
commite32c1eeed3427832b40d1e9f43a17dbec8cb56ae (patch)
treec0857fa0435f41004ca7132c60430ccbf2904ce4
parentd7855a2b93be4aa1008643e54249cb739986869e (diff)
feat(fairy): implement fairy with wandering logic
-rw-r--r--include/fairy.h18
-rw-r--r--include/player.h1
-rw-r--r--src/fairy.c51
-rw-r--r--src/main.c69
4 files changed, 99 insertions, 40 deletions
diff --git a/include/fairy.h b/include/fairy.h
new file mode 100644
index 0000000..cdead11
--- /dev/null
+++ b/include/fairy.h
@@ -0,0 +1,18 @@
+#ifndef FAIRY_H
+#define FAIRY_H
+
+#include "raylib.h"
+
+
+typedef struct Fairy {
+ Vector2 position;
+ Vector2 targetOffset;
+ Vector2 targetWorld;
+
+ float wandTimer;
+} Fairy;
+
+void UpdateFairy(Fairy *Fairy, Vector2 playerWorldPosition);
+void DrawFairy(Fairy *Fairy);
+
+#endif // FAIRY_H
diff --git a/include/player.h b/include/player.h
index 0c9799b..f77de50 100644
--- a/include/player.h
+++ b/include/player.h
@@ -15,6 +15,7 @@ typedef struct Player {
float frameTime;
int state; // 0: idle, 1: walk, etc.
bool facingRight;
+
} Player;
void UpdatePlayer(Player *p, MapManager *mapMgr);
diff --git a/src/fairy.c b/src/fairy.c
new file mode 100644
index 0000000..6e9c6cc
--- /dev/null
+++ b/src/fairy.c
@@ -0,0 +1,51 @@
+#include "raylib.h"
+#include "raymath.h"
+#include <math.h>
+
+#include "fairy.h"
+#include "globals.h"
+
+#define FAIRY_WAND_RADIUS 20
+#define FAIRY_STAY_MIN 1
+#define FAIRY_STAY_MAX 3
+#define FAIRY_SMOOTHNESS 0.25f
+
+#define FAIRY_BOB_SPEED 4
+#define FAIRY_BOB_HEIGHT 5
+
+void UpdateFairy(Fairy *fairy, Vector2 playerWorldPosiion) {
+ float deltaTime = GetFrameTime();
+
+ fairy->wandTimer -= deltaTime;
+ if (fairy->wandTimer <= 0) {
+ fairy->targetOffset =
+ (Vector2){GetRandomValue(-FAIRY_WAND_RADIUS, FAIRY_WAND_RADIUS),
+ GetRandomValue(-FAIRY_WAND_RADIUS, FAIRY_WAND_RADIUS)};
+ fairy->wandTimer = GetRandomValue(FAIRY_STAY_MIN, FAIRY_STAY_MAX);
+ }
+
+ fairy->targetWorld = Vector2Add(playerWorldPosiion, fairy->targetOffset);
+
+ fairy->position = Vector2Lerp(fairy->position, fairy->targetWorld,
+ FAIRY_SMOOTHNESS * deltaTime);
+}
+
+void DrawFairy(Fairy *fairy) {
+ float bob = sin(GetTime() * FAIRY_BOB_SPEED) * FAIRY_BOB_HEIGHT;
+ int x = (int)fairy->position.x;
+ int y = (int)(fairy->position.y + bob);
+
+ if (debugMode) {
+ DrawCircleV(fairy->targetWorld, 1, RED);
+ DrawCircleV(fairy->position, 1, GREEN);
+ }
+
+ // Outer cross glow
+ DrawRectangle(x, y - 3, 1, 7, (Color){140, 180, 255, 40});
+ DrawRectangle(x - 3, y, 7, 1, (Color){140, 180, 255, 40});
+ // Mid cross
+ DrawRectangle(x, y - 1, 1, 3, (Color){190, 215, 255, 120});
+ DrawRectangle(x - 1, y, 3, 1, (Color){190, 215, 255, 120});
+ // Bright core pixel
+ DrawRectangle(x, y, 1, 1, (Color){255, 255, 255, 255});
+}
diff --git a/src/main.c b/src/main.c
index c50669c..0ffcd6b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,11 +1,12 @@
// src/main.c
#include "raylib.h"
#define RAYTMX_IMPLEMENTATION
-#include "game.h"
-#include "player.h"
-#include "map_manager.h"
#include "entity.h"
+#include "fairy.h"
+#include "game.h"
#include "globals.h"
+#include "map_manager.h"
+#include "player.h"
bool debugMode = false;
@@ -15,49 +16,34 @@ int main(void) {
GameScreen currentScreen = SCREEN_TITLE;
- MapManager mapMgr = LoadGameMap("assets/maps/debug.tmx");
-
+ MapManager mapMgr = LoadGameMap("assets/maps/debug.tmx");
+
EntityManager entityMgr = InitEntityManager(100);
if (mapMgr.map) {
SpawnEntitiesFromMap(&entityMgr, mapMgr.map);
}
-
+
RaytmxExternalTileset elfTS = LoadTSX("assets/tilesets/elf.tsx");
- Player player = {
- .position = { 200, 200},
- .speed = 120.0f,
- .bounds = { 204, 204, 12, 12 },
- .tileset = elfTS.tileset,
- .currentFrame = 0,
- .frameTime = 0.0f,
- .state = 0, // idle
- .facingRight = true
- };
+ Player player = {.position = {200, 200},
+ .speed = 120.0f,
+ .bounds = {204, 204, 12, 12},
+ .tileset = elfTS.tileset,
+ .currentFrame = 0,
+ .frameTime = 0.0f,
+ .state = 0, // idle
+ .facingRight = true};
+
+ Fairy fairy = {.position = player.position, .targetOffset = {0}};
- Camera2D camera = { 0 };
+ Camera2D camera = {0};
camera.offset.x = (float)SCREEN_WIDTH / 2.0f;
camera.offset.y = (float)SCREEN_HEIGHT / 2.0f;
camera.target = player.position;
camera.zoom = 4.0f;
while (!WindowShouldClose()) {
- if (IsKeyPressed(KEY_B)) debugMode = !debugMode;
- if (IsKeyPressed(KEY_R)) {
- // Reload map and entities
- UnloadGameMap(&mapMgr);
- UnloadEntityManager(&entityMgr);
-
- mapMgr = LoadGameMap("assets/maps/debug.tmx");
- entityMgr = InitEntityManager(100);
- if (mapMgr.map) {
- SpawnEntitiesFromMap(&entityMgr, mapMgr.map);
- }
-
- // Reset player position
- player.position = (Vector2){ 200, 200 };
- player.bounds = (Rectangle){ 204, 204, 12, 12 };
- }
-
+ if (IsKeyPressed(KEY_B))
+ debugMode = !debugMode;
switch (currentScreen) {
case SCREEN_TITLE:
if (IsKeyPressed(KEY_ENTER))
@@ -66,9 +52,10 @@ int main(void) {
case SCREEN_PLAYING:
if (IsKeyDown(KEY_ESCAPE))
currentScreen = SCREEN_PAUSED;
- UpdatePlayer(&player, &mapMgr);
+ UpdatePlayer(&player, &mapMgr);
+ UpdateFairy(&fairy, player.position);
UpdateEntities(&entityMgr, &player, &mapMgr);
- camera.target = player.position;
+ camera.target = player.position;
break;
case SCREEN_PAUSED:
if (IsKeyDown(KEY_ESCAPE))
@@ -82,7 +69,7 @@ int main(void) {
// --- DRAW ---
BeginDrawing();
-
+
switch (currentScreen) {
case SCREEN_TITLE:
ClearBackground(BLACK);
@@ -98,10 +85,12 @@ int main(void) {
{
DrawMap(&mapMgr);
DrawEntities(&entityMgr, mapMgr.map);
- DrawPlayer(&player);
+ DrawPlayer(&player);
+ DrawFairy(&fairy);
}
EndMode2D();
- if (debugMode) DrawFPS(10, 10);
+ if (debugMode)
+ DrawFPS(10, 10);
break;
case SCREEN_GAME_OVER:
ClearBackground(BLACK);
@@ -112,7 +101,7 @@ int main(void) {
EndDrawing();
}
- UnloadGameMap(&mapMgr);
+ UnloadGameMap(&mapMgr);
UnloadEntityManager(&entityMgr);
UnloadTexture(player.tileset.image.texture);
CloseWindow();