Implement naïve buckets of bboxes.

Allows faster spatial querying entities for collisions and overlapping.

Fixes #3
This commit is contained in:
2024-10-07 02:46:16 +02:00
parent 9dab1ad99e
commit 91deaf34b2
7 changed files with 409 additions and 77 deletions

View File

@@ -31,6 +31,7 @@ set(GAMELIB_HEADERS
src/Audio.h
src/Anim.h
src/Entity.h
src/Bucket.h
src/GameLib.h)
set(GAMELIB_SOURCE
@@ -42,6 +43,7 @@ set(GAMELIB_SOURCE
src/Audio.c
src/Anim.c
src/Entity.c
src/Bucket.c
src/GameLib.c)
add_library(GameLib STATIC

185
src/Bucket.c Normal file
View File

@@ -0,0 +1,185 @@
// Copyright (C) 2024 Valeriano Alfonso Rodriguez (Kableado)
#include "Bucket.h"
#include "Util.h"
#include <stdlib.h>
#include <tgmath.h>
////////////////////////////////////////////////
// BBox
//
int BBox_Intersect(BBox bbox1, BBox bbox2) {
if (bbox1->x2 >= bbox2->x1 && bbox1->x1 <= bbox2->x2 && bbox1->y2 >= bbox2->y1 && bbox1->y1 <= bbox2->y2) {
return (1);
}
return (0);
}
////////////////////////////////////////////////
// Bucket
//
void Bucket_Init(Bucket bucket) { bucket->count = 0; }
void Bucket_AddItem(Bucket bucket, BBox item) {
if (bucket->count >= Max_ItemsPerBucket) {
Print("Bucket Overflow\n");
return;
}
bucket->bbox[bucket->count] = item;
bucket->count++;
}
void Bucket_AddItemUnique(Bucket bucket, BBox item) {
for (int i = 0; i < bucket->count; i++) {
if (bucket->bbox[i]->parent == item->parent) {
return;
}
}
Bucket_AddItem(bucket, item);
}
int Bucket_SearchItem(Bucket bucket, BBox item) {
for (int i = 0; i < bucket->count; i++) {
if (bucket->bbox[i]->parent == item->parent) {
return i;
}
}
return -1;
}
void Bucket_RemoveIndex(Bucket bucket, int index) {
bucket->bbox[index] = bucket->bbox[bucket->count - 1];
bucket->count--;
bucket->bbox[bucket->count] = NULL;
}
void Bucket_RemoveItem(Bucket bucket, BBox item) {
int index = Bucket_SearchItem(bucket, item);
if (index < 0) {
return;
}
Bucket_RemoveIndex(bucket, index);
}
////////////////////////////////////////////////
// BucketGrid
//
void BucketGrid_Init(BucketGrid bucketGrid, int width, int height, float bucketSize, float offsetX, float offsetY) {
bucketGrid->width = width;
bucketGrid->height = height;
bucketGrid->bucketSize = bucketSize;
bucketGrid->offsetX = offsetX;
bucketGrid->offsetY = offsetY;
bucketGrid->bucket = (TBucket *)malloc(sizeof(TBucket) * bucketGrid->width * bucketGrid->height);
for (int y = 0; y < bucketGrid->height; y++) {
for (int x = 0; x < bucketGrid->width; x++) {
Bucket_Init(&bucketGrid->bucket[x + y * width]);
}
}
}
void BucketGrid_DeInit(BucketGrid bucketGrid) { free(bucketGrid->bucket); }
int BucketGrid_AddItem(BucketGrid bucketGrid, BBox item) {
const int x1Bucket = (int)floorf((item->x1 + bucketGrid->offsetX) / bucketGrid->bucketSize);
const int x2Bucket = (int)ceilf((item->x2 + bucketGrid->offsetX) / bucketGrid->bucketSize);
const int y1Bucket = (int)floorf((item->y1 + bucketGrid->offsetY) / bucketGrid->bucketSize);
const int y2Bucket = (int)ceilf((item->y2 + bucketGrid->offsetY) / bucketGrid->bucketSize);
int inserted = 0;
for (int y = y1Bucket; y <= y2Bucket; y++) {
for (int x = x1Bucket; x <= x2Bucket; x++) {
if (y < 0 || y >= bucketGrid->height || x < 0 || x >= bucketGrid->width) {
continue;
}
Bucket bucket = &bucketGrid->bucket[x + y * bucketGrid->width];
Bucket_AddItem(bucket, item);
inserted = 1;
}
}
if (inserted) {
item->changed = 0;
}
return inserted;
}
void BucketGrid_RemoveItem(BucketGrid bucketGrid, BBox item) {
const int x1Bucket = (int)floorf((item->x1 + bucketGrid->offsetX) / bucketGrid->bucketSize);
const int x2Bucket = (int)ceilf((item->x2 + bucketGrid->offsetX) / bucketGrid->bucketSize);
const int y1Bucket = (int)floorf((item->y1 + bucketGrid->offsetY) / bucketGrid->bucketSize);
const int y2Bucket = (int)ceilf((item->y2 + bucketGrid->offsetY) / bucketGrid->bucketSize);
for (int y = y1Bucket; y <= y2Bucket; y++) {
for (int x = x1Bucket; x <= x2Bucket; x++) {
if (y < 0 || y >= bucketGrid->height || x < 0 || x >= bucketGrid->width) {
continue;
}
Bucket bucket = &bucketGrid->bucket[x + y * bucketGrid->width];
Bucket_RemoveItem(bucket, item);
}
}
}
void BucketGrid_Query(BucketGrid bucketGrid, BBox item, Bucket resultBucket) {
const int x1Bucket = (int)floorf((item->x1 + bucketGrid->offsetX) / bucketGrid->bucketSize);
const int x2Bucket = (int)ceilf((item->x2 + bucketGrid->offsetX) / bucketGrid->bucketSize);
const int y1Bucket = (int)floorf((item->y1 + bucketGrid->offsetY) / bucketGrid->bucketSize);
const int y2Bucket = (int)ceilf((item->y2 + bucketGrid->offsetY) / bucketGrid->bucketSize);
Bucket_Init(resultBucket);
for (int y = y1Bucket; y <= y2Bucket; y++) {
for (int x = x1Bucket; x <= x2Bucket; x++) {
if (y < 0 || y >= bucketGrid->height || x < 0 || x >= bucketGrid->width) {
continue;
}
Bucket bucket = &bucketGrid->bucket[x + y * bucketGrid->width];
for (int i = 0; i < bucket->count; i++) {
if (BBox_Intersect(bucket->bbox[i], item)) {
Bucket_AddItemUnique(resultBucket, bucket->bbox[i]);
}
}
}
}
}
int BucketGrid_ProcessChanged(BucketGrid bucketGrid) {
TBucket bucketChanged;
Bucket_Init(&bucketChanged);
for (int y = 0; y < bucketGrid->height; y++) {
for (int x = 0; x <= bucketGrid->width; x++) {
Bucket bucket = &bucketGrid->bucket[x + y * bucketGrid->width];
int i = 0;
while (i < bucket->count) {
if (bucket->bbox[i]->changed) {
if (bucketChanged.count == Max_ItemsPerBucket) {
return 0;
}
Bucket_AddItemUnique(&bucketChanged, bucket->bbox[i]);
Bucket_RemoveIndex(bucket, i);
} else {
i++;
}
}
}
}
for (int i = 0; i < bucketChanged.count; i++) {
BucketGrid_AddItem(bucketGrid, bucketChanged.bbox[i]);
}
return 1;
}
void BucketGrid_Clean(BucketGrid bucketGrid) {
for (int y = 0; y < bucketGrid->height; y++) {
for (int x = 0; x <= bucketGrid->width; x++) {
Bucket bucket = &bucketGrid->bucket[x + y * bucketGrid->width];
Bucket_Init(bucket);
}
}
}

68
src/Bucket.h Normal file
View File

@@ -0,0 +1,68 @@
// Copyright (C) 2024 Valeriano Alfonso Rodriguez (Kableado)
#ifndef Bucket_H
#define Bucket_H
////////////////////////////////////////////////
// BBox
//
typedef struct TBBox TBBox, *BBox;
struct TBBox {
float x1, x2;
float y1, y2;
void *parent;
int changed;
};
int BBox_Intersect(BBox bbox1, BBox bbox2);
////////////////////////////////////////////////
// Bucket
//
#define Max_ItemsPerBucket 200
typedef struct TBucket TBucket, *Bucket;
struct TBucket {
BBox bbox[Max_ItemsPerBucket];
int count;
};
void Bucket_Init(Bucket bucket);
void Bucket_AddItem(Bucket bucket, BBox item);
void Bucket_AddItemUnique(Bucket bucket, BBox item);
int Bucket_SearchItem(Bucket bucket, BBox item);
void Bucket_RemoveIndex(Bucket bucket, int index);
void Bucket_RemoveItem(Bucket bucket, BBox item);
////////////////////////////////////////////////
// BucketGrid
//
typedef struct TBucketGrid TBucketGrid, *BucketGrid;
struct TBucketGrid {
TBucket *bucket;
int width;
int height;
float bucketSize;
float offsetX;
float offsetY;
};
void BucketGrid_Init(BucketGrid bucketGrid, int width, int height, float bucketSize, float offsetX, float offsetY);
void BucketGrid_DeInit(BucketGrid bucketGrid);
int BucketGrid_AddItem(BucketGrid bucketGrid, BBox item);
void BucketGrid_RemoveItem(BucketGrid bucketGrid, BBox item);
void BucketGrid_Query(BucketGrid bucketGrid, BBox item, Bucket resultBucket);
int BucketGrid_ProcessChanged(BucketGrid bucketGrid);
void BucketGrid_Clean(BucketGrid bucketGrid);
#endif

View File

@@ -8,6 +8,7 @@
#include "Draw.h"
#include "Util.h"
#include "Bucket.h"
#include "Entity.h"
#define EntityIntFlag_UpdateLight 1
@@ -195,6 +196,7 @@ Entity Entity_Copy(Entity e) {
n->E = e->E;
n->child = e->child;
n->bbox.parent = n;
Entity_CalcBBox(n);
// Call the copy event
@@ -215,19 +217,20 @@ void Entity_CalcBBox(Entity e) {
float hHeight = (max(e->height, e->radius) / 2) + BBox_ExtraMargin;
float hWidth = (max(e->width, e->radius) / 2) + BBox_ExtraMargin;
if (e->vel[0] > 0) {
e->maxX = e->pos[0] + e->vel[0] + hWidth;
e->minX = e->pos[0] - hWidth;
e->bbox.x2 = e->pos[0] + e->vel[0] + hWidth;
e->bbox.x1 = e->pos[0] - hWidth;
} else {
e->minX = (e->pos[0] + e->vel[0]) - hWidth;
e->maxX = e->pos[0] + hWidth;
e->bbox.x1 = (e->pos[0] + e->vel[0]) - hWidth;
e->bbox.x2 = e->pos[0] + hWidth;
}
if (e->vel[1] > 0) {
e->maxY = e->pos[1] + e->vel[1] + hHeight;
e->minY = e->pos[1] - hHeight;
e->bbox.y2 = e->pos[1] + e->vel[1] + hHeight;
e->bbox.y1 = e->pos[1] - hHeight;
} else {
e->minY = (e->pos[1] + e->vel[1]) - hHeight;
e->maxY = e->pos[1] + hHeight;
e->bbox.y1 = (e->pos[1] + e->vel[1]) - hHeight;
e->bbox.y2 = e->pos[1] + hHeight;
}
e->bbox.changed = 1;
}
/////////////////////////////
@@ -235,10 +238,7 @@ void Entity_CalcBBox(Entity e) {
//
//
int Entity_BBoxIntersect(Entity ent1, Entity ent2) {
if (ent1->maxX >= ent2->minX && ent1->minX <= ent2->maxX && ent1->maxY >= ent2->minY && ent1->minY <= ent2->maxY) {
return (1);
}
return (0);
return BBox_Intersect(&ent1->bbox, &ent2->bbox);
}
/////////////////////////////

View File

@@ -4,6 +4,7 @@
#define Entity_H
#include "Anim.h"
#include "Bucket.h"
#include "Draw.h"
#include "Util.h"
@@ -76,8 +77,7 @@ struct TEntity {
vec2 VecB;
Entity child;
float maxX, minX;
float maxY, minY;
TBBox bbox;
Entity next;
};

View File

@@ -8,6 +8,8 @@
#include "GameLib.h"
#include <float.h>
// Globals
Entity *g_Entity = NULL;
int *g_EntityFlag = NULL;
@@ -44,6 +46,8 @@ struct TParallaxBackground {
TParallaxBackground g_ParallaxBackground[MaxParallaxBackgrounds];
int g_NumParallaxBackgrounds = 0;
TBucketGrid g_BucketGrid;
/////////////////////////////
// GameLib_Init
//
@@ -66,9 +70,52 @@ int GameLib_Init(int w, int h, char *title, int pFps, int fps) {
g_ProcFt = 1000 / pFps;
BucketGrid_Init(&g_BucketGrid, 1, 1, 64, 32, 32);
return (1);
}
/////////////////////////////
// GameLib_PrepareSize
//
//
void GameLib_PrepareSize(const float x1, const float y1, const float x2, const float y2) {
const float bucketSize = 64;
const float width = x2 - x1;
const float height = y2 - y1;
const int widthBuckets = (int)ceilf(width / bucketSize);
const int heightBuckets = (int)ceilf(height / bucketSize);
BucketGrid_DeInit(&g_BucketGrid);
BucketGrid_Init(&g_BucketGrid, widthBuckets, heightBuckets, bucketSize, -x1, -y1);
for (int i = 0; i < g_NumEntities; i++) {
BucketGrid_AddItem(&g_BucketGrid, &g_Entity[i]->bbox);
}
}
/////////////////////////////
// GameLib_CheckSize
//
//
void GameLib_CheckSize() {
float xMin = FLT_MAX;
float yMin = FLT_MAX;
float xMax = FLT_MIN;
float yMax = FLT_MIN;
for (int i = 0; i < g_NumEntities; i++) {
if (g_Entity[i]->bbox.x1 < xMin)
xMin = g_Entity[i]->bbox.x1;
if (g_Entity[i]->bbox.x2 > xMax)
xMax = g_Entity[i]->bbox.x2;
if (g_Entity[i]->bbox.y1 < yMin)
yMin = g_Entity[i]->bbox.y1;
if (g_Entity[i]->bbox.y2 > yMax)
yMax = g_Entity[i]->bbox.y2;
}
GameLib_PrepareSize(xMin, yMin, xMax, yMax);
}
/////////////////////////////
// GameLib_AddEntity
//
@@ -108,6 +155,9 @@ void GameLib_AddEntity(Entity e) {
Entity_MarkUpdateLight(e, g_Entity, g_NumEntities);
Entity_CalcBBox(e);
if (BucketGrid_AddItem(&g_BucketGrid, &e->bbox) == 0) {
GameLib_CheckSize();
}
Entity_Init(e);
}
@@ -152,6 +202,7 @@ int GameLib_DelEntity(Entity e) {
g_EntityFlag[i] = -1;
} else {
// Delete now
BucketGrid_RemoveItem(&g_BucketGrid, &g_Entity[i]->bbox);
Entity_Destroy(e);
}
return (1);
@@ -172,6 +223,7 @@ void GameLib_Compactate() {
continue;
}
if (g_EntityFlag[i] == -1) {
BucketGrid_RemoveItem(&g_BucketGrid, &g_Entity[i]->bbox);
Entity_Destroy(g_Entity[i]);
continue;
}
@@ -191,7 +243,7 @@ void GameLib_Compactate() {
// Process the loop.
void GameLib_ProcLoop(void *data) {
int i, j;
int repeat, count;
int repeat;
long long time;
// Step the gamePosition
@@ -212,30 +264,42 @@ void GameLib_ProcLoop(void *data) {
}
GameLib_Compactate();
g_EntitiesLock = 0;
if (BucketGrid_ProcessChanged(&g_BucketGrid) == 0) {
Print("Rebuild BucketGrid");
BucketGrid_Clean(&g_BucketGrid);
for (int i = 0; i < g_NumEntities; i++) {
BucketGrid_AddItem(&g_BucketGrid, &g_Entity[i]->bbox);
}
}
t_proc += Time_GetTime() - time;
// Collisions between entities
time = Time_GetTime();
g_EntitiesLock = 1;
count = 0;
int count = 0;
int maxCount = 50;
do {
repeat = 0;
CollisionInfo collInfo = NULL;
for (i = 0; i < g_NumEntities; i++) {
if (!(g_Entity[i]->flags & EntityFlag_Collision) || g_Entity[i]->mass < 0.0f) {
Entity ent = g_Entity[i];
if (!(ent->flags & EntityFlag_Collision) || ent->mass < 0.0f) {
continue;
}
if (g_Entity[i]->vel[0] <= 0.0f && g_Entity[i]->vel[0] >= -0.0f && g_Entity[i]->vel[1] <= 0.0f &&
g_Entity[i]->vel[1] >= -0.0f) {
if (ent->vel[0] <= 0.0f && ent->vel[0] >= -0.0f && ent->vel[1] <= 0.0f && ent->vel[1] >= -0.0f) {
continue;
}
for (j = 0; j < g_NumEntities; j++) {
if (i == j || !(g_Entity[j]->flags & EntityFlag_Collision) ||
CollisionInfo_CheckRepetition(collInfo, g_Entity[i], g_Entity[j]) ||
!Entity_BBoxIntersect(g_Entity[i], g_Entity[j])) {
TBucket bucket;
BucketGrid_Query(&g_BucketGrid, &ent->bbox, &bucket);
for (j = 0; j < bucket.count; j++) {
Entity entCollision = bucket.bbox[j]->parent;
if (ent == entCollision || !(entCollision->flags & EntityFlag_Collision) ||
CollisionInfo_CheckRepetition(collInfo, ent, entCollision)) {
continue;
}
Entity_CheckCollision(g_Entity[i], g_Entity[j], &collInfo);
Entity_CheckCollision(ent, entCollision, &collInfo);
}
}
if (Entity_CollisionInfoResponse(collInfo)) {
@@ -243,24 +307,27 @@ void GameLib_ProcLoop(void *data) {
}
CollisionInfo_Destroy(&collInfo);
count++;
} while (repeat && count < 50);
} while (repeat && count < maxCount);
// Stop remaining collisions
if (count == 10) {
if (count >= maxCount) {
for (i = 0; i < g_NumEntities; i++) {
if (!(g_Entity[i]->flags & EntityFlag_Collision) || g_Entity[i]->mass < 0.0f) {
Entity ent = g_Entity[i];
if (!(ent->flags & EntityFlag_Collision) || ent->mass < 0.0f) {
continue;
}
for (j = 0; j < g_NumEntities; j++) {
if (i == j || !(g_Entity[j]->flags & EntityFlag_Collision) ||
!Entity_BBoxIntersect(g_Entity[i], g_Entity[j])) {
TBucket bucket;
BucketGrid_Query(&g_BucketGrid, &ent->bbox, &bucket);
for (j = 0; j < bucket.count; j++) {
Entity entCollision = bucket.bbox[j]->parent;
if (ent == entCollision || !(entCollision->flags & EntityFlag_Collision)) {
continue;
}
if (Entity_CheckCollision(g_Entity[i], g_Entity[j], NULL)) {
vec2_set(g_Entity[i]->vel, 0, 0);
Entity_CalcBBox(g_Entity[i]);
vec2_set(g_Entity[j]->vel, 0, 0);
Entity_CalcBBox(g_Entity[j]);
if (Entity_CheckCollision(ent, entCollision, NULL)) {
vec2_set(ent->vel, 0, 0);
Entity_CalcBBox(ent);
vec2_set(entCollision->vel, 0, 0);
Entity_CalcBBox(entCollision);
}
}
}
@@ -273,14 +340,18 @@ void GameLib_ProcLoop(void *data) {
time = Time_GetTime();
g_EntitiesLock = 1;
for (i = 0; i < g_NumEntities; i++) {
if (!(g_Entity[i]->flags & EntityFlag_Overlap) || g_Entity[i]->mass < 0.0f) {
Entity ent = g_Entity[i];
if (!(ent->flags & EntityFlag_Overlap) || ent->mass < 0.0f) {
continue;
}
for (j = 0; j < g_NumEntities; j++) {
if (!(g_Entity[j]->flags & EntityFlag_Overlap) || i == j) {
TBucket bucket;
BucketGrid_Query(&g_BucketGrid, &ent->bbox, &bucket);
for (j = 0; j < bucket.count; j++) {
Entity entCollision = bucket.bbox[j]->parent;
if (!(entCollision->flags & EntityFlag_Overlap) || ent == entCollision) {
continue;
}
Entity_Overlaps(g_Entity[i], g_Entity[j]);
Entity_Overlaps(ent, entCollision);
}
}
GameLib_Compactate();
@@ -288,14 +359,13 @@ void GameLib_ProcLoop(void *data) {
t_over += Time_GetTime() - time;
// Sort
int n, n2, swap;
n = g_NumEntities;
int n = g_NumEntities;
do {
n2 = 0;
int n2 = 0;
for (i = 1; i < n; i++) {
Entity ent1 = g_Entity[i - 1];
Entity ent2 = g_Entity[i];
swap = 0;
int swap = 0;
if (ent1->zorder > ent2->zorder) {
// Lower level
swap = 1;
@@ -303,8 +373,8 @@ void GameLib_ProcLoop(void *data) {
// Upper level
} else {
// Same level
float y1 = ent1->pos[1] + ent1->sortYOffset;
float y2 = ent2->pos[1] + ent2->sortYOffset;
const float y1 = ent1->pos[1] + ent1->sortYOffset;
const float y2 = ent2->pos[1] + ent2->sortYOffset;
if (y1 == y2) {
if (ent1->pos[0] < ent2->pos[0]) {
swap = 1;
@@ -314,8 +384,7 @@ void GameLib_ProcLoop(void *data) {
}
}
if (swap) {
Entity ent;
ent = g_Entity[i];
Entity ent = g_Entity[i];
g_Entity[i] = g_Entity[i - 1];
g_Entity[i - 1] = ent;
n2 = i;
@@ -442,11 +511,11 @@ void GameLib_DrawLoop(void *data, float f) {
// GameLib_Loop
//
// Loops the game.
void GameLib_Loop(void (*gameproc)(), void (*gamepostproc)(), void (*gamepredraw)(float f), void (*gamedraw)(float f)) {
g_GameProcFunc = gameproc;
g_GamePostProcFunc = gamepostproc;
g_GamePreDrawFunc = gamepredraw;
g_GameDrawFunc = gamedraw;
void GameLib_Loop(void (*gameProc)(), void (*gamePostProc)(), void (*gamePreDraw)(float f), void (*gameDraw)(float f)) {
g_GameProcFunc = gameProc;
g_GamePostProcFunc = gamePostProc;
g_GamePreDrawFunc = gamePreDraw;
g_GameDrawFunc = gameDraw;
t_proc = 0;
t_col = 0;
t_over = 0;
@@ -503,10 +572,10 @@ void GameLib_MoveToPos(vec2 pos, float f) {
GameLib_MoveToPosH(pos, f);
GameLib_MoveToPosV(pos, f);
}
void GameLib_MoveToPosH(const vec2 pos, float f) {
void GameLib_MoveToPosH(const vec2 pos, const float f) {
g_GamePos1[0] = g_GamePos1[0] + (pos[0] - (g_GamePos1[0] + (g_GameSize[0] / 2.0f))) * f;
}
void GameLib_MoveToPosV(const vec2 pos, float f) {
void GameLib_MoveToPosV(const vec2 pos, const float f) {
g_GamePos1[1] = g_GamePos1[1] + (pos[1] - (g_GamePos1[1] + (g_GameSize[1] / 2.0f))) * f;
}
@@ -515,15 +584,15 @@ void GameLib_MoveToPosV(const vec2 pos, float f) {
//
// Deletes every entity.
void GameLib_DelEnts() {
int i;
for (i = 0; i < g_NumEntities; i++) {
for (int i = 0; i < g_NumEntities; i++) {
if (!g_Entity[i]) {
continue;
}
Entity_Destroy(g_Entity[i]);
}
g_NumEntities = 0;
BucketGrid_DeInit(&g_BucketGrid);
BucketGrid_Init(&g_BucketGrid, 1, 1, 100, 50, 50);
}
/////////////////////////////
@@ -531,8 +600,7 @@ void GameLib_DelEnts() {
//
// Iterates every entity.
void GameLib_ForEachEnt(int (*func)(Entity ent)) {
int i;
for (i = 0; i < g_NumEntities; i++) {
for (int i = 0; i < g_NumEntities; i++) {
if (!g_Entity[i]) {
continue;
}
@@ -547,9 +615,8 @@ void GameLib_ForEachEnt(int (*func)(Entity ent)) {
//
// Searches throught the entities.
Entity GameLib_SearchEnt(int (*func)(Entity ent, void *d), void *d) {
int i;
Entity ent = NULL;
for (i = 0; i < g_NumEntities; i++) {
for (int i = 0; i < g_NumEntities; i++) {
if (!g_Entity[i]) {
continue;
}
@@ -569,13 +636,12 @@ int GameLib_EntityCustomCheckCollision(Entity ent, vec2 vel) {
int collision = 0;
CollisionInfo collInfo = NULL;
vec2 originalVel;
int j;
vec2_copy(originalVel, ent->vel);
vec2_copy(ent->vel, vel);
Entity_CalcBBox(ent);
for (j = 0; j < g_NumEntities; j++) {
for (int j = 0; j < g_NumEntities; j++) {
if (!(g_Entity[j]->flags & EntityFlag_Collision) || !Entity_BBoxIntersect(ent, g_Entity[j])) {
continue;
}
@@ -598,27 +664,26 @@ int GameLib_EntityCustomCheckCollision(Entity ent, vec2 vel) {
//
//
void GameLib_PlaySound(AudioSnd snd, int x, int y) {
float vLeft, vRight, dx, dy;
int r, cx, cy, off;
int r;
// Get the screen context
cx = g_GamePos1[0] + g_GameSize[0] / 2;
cy = g_GamePos1[1] + g_GameSize[1] / 2;
int cx = g_GamePos1[0] + g_GameSize[0] / 2;
int cy = g_GamePos1[1] + g_GameSize[1] / 2;
if (g_GameSize[0] > g_GameSize[1]) {
r = g_GameSize[0] / 2;
} else {
r = g_GameSize[1] / 2;
}
r = r * 1.2f;
off = r / 10.0f;
r = r * 1.2f;
int off = r / 10.0f;
// Calculate volumes
dx = x - (cx + off);
dy = y - (cy);
vRight = 1.0f - (sqrtf(dx * dx + dy * dy) / (float)r);
dx = x - (cx - off);
dy = y - (cy);
vLeft = 1.0f - (sqrtf(dx * dx + dy * dy) / (float)r);
float dx = x - (cx + off);
float dy = y - (cy);
float vRight = 1.0f - (sqrtf(dx * dx + dy * dy) / (float)r);
dx = x - (cx - off);
dy = y - (cy);
float vLeft = 1.0f - (sqrtf(dx * dx + dy * dy) / (float)r);
// Clamp to 0
if (vLeft < 0.0f) {
@@ -677,7 +742,7 @@ void GameLib_ConvertScreenPositionToGamePosition(vec2 screenPos, vec2 gamePos, f
//
//
void GameLib_AddParallaxBackground(DrawImg img, int imgSize[2], int imgOffset[2], float parallaxFactor[2]) {
int idx = g_NumParallaxBackgrounds;
const int idx = g_NumParallaxBackgrounds;
if ((idx + 1) >= MaxParallaxBackgrounds) {
Print("GameLib: Can't add parallaxBackground, limit reached.");
return;

View File

@@ -17,6 +17,18 @@
// Initializes the game.
int GameLib_Init(int w, int h, char *title, int pFps, int fps);
/////////////////////////////
// GameLib_PrepareSize
//
//
void GameLib_PrepareSize(float x1, float y1, float x2, float y2);
/////////////////////////////
// GameLib_CheckSize
//
//
void GameLib_CheckSize();
/////////////////////////////
// GameLib_AddEntity
//
@@ -39,7 +51,7 @@ int GameLib_DelEntity(Entity e);
// GameLib_Loop
//
// Loops the game.
void GameLib_Loop(void (*gameproc)(), void (*gamepostproc)(), void (*gamepredraw)(float f), void (*gamedraw)(float f));
void GameLib_Loop(void (*gameProc)(), void (*gamePostProc)(), void (*gamePreDraw)(float f), void (*gameDraw)(float f));
/////////////////////////////
// GameLib_GetPos