+31
-1
include/keraforge/actor.h
+31
-1
include/keraforge/actor.h
···
10
10
#include <raylib.h>
11
11
12
12
13
+
/* The maximum number of registered actors. */
14
+
#define KF_MAX_ACTOR_TYPES 1024
15
+
16
+
17
+
/* Stores serializers and deserializers for actors. Any actor you plan to save MUST be registered here!
18
+
TODO: This will probably be better as a hash table (especially for kf_actor_getregistryid). */
19
+
struct kf_actorregistry
20
+
{
21
+
int count;
22
+
char *id[KF_MAX_ACTOR_TYPES];
23
+
u8 *(*serialize[KF_MAX_ACTOR_TYPES])(struct kf_actor *self, size_t *plen);
24
+
void (*deserialize[KF_MAX_ACTOR_TYPES])(struct kf_actor *self, u8 *data, size_t len);
25
+
};
26
+
/* Global actor registry instance. */
27
+
extern struct kf_actorregistry kf_actorregistry;
28
+
13
29
/* Represents any kinematic body in the world (players, NPCs, etc). */
14
30
struct kf_actor
15
31
{
32
+
/* Unique string identifier for this actor. */
33
+
char *id;
16
34
/* Spritesheet for the actor. */
17
35
struct kf_spritesheet sprites;
18
36
/* The actor's position. */
···
41
59
void (*tick)(struct kf_actor *self);
42
60
/* Called every frame to render the actor. */
43
61
void (*draw)(struct kf_actor *self);
62
+
/* Doubly-linked list of actors. */
63
+
struct kf_actor *prev, *next;
44
64
};
65
+
/* Linked list of actors. */
66
+
extern struct kf_actor *kf_actors, *kf_actors_last;
67
+
extern u32 kf_actor_count;
45
68
46
69
47
70
/* Create a new actor. */
48
-
struct kf_actor *kf_actor_new(struct kf_spritesheet sprites, f32 width, f32 height, bool collides);
71
+
struct kf_actor *kf_actor_new(char *id, struct kf_spritesheet sprites, f32 width, f32 height, bool collides);
49
72
50
73
/* Load a spritesheet, filling in the details for loading character spritesheets. */
51
74
struct kf_spritesheet kf_actor_loadspritesheet(char *filename);
···
58
81
void kf_actor_move(struct kf_world *world, struct kf_actor *actor, f32 deltatime);
59
82
/* Draw the actor. */
60
83
void kf_actor_draw(struct kf_actor *actor);
84
+
85
+
/* Get the registry ID of a given actor ID.
86
+
This will perform a lot of string comparisons, use sparingly! */
87
+
int kf_actor_getregistryid(char *id);
88
+
89
+
/* Save actor data. */
90
+
int kf_saveactors(void);
61
91
62
92
63
93
#endif
+2
include/keraforge/player.h
+2
include/keraforge/player.h
+90
-1
src/actor.c
+90
-1
src/actor.c
···
1
+
#include "keraforge/fs.h"
1
2
#include <keraforge.h>
2
3
#include <stdlib.h>
3
4
#include <raymath.h>
5
+
#include <string.h>
6
+
4
7
8
+
struct kf_actorregistry kf_actorregistry = {0};
9
+
struct kf_actor *kf_actors = NULL, *kf_actors_last = NULL;
10
+
u32 kf_actor_count = 0;
5
11
6
-
struct kf_actor *kf_actor_new(struct kf_spritesheet sprites, f32 width, f32 height, bool collides)
12
+
13
+
struct kf_actor *kf_actor_new(char *id, struct kf_spritesheet sprites, f32 width, f32 height, bool collides)
7
14
{
8
15
struct kf_actor *actor = calloc(1, sizeof(struct kf_actor));
16
+
kf_actor_count++;
9
17
18
+
if (!kf_actors)
19
+
{
20
+
kf_actors = kf_actors_last = actor;
21
+
}
22
+
else
23
+
{
24
+
actor->prev = kf_actors_last;
25
+
kf_actors_last->next = actor;
26
+
kf_actors_last = actor;
27
+
}
28
+
29
+
actor->id = id;
10
30
actor->sprites = sprites;
11
31
actor->size.x = width;
12
32
actor->size.y = height;
···
156
176
157
177
kf_drawsprite(&actor->sprites, actor->pos.x, actor->pos.y, x, y);
158
178
}
179
+
180
+
int kf_actor_getregistryid(char *id)
181
+
{
182
+
size_t l = strlen(id);
183
+
for (int i = 0 ; i < kf_actorregistry.count ; i++)
184
+
{
185
+
char *c = kf_actorregistry.id[i];
186
+
size_t cl = strlen(c);
187
+
if (strncmp(c, id, l>cl?l:cl) == 0)
188
+
{
189
+
return i;
190
+
}
191
+
}
192
+
return -1;
193
+
}
194
+
195
+
#define _KF_ACTORFILE_TMP "data/tmp/actors.bin"
196
+
#define _KF_ACTORFILE_XZ "data/actors.bin.xz"
197
+
#define _KF_ACTORFILE "data/actors.bin"
198
+
199
+
int kf_saveactors(void)
200
+
{
201
+
// char *outfile = compress ? _KF_ACTORFILE_TMP : _KF_ACTORFILE;
202
+
char *outfile = _KF_ACTORFILE;
203
+
204
+
FILE *fp = fopen(outfile, "wb");
205
+
if (!fp)
206
+
KF_THROW("failed to open %s", outfile);
207
+
208
+
size_t nactors = 0;
209
+
size_t total_bytes = 0;
210
+
211
+
for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
212
+
{
213
+
if (!actor->id)
214
+
continue;
215
+
int id = kf_actor_getregistryid(actor->id);
216
+
if (id == -1)
217
+
continue;
218
+
size_t n = strlen(actor->id);
219
+
if (fwrite(actor->id, 1, n, fp) != n)
220
+
{
221
+
KF_THROWSOFTER("failed to write actor ID: %s", actor->id);
222
+
fclose(fp);
223
+
return 0;
224
+
}
225
+
n = 0;
226
+
u8 *data = kf_actorregistry.serialize[id](actor, &n);
227
+
if (!data)
228
+
{
229
+
KF_THROWSOFTER("failed to serialize actor of type %s", actor->id);
230
+
fclose(fp);
231
+
return 0;
232
+
}
233
+
if (fwrite(data, 1, n, fp) != n)
234
+
{
235
+
KF_THROWSOFTER("failed to write serialized actor of type %s", actor->id);
236
+
fclose(fp);
237
+
return 0;
238
+
}
239
+
nactors++;
240
+
total_bytes += n;
241
+
}
242
+
243
+
kf_logdbg("serialized %d actors (%lu bytes)", nactors, total_bytes);
244
+
fclose(fp);
245
+
246
+
return 1;
247
+
}
+23
-3
src/graphics.c
+23
-3
src/graphics.c
···
1
+
#include "keraforge/actor.h"
1
2
#include <keraforge.h>
2
3
#include <raylib.h>
3
4
···
49
50
kf_world_load(&world, true);
50
51
kf_window.room = world;
51
52
52
-
struct kf_actor *player = kf_actor_new(kf_actor_loadspritesheet("data/res/img/char/template.png"), 10, 10, true);
53
+
kf_actorregistry.id[0] = "player";
54
+
kf_actorregistry.serialize[0] = kf_player_serialize;
55
+
kf_actorregistry.deserialize[0] = kf_player_deserialize;
56
+
kf_actorregistry.count++;
57
+
58
+
struct kf_actor *player = kf_actor_new("player", kf_actor_loadspritesheet("data/res/img/char/template.png"), 10, 10, true);
53
59
player->sizeoffset.y = 6;
54
60
player->tick = kf_player_tick;
55
61
player->draw = kf_player_draw;
···
63
69
player->pos.y = state->player.pos.y;
64
70
kf_window.player = player;
65
71
72
+
struct kf_actor *player2 = kf_actor_new("player", kf_actor_loadspritesheet("data/res/img/char/whom.png"), 10, 10, true);
73
+
player2->sizeoffset.y = 6;
74
+
player2->tick = kf_player_tick; /* when controlled is false, player_tick won't process keybinds */
75
+
player2->draw = kf_player_draw;
76
+
player2->pos.x = player->pos.x;
77
+
player2->pos.y = player->pos.y - 24;
78
+
66
79
kf_window.cam.target.x = player->pos.x + (player->size.x / 2);
67
80
kf_window.cam.target.y = player->pos.y + (player->size.y / 2);
68
81
kf_window.cam.zoom = 2;
···
75
88
kf_window.running = 1;
76
89
kf_window.cam.offset.x = GetScreenWidth() / 2.0f;
77
90
kf_window.cam.offset.y = GetScreenHeight() / 2.0f;
91
+
78
92
while (!WindowShouldClose() && kf_window.running)
79
93
{
80
94
if (IsWindowResized())
···
116
130
kf_setmenu(NULL);
117
131
kf_setmodal(NULL);
118
132
133
+
kf_saveactors();
134
+
119
135
kf_window.state->player.pos = kf_window.player->pos;
120
136
kf_state_save(kf_window.state);
121
137
···
163
179
static
164
180
void _kf_modal_play_update(void)
165
181
{
166
-
kf_window.player->tick(kf_window.player);
182
+
// kf_window.player->tick(kf_window.player);
183
+
for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
184
+
actor->tick(actor);
167
185
168
186
Vector2 v = GetScreenToWorld2D(GetMousePosition(), kf_window.cam);
169
187
kf_window.select.x = v.x / KF_TILE_SIZE_PX;
···
193
211
{
194
212
kf_world_draw(kf_window.room, kf_window.cam);
195
213
// kf_world_drawcolliders(world, player, cam);
196
-
kf_window.player->draw(kf_window.player);
214
+
// kf_window.player->draw(kf_window.player);
215
+
for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
216
+
actor->draw(actor);
197
217
}
198
218
199
219
static
+27
-3
src/player.c
+27
-3
src/player.c
···
51
51
52
52
void kf_player_tick(struct kf_actor *self)
53
53
{
54
-
if (!kf_window.menu)
54
+
if (!kf_window.menu && self->controlled)
55
55
{
56
56
_player_tick_move(self);
57
57
···
74
74
{
75
75
kf_actor_draw(self);
76
76
77
-
kf_window.cam.target.x = self->pos.x + (self->size.x / 2);
78
-
kf_window.cam.target.y = self->pos.y + (self->size.y / 2);
77
+
if (self->controlled)
78
+
{
79
+
kf_window.cam.target.x = self->pos.x + (self->size.x / 2);
80
+
kf_window.cam.target.y = self->pos.y + (self->size.y / 2);
81
+
}
82
+
}
83
+
84
+
85
+
struct _kf_serialized_player
86
+
{
87
+
struct kf_vec2(f32) pos;
88
+
};
89
+
90
+
u8* kf_player_serialize(struct kf_actor *self, size_t *plen)
91
+
{
92
+
*plen = sizeof(struct _kf_serialized_player);
93
+
struct _kf_serialized_player *s = malloc(*plen);
94
+
s->pos = self->pos;
95
+
return (u8 *)s;
96
+
}
97
+
98
+
void kf_player_deserialize(struct kf_actor *self, u8 *data, size_t len)
99
+
{
100
+
(void)len;
101
+
struct _kf_serialized_player *s = (struct _kf_serialized_player *)data;
102
+
self->pos = s->pos;
79
103
}