Compare commits

...

10 Commits

Author SHA1 Message Date
PoliEcho d24f097223 attampt at adding zoom 2025-02-19 16:48:08 +01:00
PoliEcho d3cb22a278 change debuging 2025-02-19 11:21:43 +01:00
PoliEcho efecc44a52 better angle precision 2025-02-19 11:20:48 +01:00
PoliEcho 4dd53284ca increase world size 2025-02-19 11:19:41 +01:00
PoliEcho 32dd6dfce7 FIX Central_position metod 2025-02-19 10:28:20 +01:00
PoliEcho 99e637fc8b removed trash 2025-02-18 20:21:35 +01:00
PoliEcho 73a7be3f43 add debug 2025-02-18 15:51:00 +01:00
PoliEcho 2dfcc72343 refactor & angle fix 2025-02-18 15:23:34 +01:00
PoliEcho 87c6b5abdf faundation for json loading 2025-02-16 21:58:49 +01:00
PoliEcho b6551d9d6d add more rubust structure 2025-02-15 19:17:11 +01:00
11 changed files with 507 additions and 196 deletions
+11
View File
@@ -0,0 +1,11 @@
{
"ship": {
"destroyer": {
"texture": "assets/entities/ships/destroyer.svg",
"width": 58,
"height": 512,
"speed": 250
}
}
}

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

