aboutsummaryrefslogtreecommitdiff
path: root/ecs.c
blob: 494a79fdbb8fec8d39dd6957932978e38c12630f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <stdio.h>
#include <stdlib.h>

/* Very simple Entity Component System, created to help a
 * Discord user understand the concept.
 *
 * I made it to be very easy to read and understand and
 * as simple as possible while still having enough features
 * to be usable for simple games.
 *
 * Areas for improvement:
 * - Using an intermediate array (or "sparse set") instead
 *   of a bitset to avoid gaps in the component arrays.
 * - Destroying entities - this can be done by simply
 *   removing all of the components in the current system,
 *   but you may want to have a way to re use-entity IDs.
 *     Hint: This will probably involve sacrificing some
 *     of the bits in the entity ID to store a "version"
 *     to check how many times the ID has been recycled.
 * - Anything else you think you need :)
 */

#define max_entities 256
#define max_component_types 8

/* Entities are just IDs. */
typedef int Entity;

typedef enum {
  ctype_null      = 1 << 0,
  ctype_transform = 1 << 1,
  ctype_enemy     = 1 << 2,
  ctype_sprite    = 1 << 3
} CType;

typedef struct {
	int x, y;
	int scale_x, scale_y;
} Transform;

typedef struct {
	int health;
	int damage;
} Enemy;

typedef struct {
	int id;
	/* Whatever else a sprite needs, you get the idea. */
} Sprite;

typedef struct {
	/* Here are the component pools. */
	Transform transforms[max_entities];
	Enemy enemies[max_entities];
	Sprite sprites[max_entities];

	/* If you have more than 8 different types of component, change this
	 * to an unsigned short or an int to fit the extra bits in the CType
	 * enum. */
	unsigned char bitset[max_entities];

	int entity_count;
} World;

void enemy_system(World* world) {
	int i;
	unsigned char bits;
	Transform* transform;
	Enemy* enemy;

	for (i = 0; i < world->entity_count; i++) {
		bits = world->bitset[i];
		/* Iterate all entities with both a transform and an enemy component. */
		if ((bits & ctype_enemy) && (bits & ctype_transform)) {
			transform = &world->transforms[i];
			enemy = &world->enemies[i];

			/* Do enemy stuff here, pathfinding, shooting etc. */
			printf("Updating enemy for %d!\n", i);
		}
	}
};

void transform_system(World* world) {
	int i;
	unsigned char bits;
	Transform* transform;

	for (i = 0; i < world->entity_count; i++) {
		bits = world->bitset[i];
		/* Iterate all entities with a transform component */
		if (bits & ctype_transform) {
			transform = &world->transforms[i];
			transform->x += 10;

			/* Do transform stuff here, for example updating matrices */
			printf("Updating transform for %d!\n", i);
		}
	}
}

void sprite_system(World* world) {
	/* etc. */
}

void init_world(World* world) {
	world->entity_count = 0;
}

Entity create_entity(World* world) {
	/* Might want to verify that we don't overflow max_entities. */
	Entity e;

	e = world->entity_count++;

	/* Make sure each entity starts with no components. */
	world->bitset[e] = ctype_null;

	return e;
}

void entity_add_components(World* world, Entity entity, unsigned int bits) {
	/* Might want to verify that this entity is valid, etc. */
	world->bitset[entity] |= bits;
}

void entity_remove_components(World* world, Entity entity, unsigned int bits) {
	world->bitset[entity] &= ~bits;
}

int main() {
	World* world;
	Entity a, b;

	world = (World*)malloc(sizeof *world);

	init_world(world);

	a = create_entity(world);
	entity_add_components(world, a, ctype_transform | ctype_enemy);

	b = create_entity(world);
	entity_add_components(world, b, ctype_transform);

	while (1) {
		/* The game loop. */
		enemy_system(world);
		transform_system(world);
		sprite_system(world);
	}

	free(world);
}