A game engine for top-down 2D RPG games.
rpg
game-engine
raylib
c99
1#include <keraforge.h>
2#include <stdlib.h>
3#include <raymath.h>
4
5
6struct kf_actor *kf_actor_new(struct kf_spritesheet sprites, f32 width, f32 height, bool collides)
7{
8 struct kf_actor *actor = calloc(1, sizeof(struct kf_actor));
9
10 actor->sprites = sprites;
11 actor->size.x = width;
12 actor->size.y = height;
13 actor->collide = collides;
14
15 actor->speed = 25;
16 actor->speedmod = 1;
17 actor->friction = 1.5f;
18 actor->pointing = kf_north;
19
20 return actor;
21}
22
23struct kf_spritesheet kf_actor_loadspritesheet(char *filename)
24{
25 return kf_loadspritesheet(filename, 20, 20);
26}
27
28int kf_actor_canmovetowards(struct kf_world *world, struct kf_actor *actor, struct kf_vec2(f32) dir)
29{
30 Rectangle r = {
31 actor->pos.x + (actor->size.x / 2) + actor->sizeoffset.x,
32 actor->pos.y + (actor->size.y / 2) + actor->sizeoffset.y,
33 actor->size.x,
34 actor->size.y
35 };
36 r.x += dir.x;
37 r.y += dir.y;
38
39 /* get a range of tiles to check */
40 const u32 sx = fmax(0, floorf(r.x / KF_TILE_SIZE_PX) - 1);
41 const u32 sy = fmax(0, floorf(r.y / KF_TILE_SIZE_PX) - 1);
42 const u32 ex = fmin(world->width, ceilf(r.width / KF_TILE_SIZE_PX) + sx + 2);
43 const u32 ey = fmin(world->height, ceilf(r.height / KF_TILE_SIZE_PX) + sy + 2);
44 const size_t down = world->width - ex + sx - 1; /* number of indexes to add to reach the next tile down */
45
46 /* check if any tiles will collide with the actor's rect */
47 const f32 trx = sx * KF_TILE_SIZE_PX;
48 Rectangle tr = {
49 trx,
50 sy * KF_TILE_SIZE_PX,
51 /* TODO:
52 Subtracting 1 as a bandaid fix to high velocities causing the player to be stopped early in collisions.
53 This is a very notorious problem in 3D collision and fwik there are plenty of 2D solutions.
54 I'll research and implement one eventually:tm: */
55 KF_TILE_SIZE_PX - 1,
56 KF_TILE_SIZE_PX - 1,
57 }; /* tile rect */
58 u32 x;
59 kf_tileid_t *tile = kf_world_gettile(world, sx, sy);
60
61 for (u32 y = sy ; y <= ey ; y++)
62 {
63 for (x = sx ; x <= ex ; x++)
64 {
65 if (kf_tiles.collide[*tile] && CheckCollisionRecs(r, tr))
66 return 0;
67 tile++; /* shift tile pointer to the right */
68 tr.x += KF_TILE_SIZE_PX;
69 }
70 tile += down; /* shift tile pointer down */
71 tr.x = trx;
72 tr.y += KF_TILE_SIZE_PX;
73 }
74
75 return 1;
76}
77
78void kf_actor_addforce(struct kf_actor *self, struct kf_vec2(f32) force)
79{
80 self->vel.x += force.x;
81 self->vel.y += force.y;
82}
83
84void kf_actor_move(struct kf_world *world, struct kf_actor *self, f32 dt)
85{
86 struct kf_vec2(f32) delta = kf_mulval_vec2(f32)(self->vel, (self->speed * self->speedmod) * dt);
87
88 if (self->collide)
89 {
90 if (delta.x && !kf_actor_canmovetowards(world, self, kf_vec2_x(f32)(delta)))
91 delta.x = 0;
92 if (delta.y && !kf_actor_canmovetowards(world, self, kf_vec2_y(f32)(delta)))
93 delta.y = 0;
94 }
95
96 if (!self->controlled)
97 {
98 if (delta.y > 0)
99 self->pointing = kf_south;
100 else if (delta.y < 0)
101 self->pointing = kf_north;
102 else if (delta.x < 0)
103 self->pointing = kf_west;
104 else if (delta.x > 0)
105 self->pointing = kf_east;
106 }
107
108 self->pos = kf_add_vec2(f32)(self->pos, delta);
109
110 static const f32 speed_deadzone = 0.1f;
111
112 if (self->vel.x > -speed_deadzone && self->vel.x < speed_deadzone)
113 self->vel.x = 0;
114 else if (self->vel.x)
115 self->vel.x /= self->friction;
116
117 if (self->vel.y > -speed_deadzone && self->vel.y < speed_deadzone)
118 self->vel.y = 0;
119 else if (self->vel.y)
120 self->vel.y /= self->friction;
121
122 if (self->speedmod > -(1+speed_deadzone) && self->speedmod < 1+speed_deadzone)
123 self->speedmod = 1;
124 else if (self->speedmod)
125 self->speedmod -= self->friction * self->friction * dt;
126}
127
128void kf_actor_draw(struct kf_actor *actor)
129{
130 int x = 0, y = 0;
131
132 switch (actor->pointing)
133 {
134 case kf_south: y = 0; break;
135 case kf_east: y = 1; break;
136 case kf_west: y = 2; break;
137 case kf_north: y = 3; break;
138 }
139
140 if (actor->vel.x != 0 || actor->vel.y != 0)
141 x += 7; /* walk sprites */
142
143 x += (kf_frame / 15) % 4;
144
145 /* todo: run and jump */
146
147 kf_drawsprite(&actor->sprites, actor->pos.x, actor->pos.y, x, y);
148}