+22
View File
@@ -0,0 +1,22 @@
#ifndef RESET
#define RESET "\033[0m"
#define BLACK "\033[30m" /* Black */
#define RED "\033[31m" /* Red */
#define GREEN "\033[32m" /* Green */
#define YELLOW "\033[33m" /* Yellow */
#define BLUE "\033[34m" /* Blue */
#define MAGENTA "\033[35m" /* Magenta */
#define CYAN "\033[36m" /* Cyan */
#define WHITE "\033[37m" /* White */
#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */
#define BOLDRED "\033[1m\033[31m" /* Bold Red */
#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */
#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */
#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */
#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */
#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */
#define BOLDWHITE "\033[1m\033[37m" /* Bold White */
#endif
+13
View File
@@ -0,0 +1,13 @@
#include <SDL3/SDL_stdinc.h>
#ifndef CONST_NS
#define CONST_NS
constexpr int SCREEN_WIDTH = 1600;
constexpr int SCREEN_HEIGHT = 1200;
constexpr int WORLD_WIDTH = 20000;
constexpr int WORLD_HEIGHT = 200000;
constexpr int TARGET_FPS = 60;
constexpr Uint64 TARGET_FRAME_TIME_NS = 1'000'000'000 / TARGET_FPS;
#endif
+63
View File
@@ -0,0 +1,63 @@
#include <errno.h>
#include <csignal>
#include "color.h"
#include <iostream>
#include "exitcleanup.hpp"
#include "types.hpp"
#include "main.hpp"
void SignalHandler(int code) {
switch (code) {
case SIGTERM:
std::cerr << "\nreceived SIGTERM exiting...\n";
break;
case SIGINT:
std::cerr << "\nreceived SIGINT exiting...\n";
break;
case SIGQUIT:
std::cerr << "\nreceived SIGQUIT exiting...\n";
break;
case SIGHUP:
std::cerr << "\nreceived SIGHUP exiting...\n";
break;
case SIGSEGV:
std::cerr << "\nreceived SIGSEGV(segmentaiton fault) exiting...\nIf this "
"repeats please report it as a bug\n";
break;
}
try {
GeneralCleanUp(code);
} catch(...) {
std::cerr << RED"[ERROR]" << RESET" general cleanup error\n";
exit(errno);
}
}
void GeneralCleanUp(int code) {
for(Entity *entity : loaded_entities) {
try {
SDL_DestroyTexture(entity->texture);
} catch(...) {
std::cerr << RED"[ERROR]" << RESET" failed to destroy texture of entity\nentity address:" << YELLOW << entity << RESET"\n";
}
}
try {
SDL_DestroyWindow(main_sdl_session.window);
} catch(...) {
std::cerr << RED"[ERROR]" << RESET" failed to destroy window\n";
}
try{
SDL_DestroyRenderer(main_sdl_session.renderer);
} catch(...) {
std::cerr << RED"[ERROR]" << RESET" failed to destroy renderer\n";
}
try {
SDL_Quit();
} catch (...) {
std::cerr << RED"[ERROR]" << RESET" failed to quit sdl\n";
}
exit(code);
}
+4
View File
@@ -0,0 +1,4 @@
#ifndef EC_NS
#define EC_NS
void GeneralCleanUp(int code = 0);
#endif
+46
View File
@@ -0,0 +1,46 @@
#include "init.hpp"
#include "color.h"
#include "main.hpp"
#include <csignal>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include <ostream>
#include <string>
using json = nlohmann::json;
void init_entity(Entity &entity, SDL_Renderer *renderer, std::string type,
std::string name) {
json entities;
try {
std::ifstream entitiesF("./assets/entities.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);
}
loaded_entities.push_back(&entity);
std::clog << entities[type];
entity.texture = IMG_LoadTexture(
renderer, entities[type][name]["texture"].get<std::string>().c_str());
if (entity.texture == NULL) {
std::cerr << "\n" << RED "[ERROR]" << RESET " failed to load texture\n";
exit(ENOENT);
}
entity.srcRect = {0, 0, entities[type][name]["width"].get<int>(),
entities[type][name]["height"].get<int>()};
entity.speed = entities[type][name]["speed"].get<float>();
entity.gotoT = false;
}
+8
View File
@@ -0,0 +1,8 @@
#include "types.hpp"
#ifndef IN_NS
#define IN_NS
void init_entity(Entity &entity, SDL_Renderer *renderer,std::string type, std::string name);
#endif
+129 -58
View File
@@ -1,44 +1,37 @@
#include "exitcleanup.hpp"
#include "init.hpp"
#include "types.hpp"
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include "types.hpp"
#include <cmath>
#include <csignal>
#include <iostream>
#include <vector>
#include <ctime>
#include <iomanip>
constexpr int SCREEN_WIDTH = 800;
constexpr int SCREEN_HEIGHT = 600;
constexpr int WORLD_WIDTH = 1600;
constexpr int WORLD_HEIGHT = 1200;
constexpr int TARGET_FPS = 60;
constexpr Uint64 TARGET_FRAME_TIME_NS = 1'000'000'000 / TARGET_FPS;
struct Entity {
SDL_FRect position;
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 = true;
float speed = 500.0f;
float smoothness = 0.1f;
};
std::vector<Entity *> loaded_entities;
sdl_session main_sdl_session;
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");
main_sdl_session.window =
SDL_CreateWindow("Naval Swarm", SCREEN_WIDTH, SCREEN_HEIGHT, 0);
SDL_Renderer *renderer =
SDL_CreateRenderer(main_sdl_session.window, "gpu,vulcan");
// 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;
init_entity(destroyer, renderer, "ship", "destroyer");
destroyer.position = {WORLD_WIDTH / 2.0f, WORLD_HEIGHT / 2.0f,
static_cast<float>(destroyer.srcRect.w),
static_cast<float>(destroyer.srcRect.h)};
// Initialize camera
Camera camera;
@@ -46,13 +39,45 @@ int main() {
Uint64 lastFrameTime = SDL_GetTicksNS();
float deltaTime = 0.0f;
time_t start_time = std::time(nullptr);
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_QUIT) {
running = false;
}
if (event.type == SDL_EVENT_MOUSE_WHEEL) {
float zoom_factor = (event.wheel.y > 0) ? 0.9f : 1.1f;
camera.view.w *= zoom_factor;
camera.view.h *= zoom_factor;
// Zoom towards mouse position
SDL_FPoint mouse_world_pos = {
camera.view.x + event.wheel.mouse_x,
camera.view.y + event.wheel.mouse_y
};
camera.view.x = mouse_world_pos.x - (event.wheel.mouse_x * zoom_factor);
camera.view.y = mouse_world_pos.y - (event.wheel.mouse_y * zoom_factor);
}
if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
// Check specific button (e.g., left mouse button)
if (event.button.button == SDL_BUTTON_LEFT) {
std::clog << "Left mouse clicked at ("
<< std::fixed << std::setprecision(1) << event.button.x << ", " << event.button.y << ")\n"
<< "Camera position: (" << camera.view.x << ", " << camera.view.y << ")\n"
<< "Target position: (" << (camera.view.x + event.button.x) << ", "
<< (camera.view.y + event.button.y) << ")\ntime since start: " << (std::time(nullptr) - start_time) << "\n";
destroyer.Tposition.x = camera.view.x + event.button.x;
destroyer.Tposition.y = camera.view.y + event.button.y;
destroyer.gotoT = true;
}
}
}
// Input handling
@@ -65,6 +90,16 @@ int main() {
lastToggle = SDL_GetTicks();
}
//DEBUG
if (keystate[SDL_SCANCODE_B] && (SDL_GetTicks() - lastToggle > 200)) {
std::clog << "x: " << destroyer.position.x << " y: " << destroyer.position.y << "\n";
}
if (keystate[SDL_SCANCODE_O] && (SDL_GetTicks() - lastToggle > 200)) {
destroyer.position.x = 0;
destroyer.position.y = 0;
}
// Player movement
int moveX = keystate[SDL_SCANCODE_RIGHT] - keystate[SDL_SCANCODE_LEFT];
int moveY = keystate[SDL_SCANCODE_DOWN] - keystate[SDL_SCANCODE_UP];
@@ -74,57 +109,95 @@ int main() {
case 1:
switch (moveY) {
case 1:
destroyer.Angle = 135;
destroyer.angle = 135;
break;
case -1:
destroyer.Angle = 45;
destroyer.angle = 45;
break;
default:
destroyer.Angle = 90;
destroyer.angle = 90;
}
break;
case -1:
switch (moveY) {
case 1:
destroyer.Angle = 225;
destroyer.angle = 225;
break;
case -1:
destroyer.Angle = 315;
destroyer.angle = 315;
break;
default:
destroyer.Angle = 270;
destroyer.angle = 270;
}
break;
default:
switch (moveY) {
case 1:
destroyer.Angle = 180;
destroyer.angle = 180;
break;
case -1:
destroyer.Angle = 0;
destroyer.angle = 0;
break;
}
}
destroyer.position.x += (float)moveX * destroyer.speed * deltaTime;
destroyer.position.y += (float)moveY * destroyer.speed * deltaTime;
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.Central_position().x;
float dy = destroyer.Tposition.y - destroyer.Central_position().y;
if(dx != 0 && dy != 0) {
destroyer.angle = std::atan2(dy, dx) * 180 / M_PI + 90;
}
float distance = std::sqrt(dx * dx + dy * dy);
if (distance > 0) {
dx /= distance;
dy /= distance;
if (distance <= step) {
destroyer.Central_position(destroyer.Tposition.x,
destroyer.Tposition.y);
} else {
destroyer.position.x += dx * step;
destroyer.position.y += dy * step;
}
} else {
destroyer.gotoT = false;
}
}
// Camera handling
camera.view.w = SCREEN_WIDTH / camera.zoom;
camera.view.h = SCREEN_HEIGHT / camera.zoom;
// 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;
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_L] - keystate[SDL_SCANCODE_J];
float camMoveY = keystate[SDL_SCANCODE_K] - keystate[SDL_SCANCODE_I];
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);
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.w = SDL_clamp(camera.view.w, SCREEN_WIDTH * camera.zoom, SCREEN_WIDTH * 4.0f);
camera.view.h = SDL_clamp(camera.view.h,SCREEN_HEIGHT * camera.zoom,SCREEN_HEIGHT * 4.0f);
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);
@@ -136,20 +209,19 @@ int main() {
// Draw background
if (bgTexture) {
SDL_FRect bgDest = { -camera.view.x, -camera.view.y, WORLD_WIDTH, WORLD_HEIGHT };
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,
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);
destroyer.position.w, destroyer.position.h};
SDL_RenderTextureRotated(renderer, destroyer.texture, &srcFRect, &destRect,
destroyer.angle, nullptr, SDL_FLIP_NONE);
SDL_RenderPresent(renderer);
@@ -158,7 +230,8 @@ int main() {
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) {}
while (SDL_GetTicksNS() - frameStart < TARGET_FRAME_TIME_NS) {
}
}
deltaTime = (SDL_GetTicksNS() - lastFrameTime) / 1e9f;
@@ -166,10 +239,8 @@ int main() {
}
// Cleanup
SDL_DestroyTexture(spriteSheet);
SDL_DestroyTexture(bgTexture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
GeneralCleanUp();
SDL_Quit();
return 0;
}
+10
View File
@@ -0,0 +1,10 @@
#include <vector>
#include "types.hpp"
#ifndef MAIN_NS
#define MAIN_NS
extern std::vector<Entity*> loaded_entities;
extern sdl_session main_sdl_session;
#endif
+72 -9
View File
@@ -1,35 +1,42 @@
#include "const.hpp"
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <iostream>
#include <optional>
#include <cmath>
struct Angle360 {
#ifndef TYPES_NS
#define TYPES_NS
struct Angle {
private:
int value{0};
float value{0};
void normalize() {
value %= 360;
if (value < 0) value += 360; // Handle negative values
value = std::fmod(value, 360);
if (value < 0)
value += 360; // Handle negative values
}
public:
// Constructor
Angle360(int val = 0) : value(val) { normalize(); }
Angle(int val = 0) : value(val) { normalize(); }
// Assignment operator
Angle360& operator=(int val) {
Angle &operator=(int val) {
value = val;
normalize();
return *this;
}
// Compound assignment
Angle360& operator+=(int rhs) {
Angle &operator+=(int rhs) {
value += rhs;
normalize();
return *this;
}
Angle360& operator-=(int rhs) {
Angle &operator-=(int rhs) {
value -= rhs;
normalize();
return *this;
@@ -39,8 +46,64 @@ struct Angle360 {
operator int() const { return value; }
// Stream output
friend std::ostream& operator<<(std::ostream& os, const Angle360& a) {
friend std::ostream &operator<<(std::ostream &os, const Angle &a) {
return os << a.value;
}
};
struct basic_cords {
float x;
float y;
};
struct Entity {
SDL_FRect position;
SDL_FRect Tposition;
bool gotoT = false;
SDL_Texture *texture;
SDL_Rect srcRect;
float speed;
Angle angle = 0;
basic_cords Central_position(std::optional<float> x = std::nullopt,
std::optional<float> y = std::nullopt) {
if (x != std::nullopt) {
position.x = *x - position.w / 2;
}
if (y != std::nullopt) {
position.y = *y - position.h / 2;
}
return {position.x + position.w / 2, position.y + position.h / 2};
}
};
struct Camera {
SDL_FRect view = {0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT};
basic_cords Center_of_view(std::optional<float> x = std::nullopt,
std::optional<float> y = std::nullopt) {
if (x != std::nullopt) {
view.x = *x - view.w / 2;
}
if (y != std::nullopt) {
view.y = *y - view.h / 2;
}
return {view.x + view.w / 2, view.y + view.h / 2};
}
bool followPlayer = false;
float speed = 500.0f;
float smoothness = 0.1f;
float zoom = 1.0f;
float minZoom = 0.5f;
float maxZoom = 3.0f;
float zoomSpeed = 0.1f;
};
struct sdl_session {
SDL_Window *window;
SDL_Renderer *renderer;
};
#endif