Start of replacing grid with quadtree.
This commit is contained in:
parent
7337460853
commit
6b1e62dd38
|
@ -13,13 +13,14 @@ OBJS += capitalShips.o challenges.o cJSON.o
|
||||||
OBJS += debris.o dev.o draw.o
|
OBJS += debris.o dev.o draw.o
|
||||||
OBJS += effects.o entities.o extractionPoint.o
|
OBJS += effects.o entities.o extractionPoint.o
|
||||||
OBJS += fighters.o
|
OBJS += fighters.o
|
||||||
OBJS += galacticMap.o game.o grid.o
|
OBJS += galacticMap.o game.o
|
||||||
OBJS += hud.o
|
OBJS += hud.o
|
||||||
OBJS += init.o input.o io.o items.o
|
OBJS += init.o input.o io.o items.o
|
||||||
OBJS += load.o locations.o lookup.o
|
OBJS += load.o locations.o lookup.o
|
||||||
OBJS += main.o messageBox.o mission.o missionInfo.o
|
OBJS += main.o messageBox.o mission.o missionInfo.o
|
||||||
OBJS += objectives.o options.o
|
OBJS += objectives.o options.o
|
||||||
OBJS += player.o
|
OBJS += player.o
|
||||||
|
OBJS += quadtree.o
|
||||||
OBJS += radar.o rope.o
|
OBJS += radar.o rope.o
|
||||||
OBJS += save.o script.o sound.o starfield.o starSystems.o stats.o
|
OBJS += save.o script.o sound.o starfield.o starSystems.o stats.o
|
||||||
OBJS += testMission.o textures.o text.o title.o transition.o
|
OBJS += testMission.o textures.o text.o title.o transition.o
|
||||||
|
|
|
@ -638,7 +638,7 @@ static int nearItems(void)
|
||||||
|
|
||||||
closest = MAX_TARGET_RANGE;
|
closest = MAX_TARGET_RANGE;
|
||||||
|
|
||||||
candidates = getAllEntsWithin(self->x - (self->w / 2) - (GRID_CELL_WIDTH / 2), self->y - (self->h / 2) - (GRID_CELL_HEIGHT / 2), GRID_CELL_WIDTH, GRID_CELL_HEIGHT, self);
|
candidates = getAllEntsWithin(self->x - (self->w / 2) - (SCREEN_WIDTH / 4), self->y - (self->h / 2) - (SCREEN_HEIGHT / 4), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, self);
|
||||||
|
|
||||||
self->target = NULL;
|
self->target = NULL;
|
||||||
|
|
||||||
|
@ -684,7 +684,7 @@ static int nearTowableCraft(void)
|
||||||
long closest, distance;
|
long closest, distance;
|
||||||
Entity *e, **candidates;
|
Entity *e, **candidates;
|
||||||
|
|
||||||
candidates = getAllEntsWithin(self->x - (self->w / 2) - (GRID_CELL_WIDTH / 2), self->y - (self->h / 2) - (GRID_CELL_HEIGHT / 2), GRID_CELL_WIDTH, GRID_CELL_HEIGHT, self);
|
candidates = getAllEntsWithin(self->x - (self->w / 2) - (SCREEN_WIDTH / 4), self->y - (self->h / 2) - (SCREEN_HEIGHT / 4), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, self);
|
||||||
|
|
||||||
closest = MAX_TARGET_RANGE;
|
closest = MAX_TARGET_RANGE;
|
||||||
|
|
||||||
|
@ -787,11 +787,8 @@ static void moveToLeader(void)
|
||||||
|
|
||||||
static void doWander(void)
|
static void doWander(void)
|
||||||
{
|
{
|
||||||
self->targetLocation.x = 5 + (rand() % (GRID_SIZE - 10));
|
self->targetLocation.x = 500 + (rand() % (BATTLE_AREA_WIDTH - 1000));
|
||||||
self->targetLocation.x *= GRID_CELL_WIDTH;
|
self->targetLocation.y = 500 + (rand() % (BATTLE_AREA_HEIGHT - 1000));
|
||||||
|
|
||||||
self->targetLocation.y = 5 + (rand() % (GRID_SIZE - 10));
|
|
||||||
self->targetLocation.y *= GRID_CELL_HEIGHT;
|
|
||||||
|
|
||||||
self->aiActionTime = FPS * 15;
|
self->aiActionTime = FPS * 15;
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,10 @@ void initBattle(void)
|
||||||
app.delegate.draw = &draw;
|
app.delegate.draw = &draw;
|
||||||
memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS);
|
memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS);
|
||||||
|
|
||||||
|
battle.quadtree.w = BATTLE_AREA_WIDTH;
|
||||||
|
battle.quadtree.h = BATTLE_AREA_HEIGHT;
|
||||||
|
initQuadtree(&battle.quadtree);
|
||||||
|
|
||||||
initBullets();
|
initBullets();
|
||||||
|
|
||||||
initEntities();
|
initEntities();
|
||||||
|
@ -436,5 +440,5 @@ void destroyBattle(void)
|
||||||
|
|
||||||
destroyScript();
|
destroyScript();
|
||||||
|
|
||||||
destroyGrid();
|
destroyQuadtree();
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,8 @@ extern void drawOptions(void);
|
||||||
extern void playSound(int id);
|
extern void playSound(int id);
|
||||||
extern void resetWaypoints(void);
|
extern void resetWaypoints(void);
|
||||||
extern void doPlayerSelect(void);
|
extern void doPlayerSelect(void);
|
||||||
extern void destroyGrid(void);
|
extern void destroyQuadtree(void);
|
||||||
|
extern void initQuadtree(Quadtree *root);
|
||||||
extern void completeMission(void);
|
extern void completeMission(void);
|
||||||
extern void initEffects(void);
|
extern void initEffects(void);
|
||||||
extern void doScript(void);
|
extern void doScript(void);
|
||||||
|
|
|
@ -164,11 +164,8 @@ static void findAITarget(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self->targetLocation.x = 5 + (rand() % (GRID_SIZE - 10));
|
self->targetLocation.x = 500 + (rand() % (BATTLE_AREA_WIDTH - 1000));
|
||||||
self->targetLocation.x *= GRID_CELL_WIDTH;
|
self->targetLocation.y = 500 + (rand() % (BATTLE_AREA_HEIGHT - 1000));
|
||||||
|
|
||||||
self->targetLocation.y = 5 + (rand() % (GRID_SIZE - 10));
|
|
||||||
self->targetLocation.y *= GRID_CELL_HEIGHT;
|
|
||||||
|
|
||||||
self->aiActionTime = FPS * (30 + (rand() % 120));
|
self->aiActionTime = FPS * (30 + (rand() % 120));
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,14 +69,9 @@ void doEntities(void)
|
||||||
|
|
||||||
numAllies = numEnemies = numActiveAllies = numActiveEnemies = 0;
|
numAllies = numEnemies = numActiveAllies = numActiveEnemies = 0;
|
||||||
|
|
||||||
destroyGrid();
|
|
||||||
|
|
||||||
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
|
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
|
||||||
{
|
{
|
||||||
if (e->active && e->alive != ALIVE_DEAD)
|
removeFromQuadtree(e, &battle.quadtree);
|
||||||
{
|
|
||||||
addToGrid(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev.playerImmortal)
|
if (dev.playerImmortal)
|
||||||
|
@ -169,6 +164,8 @@ void doEntities(void)
|
||||||
|
|
||||||
e->x += e->dx;
|
e->x += e->dx;
|
||||||
e->y += e->dy;
|
e->y += e->dy;
|
||||||
|
|
||||||
|
addToQuadtree(e, &battle.quadtree);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -261,30 +258,30 @@ static void restrictToGrid(Entity *e)
|
||||||
{
|
{
|
||||||
float force;
|
float force;
|
||||||
|
|
||||||
if (e->x <= GRID_RESTRICTION_SIZE)
|
if (e->x <= BATTLE_AREA_EDGE)
|
||||||
{
|
{
|
||||||
force = GRID_RESTRICTION_SIZE - e->x;
|
force = BATTLE_AREA_EDGE - e->x;
|
||||||
e->dx += force * 0.001;
|
e->dx += force * 0.001;
|
||||||
e->dx *= 0.95;
|
e->dx *= 0.95;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->y <= GRID_RESTRICTION_SIZE)
|
if (e->y <= BATTLE_AREA_EDGE)
|
||||||
{
|
{
|
||||||
force = GRID_RESTRICTION_SIZE - e->y;
|
force = BATTLE_AREA_EDGE - e->y;
|
||||||
e->dy += force * 0.001;
|
e->dy += force * 0.001;
|
||||||
e->dy *= 0.95;
|
e->dy *= 0.95;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->x >= (GRID_SIZE * GRID_CELL_WIDTH) - GRID_RESTRICTION_SIZE)
|
if (e->x >= BATTLE_AREA_WIDTH - BATTLE_AREA_EDGE)
|
||||||
{
|
{
|
||||||
force = e->x - ((GRID_SIZE * GRID_CELL_WIDTH) - GRID_RESTRICTION_SIZE);
|
force = e->x - (BATTLE_AREA_WIDTH - BATTLE_AREA_EDGE);
|
||||||
e->dx -= force * 0.001;
|
e->dx -= force * 0.001;
|
||||||
e->dx *= 0.95;
|
e->dx *= 0.95;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->y >= (GRID_SIZE * GRID_CELL_HEIGHT) - GRID_RESTRICTION_SIZE)
|
if (e->y >= BATTLE_AREA_HEIGHT - BATTLE_AREA_EDGE)
|
||||||
{
|
{
|
||||||
force = e->y - ((GRID_SIZE * GRID_CELL_HEIGHT) - GRID_RESTRICTION_SIZE);
|
force = e->y - (BATTLE_AREA_HEIGHT - BATTLE_AREA_EDGE);
|
||||||
e->dy -= force * 0.001;
|
e->dy -= force * 0.001;
|
||||||
e->dy *= 0.95;
|
e->dy *= 0.95;
|
||||||
}
|
}
|
||||||
|
@ -353,7 +350,7 @@ void drawEntities(void)
|
||||||
{
|
{
|
||||||
Entity *e, **candidates;
|
Entity *e, **candidates;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
candidates = getAllEntsWithin(battle.camera.x, battle.camera.y, SCREEN_WIDTH, SCREEN_HEIGHT, NULL);
|
candidates = getAllEntsWithin(battle.camera.x, battle.camera.y, SCREEN_WIDTH, SCREEN_HEIGHT, NULL);
|
||||||
|
|
||||||
/* count number of candidates for use with qsort */
|
/* count number of candidates for use with qsort */
|
||||||
|
|
|
@ -27,14 +27,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
extern void blitRotated(SDL_Texture *texture, int x, int y, float angle);
|
extern void blitRotated(SDL_Texture *texture, int x, int y, float angle);
|
||||||
extern void doFighter(void);
|
extern void doFighter(void);
|
||||||
extern void doCapitalShip(void);
|
extern void doCapitalShip(void);
|
||||||
extern void addToGrid(Entity *e);
|
|
||||||
extern void removeFromGrid(Entity *e);
|
|
||||||
extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore);
|
extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore);
|
||||||
extern void doRope(Entity *e);
|
extern void doRope(Entity *e);
|
||||||
extern void drawRope(Entity *e);
|
extern void drawRope(Entity *e);
|
||||||
extern void cutRope(Entity *e);
|
extern void cutRope(Entity *e);
|
||||||
extern void drawShieldHitEffect(Entity *e);
|
extern void drawShieldHitEffect(Entity *e);
|
||||||
extern void destroyGrid(void);
|
extern void removeFromQuadtree(Entity *e, Quadtree *root);
|
||||||
|
extern void addToQuadtree(Entity *e, Quadtree *root);
|
||||||
extern void updateCapitalShipComponentProperties(Entity *parent);
|
extern void updateCapitalShipComponentProperties(Entity *parent);
|
||||||
|
|
||||||
extern App app;
|
extern App app;
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (C) 2015 Parallel Realities
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License
|
|
||||||
as published by the Free Software Foundation; either version 2
|
|
||||||
of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "grid.h"
|
|
||||||
|
|
||||||
static Entity *candidates[MAX_GRID_CANDIDATES];
|
|
||||||
static void addCandidate(Entity *e);
|
|
||||||
|
|
||||||
void addToGrid(Entity *e)
|
|
||||||
{
|
|
||||||
GridCell *cell, *prev;
|
|
||||||
int x, y, x1, y1, x2, y2;
|
|
||||||
|
|
||||||
x1 = (e->x - e->w / 2) / GRID_CELL_WIDTH;
|
|
||||||
y1 = (e->y - e->h / 2) / GRID_CELL_HEIGHT;
|
|
||||||
x2 = (e->x + e->w / 2) / GRID_CELL_WIDTH;
|
|
||||||
y2 = (e->y + e->h / 2) / GRID_CELL_HEIGHT;
|
|
||||||
|
|
||||||
for (x = x1 ; x <= x2 ; x++)
|
|
||||||
{
|
|
||||||
for (y = y1 ; y <= y2 ; y++)
|
|
||||||
{
|
|
||||||
if (x >= 0 && y >= 0 && x < GRID_SIZE && y < GRID_SIZE)
|
|
||||||
{
|
|
||||||
prev = &battle.grid[x][y];
|
|
||||||
|
|
||||||
for (cell = battle.grid[x][y].next ; cell != NULL ; cell = cell->next)
|
|
||||||
{
|
|
||||||
prev = cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell = malloc(sizeof(GridCell));
|
|
||||||
memset(cell, 0, sizeof(GridCell));
|
|
||||||
prev->next = cell;
|
|
||||||
|
|
||||||
cell->entity = e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore)
|
|
||||||
{
|
|
||||||
GridCell *cell;
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
|
|
||||||
memset(candidates, 0, sizeof(Entity*) * MAX_GRID_CANDIDATES);
|
|
||||||
|
|
||||||
x1 = x / GRID_CELL_WIDTH;
|
|
||||||
y1 = y / GRID_CELL_HEIGHT;
|
|
||||||
x2 = (x + w) / GRID_CELL_WIDTH;
|
|
||||||
y2 = (y + h) / GRID_CELL_HEIGHT;
|
|
||||||
|
|
||||||
for (x = x1 ; x <= x2 ; x++)
|
|
||||||
{
|
|
||||||
for (y = y1 ; y <= y2 ; y++)
|
|
||||||
{
|
|
||||||
if (x >= 0 && y >= 0 && x < GRID_SIZE && y < GRID_SIZE)
|
|
||||||
{
|
|
||||||
for (cell = battle.grid[x][y].next ; cell != NULL ; cell = cell->next)
|
|
||||||
{
|
|
||||||
if (cell->entity != ignore)
|
|
||||||
{
|
|
||||||
addCandidate(cell->entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NULL terminate, to allow us to loop through them more easily */
|
|
||||||
candidates[MAX_GRID_CANDIDATES - 1] = NULL;
|
|
||||||
|
|
||||||
return candidates;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addCandidate(Entity *e)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (i = 0 ; i < MAX_GRID_CANDIDATES ; i++)
|
|
||||||
{
|
|
||||||
if (candidates[i] == NULL || candidates[i] == e)
|
|
||||||
{
|
|
||||||
candidates[i] = e;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Out of grid candidate space!");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroyGrid(void)
|
|
||||||
{
|
|
||||||
int x, y;
|
|
||||||
GridCell *cell;
|
|
||||||
|
|
||||||
for (x = 0 ; x < GRID_SIZE ; x++)
|
|
||||||
{
|
|
||||||
for (y = 0 ; y < GRID_SIZE ; y++)
|
|
||||||
{
|
|
||||||
while (battle.grid[x][y].next)
|
|
||||||
{
|
|
||||||
cell = battle.grid[x][y].next;
|
|
||||||
battle.grid[x][y].next = cell->next;
|
|
||||||
free(cell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -247,14 +247,14 @@ static void handleMouse(void)
|
||||||
|
|
||||||
if (app.mouse.button[SDL_BUTTON_X1])
|
if (app.mouse.button[SDL_BUTTON_X1])
|
||||||
{
|
{
|
||||||
cycleRadarZoom();
|
switchGuns();
|
||||||
|
|
||||||
app.mouse.button[SDL_BUTTON_X1] = 0;
|
app.mouse.button[SDL_BUTTON_X1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app.mouse.button[SDL_BUTTON_X2])
|
if (app.mouse.button[SDL_BUTTON_X2])
|
||||||
{
|
{
|
||||||
switchGuns();
|
cycleRadarZoom();
|
||||||
|
|
||||||
app.mouse.button[SDL_BUTTON_X2] = 0;
|
app.mouse.button[SDL_BUTTON_X2] = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2015 Parallel Realities
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "quadtree.h"
|
||||||
|
|
||||||
|
static Entity *candidates[QT_MAX_CANDIDATES];
|
||||||
|
static int cIndex;
|
||||||
|
static int memory;
|
||||||
|
|
||||||
|
static int getIndex(Quadtree *root, int x, int y, int w, int h);
|
||||||
|
static void removeEntity(Entity *e, Quadtree *root);
|
||||||
|
static void addCandidate(Entity *e);
|
||||||
|
static int candidatesComparator(const void *a, const void *b);
|
||||||
|
static void getAllEntsWithinNode(int x, int y, int w, int h, Entity *ignore, Quadtree *root);
|
||||||
|
static void destroyQuadtreeNode(Quadtree *root);
|
||||||
|
|
||||||
|
void initQuadtree(Quadtree *root)
|
||||||
|
{
|
||||||
|
Quadtree *node;
|
||||||
|
int i, w, h;
|
||||||
|
|
||||||
|
if (root->depth == 0)
|
||||||
|
{
|
||||||
|
memory = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory += sizeof(Quadtree);
|
||||||
|
|
||||||
|
w = root->w / 2;
|
||||||
|
h = root->h / 2;
|
||||||
|
|
||||||
|
if (root->depth + 1 < QT_MAX_DEPTH)
|
||||||
|
{
|
||||||
|
for (i = 0 ; i < 4 ; i++)
|
||||||
|
{
|
||||||
|
node = malloc(sizeof(Quadtree));
|
||||||
|
memset(node, 0, sizeof(Quadtree));
|
||||||
|
root->node[i] = node;
|
||||||
|
|
||||||
|
node->depth = root->depth + 1;
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
node->x = root->x;
|
||||||
|
node->y = root->y;
|
||||||
|
node->w = w;
|
||||||
|
node->h = h;
|
||||||
|
}
|
||||||
|
else if (i == 1)
|
||||||
|
{
|
||||||
|
node->x = root->x + w;
|
||||||
|
node->y = root->y;
|
||||||
|
node->w = w;
|
||||||
|
node->h = h;
|
||||||
|
}
|
||||||
|
else if (i == 2)
|
||||||
|
{
|
||||||
|
node->x = root->x;
|
||||||
|
node->y = root->y + h;
|
||||||
|
node->w = w;
|
||||||
|
node->h = h;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node->x = root->x + w;
|
||||||
|
node->y = root->y + h;
|
||||||
|
node->w = w;
|
||||||
|
node->h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
initQuadtree(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root->depth == 0)
|
||||||
|
{
|
||||||
|
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Quadtree memory footprint: %d bytes", memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToQuadtree(Entity *e, Quadtree *root)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
if (root->node[0])
|
||||||
|
{
|
||||||
|
index = getIndex(root, e->x - (e->w / 2), e->y - (e->h / 2), e->w, e->h);
|
||||||
|
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
addToQuadtree(e, root->node[index]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root->numEnts < QT_MAX_ENTS)
|
||||||
|
{
|
||||||
|
root->ents[root->numEnts++] = e;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Couldn't add %s to quadtree - out of node ent space", e->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getIndex(Quadtree *root, int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
|
int verticalMidpoint = root->x + (root->w / 2);
|
||||||
|
int horizontalMidpoint = root->y + (root->h / 2);
|
||||||
|
int topQuadrant = (y < horizontalMidpoint && y + h < horizontalMidpoint);
|
||||||
|
int bottomQuadrant = (y > horizontalMidpoint);
|
||||||
|
|
||||||
|
if (x < verticalMidpoint && x + w < verticalMidpoint)
|
||||||
|
{
|
||||||
|
if (topQuadrant)
|
||||||
|
{
|
||||||
|
index = 1;
|
||||||
|
}
|
||||||
|
else if (bottomQuadrant)
|
||||||
|
{
|
||||||
|
index = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (x > verticalMidpoint)
|
||||||
|
{
|
||||||
|
if (topQuadrant)
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
else if (bottomQuadrant)
|
||||||
|
{
|
||||||
|
index = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeFromQuadtree(Entity *e, Quadtree *root)
|
||||||
|
{
|
||||||
|
int index, i;
|
||||||
|
|
||||||
|
index = getIndex(root, e->x - (e->w / 2), e->y - (e->h / 2), e->w, e->h);
|
||||||
|
|
||||||
|
removeEntity(e, root);
|
||||||
|
|
||||||
|
if (root->node[0])
|
||||||
|
{
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
removeFromQuadtree(e, root->node[index]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
removeFromQuadtree(e, root->node[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void removeEntity(Entity *e, Quadtree *root)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
n = root->numEnts;
|
||||||
|
|
||||||
|
for (i = 0 ; i < QT_MAX_ENTS ; i++)
|
||||||
|
{
|
||||||
|
if (root->ents[i] == e)
|
||||||
|
{
|
||||||
|
root->ents[i] = NULL;
|
||||||
|
root->numEnts--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(root->ents, n, sizeof(Entity*), candidatesComparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore)
|
||||||
|
{
|
||||||
|
cIndex = 0;
|
||||||
|
memset(candidates, 0, sizeof(Entity*) * QT_MAX_CANDIDATES);
|
||||||
|
|
||||||
|
getAllEntsWithinNode(x, y, w, h, ignore, &battle.quadtree);
|
||||||
|
|
||||||
|
/* NULL terminate, to allow us to loop through them more easily */
|
||||||
|
candidates[QT_MAX_CANDIDATES - 1] = NULL;
|
||||||
|
|
||||||
|
return candidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void getAllEntsWithinNode(int x, int y, int w, int h, Entity *ignore, Quadtree *root)
|
||||||
|
{
|
||||||
|
Quadtree *node;
|
||||||
|
int index, i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < root->numEnts ; i++)
|
||||||
|
{
|
||||||
|
addCandidate(root->ents[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
index = getIndex(root, x, y, w, h);
|
||||||
|
|
||||||
|
if (root->node[0])
|
||||||
|
{
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
node = root->node[index];
|
||||||
|
|
||||||
|
getAllEntsWithinNode(node->x, node->y, node->w, node->h, ignore, node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
node = root->node[i];
|
||||||
|
|
||||||
|
getAllEntsWithinNode(node->x, node->y, node->w, node->h, ignore, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addCandidate(Entity *e)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0 ; i <= cIndex ; i++)
|
||||||
|
{
|
||||||
|
/* already added */
|
||||||
|
if (candidates[i] == e)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!candidates[i])
|
||||||
|
{
|
||||||
|
candidates[cIndex++] = e;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Out of quadtree candidate space");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyQuadtree(void)
|
||||||
|
{
|
||||||
|
destroyQuadtreeNode(&battle.quadtree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroyQuadtreeNode(Quadtree *root)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (root->node[0])
|
||||||
|
{
|
||||||
|
for (i = 0 ; i < 4 ; i++)
|
||||||
|
{
|
||||||
|
destroyQuadtreeNode(root->node[i]);
|
||||||
|
|
||||||
|
free(root->node[i]);
|
||||||
|
|
||||||
|
root->node[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int candidatesComparator(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
Entity *e1 = *((Entity**)a);
|
||||||
|
Entity *e2 = *((Entity**)b);
|
||||||
|
|
||||||
|
if (!e1)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (!e2)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,8 +90,8 @@ void drawRadarRangeWarning(void)
|
||||||
{
|
{
|
||||||
int x, y, leaving;
|
int x, y, leaving;
|
||||||
|
|
||||||
x = (int)player->x / GRID_CELL_WIDTH;
|
x = (int)player->x / (SCREEN_WIDTH / 2);
|
||||||
y = (int)player->y / GRID_CELL_HEIGHT;
|
y = (int)player->y / (SCREEN_HEIGHT / 2);
|
||||||
leaving = 0;
|
leaving = 0;
|
||||||
|
|
||||||
if (x <= 2 && player->dx < 0)
|
if (x <= 2 && player->dx < 0)
|
||||||
|
@ -108,14 +108,14 @@ void drawRadarRangeWarning(void)
|
||||||
leaving = 1;
|
leaving = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x >= GRID_SIZE - 2 && player->dx > 0)
|
if (x >= (SCREEN_WIDTH / 2) - 2 && player->dx > 0)
|
||||||
{
|
{
|
||||||
blitRotated(radarWarningTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 90);
|
blitRotated(radarWarningTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 90);
|
||||||
|
|
||||||
leaving = 1;
|
leaving = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (y >= GRID_SIZE - 2 && player->dy > 0)
|
if (y >= (SCREEN_HEIGHT / 2) - 2 && player->dy > 0)
|
||||||
{
|
{
|
||||||
blitRotated(radarWarningTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 180);
|
blitRotated(radarWarningTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 180);
|
||||||
|
|
||||||
|
|
13
src/defs.h
13
src/defs.h
|
@ -60,11 +60,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define MAX_FIGHTER_GUNS 12
|
#define MAX_FIGHTER_GUNS 12
|
||||||
#define MAX_TARGET_RANGE 65536
|
#define MAX_TARGET_RANGE 65536
|
||||||
|
|
||||||
#define GRID_CELL_WIDTH 640
|
#define QT_MAX_DEPTH 5
|
||||||
#define GRID_CELL_HEIGHT 360
|
#define QT_MAX_ENTS 96
|
||||||
#define GRID_SIZE 50
|
#define QT_MAX_CANDIDATES 256
|
||||||
#define MAX_GRID_CANDIDATES 256
|
|
||||||
#define GRID_RESTRICTION_SIZE 250
|
#define BATTLE_AREA_CELLS 50
|
||||||
|
#define BATTLE_AREA_WIDTH (640 * BATTLE_AREA_CELLS)
|
||||||
|
#define BATTLE_AREA_HEIGHT (360 * BATTLE_AREA_CELLS)
|
||||||
|
#define BATTLE_AREA_EDGE 250
|
||||||
|
|
||||||
#define BF_NONE 0
|
#define BF_NONE 0
|
||||||
#define BF_ENGINE (2 << 0)
|
#define BF_ENGINE (2 << 0)
|
||||||
|
|
|
@ -192,13 +192,13 @@ static void loadPlayer(cJSON *node)
|
||||||
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
|
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
|
||||||
|
|
||||||
player = spawnFighter(type, 0, 0, side);
|
player = spawnFighter(type, 0, 0, side);
|
||||||
player->x = (GRID_SIZE * GRID_CELL_WIDTH) / 2;
|
player->x = BATTLE_AREA_WIDTH / 2;
|
||||||
player->y = (GRID_SIZE * GRID_CELL_HEIGHT) / 2;
|
player->y = BATTLE_AREA_HEIGHT / 2;
|
||||||
|
|
||||||
if (cJSON_GetObjectItem(node, "x"))
|
if (cJSON_GetObjectItem(node, "x"))
|
||||||
{
|
{
|
||||||
player->x = (cJSON_GetObjectItem(node, "x")->valueint * GRID_CELL_WIDTH);
|
player->x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
|
||||||
player->y = (cJSON_GetObjectItem(node, "y")->valueint * GRID_CELL_HEIGHT);
|
player->y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(type, "Tug") == 0)
|
if (strcmp(type, "Tug") == 0)
|
||||||
|
@ -237,8 +237,8 @@ static void loadFighters(cJSON *node)
|
||||||
|
|
||||||
types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes);
|
types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes);
|
||||||
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
|
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
|
||||||
x = cJSON_GetObjectItem(node, "x")->valuedouble * GRID_CELL_WIDTH;
|
x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
|
||||||
y = cJSON_GetObjectItem(node, "y")->valuedouble * GRID_CELL_HEIGHT;
|
y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
|
||||||
|
|
||||||
if (cJSON_GetObjectItem(node, "name"))
|
if (cJSON_GetObjectItem(node, "name"))
|
||||||
{
|
{
|
||||||
|
@ -364,8 +364,8 @@ static void loadCapitalShips(cJSON *node)
|
||||||
|
|
||||||
types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes);
|
types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes);
|
||||||
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
|
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
|
||||||
x = cJSON_GetObjectItem(node, "x")->valuedouble * GRID_CELL_WIDTH;
|
x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
|
||||||
y = cJSON_GetObjectItem(node, "y")->valuedouble * GRID_CELL_HEIGHT;
|
y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
|
||||||
|
|
||||||
if (cJSON_GetObjectItem(node, "name"))
|
if (cJSON_GetObjectItem(node, "name"))
|
||||||
{
|
{
|
||||||
|
@ -465,8 +465,8 @@ static void loadEntities(cJSON *node)
|
||||||
{
|
{
|
||||||
e = NULL;
|
e = NULL;
|
||||||
type = lookup(cJSON_GetObjectItem(node, "type")->valuestring);
|
type = lookup(cJSON_GetObjectItem(node, "type")->valuestring);
|
||||||
x = cJSON_GetObjectItem(node, "x")->valuedouble * GRID_CELL_WIDTH;
|
x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
|
||||||
y = cJSON_GetObjectItem(node, "y")->valuedouble * GRID_CELL_HEIGHT;
|
y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
|
||||||
name = NULL;
|
name = NULL;
|
||||||
groupName = NULL;
|
groupName = NULL;
|
||||||
number = 1;
|
number = 1;
|
||||||
|
@ -563,8 +563,8 @@ static void loadItems(cJSON *node)
|
||||||
while (node)
|
while (node)
|
||||||
{
|
{
|
||||||
type = cJSON_GetObjectItem(node, "type")->valuestring;
|
type = cJSON_GetObjectItem(node, "type")->valuestring;
|
||||||
x = cJSON_GetObjectItem(node, "x")->valuedouble * GRID_CELL_WIDTH;
|
x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
|
||||||
y = cJSON_GetObjectItem(node, "y")->valuedouble * GRID_CELL_HEIGHT;
|
y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
|
||||||
name = NULL;
|
name = NULL;
|
||||||
groupName = NULL;
|
groupName = NULL;
|
||||||
number = 1;
|
number = 1;
|
||||||
|
@ -665,8 +665,9 @@ static void loadLocations(cJSON *node)
|
||||||
battle.locationTail = l;
|
battle.locationTail = l;
|
||||||
|
|
||||||
STRNCPY(l->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH);
|
STRNCPY(l->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH);
|
||||||
l->x = cJSON_GetObjectItem(node, "x")->valueint * GRID_CELL_WIDTH;
|
l->x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
|
||||||
l->y = cJSON_GetObjectItem(node, "y")->valueint * GRID_CELL_HEIGHT;
|
l->y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
|
||||||
|
|
||||||
l->size = cJSON_GetObjectItem(node, "size")->valueint;
|
l->size = cJSON_GetObjectItem(node, "size")->valueint;
|
||||||
|
|
||||||
if (cJSON_GetObjectItem(node, "active"))
|
if (cJSON_GetObjectItem(node, "active"))
|
||||||
|
@ -674,8 +675,8 @@ static void loadLocations(cJSON *node)
|
||||||
active = cJSON_GetObjectItem(node, "active")->valueint;
|
active = cJSON_GetObjectItem(node, "active")->valueint;
|
||||||
}
|
}
|
||||||
|
|
||||||
l->x += (GRID_CELL_WIDTH / 2);
|
l->x += (SCREEN_WIDTH / 2);
|
||||||
l->y += (GRID_CELL_HEIGHT / 2);
|
l->y += (SCREEN_HEIGHT / 2);
|
||||||
l->active = active;
|
l->active = active;
|
||||||
|
|
||||||
node = node->next;
|
node = node->next;
|
||||||
|
|
|
@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
typedef struct Texture Texture;
|
typedef struct Texture Texture;
|
||||||
typedef struct Lookup Lookup;
|
typedef struct Lookup Lookup;
|
||||||
typedef struct Weapon Weapon;
|
typedef struct Weapon Weapon;
|
||||||
|
typedef struct Quadtree Quadtree;
|
||||||
typedef struct Entity Entity;
|
typedef struct Entity Entity;
|
||||||
typedef struct Bullet Bullet;
|
typedef struct Bullet Bullet;
|
||||||
typedef struct Debris Debris;
|
typedef struct Debris Debris;
|
||||||
|
@ -263,9 +264,12 @@ struct StarSystem {
|
||||||
StarSystem *next;
|
StarSystem *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GridCell {
|
struct Quadtree {
|
||||||
Entity *entity;
|
int depth;
|
||||||
GridCell *next;
|
int x, y, w, h;
|
||||||
|
Entity *ents[QT_MAX_ENTS];
|
||||||
|
int numEnts;
|
||||||
|
Quadtree *node[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -298,7 +302,7 @@ typedef struct {
|
||||||
Location locationHead, *locationTail;
|
Location locationHead, *locationTail;
|
||||||
struct cJSON *missionJSON;
|
struct cJSON *missionJSON;
|
||||||
unsigned int stats[STAT_MAX];
|
unsigned int stats[STAT_MAX];
|
||||||
GridCell grid[GRID_SIZE][GRID_SIZE];
|
Quadtree quadtree;
|
||||||
} Battle;
|
} Battle;
|
||||||
|
|
||||||
struct ScriptRunner {
|
struct ScriptRunner {
|
||||||
|
|
Loading…
Reference in New Issue