aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authornathansmithsmith <thenathansmithsmith@gmail.com>2023-07-07 23:10:23 -0600
committernathansmithsmith <thenathansmithsmith@gmail.com>2023-07-07 23:10:23 -0600
commite5268813dcbdc0d90a081b2223ebc21749038635 (patch)
tree7c917996749e4123fb1fe49ddd1ed3b8f7e92334 /src
parenta90e1987de75cfecc2693952625af8cce507ae95 (diff)
Better world
Diffstat (limited to 'src')
-rw-r--r--src/assets.c39
-rw-r--r--src/assets.h37
-rw-r--r--src/entities/antifaShip.c19
-rw-r--r--src/entities/antifaShip.h2
-rw-r--r--src/entities/soldato.c18
-rw-r--r--src/entities/soldato.h12
-rw-r--r--src/entity.c16
-rw-r--r--src/entity.h12
-rw-r--r--src/game.c68
-rw-r--r--src/game.h6
-rw-r--r--src/gameCommon.h7
-rw-r--r--src/gameScreen.c8
-rw-r--r--src/mainMenu.c38
-rw-r--r--src/mainMenu.h6
-rw-r--r--src/playerCamera.c8
-rw-r--r--src/util.h7
-rw-r--r--src/world.c250
-rw-r--r--src/world.h31
18 files changed, 539 insertions, 45 deletions
diff --git a/src/assets.c b/src/assets.c
new file mode 100644
index 0000000..1f0c95b
--- /dev/null
+++ b/src/assets.c
@@ -0,0 +1,39 @@
+#include "assets.h"
+
+const char textureAssetPaths[TEXTURE_ASSET_COUNT][ASSET_PATH_MAX] = {
+ "/home/nathan/Documents/KillaFacsista/assets/icon.png",
+ "/home/nathan/Documents/KillaFacsista/assets/icon128.png",
+ "/home/nathan/Documents/KillaFacsista/assets/icon64.png"
+};
+
+const char modelAssetPaths[MODEL_ASSET_COUNT][ASSET_PATH_MAX] = {
+ "/home/nathan/Documents/KillaFacsista/assets/antifaShip.obj"
+};
+
+void LoadAssets(Assets * assets) {
+ int i;
+
+ // Textures.
+ for (i = 0; i < TEXTURE_ASSET_COUNT; ++i)
+ assets->textures[i] = LoadTexture(textureAssetPaths[i]);
+
+ // Models.
+ for (i = 0; i < MODEL_ASSET_COUNT; ++i)
+ assets->models[i] = LoadModel(modelAssetPaths[i]);
+
+ TraceLog(LOG_INFO, "Assets loaded");
+}
+
+void unloadAssets(Assets * assets) {
+ int i;
+
+ // Textures.
+ for (i = 0; i < TEXTURE_ASSET_COUNT; ++i)
+ UnloadTexture(assets->textures[i]);
+
+ // Models.
+ for (i = 0; i < MODEL_ASSET_COUNT; ++i)
+ UnloadModel(assets->models[i]);
+
+ TraceLog(LOG_INFO, "Assets unloaded");
+}
diff --git a/src/assets.h b/src/assets.h
new file mode 100644
index 0000000..f28ddb8
--- /dev/null
+++ b/src/assets.h
@@ -0,0 +1,37 @@
+#include "gameCommon.h"
+
+#ifndef ASSETS_H
+#define ASSETS_H
+
+#define ASSET_PATH_MAX 255
+
+#define TEXTURE_ASSET_COUNT 3
+#define MODEL_ASSET_COUNT 1
+
+// Paths to assets.
+extern const char textureAssetPaths[TEXTURE_ASSET_COUNT][ASSET_PATH_MAX];
+extern const char modelAssetPaths[MODEL_ASSET_COUNT][ASSET_PATH_MAX];
+
+typedef int32_t AssetId;
+
+// Texture asset ids.
+enum {
+ ICON_ASSET,
+ ICON128_ASSET,
+ ICON64_ASSET
+};
+
+// Model asset ids.
+enum {
+ ANTIFA_SHIP_ASSET
+};
+
+typedef struct Assets {
+ Texture2D textures[TEXTURE_ASSET_COUNT];
+ Model models[MODEL_ASSET_COUNT];
+} Assets;
+
+void LoadAssets(Assets * assets);
+void unloadAssets(Assets * assets);
+
+#endif
diff --git a/src/entities/antifaShip.c b/src/entities/antifaShip.c
index 1944053..f43a7df 100644
--- a/src/entities/antifaShip.c
+++ b/src/entities/antifaShip.c
@@ -1,28 +1,21 @@
#include "antifaShip.h"
-#include <raylib.h>
+#include "game.h"
-void initAntifaShip(Entity * entity) {
- entity->model = LoadModel("/home/nathan/Documents/KillaFacsista/assets/antifaShip.obj");
+void initAntifaShip(Entity * entity, Game * game) {
+ entity->model = &game->assets.models[ANTIFA_SHIP_ASSET];
entity->useAcceleration = true;
entity->acceleration = (EntityAcceleration){
.speedUp = 30.0,
.speedDown = 15,
- .rotationUp = (Vector3){0.6, 0.6, 0.6},
- .rotationDown = (Vector3){0.6, 0.6, 0.6}
+ .rotation = (Vector3){0.7, 0.7, 0.7}
};
}
void closeAntifaShip(Entity * entity) {
- UnloadModel(entity->model);
}
void updateAntifaShip(Game * game, Entity * entity, EntityId id) {
-}
-
-void drawAntifaShip(Game * game, Entity * entity, EntityId id) {
- entityDraw(entity);
-
Vector3 stick = (Vector3){
GetGamepadAxisMovement(0, 1),
-GetGamepadAxisMovement(0, 0),
@@ -33,3 +26,7 @@ void drawAntifaShip(Game * game, Entity * entity, EntityId id) {
entityJoystickControl(entity, stick, fabs(GetGamepadAxisMovement(0, 3) * 300.0));
}
+
+void drawAntifaShip(Game * game, Entity * entity, EntityId id) {
+ entityDraw(entity);
+}
diff --git a/src/entities/antifaShip.h b/src/entities/antifaShip.h
index 15e9009..a1b97d2 100644
--- a/src/entities/antifaShip.h
+++ b/src/entities/antifaShip.h
@@ -4,7 +4,7 @@
#ifndef ANTIFA_SHIP_H
#define ANTIFA_SHIP_H
-void initAntifaShip(Entity * entity);
+void initAntifaShip(Entity * entity, Game * game);
void closeAntifaShip(Entity * entity);
void updateAntifaShip(Game * game, Entity * entity, EntityId id);
void drawAntifaShip(Game * game, Entity * entity, EntityId id);
diff --git a/src/entities/soldato.c b/src/entities/soldato.c
new file mode 100644
index 0000000..c1903d4
--- /dev/null
+++ b/src/entities/soldato.c
@@ -0,0 +1,18 @@
+#include "soldato.h"
+#include "game.h"
+
+void initSoldato(Entity * entity, Game * game) {
+ entity->model = &game->assets.models[ANTIFA_SHIP_ASSET];
+ entity->velocity.angularVelocity = (AxisAngle){(Vector3){1.0, 1.0, 1.0}, 1.0};
+}
+
+void closeSoldato(Entity * entity) {
+}
+
+void updateSoldato(Game * game, Entity * entity, EntityId id) {
+ entityUpdateRotation(entity);
+}
+
+void drawSoldato(Game * game, Entity * entity, EntityId id) {
+ entityDraw(entity);
+}
diff --git a/src/entities/soldato.h b/src/entities/soldato.h
new file mode 100644
index 0000000..4069b26
--- /dev/null
+++ b/src/entities/soldato.h
@@ -0,0 +1,12 @@
+#include "gameCommon.h"
+#include "entity.h"
+
+#ifndef SOLDATO_H
+#define SOLDATO_H
+
+void initSoldato(Entity * entity, Game * game);
+void closeSoldato(Entity * entity);
+void updateSoldato(Game * game, Entity * entity, EntityId id);
+void drawSoldato(Game * game, Entity * entity, EntityId id);
+
+#endif
diff --git a/src/entity.c b/src/entity.c
index c88c767..f4066b5 100644
--- a/src/entity.c
+++ b/src/entity.c
@@ -1,9 +1,11 @@
#include "entity.h"
#include "entities/antifaShip.h"
+#include "entities/soldato.h"
// This fucker is used for creating entities.
const EntityTypeInfo entityTypeInfo[ENTITY_TYPE_COUNT] = {
- (EntityTypeInfo){initAntifaShip, closeAntifaShip, updateAntifaShip, drawAntifaShip}
+ (EntityTypeInfo){initAntifaShip, closeAntifaShip, updateAntifaShip, drawAntifaShip},
+ (EntityTypeInfo){initSoldato, closeSoldato, updateSoldato, drawSoldato}
};
EntityVelocity entityVelocityIdentity() {
@@ -32,7 +34,7 @@ Vector3 accelerateVector3(Vector3 value, Vector3 lastValue, Vector3 up, Vector3
};
}
-Entity createEntity(EntityType type) {
+Entity createEntity(EntityType type, Game * game) {
EntityTypeInfo info = entityTypeInfo[type];
// Set defaults.
@@ -49,7 +51,7 @@ Entity createEntity(EntityType type) {
};
// Init.
- info.initCb(&entity);
+ info.initCb(&entity, game);
return entity;
}
@@ -60,10 +62,10 @@ void closeEntity(Entity * entity) {
// Basic wireframe drawing.
void entityDraw(Entity * entity) {
- entity->model.transform = QuaternionToMatrix(entity->rotation);
+ entity->model->transform = QuaternionToMatrix(entity->rotation);
DrawModelWires(
- entity->model,
+ *entity->model,
entity->position,
1,
GREEN
@@ -110,8 +112,8 @@ void entityJoystickControl(Entity * entity, Vector3 stick, float speed) {
st = accelerateVector3(
stick,
entity->lastVelocity.stick,
- Vector3Scale(entity->acceleration.rotationUp, t),
- Vector3Scale(entity->acceleration.rotationDown, t)
+ Vector3Scale(entity->acceleration.rotation, t),
+ Vector3Scale(entity->acceleration.rotation, t)
);
}
diff --git a/src/entity.h b/src/entity.h
index 7d27258..128365f 100644
--- a/src/entity.h
+++ b/src/entity.h
@@ -19,6 +19,7 @@ enum {
typedef int8_t EntityType;
typedef int16_t EntityId; // Id in world.
+typedef uint32_t EntityFingerprint;
// Callbacks.
typedef void (*EntityUpdateCb)(Game * game, Entity * entity, EntityId id);
@@ -26,8 +27,7 @@ typedef void (*EntityDrawCb)(Game * game, Entity * entity, EntityId id);
// Acceleration indeed hehehe.
typedef struct EntityAcceleration {
- Vector3 rotationUp;
- Vector3 rotationDown;
+ Vector3 rotation;
float speedUp;
float speedDown;
} EntityAcceleration;
@@ -46,8 +46,10 @@ EntityVelocity entityVelocityIdentity();
// This fucker is a entity.
typedef struct Entity {
+ EntityId id;
+ EntityFingerprint fingerprint;
EntityType type;
- Model model;
+ Model * model;
Vector3 position;
Quaternion rotation;
@@ -65,7 +67,7 @@ typedef struct Entity {
void * data;
} Entity;
-typedef void (*EntityInitCb)(Entity * entity);
+typedef void (*EntityInitCb)(Entity * entity, Game * game);
typedef void (*EntityCloseCb)(Entity * entity);
// Info for each entity type.
@@ -79,7 +81,7 @@ typedef struct EntityTypeInfo {
const extern EntityTypeInfo entityTypeInfo[ENTITY_TYPE_COUNT];
// Do I need a fucking comment?
-Entity createEntity(EntityType type);
+Entity createEntity(EntityType type, Game * game);
void closeEntity(Entity * entity);
// Helper functions for updating and drawing.
diff --git a/src/game.c b/src/game.c
index 2e966f2..bffc6b5 100644
--- a/src/game.c
+++ b/src/game.c
@@ -4,23 +4,81 @@ void initGame(Game * game) {
// Window.
InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Killa Facsista");
+ // Assets.
+ LoadAssets(&game->assets);
+
// Screen id.
game->screenId = SCREEN_GAME;
+ // Main menu.
+ initMainMenu(game);
+
// Camera.
initPlayerCamera(&game->playerCamera);
- // Ship test.
- game->ship = createEntity(ENTITY_ANTIFA);
-
SetTargetFPS(60);
//DisableCursor();
+
+ // World.
+ initWorld(&game->world);
+
+ // Debug.
+ // Add player.
+ addEntityToWorld(
+ &game->world,
+ createEntity(ENTITY_ANTIFA, game)
+ );
+
+ // Test entity.
+ Entity soldato = createEntity(ENTITY_SOLDATO, game);
+ soldato.position = (Vector3){10.0, 10.0, 10.0};
+ addEntityToWorld(&game->world, soldato);
+
+ soldato = createEntity(ENTITY_SOLDATO, game);
+ soldato.position = (Vector3){20.0, 20.0, 20.0};
+ addEntityToWorld(&game->world, soldato);
+
+ soldato = createEntity(ENTITY_SOLDATO, game);
+ soldato.position = (Vector3){30.0, 30.0, 30.0};
+ addEntityToWorld(&game->world, soldato);
+
+ printf("%d\n", removeEntityFromWorld(&game->world, 2));
+ printf("%d\n", removeEntityFromWorld(&game->world, 3));
+
+ soldato = createEntity(ENTITY_SOLDATO, game);
+ soldato.position = (Vector3){-30.0, -30.0, -30.0};
+ addEntityToWorld(&game->world, soldato);
+
+
+ puts("v");
+
+ for (int i = 0; i < game->world.vacantIdsCount; ++i)
+ printf("%d\n", game->world.vacantIds[i]);
+
+ puts("l");
+
+ for (int i = 0; i < game->world.lookUpSize; ++i) {
+ printf("%d\n", game->world.lookUp[i]);
+
+ Entity * e = getEntityFromWorld(game->world, i);
+
+ if (e == NULL) {
+ puts("null");
+ continue;
+ }
+
+ if (e->id == i)
+ printf("good %x\n", e->fingerprint);
+ else
+ printf("bad %d\n", e->id);
+ }
}
void closeGame(Game * game) {
- // Close ship test.
- closeEntity(&game->ship);
+ unloadAssets(&game->assets);
+ freeWorld(&game->world);
+ // Close window last.
CloseWindow();
}
diff --git a/src/game.h b/src/game.h
index f875b62..e1f318a 100644
--- a/src/game.h
+++ b/src/game.h
@@ -3,6 +3,8 @@
#include "gameScreen.h"
#include "playerCamera.h"
#include "entity.h"
+#include "assets.h"
+#include "world.h"
#ifndef GAME_H
#define GAME_H
@@ -17,8 +19,8 @@ typedef struct Game {
MainMenu mainMenu;
GameScreen gameScreen;
Camera3D playerCamera;
-
- Entity ship;
+ Assets assets;
+ World world;
} Game;
void initGame(Game * game);
diff --git a/src/gameCommon.h b/src/gameCommon.h
index 0d18d32..08ce5fe 100644
--- a/src/gameCommon.h
+++ b/src/gameCommon.h
@@ -22,13 +22,6 @@ typedef struct Entity Entity;
#define WINDOW_WIDTH 960
#define WINDOW_HEIGHT 540
-// Bit shit.
-#define SET_BIT(b, n) (b | (0x1 << n))
-#define CLEAR_BIT(b, n) (b & ~(0x1 << n))
-#define IS_BIT_SET(b, n) ((b >> n) & 0x1)
-#define TOGGLE_BIT(b, n) (b ^ (0x1 << n))
-#define HAS_FLAG(v, f) ((v & f) == f)
-
// Memory management.
#define KF_MALLOC(size) malloc(size)
#define KF_CALLOC(nmemb, size) calloc(nmemb, size)
diff --git a/src/gameScreen.c b/src/gameScreen.c
index 893da0c..1eb6b55 100644
--- a/src/gameScreen.c
+++ b/src/gameScreen.c
@@ -1,7 +1,12 @@
#include "gameScreen.h"
#include "game.h"
+#include "world.h"
void updateGameScreen(Game * game) {
+
+ // Update world.
+ updateWorld(&game->world, game);
+
ClearBackground(BLACK);
// Camera.
@@ -11,7 +16,8 @@ void updateGameScreen(Game * game) {
DrawGrid(500, 25.0);
- game->ship.drawCb(game, &game->ship, 0);
+ // Draw world.
+ drawWorld(&game->world, game);
EndMode3D();
}
diff --git a/src/mainMenu.c b/src/mainMenu.c
index 10f293a..fc67972 100644
--- a/src/mainMenu.c
+++ b/src/mainMenu.c
@@ -1,14 +1,46 @@
#include "mainMenu.h"
#include "game.h"
+void initMainMenu(Game * game) {
+ game->mainMenu = (MainMenu){
+ .startButton = (Rectangle){0, 0, 100, 50},
+ .logoTexture = &game->assets.textures[ICON128_ASSET]
+ };
+
+ resizeMainMenu(game);
+}
+
void updateMainMenu(Game * game) {
+ MainMenu * mainMenu = &game->mainMenu;
ClearBackground(RAYWHITE);
- bool start = GuiButton(
- (Rectangle){10, 10, 100, 50},
- "Start"
+ // Logo.
+ DrawTextureV(
+ *mainMenu->logoTexture,
+ mainMenu->logoPosition,
+ WHITE
);
+ // Start button.
+ bool start = GuiButton(mainMenu->startButton, "Start");
+
if (start)
game->screenId = SCREEN_GAME;
+
+ if (IsWindowResized())
+ resizeMainMenu(game);
+}
+
+void resizeMainMenu(Game * game) {
+ MainMenu * mainMenu = &game->mainMenu;
+
+ // Logo.
+ mainMenu->logoPosition = (Vector2){
+ (GetScreenWidth() / 2.0) - (mainMenu->logoTexture->width / 2.0),
+ (GetScreenHeight() / 2.0) - (mainMenu->logoTexture->height * 1.50)
+ };
+
+ // Start button.
+ mainMenu->startButton.x = (GetScreenWidth() / 2.0) - (mainMenu->startButton.width / 2.0);
+ mainMenu->startButton.y = (GetScreenHeight() / 2.0) - (mainMenu->startButton.height / 2.0);
}
diff --git a/src/mainMenu.h b/src/mainMenu.h
index 7dd5036..10ce855 100644
--- a/src/mainMenu.h
+++ b/src/mainMenu.h
@@ -4,8 +4,14 @@
#define MAIN_MENU_H
typedef struct MainMenu {
+ Vector2 logoPosition;
+ Texture2D * logoTexture;
+
+ Rectangle startButton;
} MainMenu;
+void initMainMenu(Game * game);
void updateMainMenu(Game * game);
+void resizeMainMenu(Game * game);
#endif
diff --git a/src/playerCamera.c b/src/playerCamera.c
index d84d6d3..df2cce4 100644
--- a/src/playerCamera.c
+++ b/src/playerCamera.c
@@ -13,10 +13,12 @@ void initPlayerCamera(Camera3D * camera) {
}
void updatePlayerCamera(Camera3D * camera, Game * game) {
+ Entity * player = &game->world.entities[0];
+
//UpdateCamera(camera, CAMERA_FIRST_PERSON);
- camera->target = game->ship.position;
+ camera->target = player->position;
- Matrix m = QuaternionToMatrix(QuaternionInvert(game->ship.rotation));
+ Matrix m = QuaternionToMatrix(QuaternionInvert(player->rotation));
Vector3 pos = (Vector3){0.0, CAMERA_DIS/2, -CAMERA_DIS};
camera->position = (Vector3){
@@ -25,7 +27,7 @@ void updatePlayerCamera(Camera3D * camera, Game * game) {
m.m8 * pos.x + m.m9 * pos.y + m.m10 * pos.z
};
- camera->position = Vector3Add(camera->position, game->ship.position);
+ camera->position = Vector3Add(camera->position, player->position);
camera->up = (Vector3){
m.m1 + m.m2,
m.m5 + m.m6,
diff --git a/src/util.h b/src/util.h
index 94a9dd6..c769488 100644
--- a/src/util.h
+++ b/src/util.h
@@ -3,6 +3,13 @@
#ifndef UTIL_H
#define UTIL_H
+// Bit shit.
+#define SET_BIT(b, n) (b | (0x1 << n))
+#define CLEAR_BIT(b, n) (b & ~(0x1 << n))
+#define IS_BIT_SET(b, n) ((b >> n) & 0x1)
+#define TOGGLE_BIT(b, n) (b ^ (0x1 << n))
+#define HAS_FLAG(v, f) ((v & f) == f)
+
typedef struct AxisAngle {
Vector3 axis;
float angle;
diff --git a/src/world.c b/src/world.c
index ea50eca..d76a2d3 100644
--- a/src/world.c
+++ b/src/world.c
@@ -1 +1,251 @@
#include "world.h"
+#include "game.h"
+
+void initWorld(World * world) {
+ world->entities = NULL;
+ world->entitiesCount = 0;
+
+ world->lookUp = NULL;
+ world->lookUpSize = 0;
+
+ world->vacantIds = NULL;
+ world->vacantIdsCount = 0;
+
+ // Set current fingerprint.
+ SetRandomSeed(time(NULL));
+
+ world->currentFingerprint = GetRandomValue(
+ FINGERPRINT_START_RANGE_MIN,
+ FINGERPRINT_START_RANGE_MAX
+ );
+}
+
+void freeWorld(World * world) {
+ int i;
+
+ if (world->entities == NULL)
+ return;
+
+ // Close entities.
+ for (i = 0; i < world->entitiesCount; ++i)
+ closeEntity(&world->entities[i]);
+
+ KF_FREE(world->entities);
+ KF_FREE(world->lookUp);
+
+ if (world->vacantIds != NULL)
+ KF_FREE(world->vacantIds);
+}
+
+// Not for direct use.
+KfError pushVacantId(World * world, EntityId id) {
+ ++world->vacantIdsCount;
+
+ // Allocate.
+ if (world->vacantIds == NULL)
+ world->vacantIds = (EntityId*)KF_CALLOC(1, sizeof(EntityId));
+ else
+ world->vacantIds = (EntityId*)KF_REALLOCARRAY(
+ world->vacantIds,
+ world->vacantIdsCount,
+ sizeof(EntityId)
+ );
+
+ if (world->vacantIds == NULL) {
+ ALLOCATION_ERROR;
+ return KFERROR;
+ }
+
+ world->vacantIds[world->vacantIdsCount - 1] = id;
+ return KFSUCCESS;
+}
+
+// Not for direct use.
+EntityId popVacantId(World * world) {
+ EntityId id;
+
+ // Already empty.
+ if (world->vacantIds == NULL)
+ return ENTITY_ID_NONE;
+
+ id = world->vacantIds[world->vacantIdsCount - 1];
+
+ // Decrease count.
+ --world->vacantIdsCount;
+
+ // Free or recallocate.
+ if (world->vacantIdsCount == 0) {
+ KF_FREE(world->vacantIds);
+ world->vacantIds = NULL;
+ } else {
+ world->vacantIds = (EntityId*)KF_REALLOCARRAY(
+ world->vacantIds,
+ world->vacantIdsCount,
+ sizeof(EntityId)
+ );
+ }
+
+ return id;
+}
+
+Entity * getEntityFromWorld(World world, EntityId id) {
+ if (world.entities == NULL || id < 0 || id >= world.lookUpSize)
+ return NULL;
+
+ int pos = world.lookUp[id];
+
+ if (pos == ENTITY_ID_NONE)
+ return NULL;
+
+ return &world.entities[pos];
+}
+
+EntityId addEntityToWorld(World * world, Entity entity) {
+ EntityId id;
+ EntityId poppedId;
+
+ Entity entityCopy = entity;
+
+ // Set fingerprint.
+ entityCopy.fingerprint = world->currentFingerprint;
+ ++world->currentFingerprint;
+
+ // Not allocated.
+ if (world->entities == NULL) {
+ // Allocate.
+ world->entities = (Entity*)KF_CALLOC(1, sizeof(Entity));
+ world->lookUp = (EntityId*)KF_CALLOC(1, sizeof(EntityId));
+ world->entitiesCount = 1;
+ world->lookUpSize = 1;
+
+ if (world->entities == NULL || world->lookUp == NULL) {
+ ALLOCATION_ERROR;
+ return ENTITY_ID_NONE;
+ }
+
+ // Set entity and id.
+ world->entities[0] = entityCopy;
+ world->entities[0].id = 0;
+ world->lookUp[0] = 0;
+ return 0;
+ }
+
+ ++world->entitiesCount;
+
+ // Resize.
+ world->entities = (Entity*)KF_REALLOCARRAY(
+ world->entities,
+ world->entitiesCount,
+ sizeof(Entity)
+ );
+
+ if (world->entities == NULL) {
+ ALLOCATION_ERROR;
+ return ENTITY_ID_NONE;
+ }
+
+ // Set entity.
+ world->entities[world->entitiesCount - 1] = entityCopy;
+
+ // Set look up.
+ poppedId = popVacantId(world);
+
+ // Got popped id.
+ if (poppedId != ENTITY_ID_NONE) {
+ world->lookUp[poppedId] = world->entitiesCount - 1;
+ world->entities[world->entitiesCount - 1].id = poppedId;
+ return poppedId;
+ }
+
+ ++world->lookUpSize;
+
+ world->lookUp = (EntityId*)KF_REALLOCARRAY(
+ world->lookUp,
+ world->lookUpSize,
+ sizeof(EntityId)
+ );
+
+ if (world->lookUp == NULL) {
+ ALLOCATION_ERROR;
+ return ENTITY_ID_NONE;
+ }
+
+ // Set id.
+ id = world->lookUpSize - 1;
+ world->entities[world->entitiesCount - 1].id = id;
+ world->lookUp[id] = world->entitiesCount - 1;
+ return id;
+}
+
+KfError removeEntityFromWorld(World * world, EntityId id) {
+ int i;
+ int pos;
+
+ if (world->entitiesCount == 1)
+ return KFERROR;
+
+ // Get position in list.
+ pos = world->lookUp[id];
+
+ if (pos == ENTITY_ID_NONE)
+ return KFSUCCESS;
+
+ // Close entity.
+ closeEntity(&world->entities[pos]);
+
+ // Push id.
+ if (pushVacantId(world, id) != KFSUCCESS)
+ return KFERROR;
+
+ // Move back entities.
+ for (i = pos; i < world->entitiesCount - 1; ++i)
+ world->entities[i] = world->entities[i + 1];
+
+ // Update lookup.
+ for (i = id + 1; i < world->lookUpSize; ++i)
+ --world->lookUp[i];
+
+ world->lookUp[id] = ENTITY_ID_NONE;
+
+ // Resize entities.
+ --world->entitiesCount;
+
+ world->entities = (Entity*)KF_REALLOCARRAY(
+ world->entities,
+ world->entitiesCount,
+ sizeof(Entity)
+ );
+
+ if (world->entities == NULL) {
+ ALLOCATION_ERROR;
+ return KFERROR;
+ }
+
+ return KFSUCCESS;
+}
+
+void updateWorld(World * world, Game * game) {
+ int i;
+ Entity * entity;
+
+ for (i = 0; i < world->entitiesCount; ++i) {
+ entity = &world->entities[i];
+
+ // Call update callback.
+ if (entity->updateCb != NULL)
+ entity->updateCb(game, entity, i);
+ }
+}
+
+void drawWorld(World * world, Game * game) {
+ int i;
+ Entity * entity;
+
+ for (i = 0; i < world->entitiesCount; ++i) {
+ entity = &world->entities[i];
+
+ // Call draw callback.
+ if (entity->drawCb != NULL)
+ entity->drawCb(game, entity, i);
+ }
+}
diff --git a/src/world.h b/src/world.h
index 379b920..b075301 100644
--- a/src/world.h
+++ b/src/world.h
@@ -4,4 +4,35 @@
#ifndef WORLD_H
#define WORLD_H
+#define FINGERPRINT_START_RANGE_MIN 0xf
+#define FINGERPRINT_START_RANGE_MAX 0xff
+
+typedef struct World {
+ Entity * entities;
+ size_t entitiesCount;
+
+ // For getting entity id;
+ EntityId * lookUp;
+ size_t lookUpSize;
+
+ EntityId * vacantIds;
+ size_t vacantIdsCount;
+
+ // Used for making fingerprints for entities.
+ EntityFingerprint currentFingerprint;
+} World;
+
+void initWorld(World * world);
+void freeWorld(World * world);
+
+#define ENTITY_ID_NONE -1
+
+// ENTITY_ID_NONE on error.
+Entity * getEntityFromWorld(World world, EntityId id);
+EntityId addEntityToWorld(World * world, Entity entity);
+KfError removeEntityFromWorld(World * world, EntityId id);
+
+void updateWorld(World * world, Game * game);
+void drawWorld(World * world, Game * game);
+
#endif