Implement naïve buckets of bboxes.
Allows faster spatial querying entities for collisions and overlapping. Fixes #3
This commit is contained in:
@@ -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
185
src/Bucket.c
Normal 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
68
src/Bucket.h
Normal 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
|
||||
24
src/Entity.c
24
src/Entity.c
@@ -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);
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
189
src/GameLib.c
189
src/GameLib.c
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user