diff --git a/Makefile b/Makefile index b5795df..0d1490c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -CXX = clang++ +CXX = clang EMCC = emcc -FLAGS = -Wall -std=c++17 $(shell pkg-config --libs --cflags raylib) -SRC = scripts/main.cpp +FLAGS = -std=c99 -g -Wall -Werror -Wpedantic -Wconversion -Wshadow -Wstrict-prototypes -fsanitize=address,undefined -O0 $(shell pkg-config --libs --cflags raylib) +SRC = scripts/main.c # ARM Build ARM_TARGET = bin/game diff --git a/assets/flower.aseprite b/assets/flower.aseprite new file mode 100644 index 0000000..fc137e9 Binary files /dev/null and b/assets/flower.aseprite differ diff --git a/assets/flower.png b/assets/flower.png new file mode 100644 index 0000000..1944bc4 Binary files /dev/null and b/assets/flower.png differ diff --git a/grass.aseprite b/assets/grass.aseprite similarity index 100% rename from grass.aseprite rename to assets/grass.aseprite diff --git a/bin/game b/bin/game index c91affa..e384799 100755 Binary files a/bin/game and b/bin/game differ diff --git a/bin/game.dSYM/Contents/Info.plist b/bin/game.dSYM/Contents/Info.plist new file mode 100644 index 0000000..4e06fe6 --- /dev/null +++ b/bin/game.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.game + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/bin/game.dSYM/Contents/Resources/DWARF/game b/bin/game.dSYM/Contents/Resources/DWARF/game new file mode 100644 index 0000000..7a7edf6 Binary files /dev/null and b/bin/game.dSYM/Contents/Resources/DWARF/game differ diff --git a/bin/game.dSYM/Contents/Resources/Relocations/aarch64/game.yml b/bin/game.dSYM/Contents/Resources/Relocations/aarch64/game.yml new file mode 100644 index 0000000..0e63948 --- /dev/null +++ b/bin/game.dSYM/Contents/Resources/Relocations/aarch64/game.yml @@ -0,0 +1,5 @@ +--- +triple: 'arm64-apple-darwin' +binary-path: 'bin/game' +relocations: [] +... diff --git a/scripts/main.c b/scripts/main.c new file mode 100644 index 0000000..0b0f8e1 --- /dev/null +++ b/scripts/main.c @@ -0,0 +1,361 @@ +#include +// WHITE, Color, +// KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, IsKeyDown(), +// InitWindow(), SetTargetFPS(), WindowShouldClose(), GetFrameTime(), CloseWindow() +// Music, InitAudioDevice(), LoadMusicStream(), PlayMusicStream(), UpdateMusicStream(), UnloadMusicStream(), CloseAudioDevice(), +// Texture2D, Rectangle, Vector2, LoadTexture(), DrawTexturePro(), UnloadTexture(), +// BeginDrawing(), EndDrawing(), ClearBackground(), +// Camera2D, BeginMode2D(), EndMode2D() +#include // Vector2Length(), Vector2Normalize(), Vector2Add(), Vector2Scale(), Lerp() +#include // rand(), srand() +#include // time() +#include // memcpy() +#include + +// Structs + +typedef struct { + Vector2 *data; + size_t count; +} Vector2Array; + +typedef struct { + Texture2D texture; // Texture for the sprite + Rectangle sourceRec; // Source rectangle for the texture + Rectangle destRec; // Destination rectangle for the texture + Vector2 frameSize; // Size of the frame in the texture + Vector2 origin; // Origin point for rotation and positioning + float rotation; // Rotation angle + Color color; +} Sprite; + +typedef struct { + Sprite sprite; + Rectangle bounds; +} TileSprite; + +typedef struct { + Sprite sprite; // Base sprite for rendering + int currentFrame; // Current animation frame + int maxFrame; // Total number of frames + int framesCounter; // Counter to control frame speed + int framesSpeed; // Speed of the animation (frames per second) + float animTimer; + bool isVertical; // Whether the animation frames are arranged vertically +} AnimSprite; + +typedef struct { + Sprite sprite; + Vector2 position; +} Object; + +typedef struct { + Object *data; + const Object *prototype; + size_t count; +} ObjectArray; + +typedef struct { + AnimSprite animSprite; + Vector2 position; + Vector2 direction; + float velocity; +} Entity; + +// Pure functions + +float GetRandomFloat(const float min, const float max){ + return min + (float)rand() / (float)(RAND_MAX / (max - min)); +} + +Vector2 GetRandomVector(const Rectangle bounds){ + return (Vector2){ + GetRandomFloat(bounds.x, bounds.x + bounds.width), + GetRandomFloat(bounds.y, bounds.y + bounds.height) + }; +} + +ObjectArray CreateObjectArray(const Object *prototype, const size_t count) { + ObjectArray objects = {0}; + + if (count <= 0) { + printf("Objects size must be greater than 0.\n"); + return objects; + } + + objects.count = count; + objects.data = malloc(count * sizeof(Object)); + + if (!objects.data) { + printf("Memory allocation of objects failed.\n"); + return objects; + } + + objects.prototype = prototype; + + for (int i = 0; i < count; i++) { + objects.data[i].position = prototype->position; + objects.data[i].sprite = prototype->sprite; + } + return objects; +} + +// Mutator Functions + +void GetDirectionFromInput(Vector2 *direction){ + *direction = (Vector2){0.0f, 0.0f}; + if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)){ direction->x += 1.0f; } + if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)){ direction->x -= 1.0f; } + if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)){ direction->y += 1.0f; } + if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)){ direction->y -= 1.0f; } + if (Vector2Length(*direction) > 0.0f) { *direction = Vector2Normalize(*direction); } +} + +void SetPositionOnDirectionAndVelocity(const Vector2 *direction, const float *velocity, Vector2 *position) { + *position = Vector2Add(*position, Vector2Scale(*direction, *velocity * GetFrameTime())); +} + +void SetDestRecOnPosition(const Vector2 *position, Sprite *sprite){ + Rectangle newDestRec = { + position->x, + position->y, + sprite->frameSize.x, + sprite->frameSize.y + }; + sprite->destRec = newDestRec; +} + +void SetAnimSpriteOnFrameTime(AnimSprite *animSprite) { + animSprite->animTimer += GetFrameTime(); + float frameTime = 1.0f / animSprite->framesSpeed; + + if (animSprite->animTimer < frameTime) { + return; + } + + animSprite->animTimer -= frameTime; + animSprite->currentFrame++; + + if (animSprite->currentFrame >= animSprite->maxFrame) { + animSprite->currentFrame = 0; + } + + if (animSprite->isVertical) { + animSprite->sprite.sourceRec.y = animSprite->currentFrame * animSprite->sprite.frameSize.y; + } else { + animSprite->sprite.sourceRec.x = animSprite->currentFrame * animSprite->sprite.frameSize.x; + } +} + +void SetRotationOnDirection(const Vector2 *direction, float *rotationDegree){ + if(Vector2Length(*direction) <= 0.0f){ + return; + } + float targetRotationDegree = (float)atan2(direction->y, direction->x) * (180.0f / PI) + 90.0f; + *rotationDegree = Lerp(*rotationDegree, targetRotationDegree, 0.1f); +} + +void SetPositionForObjectArray(ObjectArray *objects, const Vector2Array *positions) { + if (positions->count != objects->count) { + printf("Warning: Position array size (%zu) does not match ObjectArray size (%zu)\n", positions->count, objects->count); + return; + } + + for (size_t i = 0; i < objects->count; i++) { + objects->data[i].position = positions->data[i]; + objects->data[i].sprite.destRec.x = positions->data[i].x; + objects->data[i].sprite.destRec.y = positions->data[i].y; + } +} + +void SetRandomPositionForObjectArray(ObjectArray *objects, const Rectangle bounds){ + srand((unsigned int)time(NULL)); + for (int i = 0; i < objects->count; i++) { + Vector2 position = GetRandomVector(bounds); + objects->data[i].position = position; + objects->data[i].sprite.destRec.x = position.x; + objects->data[i].sprite.destRec.y = position.y; + } +} + +void UpdateEntity(Entity *entity) { + GetDirectionFromInput(&entity->direction); + SetRotationOnDirection(&entity->direction, &entity->animSprite.sprite.rotation); + SetPositionOnDirectionAndVelocity(&entity->direction, &entity->velocity, &entity->position); + SetDestRecOnPosition(&entity->position, &entity->animSprite.sprite); + SetAnimSpriteOnFrameTime(&entity->animSprite); +} + +void UpdateTileSprite(TileSprite *tileSprite, const Camera2D *camera){ + tileSprite->bounds.x = (int)((camera->target.x - (GetScreenWidth() / 2.0f / camera->zoom)) / tileSprite->sprite.frameSize.x) - 1; + tileSprite->bounds.width = (int)((camera->target.x + (GetScreenWidth() / 2.0f / camera->zoom)) / tileSprite->sprite.frameSize.x) + 1; + tileSprite->bounds.y = (int)((camera->target.y - (GetScreenHeight() / 2.0f / camera->zoom)) / tileSprite->sprite.frameSize.y) - 1; + tileSprite->bounds.height = (int)((camera->target.y + (GetScreenHeight() / 2.0f / camera->zoom)) / tileSprite->sprite.frameSize.y) + 1; +} + +void UpdateCamera2D(Camera2D *camera, const Entity *player, const float smoothness){ + camera->target = Vector2Lerp(camera->target, player->position, smoothness * GetFrameTime()); +} + +void SwapAndPopObjectsArrayOnCollision(ObjectArray *objects, const Rectangle rec){ + for (int i = 0; i < objects->count; i++){ + + if (CheckCollisionRecs(rec, objects->data[i].sprite.destRec)){ + if (objects->count == 1) { + objects->count = 0; + break; + } + objects->data[i] = objects->data[objects->count - 1]; + objects->count--; + i--; + } + } +} + +void RenderSprite(const Sprite *sprite){ + DrawTexturePro( + sprite->texture, + sprite->sourceRec, + sprite->destRec, + sprite->origin, + sprite->rotation, + sprite->color + ); +} + +void RenderTileSprite(TileSprite *tileSprite){ + for (float y = tileSprite->bounds.y; y <= tileSprite->bounds.height; y++) + { + for (float x = tileSprite->bounds.x; x <= tileSprite->bounds.width; x++) + { + Vector2 tilePosition = {x * tileSprite->sprite.frameSize.x, y * tileSprite->sprite.frameSize.y}; + SetDestRecOnPosition(&tilePosition, &tileSprite->sprite); + RenderSprite(&tileSprite->sprite); + } + } +} + +void RenderObjectArray(const ObjectArray *objects){ + for (int i = 0; i < objects->count; i++){ + RenderSprite(&objects->data[i].sprite); + } +} + +// Main + +int main(void) +{ + // Load + // SetConfigFlags(FLAG_VSYNC_HINT); + InitWindow(1280, 720, "Lazy Bee"); + InitAudioDevice(); + Music music = LoadMusicStream("assets/beez.mp3"); + PlayMusicStream(music); + TileSprite floor = { + .sprite = { + .texture = LoadTexture("assets/grass.png"), + .frameSize = {16.0f,16.0f}, + .sourceRec = { 0.0f, 0.0f, 16.0f, 16.0f}, + .destRec = {0.0f, 0.0f, 16.0f, 16.0f}, + .origin = {8.0f, 8.0f}, + .rotation = 0.0f, + .color = WHITE + }, + .bounds = {0.0f,0.0f,0.0f,0.0f} + }; + Object hive = { + .sprite = { + .texture = LoadTexture("assets/hive.png"), + .frameSize = {32.0f,32.0f}, + .sourceRec = {0.0f, 0.0f, 32.0f, 32.0f}, + .destRec = {0.0f, 0.0f, 32.0f, 32.0f}, + .origin = {16.0f, 16.0f}, + .rotation = 0.0f, + .color = WHITE + }, + .position = (Vector2){0.0f,0.0f} + }; + Texture2D flower = LoadTexture("assets/flower.png"); + ObjectArray flowers = CreateObjectArray(&(Object){ + .sprite = { + .texture = flower, + .frameSize = {16.0f, 16.0f}, + .sourceRec = {0.0f, 0.0f, 16.0f, 16.0f}, + .destRec = {0.0f, 0.0f, 16.0f, 16.0f}, + .origin = {8.0f, 8.0f}, + .rotation = 45.0f, + .color = WHITE + }, + .position = {0.0f, 0.0f} + }, 10); + if (!flowers.data) { + printf("Memory allocation failed.\n"); + exit(1); + } + Rectangle flowerField = {-50.0f, -50.0f, 100.0f, 100.0f}; + SetRandomPositionForObjectArray(&flowers, flowerField); + Entity player = { + .animSprite = { + .sprite = { + .texture = LoadTexture("assets/character_bee.png"), + .frameSize = {16.0f, 16.0f}, + .sourceRec = {0.0f, 0.0f, 16.0f, 16.0f}, + .destRec = {0.0f, 0.0f, 16.0f, 16.0f}, + .origin = {8.0f, 8.0f}, + .rotation = 0.0f, + .color = WHITE + }, + .currentFrame = 0, + .maxFrame = 4, + .framesCounter = 0, + .framesSpeed = 10, + .isVertical = true, + .animTimer = 0.0f + }, + .position = hive.position, + .direction = (Vector2){0.0f,0.0f}, + .velocity = 50.0f + }; + Camera2D camera = { + .offset = (Vector2){GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f}, + .target = player.position, + .rotation = 0.0f, + .zoom = 10.0f + }; + float followSmoothness = 5.0f; + Vector2 mousePoint = { 0.0f, 0.0f}; + + // Update & Render + while (!WindowShouldClose()) + { + // Update + mousePoint = GetMousePosition(); + UpdateMusicStream(music); + UpdateTileSprite(&floor, &camera); + UpdateEntity(&player); + UpdateCamera2D(&camera, &player, followSmoothness); + SwapAndPopObjectsArrayOnCollision(&flowers, player.animSprite.sprite.destRec); + // Render + BeginDrawing(); + ClearBackground(BLACK); + BeginMode2D(camera); + RenderTileSprite(&floor); + RenderSprite(&hive.sprite); + RenderObjectArray(&flowers); + RenderSprite(&player.animSprite.sprite); + EndMode2D(); + DrawFPS(10,10); + EndDrawing(); + } + // Unload + UnloadTexture(floor.sprite.texture); + UnloadTexture(hive.sprite.texture); + UnloadTexture(flower); + UnloadTexture(player.animSprite.sprite.texture); + UnloadMusicStream(music); + free(flowers.data); + // Close + CloseAudioDevice(); + CloseWindow(); + return 0; +} diff --git a/scripts/main.cpp b/scripts/main.cpp deleted file mode 100644 index 3a84c63..0000000 --- a/scripts/main.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include - -Vector2 getDirection(){ - Vector2 direction = {0.0f, 0.0f}; - if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)){ direction = Vector2Add(direction, {1.0f , 0.0f}); } - if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)){ direction = Vector2Add(direction, {-1.0f, 0.0f}); } - if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)){ direction = Vector2Add(direction, {0.0f, 1.0f}); } - if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)){ direction = Vector2Add(direction, {0.0f, -1.0f}); } - if (Vector2Length(direction) > 0.0f) { direction = Vector2Normalize(direction); } - return direction; -} - -int main() -{ - int screenWidth = 1280; - int screenHeight = 720; - InitWindow(screenWidth, screenHeight, "Lazy Bee"); - SetTargetFPS(60); - - // Init Audio - InitAudioDevice(); - Music music = LoadMusicStream("assets/beez.mp3"); - PlayMusicStream(music); - - // Init Tiles - Texture2D tileTexture = LoadTexture("assets/grass.png"); - Vector2 tileFrameSize = {16.0f, 16.0f}; - Rectangle tileSourceRec = { tileFrameSize.x, tileFrameSize.y, tileFrameSize.x, tileFrameSize.y}; - - // Init Character - Texture2D characterTexture = LoadTexture("assets/character_bee.png"); - Vector2 charFrameSize = {16.0f, 16.0f}; - Rectangle charSourceRec = {0.0f, 0.0f, charFrameSize.x, charFrameSize.y}; - Vector2 charPosition = {0.0f, 0.0f}; - Vector2 charOrigin = {charFrameSize.x / 2.0f, charFrameSize.y / 2.0f}; - float charRotation = 0.0f; - - // Init Character Animation - int currentFrame = 0; - int framesCounter = 0; - int framesSpeed = 10; - - // Init Camera - Camera2D camera = { 0 }; - camera.target = charPosition; - camera.offset = (Vector2){screenWidth / 2.0f, screenHeight / 2.0f}; - camera.rotation = 0.0f; - camera.zoom = 10.0f; - - // Init hive - Texture2D hiveTexture = LoadTexture("assets/hive.png"); - Vector2 hiveFrameSize = {32.0f,32.0f}; - Rectangle hiveSourceRec = {0.0f, 0.0f, hiveFrameSize.x, hiveFrameSize.y}; - Vector2 hivePosition = {0.0f,0.0f}; - Rectangle hiveDestRec = {hivePosition.x, hivePosition.y, hiveFrameSize.x, hiveFrameSize.y}; - Vector2 hiveOrigin = {hiveFrameSize.x / 2.0f, hiveFrameSize.y / 2.0f}; - - while (!WindowShouldClose()) - { - UpdateMusicStream(music); - - - // Update Char Movement - Vector2 direction = getDirection(); - Vector2 targetPosition = Vector2Add(charPosition, Vector2Scale(direction, 100.0f * GetFrameTime())); - charPosition = {Lerp(charPosition.x, targetPosition.x, 0.3f),Lerp(charPosition.y, targetPosition.y, 0.3f)}; - - // Update Char Rotation - if (Vector2Length(direction) > 0.0f) { - float targetRotation = atan2(direction.y, direction.x) * (180.0f / PI) + 90.0f; - charRotation = Lerp(charRotation, targetRotation, 0.1f); - } - - // Update Char Animation - framesCounter++; - - if (framesCounter >= (60 / framesSpeed)) - { - framesCounter = 0; - currentFrame++; - if (currentFrame >= 4) - currentFrame = 0; - charSourceRec.y = currentFrame * charFrameSize.y; - } - - // Update Char Camera - camera.target = charPosition; - - // Render - BeginDrawing(); - ClearBackground(BLACK); - BeginMode2D(camera); - - // Render Tiles - float left = camera.target.x - (screenWidth / 2.0f / camera.zoom); - float right = camera.target.x + (screenWidth / 2.0f / camera.zoom); - float top = camera.target.y - (screenHeight / 2.0f / camera.zoom); - float bottom = camera.target.y + (screenHeight / 2.0f / camera.zoom); - - int startX = (int)(left / tileFrameSize.x) - 1; - int endX = (int)(right / tileFrameSize.x) + 1; - int startY = (int)(top / tileFrameSize.y) - 1; - int endY = (int)(bottom / tileFrameSize.y) + 1; - - for (int y = startY; y <= endY; y++) - { - for (int x = startX; x <= endX; x++) - { - Vector2 tilePosition = {x * tileFrameSize.x, y * tileFrameSize.y}; - Rectangle tileDestRec = {tilePosition.x, tilePosition.y, tileFrameSize.x, tileFrameSize.y}; - DrawTexturePro(tileTexture, tileSourceRec, tileDestRec, (Vector2){0.0f, 0.0f}, 0.0f, WHITE); - } - } - - // Render Hive - DrawTexturePro(hiveTexture, hiveSourceRec, hiveDestRec, hiveOrigin, 0.0f, WHITE); - - // Render Character - Rectangle charDestRec = {charPosition.x, charPosition.y, charFrameSize.x, charFrameSize.y}; - DrawTexturePro(characterTexture, charSourceRec, charDestRec, charOrigin, charRotation, WHITE); - - EndMode2D(); - EndDrawing(); - } - - // Unload Character - UnloadTexture(characterTexture); - UnloadTexture(tileTexture); - UnloadMusicStream(music); - - CloseAudioDevice(); - CloseWindow(); - - return 0; -} \ No newline at end of file diff --git a/scripts/main_crossplattform.cpp b/scripts/main_crossplattform.cpp new file mode 100644 index 0000000..20d73ac --- /dev/null +++ b/scripts/main_crossplattform.cpp @@ -0,0 +1,26 @@ +#include "raylib.h" +#include "Game.h" + +#ifdef PLATFORM_WEB + #include +#endif + +Game game; + +void UpdateDrawFrame() { + game.update(); + game.render(); +} + +int main() { + InitWindow(1280, 720, "Lazy Bee"); + SetTargetFPS(60); + game.init(); +#ifdef PLATFORM_WEB + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + while (!WindowShouldClose()) { game.update(); game.render(); } +#endif + game.close(); + return 0; +} diff --git a/scripts/object.c b/scripts/object.c new file mode 100644 index 0000000..e69de29