diff --git a/assets/entities.json b/assets/entities.json new file mode 100644 index 0000000..7e31745 --- /dev/null +++ b/assets/entities.json @@ -0,0 +1,11 @@ +{ + "ships": [ + { + "destroyer": { + "texture": "assets/entities/ships/destroyer.svg", + "width": 58, + "height": 512 + } + } + ] +} \ No newline at end of file diff --git a/src/helper_funcs.cpp b/src/helper_funcs.cpp new file mode 100644 index 0000000..1a2bd04 --- /dev/null +++ b/src/helper_funcs.cpp @@ -0,0 +1,23 @@ +#include "types.hpp" +#include +#include +#include + +using json = nlohmann::json; + +void load_entity(Entity &entity, std::string type, std::string name) { + try { + std::ifstream entitiesF("assets/entities.json"); + json entities = json::parse(entitiesF); + + } catch (const json::parse_error &e) { + std::cerr << "Parse error: " << e.what() << "\n"; + exit(1); + } catch (const std::exception &e) { + std::cerr << "Error: " << e.what() << "\n"; + exit(2); + } + + + +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0670b43..878a6a5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,173 +1,205 @@ +#include "types.hpp" #include #include #include -#include "types.hpp" - +#define destroyer_width 58 +#define destroyer_height 512 int main() { - SDL_Init(SDL_INIT_VIDEO); - SDL_Window* window = SDL_CreateWindow("Naval Swarm", SCREEN_WIDTH, SCREEN_HEIGHT, 0); - SDL_Renderer* renderer = SDL_CreateRenderer(window, "gpu,vulcan"); + SDL_Init(SDL_INIT_VIDEO); + SDL_Window *window = + SDL_CreateWindow("Naval Swarm", SCREEN_WIDTH, SCREEN_HEIGHT, 0); + SDL_Renderer *renderer = SDL_CreateRenderer(window, "gpu,vulcan"); - // Load textures - SDL_Texture* spriteSheet = IMG_LoadTexture(renderer, "assets/destroyer.svg"); - SDL_Texture* bgTexture = IMG_LoadTexture(renderer, "assets/background.png"); + // Load textures + SDL_Texture *spriteSheet = IMG_LoadTexture(renderer, "assets/destroyer.svg"); + SDL_Texture *bgTexture = IMG_LoadTexture(renderer, "assets/background.png"); - // Initialize player - Entity destroyer; - destroyer.texture = spriteSheet; - destroyer.position = {WORLD_WIDTH/2.0f, WORLD_HEIGHT/2.0f, 58.0f, 512.0f}; - destroyer.srcRect = {0, 0, 58, 512}; // Static source rectangle - destroyer.angle = 0; + // Initialize player + Entity destroyer; + destroyer.texture = spriteSheet; + destroyer.set_offset(destroyer_width / 2, destroyer_height / 2); + destroyer.position() = {WORLD_WIDTH / 2.0f, WORLD_HEIGHT / 2.0f, 58.0f, + 512.0f}; + destroyer.srcRect = {0, 0, destroyer_width, + destroyer_height}; // Static source rectangle + destroyer.angle = 0; - // Initialize camera - Camera camera; - bool running = true; - Uint64 lastFrameTime = SDL_GetTicksNS(); - float deltaTime = 0.0f; + // Initialize camera + Camera camera; + bool running = true; + Uint64 lastFrameTime = SDL_GetTicksNS(); + float deltaTime = 0.0f; - while (running) { - const Uint64 frameStart = SDL_GetTicksNS(); + while (running) { + const Uint64 frameStart = SDL_GetTicksNS(); - // Event handling - SDL_Event event; - while (SDL_PollEvent(&event)) { - if (event.type == SDL_EVENT_QUIT) running = false; - if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { - // Check specific button (e.g., left mouse button) - if (event.button.button == SDL_BUTTON_LEFT) { - printf("Left mouse clicked at (%.1f, %.1f)\nCamera position: (%.1f, %.1f)\nTarget position: (%.1f, %.1f)\n", - event.button.x, event.button.y, camera.view.x, camera.view.y, camera.view.x+event.button.x, camera.view.y+event.button.y); - destroyer.Tposition.x = camera.view.x+event.button.x; - destroyer.Tposition.y = camera.view.y+event.button.y; - destroyer.gotoT = true; - } - } + // Event handling + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_EVENT_QUIT) + running = false; + if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { + // Check specific button (e.g., left mouse button) + if (event.button.button == SDL_BUTTON_LEFT) { + printf("Left mouse clicked at (%.1f, %.1f)\nCamera position: (%.1f, " + "%.1f)\nTarget position: (%.1f, %.1f)\n", + event.button.x, event.button.y, camera.view.x, camera.view.y, + camera.view.x + event.button.x, + camera.view.y + event.button.y); + destroyer.Tposition.x = camera.view.x + event.button.x; + destroyer.Tposition.y = camera.view.y + event.button.y; + destroyer.gotoT = true; } - - - - - // Input handling - const bool* keystate = SDL_GetKeyboardState(NULL); - - // Toggle camera mode with C key - static Uint32 lastToggle = 0; - if (keystate[SDL_SCANCODE_C] && (SDL_GetTicks() - lastToggle > 200)) { - camera.followPlayer = !camera.followPlayer; - lastToggle = SDL_GetTicks(); - } - - // Player movement - int moveX = keystate[SDL_SCANCODE_RIGHT] - keystate[SDL_SCANCODE_LEFT]; - int moveY = keystate[SDL_SCANCODE_DOWN] - keystate[SDL_SCANCODE_UP]; - - // There is propably more eficient way to do this - switch (moveX) { - case 1: - switch (moveY) { - case 1: - destroyer.angle = 135; - break; - case -1: - destroyer.angle = 45; - break; - default: - destroyer.angle = 90; - } - break; - case -1: - switch (moveY) { - case 1: - destroyer.angle = 225; - break; - case -1: - destroyer.angle = 315; - break; - default: - destroyer.angle = 270; - } - break; - default: - switch (moveY) { - case 1: - destroyer.angle = 180; - break; - case -1: - destroyer.angle = 0; - break; - } - } - - destroyer.position.x += (float)moveX * destroyer.speed * deltaTime; - destroyer.position.y += (float)moveY * destroyer.speed * deltaTime; - - if(destroyer.gotoT) { - destroyer.angle = std::atan2(destroyer.Tposition.y - destroyer.position.y, destroyer.Tposition.x - destroyer.position.x) * 180 / M_PI; - } - - // Camera movement - if (camera.followPlayer) { - float targetX = destroyer.position.x + destroyer.position.w/2 - camera.view.w/2; - float targetY = destroyer.position.y + destroyer.position.h/2 - camera.view.h/2; - camera.view.x += (targetX - camera.view.x) * camera.smoothness; - camera.view.y += (targetY - camera.view.y) * camera.smoothness; - } else { - float camMoveX = keystate[SDL_SCANCODE_D] - keystate[SDL_SCANCODE_A]; - float camMoveY = keystate[SDL_SCANCODE_S] - keystate[SDL_SCANCODE_W]; - camera.view.x += camMoveX * camera.speed * deltaTime; - camera.view.y += camMoveY * camera.speed * deltaTime; - } - - // World bounds - destroyer.position.x = SDL_clamp(destroyer.position.x, 0.0f, WORLD_WIDTH - destroyer.position.w); - destroyer.position.y = SDL_clamp(destroyer.position.y, 0.0f, WORLD_HEIGHT - destroyer.position.h); - camera.view.x = SDL_clamp(camera.view.x, 0.0f, WORLD_WIDTH - camera.view.w); - camera.view.y = SDL_clamp(camera.view.y, 0.0f, WORLD_HEIGHT - camera.view.h); - - //ANIMATION HERE - - // Rendering - SDL_SetRenderDrawColor(renderer, 30, 30, 45, 255); - SDL_RenderClear(renderer); - - // Draw background - if (bgTexture) { - SDL_FRect bgDest = { -camera.view.x, -camera.view.y, WORLD_WIDTH, WORLD_HEIGHT }; - SDL_RenderTexture(renderer, bgTexture, NULL, &bgDest); - } - - // Draw player (simplified without animation) - SDL_FRect srcFRect; - SDL_RectToFRect(&destroyer.srcRect, &srcFRect); - SDL_FRect destRect = { - destroyer.position.x - camera.view.x, - destroyer.position.y - camera.view.y, - destroyer.position.w, - destroyer.position.h - }; - SDL_RenderTextureRotated(renderer, destroyer.texture, &srcFRect, &destRect, destroyer.angle, nullptr, SDL_FLIP_NONE); - - SDL_RenderPresent(renderer); - - // Frame timing (unchanged) - const Uint64 frameTime = SDL_GetTicksNS() - frameStart; - if (frameTime < TARGET_FRAME_TIME_NS) { - const Uint64 sleepTime = TARGET_FRAME_TIME_NS - frameTime; - SDL_DelayNS(sleepTime - 2'000'000); - while (SDL_GetTicksNS() - frameStart < TARGET_FRAME_TIME_NS) {} - } - - deltaTime = (SDL_GetTicksNS() - lastFrameTime) / 1e9f; - lastFrameTime = SDL_GetTicksNS(); + } } - // Cleanup - SDL_DestroyTexture(spriteSheet); - SDL_DestroyTexture(bgTexture); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); - return 0; + // Input handling + const bool *keystate = SDL_GetKeyboardState(NULL); + + // Toggle camera mode with C key + static Uint32 lastToggle = 0; + if (keystate[SDL_SCANCODE_C] && (SDL_GetTicks() - lastToggle > 200)) { + camera.followPlayer = !camera.followPlayer; + lastToggle = SDL_GetTicks(); + } + + // Player movement + int moveX = keystate[SDL_SCANCODE_RIGHT] - keystate[SDL_SCANCODE_LEFT]; + int moveY = keystate[SDL_SCANCODE_DOWN] - keystate[SDL_SCANCODE_UP]; + + // There is propably more eficient way to do this + switch (moveX) { + case 1: + switch (moveY) { + case 1: + destroyer.angle = 135; + break; + case -1: + destroyer.angle = 45; + break; + default: + destroyer.angle = 90; + } + break; + case -1: + switch (moveY) { + case 1: + destroyer.angle = 225; + break; + case -1: + destroyer.angle = 315; + break; + default: + destroyer.angle = 270; + } + break; + default: + switch (moveY) { + case 1: + destroyer.angle = 180; + break; + case -1: + destroyer.angle = 0; + break; + } + } + + float step = destroyer.speed * deltaTime; + destroyer.position().x += (float)moveX * step; + destroyer.position().y += (float)moveY * step; + + if (destroyer.gotoT) { + float dx = destroyer.Tposition.x - destroyer.position().x; + float dy = destroyer.Tposition.y - destroyer.position().y; + + destroyer.angle = std::atan2(dy, dx) * 180 / M_PI; + + float distance = std::sqrt(dx * dx + dy * dy); + if (distance > 0) { + dx /= distance; + dy /= distance; + + if (distance <= step) { + destroyer.position().x = destroyer.Tposition.x; + destroyer.position().y = destroyer.Tposition.y; + } else { + destroyer.position().x += dx * step; + destroyer.position().y += dy * step; + } + + } else { + destroyer.gotoT = false; + } + } + + // Camera movement + if (camera.followPlayer) { + float targetX = destroyer.position().x + destroyer.position().w / 2 - + camera.view.w / 2; + float targetY = destroyer.position().y + destroyer.position().h / 2 - + camera.view.h / 2; + camera.view.x += (targetX - camera.view.x) * camera.smoothness; + camera.view.y += (targetY - camera.view.y) * camera.smoothness; + } else { + float camMoveX = keystate[SDL_SCANCODE_D] - keystate[SDL_SCANCODE_A]; + float camMoveY = keystate[SDL_SCANCODE_S] - keystate[SDL_SCANCODE_W]; + camera.view.x += camMoveX * camera.speed * deltaTime; + camera.view.y += camMoveY * camera.speed * deltaTime; + } + + // World bounds + destroyer.position().x = SDL_clamp(destroyer.position().x, 0.0f, + WORLD_WIDTH - destroyer.position().w); + destroyer.position().y = SDL_clamp(destroyer.position().y, 0.0f, + WORLD_HEIGHT - destroyer.position().h); + camera.view.x = SDL_clamp(camera.view.x, 0.0f, WORLD_WIDTH - camera.view.w); + camera.view.y = + SDL_clamp(camera.view.y, 0.0f, WORLD_HEIGHT - camera.view.h); + + // ANIMATION HERE + + // Rendering + SDL_SetRenderDrawColor(renderer, 30, 30, 45, 255); + SDL_RenderClear(renderer); + + // Draw background + if (bgTexture) { + SDL_FRect bgDest = {-camera.view.x, -camera.view.y, WORLD_WIDTH, + WORLD_HEIGHT}; + SDL_RenderTexture(renderer, bgTexture, NULL, &bgDest); + } + + // Draw player (simplified without animation) + SDL_FRect srcFRect; + SDL_RectToFRect(&destroyer.srcRect, &srcFRect); + SDL_FRect destRect = {destroyer.position().x - camera.view.x, + destroyer.position().y - camera.view.y, + destroyer.position().w, destroyer.position().h}; + SDL_RenderTextureRotated(renderer, destroyer.texture, &srcFRect, &destRect, + destroyer.angle, nullptr, SDL_FLIP_NONE); + + SDL_RenderPresent(renderer); + + // Frame timing (unchanged) + const Uint64 frameTime = SDL_GetTicksNS() - frameStart; + if (frameTime < TARGET_FRAME_TIME_NS) { + const Uint64 sleepTime = TARGET_FRAME_TIME_NS - frameTime; + SDL_DelayNS(sleepTime - 2'000'000); + while (SDL_GetTicksNS() - frameStart < TARGET_FRAME_TIME_NS) { + } + } + + deltaTime = (SDL_GetTicksNS() - lastFrameTime) / 1e9f; + lastFrameTime = SDL_GetTicksNS(); + } + + // Cleanup + SDL_DestroyTexture(spriteSheet); + SDL_DestroyTexture(bgTexture); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + return 0; } diff --git a/src/types.hpp b/src/types.hpp index b2fd1b4..4384f48 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -1,63 +1,82 @@ +#include "const.hpp" #include #include -#include "const.hpp" #include struct Angle360 { - private: - int value{0}; - - void normalize() { - value %= 360; - if (value < 0) value += 360; // Handle negative values - } - - public: - // Constructor - Angle360(int val = 0) : value(val) { normalize(); } - - // Assignment operator - Angle360& operator=(int val) { - value = val; - normalize(); - return *this; - } - - // Compound assignment - Angle360& operator+=(int rhs) { - value += rhs; - normalize(); - return *this; - } - - Angle360& operator-=(int rhs) { - value -= rhs; - normalize(); - return *this; - } - - // Type conversion - operator int() const { return value; } - - // Stream output - friend std::ostream& operator<<(std::ostream& os, const Angle360& a) { - return os << a.value; - } +private: + int value{0}; + + void normalize() { + value %= 360; + if (value < 0) + value += 360; // Handle negative values + } + +public: + // Constructor + Angle360(int val = 0) : value(val) { normalize(); } + + // Assignment operator + Angle360 &operator=(int val) { + value = val; + normalize(); + return *this; + } + + // Compound assignment + Angle360 &operator+=(int rhs) { + value += rhs; + normalize(); + return *this; + } + + Angle360 &operator-=(int rhs) { + value -= rhs; + normalize(); + return *this; + } + + // Type conversion + operator int() const { return value; } + + // Stream output + friend std::ostream &operator<<(std::ostream &os, const Angle360 &a) { + return os << a.value; + } }; - + struct Entity { - SDL_FRect position; - SDL_FRect Tposition; - bool gotoT; - SDL_Texture* texture; - SDL_Rect srcRect; - float speed = 250.0f; - Angle360 angle; +private: + SDL_FRect m_position; + SDL_FPoint m_offset{0, 0}; // Default offset + +public: + // Direct access reference with auto-sync + SDL_FRect &position() { return m_position; } + const SDL_FRect &position() const { return m_position; } + + // Computed central position (always fresh) + SDL_FRect Central_position() const { + return {m_position.x + m_offset.x, m_position.y + m_offset.y, m_position.w, + m_position.h}; + } + + // Set offset values + void set_offset(float x, float y) { m_offset = {x, y}; } + + // --- Existing members --- + SDL_FRect Tposition; + bool gotoT; + SDL_Texture *texture; + SDL_Rect srcRect; + float speed = 250.0f; + Angle360 angle; }; - + struct Camera { - SDL_FRect view = {0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT}; - bool followPlayer = false; - float speed = 500.0f; - float smoothness = 0.1f; + SDL_FRect view = {0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT}; + bool followPlayer = false; + float speed = 500.0f; + float smoothness = 0.1f; }; \ No newline at end of file