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 struct kf_tile *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->id] && 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 += (int)(kf_s * 5) % 4; 144 145 /* todo: run and jump */ 146 147 kf_drawsprite(&actor->sprites, actor->pos.x, actor->pos.y, x, y); 148}