base frame of an item system is standing, rendering is working. Fixed a bug with the renderer
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 922 B After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 300 B |
Binary file not shown.
|
After Width: | Height: | Size: 624 B |
Binary file not shown.
|
After Width: | Height: | Size: 537 B |
+3
-3
@@ -14,10 +14,10 @@ typedef struct Enemy {
|
||||
path_t path;
|
||||
|
||||
int vision_radius;
|
||||
void* data;
|
||||
|
||||
void (*set_vel_func)(world_t*, enemy_t*, player_t*);
|
||||
int (*move_func)(enemy_t*, player_t*, world_t*);
|
||||
void (*update_anim_func)(enemy_t*, player_t*);
|
||||
void (*execute_state)(world_t*, enemy_t*, player_t*);
|
||||
void (*update_state)(world_t*, enemy_t*, player_t*);
|
||||
|
||||
} enemy_t;
|
||||
|
||||
|
||||
+9
-1
@@ -1,14 +1,21 @@
|
||||
# pragma once
|
||||
|
||||
# include <raylib.h>
|
||||
# include <raylib.h>
|
||||
# include <sys/time.h>
|
||||
|
||||
|
||||
# include "../include/tilemap.h"
|
||||
# include "../include/anim.h"
|
||||
|
||||
typedef struct Player player_t;
|
||||
|
||||
typedef struct Entity {
|
||||
int health;
|
||||
|
||||
// visual
|
||||
animator_t anim;
|
||||
timeval_t action_timer;
|
||||
Color tint;
|
||||
|
||||
int bb_size; // bounding box
|
||||
Vector2 sprite_size;
|
||||
@@ -28,4 +35,5 @@ void set_entity_center(entity_t* entity, Vector2 center_pos);
|
||||
Vector2 get_entity_center(entity_t* entity);
|
||||
float get_entity_bottom(entity_t* entity);
|
||||
Rectangle get_entity_rect(entity_t* entity);
|
||||
void entity_face_player(entity_t* entity, player_t* player);
|
||||
Rectangle** get_col_tiles_around_entity(entity_t* entity, tilemap_t* col_map);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# pragma once
|
||||
|
||||
#include <raylib.h>
|
||||
|
||||
typedef struct Player player_t;
|
||||
typedef struct World world_t;
|
||||
|
||||
typedef enum ItemType {
|
||||
MEELE_WEAPON,
|
||||
} itemtype_t;
|
||||
|
||||
typedef struct Item {
|
||||
Texture2D sprite;
|
||||
Vector2 render_offset;
|
||||
|
||||
itemtype_t type;
|
||||
|
||||
void* item_data;
|
||||
void (*item_action)(player_t*, world_t*);
|
||||
} item_t;
|
||||
|
||||
void free_item(item_t* item);
|
||||
@@ -0,0 +1,9 @@
|
||||
typedef struct ItemDataMeele {
|
||||
int damage;
|
||||
|
||||
} itemdata_meele_t;
|
||||
|
||||
itemdata_meele_t* get_meele_data(void* data) {
|
||||
return (itemdata_meele_t*) data;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# pragma once
|
||||
|
||||
typedef struct Item item_t;
|
||||
|
||||
item_t* create_item_sword();
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# pragma once
|
||||
|
||||
#include <raylib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "../include/world.h"
|
||||
#include "../include/entity.h"
|
||||
#include "../include/item.h"
|
||||
|
||||
typedef enum State {
|
||||
// index == spritesheet row
|
||||
@@ -12,12 +14,20 @@ typedef enum State {
|
||||
} state_t;
|
||||
|
||||
typedef struct Player {
|
||||
item_t* current_item;
|
||||
|
||||
// visual
|
||||
float anim_speed;
|
||||
timeval_t last_damage;
|
||||
Texture2D no_arms_tex;
|
||||
|
||||
entity_t entity;
|
||||
} player_t;
|
||||
|
||||
void hurt_player(player_t* player, int damage);
|
||||
void equip_item(player_t* player, item_t* item);
|
||||
void unequip_item(player_t* player);
|
||||
|
||||
void init_player(player_t* player);
|
||||
void update_player(player_t* player, world_t* world);
|
||||
void render_player(player_t* player, world_t* world);
|
||||
|
||||
@@ -5,6 +5,8 @@ typedef enum Rendertype {
|
||||
} rendertype_t;
|
||||
|
||||
typedef struct Renderdata {
|
||||
// debug
|
||||
char name[21];
|
||||
// texture pro
|
||||
rendertype_t type;
|
||||
float ypos;
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ typedef struct Path {
|
||||
|
||||
bool finished;
|
||||
Vector2 current_dir;
|
||||
float current_speed;
|
||||
bool currently_moving;
|
||||
} path_t;
|
||||
|
||||
void init_world(world_t* world, char* collision_map);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "../include/world.h"
|
||||
|
||||
void pathfind_player(world_t* world, enemy_t* enemy, player_t* player);
|
||||
|
||||
void init_zombie_enemy(enemy_t* enemy);
|
||||
void update_animation_from_path(enemy_t* enemy, player_t* player);
|
||||
void update_animation_from_velocity(enemy_t* enemy, player_t* player);
|
||||
|
||||
void zombie_execute_state(world_t* world, enemy_t* enemy, player_t* player);
|
||||
void zombie_update_state(world_t* world, enemy_t* enemy, player_t* player);
|
||||
|
||||
+2
-5
@@ -4,7 +4,6 @@
|
||||
|
||||
# include "../include/anim.h"
|
||||
# include "../include/entity.h"
|
||||
# include "../include/config.h"
|
||||
# include "../include/renderer.h"
|
||||
# include "../include/world.h"
|
||||
|
||||
@@ -22,7 +21,6 @@ Rectangle get_animation_frame(entity_t* entity) {
|
||||
size,
|
||||
};
|
||||
|
||||
// printf("%f|%f player: \n", rect.x, rect.y);
|
||||
return rect;
|
||||
}
|
||||
|
||||
@@ -71,9 +69,8 @@ void render_entity(entity_t* entity, world_t* world) {
|
||||
|
||||
float bottom_ypos = get_entity_bottom(entity);
|
||||
|
||||
// DrawTexturePro(entity->anim.texture, source_rect, dest_rect, (Vector2) { 0.0, 0.0 }, 0, WHITE);
|
||||
//
|
||||
push_to_render_buffer((renderdata_t) {
|
||||
.name = "Entity",
|
||||
.type = TEXTURE_PRO,
|
||||
.ypos = bottom_ypos,
|
||||
.texture = entity->anim.texture,
|
||||
@@ -81,6 +78,6 @@ void render_entity(entity_t* entity, world_t* world) {
|
||||
.dest = dest_rect,
|
||||
.origin = (Vector2) { 0.0f, 0.0f },
|
||||
.rotation = 0.0f,
|
||||
.tint = WHITE
|
||||
.tint = entity->tint,
|
||||
});
|
||||
}
|
||||
|
||||
+4
-8
@@ -22,15 +22,11 @@ enemy_t create_enemy(enemy_type_t type) {
|
||||
}
|
||||
|
||||
void update_enemy(enemy_t* enemy, player_t* player, world_t* world) {
|
||||
assert(enemy->set_vel_func != NULL);
|
||||
assert(enemy->move_func != NULL);
|
||||
assert(enemy->update_anim_func != NULL);
|
||||
assert(enemy->execute_state != NULL);
|
||||
assert(enemy->update_state != NULL);
|
||||
|
||||
enemy->set_vel_func(world, enemy, player);
|
||||
enemy->move_func(enemy, player, world);
|
||||
enemy->update_anim_func(enemy, player);
|
||||
|
||||
entity_face_moving_dir(&(enemy->entity));
|
||||
enemy->execute_state(world, enemy, player);
|
||||
enemy->update_state(world, enemy, player);
|
||||
}
|
||||
|
||||
void update_enemies(enemy_t* enemies, int enemy_count, player_t* player, world_t* world) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "../include/entity.h"
|
||||
#include "../include/config.h"
|
||||
#include "../include/astar.h"
|
||||
#include "../include/player.h"
|
||||
|
||||
Rectangle** get_col_tiles_around_entity(entity_t* entity, tilemap_t* col_map) {
|
||||
const int ts = TILE_SIZE; // tile size
|
||||
@@ -80,6 +81,10 @@ float get_entity_bottom(entity_t* entity) {
|
||||
return get_entity_center(entity).y + 0.5*entity->sprite_size.y;
|
||||
}
|
||||
|
||||
void entity_face_player(entity_t* entity, player_t* player) {
|
||||
entity->anim.flipped = entity->position.x > player->entity.position.x;
|
||||
}
|
||||
|
||||
void set_entity_center(entity_t* entity, Vector2 center_pos) {
|
||||
Vector2 offset = entity->sprite_size;
|
||||
entity->position = Vector2Subtract(center_pos, offset);
|
||||
|
||||
+12
-2
@@ -10,7 +10,8 @@
|
||||
#include "../include/config.h"
|
||||
#include "../include/debug.h"
|
||||
#include "../include/enemy.h"
|
||||
#include "../include/zombie_enemy.h"
|
||||
#include "../include/item.h"
|
||||
#include "../include/item_sword.h"
|
||||
|
||||
int start_game() {
|
||||
player_t player;
|
||||
@@ -34,7 +35,7 @@ int start_game() {
|
||||
tilemap_t* tilemap_ground = load_tilemap("assets/levels/test_ground.csv");
|
||||
printf("\n[!] Loaded tilemaps successfully!\n\n");
|
||||
|
||||
spawn_enemy(ZOMBIE, &world, Vector2Zero());
|
||||
spawn_enemy(ZOMBIE, &world, (Vector2) { 200, 10 } );
|
||||
|
||||
while (!WindowShouldClose()) {
|
||||
// UPDATE
|
||||
@@ -43,6 +44,15 @@ int start_game() {
|
||||
update_enemies(world.enemies, world.enemy_counter, &player, &world);
|
||||
|
||||
read_debug_input();
|
||||
if (IsKeyPressed(KEY_E)) {
|
||||
if (!player.current_item) {
|
||||
equip_item(&player, create_item_sword());
|
||||
}
|
||||
else {
|
||||
unequip_item(&player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// RENDER
|
||||
start_render(&camera);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# include <stdlib.h>
|
||||
|
||||
# include "../include/item.h"
|
||||
|
||||
void free_item(item_t* item) {
|
||||
free(item->item_data);
|
||||
free(item);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
# include "../include/item_sword.h"
|
||||
# include "../include/item.h"
|
||||
# include "../include/item_meele.h"
|
||||
|
||||
|
||||
item_t* create_item_sword() {
|
||||
item_t* item_p = malloc(sizeof(item_t));
|
||||
assert(item_p);
|
||||
|
||||
item_p->item_data = (itemdata_meele_t*)malloc(sizeof(itemdata_meele_t));
|
||||
assert(item_p->item_data);
|
||||
|
||||
// item_p->icon = LoadTexture("");
|
||||
item_p->sprite = LoadTexture("assets/sprites/items/sword.png");
|
||||
item_p->render_offset = (Vector2) { 6, -6 };
|
||||
|
||||
item_p->type = MEELE_WEAPON;
|
||||
item_p->item_action = NULL;
|
||||
return item_p;
|
||||
}
|
||||
+3
-7
@@ -1,5 +1,4 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../include/world.h"
|
||||
@@ -15,10 +14,8 @@
|
||||
|
||||
int enemy_follow_path(enemy_t* enemy, player_t* player, world_t* world) {
|
||||
if (enemy->path.finished) {
|
||||
printf("closing in!\n");
|
||||
// target is reached
|
||||
Vector2 player_pos = get_entity_center(&player->entity);
|
||||
player_pos.y -= 3;
|
||||
Vector2 p_to_e = Vector2Subtract(get_entity_center(&enemy->entity), player_pos);
|
||||
Vector2 p_to_e_len_5 = Vector2Scale(Vector2Normalize(p_to_e), 5.0);
|
||||
|
||||
@@ -28,7 +25,7 @@ int enemy_follow_path(enemy_t* enemy, player_t* player, world_t* world) {
|
||||
float speed = 2.0;
|
||||
Vector2 step = Vector2Scale(dir_target, GetFrameTime() * speed);
|
||||
enemy->entity.position = Vector2Add(enemy->entity.position, step);
|
||||
enemy->path.current_speed = (int)(Vector2Length(step) * 100);
|
||||
enemy->path.currently_moving = Vector2Length(step) > 0.001;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -43,7 +40,7 @@ int enemy_follow_path(enemy_t* enemy, player_t* player, world_t* world) {
|
||||
Vector2 norm_dir = Vector2Normalize(dir);
|
||||
|
||||
enemy->path.current_dir = norm_dir;
|
||||
enemy->path.current_speed = dir_len;
|
||||
enemy->path.currently_moving = dir_len > 0.2;
|
||||
|
||||
// printf("Next node posi [%d|%d]\n", (int)dir.x, (int)dir.y);
|
||||
// printf("Next direction [%f|%f]\n", norm_dir.x, norm_dir.y);
|
||||
@@ -66,9 +63,8 @@ int enemy_follow_path(enemy_t* enemy, player_t* player, world_t* world) {
|
||||
enemy->path.finished = true;
|
||||
enemy->path.index++;
|
||||
enemy->path.current_dir = Vector2Zero();
|
||||
enemy->path.current_speed = 0;
|
||||
enemy->path.currently_moving = false;
|
||||
// GOAL REACHED
|
||||
printf("just reached the goal\n");
|
||||
return 0;
|
||||
}
|
||||
enemy->path.index++;
|
||||
|
||||
+107
-3
@@ -1,4 +1,5 @@
|
||||
#include <raylib.h>
|
||||
#include <assert.h>
|
||||
#include <raymath.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -9,10 +10,16 @@
|
||||
#include "../include/entity.h"
|
||||
#include "../include/anim.h"
|
||||
#include "../include/movement.h"
|
||||
#include "../include/renderer.h"
|
||||
|
||||
void init_player(player_t* player) {
|
||||
|
||||
player->current_item = NULL;
|
||||
player->no_arms_tex = LoadTexture("assets/sprites/player_no_hand.png");
|
||||
assert(IsTextureValid(player->no_arms_tex));
|
||||
|
||||
|
||||
// visual
|
||||
|
||||
animator_t animt = {
|
||||
.texture = LoadTexture("assets/sprites/player.png"),
|
||||
.anim_speed = 0.008f,
|
||||
@@ -21,13 +28,20 @@ void init_player(player_t* player) {
|
||||
.frame_count = 4,
|
||||
};
|
||||
if (!IsTextureValid(animt.texture)) { printf("WARINING: Player texture loading failed\n"); exit(1); }
|
||||
|
||||
|
||||
gettimeofday(&player->last_damage, NULL);
|
||||
player->last_damage.tv_usec = 0;
|
||||
player->last_damage.tv_sec = 0;
|
||||
|
||||
player->entity = (entity_t){
|
||||
.health = 20,
|
||||
|
||||
.anim = animt,
|
||||
.bb_size = 16,
|
||||
.sprite_size = (Vector2) { 8, 8 }, // Bug, collision only works with some values
|
||||
.sprite_offset = (Vector2) { -1, -5 }, // X axis relative to player movement direction
|
||||
|
||||
.action_timer = 0,
|
||||
// Physics
|
||||
.position = Vector2Zero(),
|
||||
.velocity = Vector2Zero(),
|
||||
@@ -39,6 +53,18 @@ void init_player(player_t* player) {
|
||||
};
|
||||
}
|
||||
|
||||
void hurt_player(player_t* player, int damage) {
|
||||
player->entity.health -= damage;
|
||||
gettimeofday(&player->last_damage, NULL);
|
||||
|
||||
printf("Player took damage, Health: %d\n", player->entity.health);
|
||||
|
||||
if (player->entity.health <= 0) {
|
||||
printf("We died :(\n");
|
||||
player->entity.health = 10;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle get_player_sprite(player_t* player, unsigned long total_ms) {
|
||||
|
||||
int frame = (int)(total_ms*player->entity.anim.anim_speed) % 4;
|
||||
@@ -80,6 +106,46 @@ void player_update_velocity_by_input(player_t* player) {
|
||||
ply_ent->velocity.y = ply_ent->velocity.y < -ply_ent->speed_cap ? -ply_ent->speed_cap : ply_ent->velocity.y;
|
||||
}
|
||||
|
||||
void equip_item(player_t* player, item_t* item) {
|
||||
player->current_item = item;
|
||||
}
|
||||
|
||||
void unequip_item(player_t* player) {
|
||||
UnloadTexture(player->current_item->sprite);
|
||||
free_item(player->current_item);
|
||||
player->current_item = NULL;
|
||||
}
|
||||
|
||||
void render_player_item(player_t* player) {
|
||||
item_t* item = player->current_item;
|
||||
|
||||
int what_the_flip = player->entity.anim.flipped ? -1 : 1;
|
||||
Vector2 item_size = { item->sprite.width, item->sprite.height };
|
||||
|
||||
Vector2 flip_rend_offs = item->render_offset;
|
||||
flip_rend_offs.x *= what_the_flip;
|
||||
|
||||
Rectangle src = { 0, 0, item_size.x * what_the_flip, item_size.y };
|
||||
Rectangle dest = {
|
||||
player->entity.position.x + flip_rend_offs.x,
|
||||
player->entity.position.y + flip_rend_offs.y,
|
||||
item_size.x, item_size.y
|
||||
};
|
||||
|
||||
float player_ypos = get_entity_bottom(&player->entity);
|
||||
push_to_render_buffer((renderdata_t) {
|
||||
.name = "sword",
|
||||
.type = TEXTURE_PRO,
|
||||
.ypos = player_ypos - 0.001,
|
||||
.texture = item->sprite,
|
||||
.src = src,
|
||||
.dest = dest,
|
||||
.origin = (Vector2) { 0.0f, 0.0f },
|
||||
.rotation = 0.0f,
|
||||
.tint = WHITE,
|
||||
});
|
||||
}
|
||||
|
||||
void player_update_state(player_t* player) {
|
||||
if (Vector2Length(player->entity.velocity) > 10.0) {
|
||||
play_animation(&(player->entity.anim), (int)RUNNING);
|
||||
@@ -102,6 +168,44 @@ void update_player(player_t* player, world_t* world) {
|
||||
}
|
||||
|
||||
void render_player(player_t* player, world_t* world) {
|
||||
render_entity(&player->entity, world);
|
||||
Color tint = get_time_since_ms(player->last_damage) < 300 ? RED : WHITE;
|
||||
player->entity.tint = tint;
|
||||
|
||||
if (player->current_item) {
|
||||
// RENDER ITEM
|
||||
render_player_item(player);
|
||||
}
|
||||
|
||||
// Render player
|
||||
|
||||
entity_t* entity = &player->entity;
|
||||
Vector2 offset = {
|
||||
.x = entity->sprite_offset.x * (entity->anim.flipped?-1:1),
|
||||
.y = entity->sprite_offset.y,
|
||||
};
|
||||
|
||||
Rectangle dest_rect = {
|
||||
entity->position.x + offset.x,
|
||||
entity->position.y + offset.y,
|
||||
entity->bb_size,
|
||||
entity->bb_size,
|
||||
};
|
||||
|
||||
Rectangle source_rect = get_animation_frame(entity);
|
||||
|
||||
float bottom_ypos = get_entity_bottom(entity);
|
||||
|
||||
push_to_render_buffer((renderdata_t) {
|
||||
.name = "player",
|
||||
.type = TEXTURE_PRO,
|
||||
.ypos = bottom_ypos,
|
||||
.texture = player->current_item ? player->no_arms_tex : entity->anim.texture,
|
||||
.src = source_rect,
|
||||
.dest = dest_rect,
|
||||
.origin = (Vector2) { 0.0f, 0.0f },
|
||||
.rotation = 0.0f,
|
||||
.tint = entity->tint,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -66,12 +66,22 @@ void sort_render_buffer() {
|
||||
qsort(r->buffer, r->buffer_counter, sizeof(renderdata_t), compare_objects);
|
||||
}
|
||||
|
||||
void print_render_buffer_names() {
|
||||
renderer_t* r = get_renderer_ptr();
|
||||
for (int i = 0; i < r->buffer_counter; i++) {
|
||||
printf("[%s] ", r->buffer[i].name);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void ysort_and_render_to_screen() {
|
||||
renderer_t* r = get_renderer_ptr();
|
||||
|
||||
sort_render_buffer();
|
||||
|
||||
for (int i = 0; i < r->buffer_capacity; i++) {
|
||||
// print_render_buffer_names();
|
||||
|
||||
for (int i = 0; i < r->buffer_counter; i++) {
|
||||
// render
|
||||
int type = r->buffer[i].type;
|
||||
renderdata_t* data = &r->buffer[i];
|
||||
|
||||
+2
-2
@@ -107,7 +107,7 @@ path_t world_get_path(world_t* world, Vector2 start, Vector2 target, int max_sea
|
||||
.index = -1,
|
||||
.finished = true,
|
||||
.current_dir = (Vector2) { -1, -1 },
|
||||
.current_speed = -1,
|
||||
.currently_moving = false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -129,7 +129,7 @@ path_t world_get_path(world_t* world, Vector2 start, Vector2 target, int max_sea
|
||||
.index = 1, // skip start node, we should already be there
|
||||
.finished = false,
|
||||
.current_dir = (Vector2) { 0.0f, 0.0f },
|
||||
.current_speed = 0,
|
||||
.currently_moving = false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+78
-49
@@ -30,7 +30,7 @@ void init_zombie_enemy(enemy_t* enemy) {
|
||||
assert(IsTextureValid(anim.texture));
|
||||
|
||||
// path
|
||||
enemy->vision_radius = 30,
|
||||
enemy->vision_radius = 100,
|
||||
enemy->path = (path_t) {
|
||||
.len = -1,
|
||||
.nodes = NULL,
|
||||
@@ -39,12 +39,16 @@ void init_zombie_enemy(enemy_t* enemy) {
|
||||
|
||||
.finished=false,
|
||||
.current_dir = Vector2Zero(),
|
||||
.current_speed = 0,
|
||||
.currently_moving = 0,
|
||||
};
|
||||
|
||||
// entity
|
||||
enemy->entity = (entity_t) {
|
||||
.health = 20,
|
||||
|
||||
.anim = anim,
|
||||
.action_timer = 0,
|
||||
.tint = WHITE,
|
||||
|
||||
.bb_size = 16,
|
||||
.sprite_size = (Vector2) { 8.0f, 8.0f },
|
||||
@@ -59,9 +63,8 @@ void init_zombie_enemy(enemy_t* enemy) {
|
||||
};
|
||||
|
||||
// unique functions
|
||||
enemy->set_vel_func = &pathfind_player;
|
||||
enemy->move_func = &enemy_follow_path;
|
||||
enemy->update_anim_func = &update_animation_from_path;
|
||||
enemy->execute_state = &zombie_execute_state;
|
||||
enemy->update_state = &zombie_update_state;
|
||||
}
|
||||
|
||||
void new_path(world_t* world, enemy_t* enemy, player_t* player) {
|
||||
@@ -72,37 +75,9 @@ void new_path(world_t* world, enemy_t* enemy, player_t* player) {
|
||||
if (enemy->path.len == 0) {
|
||||
enemy->path.finished = true;
|
||||
}
|
||||
|
||||
// DEBUG:
|
||||
// printf("PATH: ");
|
||||
// for (int i = 0; i < enemy->path.len; i++) {
|
||||
// printf("[%d, %d] ", (int)enemy->path.nodes[i].x, (int)enemy->path.nodes[i].y);
|
||||
// }
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
void zombie_state_machine(world_t* world, enemy_t* enemy, player_t* player) {
|
||||
switch (enemy->entity.anim.state) {
|
||||
case ZOMBIE_ENEMY_IDLE:
|
||||
break;
|
||||
case ZOMBIE_ENEMY_MOVE:
|
||||
// check if a new path is needed (player moved, no path exists yet, )
|
||||
pathfind_player(world, enemy, player);
|
||||
// move to player, first by path then directly
|
||||
enemy_follow_path(enemy, player, world);
|
||||
break;
|
||||
case ZOMBIE_ENEMY_ATTACK:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void pathfind_player(world_t* world, enemy_t* enemy, player_t* player) {
|
||||
int dist = Vector2Length(Vector2Subtract(player->entity.position, enemy->entity.position));
|
||||
|
||||
if (dist < 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enemy->path.nodes) {
|
||||
float target_pos_change = Vector2Length(Vector2Subtract(get_entity_center(&player->entity), tilemap_to_world_coord(enemy->path.target_pos)));
|
||||
if (target_pos_change > MAX_TARGET_POS_CHANGE) {
|
||||
@@ -117,22 +92,76 @@ void pathfind_player(world_t* world, enemy_t* enemy, player_t* player) {
|
||||
}
|
||||
}
|
||||
|
||||
void update_animation_from_path(enemy_t* enemy, player_t* player) {
|
||||
// printf("FINISHED: %d, LEN: %d\n", enemy->path.finished, enemy->path.len);
|
||||
void reset_action_timer(enemy_t* enemy) {
|
||||
gettimeofday(&enemy->entity.action_timer, NULL);
|
||||
}
|
||||
|
||||
if (enemy->path.current_dir.x != 0) {
|
||||
// look in direction of path if there is horizontal movement
|
||||
enemy->entity.anim.flipped = enemy->path.current_dir.x < 0;
|
||||
}
|
||||
else {
|
||||
// when walking only vertiacally look at player
|
||||
enemy->entity.anim.flipped = player->entity.position.x < enemy->entity.position.x;
|
||||
}
|
||||
|
||||
if (enemy->path.current_speed > 0) {
|
||||
play_animation(&enemy->entity.anim, ZOMBIE_ENEMY_MOVE);
|
||||
}
|
||||
else {
|
||||
play_animation(&enemy->entity.anim, ZOMBIE_ENEMY_ATTACK);
|
||||
void zombie_tick_attack(enemy_t* enemy, player_t* player) {
|
||||
int attack_frequency = 500;
|
||||
long int time_since = get_time_since_ms(enemy->entity.action_timer);
|
||||
if (time_since >= attack_frequency) {
|
||||
gettimeofday(&enemy->entity.action_timer, NULL);
|
||||
hurt_player(player, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void zombie_execute_state(world_t* world, enemy_t* enemy, player_t* player) {
|
||||
// printf("path finished: %d\n", (int)enemy->path.finished);
|
||||
switch (enemy->entity.anim.state) {
|
||||
case ZOMBIE_ENEMY_IDLE:
|
||||
break;
|
||||
case ZOMBIE_ENEMY_MOVE:
|
||||
// check if a new path is needed (player moved, no path exists yet, )
|
||||
pathfind_player(world, enemy, player);
|
||||
// move to player, first by path then directly
|
||||
enemy_follow_path(enemy, player, world);
|
||||
break;
|
||||
case ZOMBIE_ENEMY_ATTACK:
|
||||
zombie_tick_attack(enemy, player);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void zombie_update_state(world_t* world, enemy_t* enemy, player_t* player) {
|
||||
float dist_player = Vector2Length(Vector2Subtract(player->entity.position, enemy->entity.position));
|
||||
|
||||
switch (enemy->entity.anim.state) {
|
||||
case ZOMBIE_ENEMY_IDLE:
|
||||
entity_face_player(&enemy->entity, player);
|
||||
|
||||
if (dist_player < enemy->vision_radius) {
|
||||
play_animation(&enemy->entity.anim, ZOMBIE_ENEMY_MOVE);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case ZOMBIE_ENEMY_MOVE:
|
||||
// --- FACE PATH OR PLAYER
|
||||
if (enemy->path.current_dir.x != 0) {
|
||||
// look in direction of path if there is horizontal movement
|
||||
enemy->entity.anim.flipped = enemy->path.current_dir.x < 0;
|
||||
}
|
||||
else {
|
||||
// when walking only vertiacally look at player
|
||||
enemy->entity.anim.flipped = player->entity.position.x < enemy->entity.position.x;
|
||||
}
|
||||
|
||||
// SWITCH STATE
|
||||
|
||||
if (!enemy->path.currently_moving) {
|
||||
play_animation(&enemy->entity.anim, ZOMBIE_ENEMY_ATTACK);
|
||||
reset_action_timer(enemy);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case ZOMBIE_ENEMY_ATTACK:
|
||||
entity_face_player(&enemy->entity, player);
|
||||
// if distance to player too big switch to movement
|
||||
if (dist_player > 10) {
|
||||
play_animation(&enemy->entity.anim, ZOMBIE_ENEMY_MOVE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user