This commit is contained in:
2025-06-08 17:22:30 +02:00
parent 64cac7578d
commit 79c8b747cd
16 changed files with 686 additions and 79 deletions

View File

@@ -33,7 +33,7 @@ void storeRect(SDL_Rect rect) {
if (allocatedRectCount < MAX_RECTS) {
allocatedRects[allocatedRectCount++] = rect;
} else {
fprintf(stderr, "Error: atlas rect limit reached!\n");
fprintf(stderr, "Error: atlas tileRect limit reached!\n");
}
}

View File

@@ -106,7 +106,7 @@ void audio_callback(void *userdata, Uint8 *stream, int len) {
float gainL = 1;
float gainR = 1;
float targetAmp = (voice->volume / 255.0f);
float targetAmp = (voice->volume / 255.0f) / 2;
if (v < NUM_SYNTH_VOICES - MIDI_VOICES) {
float distanceAtten = 1.0f - fminf(fabsf(dx) / audio->maxPanDistance, 1.0f);
targetAmp *= distanceAtten;

128
util/pathfinding.c Normal file
View File

@@ -0,0 +1,128 @@
//
// Created by bruno on 7.6.2025.
//
#include "pathfinding.h"
uint32_t globalPathfindingVersion = 1;
Node openList[MAX_OPEN_NODES];
int openCount = 0;
void clear_pathfind_data() {
for (int y = 0; y < MAP_HEIGHT; ++y)
for (int x = 0; x < MAP_WIDTH; ++x)
tileMap[y][x].pathFind = (PathFindDat) {0};
}
int heuristic(MiniRect a, MiniRect b) {
return abs(a.x - b.x) + abs(a.y - b.y);
}
void add_to_open(MiniRect pos, int fCost) {
if (openCount < MAX_OPEN_NODES)
openList[openCount++] = (Node) {pos.x, pos.y, fCost};
}
Node pop_best_node() {
int bestIdx = 0;
for (int i = 1; i < openCount; ++i) {
if (openList[i].fCost < openList[bestIdx].fCost)
bestIdx = i;
}
Node best = openList[bestIdx];
openList[bestIdx] = openList[--openCount];
return best;
}
bool find_path(MiniRect start, MiniRect end) {
clear_pathfind_data();
openCount = 0;
Tile *startT = &tileMap[start.y][start.x];
startT->pathFind.gCost = 0;
startT->pathFind.hCost = heuristic(start, end);
startT->pathFind.open = true;
add_to_open(start, startT->pathFind.gCost + startT->pathFind.hCost);
const int dirs[4][2] = {
{0, -1},
{1, 0},
{0, 1},
{-1, 0}
};
while (openCount > 0) {
Node current = pop_best_node();
PathFindDat *currentPath = &tileMap[current.pos.y][current.pos.x].pathFind;
currentPath->open = false;
currentPath->closed = true;
if (memcmp(&current.pos, &end, sizeof(MiniRect)) == 0) {
return true; // Path found!
}
for (int i = 0; i < 4; ++i) {
MiniRect n = {current.pos.x + dirs[i][0], current.pos.y + dirs[i][1]};
if (!isWalkable(n)) continue;
PathFindDat *neighbor = &tileMap[n.y][n.x].pathFind;
if (neighbor->closed) continue;
int tentativeG = currentPath->gCost + 1;
if (!neighbor->open || tentativeG < neighbor->gCost) {
neighbor->gCost = tentativeG;
neighbor->hCost = heuristic(n, end);
neighbor->parent = currentPath;
if (!neighbor->open) {
neighbor->open = true;
add_to_open(n, neighbor->gCost + neighbor->hCost);
}
}
}
}
return false; // No path found
}
Path reconstruct_path(MiniRect end) {
Path path = { .length = 0 };
PathFindDat* current = &tileMap[end.y][end.x].pathFind;
// Walk back through the parent pointers
while (current != NULL) {
// Find the tile coordinates for the current node
for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x) {
if (&tileMap[y][x].pathFind == current) {
if (path.length < MAX_OPEN_NODES) {
path.steps[path.length++] = (MiniRect){ x, y };
}
goto found;
}
}
}
found:
current = current->parent;
}
// Reverse the path to go from start to end
for (int i = 0; i < path.length / 2; ++i) {
MiniRect tmp = path.steps[i];
path.steps[i] = path.steps[path.length - i - 1];
path.steps[path.length - i - 1] = tmp;
}
path.stepIndex = 0;
return path;
}

42
util/pathfinding.h Normal file
View File

@@ -0,0 +1,42 @@
//
// Created by bruno on 7.6.2025.
//
#ifndef FACTORYGAME_PATHFINDING_H
#define FACTORYGAME_PATHFINDING_H
#include <stdint.h>
#include "../tiles/tile.h"
//extern uint32_t globalPathfindingVersion;
//#define MAX_OPEN_NODES (MAP_WIDTH * MAP_HEIGHT)
#define MAX_OPEN_NODES 100
typedef struct Node {
MiniRect pos;
int fCost;
} Node;
typedef struct {
MiniRect steps[MAX_OPEN_NODES];
int stepIndex;
int length;
} Path;
extern Node openList[MAX_OPEN_NODES];
extern int openCount;
int heuristic(MiniRect a, MiniRect b);
Path reconstruct_path(MiniRect end);
bool find_path(MiniRect start, MiniRect end);
Node pop_best_node();
void add_to_open(MiniRect pos, int fCost);
void clear_pathfind_data();
#endif //FACTORYGAME_PATHFINDING_H

View File

@@ -4,6 +4,8 @@
#include <dirent.h>
#include "util.h"
#include "../tiles/tile.h"
#include "font.h"
//#include "font.h"
@@ -132,7 +134,7 @@ void renderBar(SDL_Renderer *renderer,
char barString[20];
sprintf(barString, "%d/%d", currentValue, maxValue);
//renderText(mainRenderer, fonts[3], barString, width / 2, margin);
renderText(mainRenderer, fonts[3], barString, width / 2, margin);
}
int cmpstringp(const void *p1, const void *p2) {
@@ -178,4 +180,109 @@ void iterateSortedDir(const char *path, DirEntryCallback callback, SDL_Renderer
}
free(names);
}
}
bool checkCollision(SDL_Rect a, SDL_Rect b) {
//The sides of the rectangles
int leftA, leftB;
int rightA, rightB;
int topA, topB;
int bottomA, bottomB;
//Calculate the sides of tileRect A
leftA = a.x;
rightA = a.x + a.w;
topA = a.y;
bottomA = a.y + a.h;
//Calculate the sides of tileRect B
leftB = b.x;
rightB = b.x + b.w;
topB = b.y;
bottomB = b.y + b.h;
//If any of the sides from A are outside of B
if (bottomA <= topB) {
return false;
}
if (topA >= bottomB) {
return false;
}
if (rightA <= leftB) {
return false;
}
if (leftA >= rightB) {
return false;
}
//If none of the sides from A are outside B
return true;
}
bool canMoveTo(SDL_Rect newRect) {
// Round down to get all tiles the rect overlaps
int left = newRect.x / TILE_SIZE;
int right = (newRect.x + newRect.w - 1) / TILE_SIZE;
int top = newRect.y / TILE_SIZE;
int bottom = (newRect.y + newRect.h - 1) / TILE_SIZE;
for (int tx = left; tx <= right; ++tx) {
for (int ty = top; ty <= bottom; ++ty) {
MiniRect tile = { tx, ty };
if (!isWalkable(tile)) {
return false;
}
}
}
return true;
}
bool canMoveWithRadius(SDL_Rect centerRect) {
// 16px radius — create a square bounding box around center
int radius = 16;
int left = (centerRect.x - radius) / TILE_SIZE;
int right = (centerRect.x + radius - 1) / TILE_SIZE;
int top = (centerRect.y - radius) / TILE_SIZE;
int bottom = (centerRect.y + radius - 1) / TILE_SIZE;
int x, y;
for (x = left; x <= right; x++) {
for (y = top; y <= bottom; y++) {
MiniRect tile;
tile.x = x;
tile.y = y;
if (!isWalkable(tile)) {
// Get pixel bounds of tile
int tileLeft = x * TILE_SIZE;
int tileRight = tileLeft + TILE_SIZE;
int tileTop = y * TILE_SIZE;
int tileBottom = tileTop + TILE_SIZE;
// Bounding box of the player
int playerLeft = centerRect.x - radius;
int playerRight = centerRect.x + radius;
int playerTop = centerRect.y - radius;
int playerBottom = centerRect.y + radius;
// AABB collision check
if (playerRight > tileLeft && playerLeft < tileRight &&
playerBottom > tileTop && playerTop < tileBottom) {
return 0; // Collision
}
}
}
}
return 1; // No collisions
}
int compareStrings(const void *a, const void *b) {
const char *strA = *(const char **) a;
const char *strB = *(const char **) b;
return strcmp(strA, strB);
}

View File

@@ -72,4 +72,12 @@ void renderBar(SDL_Renderer *renderer,
int maxValue, int currentValue,
SDL_Color barColor, int margin);
#endif //FACTORYGAME_UTIL_H
bool checkCollision(SDL_Rect a, SDL_Rect b);
int compareStrings(const void *a, const void *b);
bool canMoveTo(SDL_Rect newRect);
bool canMoveWithRadius(SDL_Rect centerRect);
#endif //FACTORYGAME_UTIL_H