Compare commits
No commits in common. "011e960cfc034588a9d36634bf702888e96cac11" and "067a3ec2c99eb5b0f4c326a22a2c09b14fcbfa89" have entirely different histories.
011e960cfc
...
067a3ec2c9
8
.ccls
8
.ccls
|
|
@ -1,9 +1,9 @@
|
||||||
gcc
|
gcc
|
||||||
# Headers
|
# Headers
|
||||||
-Isrc/components/headers
|
-Isrc/headers
|
||||||
|
-Isrc/ecs/headers
|
||||||
|
-Isrc/ecs/components/headers
|
||||||
-ISDL2_Core/src/headers
|
-ISDL2_Core/src/headers
|
||||||
#-INCurses_Core/src/headers
|
#-INCurses_Core/src/headers
|
||||||
-Iassets/asset_builder/src/headers
|
-Iassets/asset_builder/src/headers
|
||||||
# Macros
|
-DASSET_FILE_NAME="$(make print-ASSET_OUTPUT)"
|
||||||
-DASSET_FILE_NAME="$(make print-ASSET_OUTPUT)"
|
|
||||||
-DDEBUG=1
|
|
||||||
6
Makefile
6
Makefile
|
|
@ -4,13 +4,13 @@ SHELL = /usr/bin/env bash
|
||||||
BUILD_DIR = build
|
BUILD_DIR = build
|
||||||
|
|
||||||
# Source output target name
|
# Source output target name
|
||||||
SOURCE_OUTPUT = $(BUILD_DIR)/2D_Engine
|
SOURCE_OUTPUT := $(BUILD_DIR)/2D_Engine
|
||||||
|
|
||||||
# Core output target name
|
# Core output target name
|
||||||
CORE_OUTPUT = $(BUILD_DIR)/libcore.a
|
CORE_OUTPUT := $(BUILD_DIR)/libcore.a
|
||||||
|
|
||||||
# Assets output
|
# Assets output
|
||||||
ASSET_OUTPUT = $(BUILD_DIR)/game.data
|
ASSET_OUTPUT := $(BUILD_DIR)/game.data
|
||||||
|
|
||||||
# Verbosity
|
# Verbosity
|
||||||
Q := @
|
Q := @
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 911bdd7999a5c8af912ea3d23ba86140541fd064
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2e1eaf4c1c512761c7585267175bed420154172d
|
Subproject commit d193aa5fd49666be31f2b97e6dcc9a0788d58d7d
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int exit_status = EXIT_FAILURE;
|
int exit_status = EXIT_SUCCESS;
|
||||||
|
|
||||||
FILE *output_asset_file = NULL;
|
FILE *output_asset_file = NULL;
|
||||||
|
|
||||||
|
|
@ -14,6 +14,7 @@ int main(int argc, char *argv[])
|
||||||
if(argc < 3)
|
if(argc < 3)
|
||||||
{
|
{
|
||||||
puts("\033[33musage\033[m: asset_builder output_file input_file [input_file_2 ...]");
|
puts("\033[33musage\033[m: asset_builder output_file input_file [input_file_2 ...]");
|
||||||
|
exit_status = EXIT_FAILURE;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,6 +26,7 @@ int main(int argc, char *argv[])
|
||||||
if(!asset_file_header.assets_header_def)
|
if(!asset_file_header.assets_header_def)
|
||||||
{
|
{
|
||||||
print_error("memory allocation failed.");
|
print_error("memory allocation failed.");
|
||||||
|
exit_status = EXIT_FAILURE;
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -55,6 +57,7 @@ int main(int argc, char *argv[])
|
||||||
if(!output_asset_file)
|
if(!output_asset_file)
|
||||||
{
|
{
|
||||||
print_error("could not create output file.");
|
print_error("could not create output file.");
|
||||||
|
exit_status = EXIT_FAILURE;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,6 +68,8 @@ int main(int argc, char *argv[])
|
||||||
if(ret)
|
if(ret)
|
||||||
{
|
{
|
||||||
print_error_description(ret);
|
print_error_description(ret);
|
||||||
|
|
||||||
|
exit_status = EXIT_FAILURE;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,6 +82,7 @@ int main(int argc, char *argv[])
|
||||||
if(write_header_to_file(&asset_file_header, output_asset_file))
|
if(write_header_to_file(&asset_file_header, output_asset_file))
|
||||||
{
|
{
|
||||||
print_error("can't write to output file.");
|
print_error("can't write to output file.");
|
||||||
|
exit_status = EXIT_FAILURE;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,12 +93,12 @@ int main(int argc, char *argv[])
|
||||||
if(ret)
|
if(ret)
|
||||||
{
|
{
|
||||||
print_error_description(ret);
|
print_error_description(ret);
|
||||||
|
|
||||||
|
exit_status = EXIT_FAILURE;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit_status = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if(asset_file_header.assets_header_def)
|
if(asset_file_header.assets_header_def)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
12
src/Makefile
12
src/Makefile
|
|
@ -1,10 +1,12 @@
|
||||||
# Source files
|
# Source files
|
||||||
SOURCES := \
|
SOURCES := \
|
||||||
|
main.c \
|
||||||
game.c \
|
game.c \
|
||||||
components/transform_component.c \
|
ecs/ecs.c \
|
||||||
components/sprite_component.c \
|
ecs/components/transform_component.c \
|
||||||
components/animation_system.c \
|
ecs/components/sprite_component.c \
|
||||||
components/player_system.c
|
ecs/components/animation_system.c \
|
||||||
|
ecs/components/player_system.c
|
||||||
|
|
||||||
# Compiler and flags
|
# Compiler and flags
|
||||||
SRC_CC = gcc
|
SRC_CC = gcc
|
||||||
|
|
@ -21,7 +23,7 @@ SRC_CFLAGS = --std=c17 --pedantic -O0 -g \
|
||||||
-Wold-style-definition # DEVELOPEMENT
|
-Wold-style-definition # DEVELOPEMENT
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SRC_INCLUDE_DIRS = $(SOURCE_DIR)/components/headers $(CORE_DIR)/headers
|
SRC_INCLUDE_DIRS = $(SOURCE_DIR)/headers $(SOURCE_DIR)/ecs/headers $(SOURCE_DIR)/ecs/components/headers $(CORE_DIR)/headers
|
||||||
SRC_INCLUDE_DIRS := $(addprefix -I, $(SRC_INCLUDE_DIRS))
|
SRC_INCLUDE_DIRS := $(addprefix -I, $(SRC_INCLUDE_DIRS))
|
||||||
|
|
||||||
SRC_LDFLAGS =
|
SRC_LDFLAGS =
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
#include "animation_system.h"
|
|
||||||
|
|
||||||
#include "game.h"
|
|
||||||
#include "memory_alloc.h"
|
#include "memory_alloc.h"
|
||||||
#include "errors.h"
|
#include "animation_system.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
// Args : size_t nb_frames, size_t actual_frame, float frame_delay_ms, bool play, bool loop, bool reverse
|
// Args : size_t nb_frames, size_t actual_frame, float frame_delay_ms, bool play, bool loop, bool reverse
|
||||||
void animation_system_init(component_t *component, va_list args)
|
void animation_system_init(component_t *component, va_list args)
|
||||||
|
|
@ -10,7 +8,6 @@ void animation_system_init(component_t *component, va_list args)
|
||||||
animation_system_data_t *system_data = component->component_data;
|
animation_system_data_t *system_data = component->component_data;
|
||||||
|
|
||||||
system_data->sprite_component_data = get_component(component->entity, SPRITE_COMPONENT)->component_data;
|
system_data->sprite_component_data = get_component(component->entity, SPRITE_COMPONENT)->component_data;
|
||||||
if(!system_data->sprite_component_data) return;
|
|
||||||
|
|
||||||
system_data->nb_frames = va_arg(args, size_t);
|
system_data->nb_frames = va_arg(args, size_t);
|
||||||
system_data->actual_frame_nb= va_arg(args, size_t);
|
system_data->actual_frame_nb= va_arg(args, size_t);
|
||||||
|
|
@ -109,10 +106,9 @@ void animation_system_create_frames_clips(animation_system_data_t *system_data)
|
||||||
|
|
||||||
inline void animation_system_change_animation(animation_system_data_t *system_data, const char *name, size_t nb_frames)
|
inline void animation_system_change_animation(animation_system_data_t *system_data, const char *name, size_t nb_frames)
|
||||||
{
|
{
|
||||||
system_data->sprite_component_data->texture = asset_manager_get_texture(&game.asset_manager, name);
|
sprite_component_set_texture(system_data->sprite_component_data, name);
|
||||||
|
system_data->sprite_component_data->src_rect = *(rect_t *)system_data->actual_frame->data;
|
||||||
|
|
||||||
system_data->nb_frames = nb_frames;
|
system_data->nb_frames = nb_frames;
|
||||||
animation_system_create_frames_clips(system_data);
|
animation_system_create_frames_clips(system_data);
|
||||||
|
|
||||||
system_data->sprite_component_data->src_rect = *(rect_t *)system_data->actual_frame->data;
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,12 +7,12 @@
|
||||||
typedef struct animation_system_data_t {
|
typedef struct animation_system_data_t {
|
||||||
sprite_component_data_t *sprite_component_data;
|
sprite_component_data_t *sprite_component_data;
|
||||||
|
|
||||||
size_t nb_frames;
|
|
||||||
linked_list_t frames;
|
|
||||||
|
|
||||||
elem_t *actual_frame;
|
elem_t *actual_frame;
|
||||||
size_t actual_frame_nb;
|
size_t actual_frame_nb;
|
||||||
|
|
||||||
|
size_t nb_frames;
|
||||||
|
linked_list_t frames;
|
||||||
|
|
||||||
float frame_delay_ms;
|
float frame_delay_ms;
|
||||||
float frame_timer_ms;
|
float frame_timer_ms;
|
||||||
|
|
||||||
|
|
@ -20,8 +20,10 @@ void sprite_component_init(component_t *, va_list);
|
||||||
|
|
||||||
void sprite_component_update(component_t *);
|
void sprite_component_update(component_t *);
|
||||||
|
|
||||||
int sprite_component_draw(component_t *);
|
void sprite_component_draw(component_t *);
|
||||||
|
|
||||||
void sprite_component_destroy(component_t *);
|
void sprite_component_destroy(component_t *);
|
||||||
|
|
||||||
|
void sprite_component_set_texture(sprite_component_data_t *, const char *);
|
||||||
|
|
||||||
#endif // SPRITE_COMPONENT_H
|
#endif // SPRITE_COMPONENT_H
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
#include "player_system.h"
|
|
||||||
|
|
||||||
#include "game.h"
|
|
||||||
#include "memory_alloc.h"
|
#include "memory_alloc.h"
|
||||||
|
#include "player_system.h"
|
||||||
#include "animation_system.h"
|
#include "animation_system.h"
|
||||||
#include "sprite_component.h"
|
#include "sprite_component.h"
|
||||||
#include "transform_component.h"
|
#include "transform_component.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
// No args
|
// No args
|
||||||
void player_system_init(component_t *component, va_list args __attribute__((unused)))
|
void player_system_init(component_t *component, va_list args __attribute__((unused)))
|
||||||
|
|
@ -16,6 +15,9 @@ void player_system_init(component_t *component, va_list args __attribute__((unus
|
||||||
system_data->transform_component_data = system_data->sprite_component_data->transform_component_data;
|
system_data->transform_component_data = system_data->sprite_component_data->transform_component_data;
|
||||||
|
|
||||||
system_data->state = PLAYER_IDLE;
|
system_data->state = PLAYER_IDLE;
|
||||||
|
|
||||||
|
asset_manager_load_asset(&game.asset_manager, "player_idle_sheet", ASSET_TEXTURE);
|
||||||
|
asset_manager_load_asset(&game.asset_manager, "player_walk_sheet", ASSET_TEXTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only for this file
|
// Only for this file
|
||||||
|
|
@ -85,5 +87,7 @@ void player_system_update(component_t *component)
|
||||||
|
|
||||||
void player_system_destroy(component_t *component)
|
void player_system_destroy(component_t *component)
|
||||||
{
|
{
|
||||||
|
asset_manager_let_go_asset(&game.asset_manager, "player_idle_sheet");
|
||||||
|
asset_manager_let_go_asset(&game.asset_manager, "player_walk_sheet");
|
||||||
free(component->component_data);
|
free(component->component_data);
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ void sprite_component_init(component_t *component, va_list args)
|
||||||
|
|
||||||
component_data->flip = false;
|
component_data->flip = false;
|
||||||
|
|
||||||
component_data->texture = asset_manager_get_texture(&game.asset_manager, va_arg(args, const char *));
|
sprite_component_set_texture(component_data, va_arg(args, const char *));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void sprite_component_update(component_t *component)
|
inline void sprite_component_update(component_t *component)
|
||||||
|
|
@ -24,15 +24,18 @@ inline void sprite_component_update(component_t *component)
|
||||||
frect_to_rect(&component_data->transform_component_data->bounds, &component_data->dst_rect);
|
frect_to_rect(&component_data->transform_component_data->bounds, &component_data->dst_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int sprite_component_draw(component_t *component)
|
inline void sprite_component_draw(component_t *component)
|
||||||
{
|
{
|
||||||
sprite_component_data_t *component_data = component->component_data;
|
sprite_component_data_t *component_data = component->component_data;
|
||||||
if(asset_manager_draw_texture(component_data->texture, &component_data->src_rect, &component_data->dst_rect, component_data->flip)) return EXIT_FAILURE;
|
asset_manager_draw_texture(component_data->texture, &component_data->src_rect, &component_data->dst_rect, component_data->flip);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void sprite_component_destroy(component_t *component)
|
inline void sprite_component_destroy(component_t *component)
|
||||||
{
|
{
|
||||||
free(component->component_data);
|
free(component->component_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void sprite_component_set_texture(sprite_component_data_t *component_data, const char *name)
|
||||||
|
{
|
||||||
|
component_data->texture = asset_manager_get_texture(&game.asset_manager, name);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "memory_alloc.h"
|
||||||
|
#include "ecs.h"
|
||||||
|
#include "components.h"
|
||||||
|
|
||||||
|
component_t *create_component(component_type_t component_type)
|
||||||
|
{
|
||||||
|
component_t *component = malloc(sizeof(component_t));
|
||||||
|
component->component_type = component_type;
|
||||||
|
|
||||||
|
switch(component_type)
|
||||||
|
{
|
||||||
|
#define COMPONENT(NAME, PREFIX, DRAW) \
|
||||||
|
case NAME: \
|
||||||
|
component->component_init = PREFIX##_init; \
|
||||||
|
component->component_update = PREFIX##_update; \
|
||||||
|
component->component_draw = DRAW(PREFIX); \
|
||||||
|
component->component_data = malloc(sizeof(PREFIX##_data_t)); \
|
||||||
|
if(!component->component_data){ free(component); return NULL; } \
|
||||||
|
component->component_deleter = PREFIX##_destroy; \
|
||||||
|
break;
|
||||||
|
#include "components.def"
|
||||||
|
|
||||||
|
default:
|
||||||
|
free(component);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void destroy_component(component_t *component)
|
||||||
|
{
|
||||||
|
component->component_deleter(component);
|
||||||
|
free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_t *create_entity(const unsigned int id)
|
||||||
|
{
|
||||||
|
entity_t *entity = malloc(sizeof(entity_t));
|
||||||
|
if(!entity) return NULL;
|
||||||
|
|
||||||
|
entity->id = id;
|
||||||
|
entity->draw_priority = 0;
|
||||||
|
|
||||||
|
linked_list_init(&entity->components, sizeof(component_t), (deleter_t)destroy_component);
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_component(entity_t *entity, component_t *component, ...)
|
||||||
|
{
|
||||||
|
if(!component) return;
|
||||||
|
|
||||||
|
component->entity = entity;
|
||||||
|
|
||||||
|
va_list args, args_copy;
|
||||||
|
|
||||||
|
va_start(args, component);
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
|
||||||
|
component->component_init(component, args_copy);
|
||||||
|
|
||||||
|
va_end(args_copy);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
linked_list_push_back(&entity->components, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only for this file
|
||||||
|
// Arg : component_type_t component_type
|
||||||
|
static inline bool condition_is_component_type(elem_t *elem, va_list args)
|
||||||
|
{
|
||||||
|
return ((component_t *)elem->data)->component_type == va_arg(args, component_type_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline component_t *get_component(entity_t *entity, component_type_t component_type)
|
||||||
|
{
|
||||||
|
return linked_list_get_if(&entity->components, condition_is_component_type, component_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only for this file
|
||||||
|
// No args
|
||||||
|
static inline void action_update_component(elem_t *elem, va_list args __attribute__((unused)))
|
||||||
|
{
|
||||||
|
component_t *component = elem->data;
|
||||||
|
component->component_update(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void update_entity(entity_t *entity)
|
||||||
|
{
|
||||||
|
linked_list_for_each(&entity->components, action_update_component);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only for this file
|
||||||
|
// No args
|
||||||
|
static inline void action_draw_component(elem_t *elem, va_list args __attribute__((unused)))
|
||||||
|
{
|
||||||
|
component_t *component = elem->data;
|
||||||
|
if(component->component_draw) component->component_draw(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void draw_entity(entity_t *entity)
|
||||||
|
{
|
||||||
|
linked_list_for_each(&entity->components, action_draw_component);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void destroy_entity(entity_t *entity)
|
||||||
|
{
|
||||||
|
linked_list_clear(&entity->components);
|
||||||
|
free(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void entity_manager_init(entity_manager_t *entity_manager)
|
||||||
|
{
|
||||||
|
linked_list_init(&entity_manager->entities, sizeof(entity_t), (deleter_t)destroy_entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void entity_manager_add_entity(entity_manager_t *entity_manager, entity_t *entity)
|
||||||
|
{
|
||||||
|
linked_list_push_back(&entity_manager->entities, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only for this file
|
||||||
|
// No args
|
||||||
|
static inline void action_update_entity(elem_t *elem, va_list args __attribute__((unused)))
|
||||||
|
{
|
||||||
|
update_entity((entity_t *)elem->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void entity_manager_update(entity_manager_t *entity_manager)
|
||||||
|
{
|
||||||
|
linked_list_for_each(&entity_manager->entities, action_update_entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only for this file
|
||||||
|
// No args
|
||||||
|
static inline void action_draw_entity(elem_t *elem, va_list args __attribute__((unused)))
|
||||||
|
{
|
||||||
|
draw_entity((entity_t *)elem->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void entity_manager_draw(entity_manager_t *entity_manager)
|
||||||
|
{
|
||||||
|
linked_list_for_each(&entity_manager->entities, action_draw_entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only for this file
|
||||||
|
// Arg : unsigned int id
|
||||||
|
static inline bool condition_is_entity_name(elem_t *elem, va_list args)
|
||||||
|
{
|
||||||
|
return ((entity_t *)elem->data)->id == va_arg(args, unsigned int);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void entity_manager_remove_entity(entity_manager_t *entity_manager, unsigned int id)
|
||||||
|
{
|
||||||
|
linked_list_remove_if(&entity_manager->entities, condition_is_entity_name, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void entity_manager_exit(entity_manager_t *entity_manager)
|
||||||
|
{
|
||||||
|
linked_list_clear(&entity_manager->entities);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
#ifndef ECS_H
|
||||||
|
#define ECS_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "linked_list.h"
|
||||||
|
|
||||||
|
typedef enum component_type_t {
|
||||||
|
#define COMPONENT(NAME, PREFIX, DRAW) NAME,
|
||||||
|
#include "components.def"
|
||||||
|
} component_type_t;
|
||||||
|
|
||||||
|
// Component forwarding
|
||||||
|
typedef struct component_t component_t;
|
||||||
|
|
||||||
|
// Component init function. It is called when component added to entity. This function is necessary.
|
||||||
|
typedef void (*component_init_t)(component_t *component, va_list args);
|
||||||
|
// Component update function. It is called in the main loop to update the component. This function is necessary.
|
||||||
|
typedef void (*component_update_t)(component_t *component);
|
||||||
|
// Component draw function. It is called in the main loop to draw the component on screen. This function is not necessary.
|
||||||
|
typedef void (*component_draw_t)(component_t *component);
|
||||||
|
// Component deleter function. It is called when the component is removed. It should free the data in the component data but not the component itself.
|
||||||
|
typedef void (*component_deleter_t)(component_t *component);
|
||||||
|
|
||||||
|
typedef struct component_t {
|
||||||
|
component_init_t component_init;
|
||||||
|
component_update_t component_update;
|
||||||
|
component_draw_t component_draw;
|
||||||
|
|
||||||
|
void *component_data;
|
||||||
|
|
||||||
|
component_deleter_t component_deleter;
|
||||||
|
|
||||||
|
struct entity_t *entity;
|
||||||
|
|
||||||
|
component_type_t component_type;
|
||||||
|
|
||||||
|
} component_t;
|
||||||
|
|
||||||
|
component_t *create_component(component_type_t component_type);
|
||||||
|
|
||||||
|
void destroy_component(component_t *component);
|
||||||
|
|
||||||
|
typedef struct entity_t {
|
||||||
|
unsigned int id;
|
||||||
|
size_t draw_priority;
|
||||||
|
linked_list_t components;
|
||||||
|
} entity_t;
|
||||||
|
|
||||||
|
entity_t *create_entity(const unsigned int id);
|
||||||
|
|
||||||
|
void add_component(entity_t *entity, component_t *component, ...);
|
||||||
|
|
||||||
|
component_t *get_component(entity_t *entity, component_type_t component_type);
|
||||||
|
|
||||||
|
void update_entity(entity_t *entity);
|
||||||
|
|
||||||
|
void draw_entity(entity_t *entity);
|
||||||
|
|
||||||
|
void destroy_entity(entity_t *entity);
|
||||||
|
|
||||||
|
typedef struct entity_manager_t {
|
||||||
|
linked_list_t entities;
|
||||||
|
} entity_manager_t;
|
||||||
|
|
||||||
|
void entity_manager_init(entity_manager_t *entity_manager);
|
||||||
|
|
||||||
|
void entity_manager_add_entity(entity_manager_t *entity_manager, entity_t *entity);
|
||||||
|
|
||||||
|
void entity_manager_update(entity_manager_t *entity_manager);
|
||||||
|
|
||||||
|
void entity_manager_draw(entity_manager_t *entity_manager);
|
||||||
|
|
||||||
|
void entity_manager_remove_entity(entity_manager_t *entity_manager, const unsigned int id);
|
||||||
|
|
||||||
|
void entity_manager_exit(entity_manager_t *entity_manager);
|
||||||
|
|
||||||
|
#endif // ECS_H
|
||||||
66
src/game.c
66
src/game.c
|
|
@ -1,20 +1,15 @@
|
||||||
#include "game.h"
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "display.h"
|
#include <event.h>
|
||||||
#include "asset_manager.h"
|
#include <display.h>
|
||||||
#include "ecs.h"
|
#include <asset_manager.h>
|
||||||
|
#include "game.h"
|
||||||
#include "components.h"
|
#include "components.h"
|
||||||
|
|
||||||
#include <SDL2/SDL_timer.h>
|
void game_init(void)
|
||||||
|
|
||||||
int game_init(void)
|
|
||||||
{
|
{
|
||||||
game.is_running = false;
|
display_init();
|
||||||
|
|
||||||
if(display_init()) return EXIT_FAILURE;
|
asset_manager_init(&game.asset_manager);
|
||||||
|
|
||||||
if(asset_manager_init(&game.asset_manager)) return EXIT_FAILURE;
|
|
||||||
entity_manager_init(&game.entity_manager);
|
entity_manager_init(&game.entity_manager);
|
||||||
|
|
||||||
entity_t *player = create_entity(0);
|
entity_t *player = create_entity(0);
|
||||||
|
|
@ -23,24 +18,12 @@ int game_init(void)
|
||||||
|
|
||||||
frect_t player_bounds = {10.0f, 10.0f, 32.0f, 32.0f};
|
frect_t player_bounds = {10.0f, 10.0f, 32.0f, 32.0f};
|
||||||
|
|
||||||
if(asset_manager_load_asset(&game.asset_manager, "player_idle_sheet", ASSET_TEXTURE)) return EXIT_FAILURE;
|
add_component(player, create_component(TRANSFORM_COMPONENT), player_bounds, PLAYER_DEFAULT_SPEED);
|
||||||
if(asset_manager_load_asset(&game.asset_manager, "player_walk_sheet", ASSET_TEXTURE)) return EXIT_FAILURE;
|
add_component(player, create_component(SPRITE_COMPONENT), "player_idle_sheet");
|
||||||
|
add_component(player, create_component(ANIMATION_SYSTEM), 4, 0, PLAYER_DEFAULT_IDLE_ANIMATION_SPEED, true, true, false);
|
||||||
component_t *component = create_component(TRANSFORM_COMPONENT); if(!component) return EXIT_FAILURE;
|
add_component(player, create_component(PLAYER_SYSTEM));
|
||||||
add_component(player, component, player_bounds, PLAYER_DEFAULT_SPEED);
|
|
||||||
|
|
||||||
component = create_component(SPRITE_COMPONENT); if(!component) return EXIT_FAILURE;
|
|
||||||
add_component(player, component, "player_idle_sheet");
|
|
||||||
|
|
||||||
component = create_component(ANIMATION_SYSTEM); if(!component) return EXIT_FAILURE;
|
|
||||||
add_component(player, component, 4, 0, PLAYER_DEFAULT_IDLE_ANIMATION_SPEED, true, true, false);
|
|
||||||
|
|
||||||
component = create_component(PLAYER_SYSTEM); if(!component) return EXIT_FAILURE;
|
|
||||||
add_component(player, component);
|
|
||||||
|
|
||||||
game.is_running = true;
|
game.is_running = true;
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_handle_event(void)
|
void game_handle_event(void)
|
||||||
|
|
@ -74,36 +57,19 @@ void game_update(void)
|
||||||
entity_manager_update(&game.entity_manager);
|
entity_manager_update(&game.entity_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
int game_render(void)
|
void game_render(void)
|
||||||
{
|
{
|
||||||
if(display_clear())
|
display_clear();
|
||||||
{
|
|
||||||
game.is_running = false;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(entity_manager_draw(&game.entity_manager))
|
|
||||||
{
|
|
||||||
game.is_running = false;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
entity_manager_draw(&game.entity_manager);
|
||||||
|
|
||||||
display_update();
|
display_update();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int game_exit(void)
|
void game_exit(void)
|
||||||
{
|
{
|
||||||
entity_manager_exit(&game.entity_manager);
|
entity_manager_exit(&game.entity_manager);
|
||||||
|
asset_manager_exit(&game.asset_manager);
|
||||||
if(asset_manager_let_go_asset(&game.asset_manager, "player_idle_sheet")) return EXIT_FAILURE;
|
|
||||||
if(asset_manager_let_go_asset(&game.asset_manager, "player_walk_sheet")) return EXIT_FAILURE;
|
|
||||||
|
|
||||||
if(asset_manager_exit(&game.asset_manager)) return EXIT_FAILURE;
|
|
||||||
|
|
||||||
display_exit();
|
display_exit();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef EVENTS_H
|
||||||
|
#define EVENTS_H
|
||||||
|
|
||||||
|
#include <keycodes.h>
|
||||||
|
#include <vector2d.h>
|
||||||
|
|
||||||
|
typedef struct events_t {
|
||||||
|
vector2d_t cursor_pos;
|
||||||
|
bool keys[MAX_KEYCODES];
|
||||||
|
} events_t;
|
||||||
|
|
||||||
|
#endif // EVENTS_H
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef GAME_H
|
||||||
|
#define GAME_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "events.h"
|
||||||
|
#include "asset_manager.h"
|
||||||
|
#include "ecs.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Game data.
|
||||||
|
* There should be only one instance of this struct.
|
||||||
|
*
|
||||||
|
* @param event Events data
|
||||||
|
* @param texture_manager Texture manager instance
|
||||||
|
* @param entity_manager Entity manager instance
|
||||||
|
* @param is_running Game running state
|
||||||
|
* @param delta_time_ms Frame time
|
||||||
|
*/
|
||||||
|
typedef struct game_t {
|
||||||
|
asset_manager_t asset_manager;
|
||||||
|
entity_manager_t entity_manager;
|
||||||
|
events_t events;
|
||||||
|
|
||||||
|
float delta_time_ms;
|
||||||
|
bool is_running;
|
||||||
|
} game_t;
|
||||||
|
|
||||||
|
// Global game instance
|
||||||
|
extern game_t game;
|
||||||
|
|
||||||
|
// Initialise game
|
||||||
|
void game_init(void);
|
||||||
|
|
||||||
|
// Handle event like inputs
|
||||||
|
void game_handle_event(void);
|
||||||
|
|
||||||
|
// Update game
|
||||||
|
void game_update(void);
|
||||||
|
|
||||||
|
// Render game
|
||||||
|
void game_render(void);
|
||||||
|
|
||||||
|
// Free game instance
|
||||||
|
void game_exit(void);
|
||||||
|
|
||||||
|
#endif // GAME_H
|
||||||
|
|
@ -0,0 +1,281 @@
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
//#define TEXTURE_TEST
|
||||||
|
//#define LINKED_LIST_TEST
|
||||||
|
|
||||||
|
game_t game;
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
game_init();
|
||||||
|
|
||||||
|
while(game.is_running)
|
||||||
|
{
|
||||||
|
game_handle_event();
|
||||||
|
game_update();
|
||||||
|
game_render();
|
||||||
|
}
|
||||||
|
|
||||||
|
game_exit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Texture Unit Tests
|
||||||
|
#ifdef TEXTURE_TEST
|
||||||
|
|
||||||
|
#include "texture_manager.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
display_clear(C_BLACK);
|
||||||
|
|
||||||
|
texture_manager_t texture_manager;
|
||||||
|
texture_manager_init(&texture_manager);
|
||||||
|
texture_manager_load_builtin_textures(&texture_manager);
|
||||||
|
|
||||||
|
texture_t *texture = texture_manager_get_texture(&texture_manager, "player_run_sheet");
|
||||||
|
|
||||||
|
rect_t srcR = {0,0,32,32};
|
||||||
|
rect_t dstR = srcR;
|
||||||
|
|
||||||
|
draw_texture(texture, &src, &dst);
|
||||||
|
|
||||||
|
src.x = 33;
|
||||||
|
dst.x = 33;
|
||||||
|
|
||||||
|
draw_texture(texture, &src, &dst);
|
||||||
|
|
||||||
|
texture_manager_remove_texture(&texture_manager, "player_run_sheet");
|
||||||
|
|
||||||
|
src.w = 128;
|
||||||
|
dst.x = 0;
|
||||||
|
dst.y = 33;
|
||||||
|
|
||||||
|
texture_manager_draw_texture(&texture_manager, "player_idle_sheet", &src, &dst);
|
||||||
|
|
||||||
|
texture_manager_clear(&texture_manager);
|
||||||
|
|
||||||
|
display_update();
|
||||||
|
getkey();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TEXTURE_TEST
|
||||||
|
|
||||||
|
// Linked List Unit Tests
|
||||||
|
#ifdef LINKED_LIST_TEST
|
||||||
|
|
||||||
|
#include "linked_list.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
display_clear(C_BLACK);
|
||||||
|
|
||||||
|
linked_list_t linked_list;
|
||||||
|
linked_list_init(&linked_list, sizeof(int), NULL);
|
||||||
|
if(linked_list.first == linked_list.last &&
|
||||||
|
linked_list.first == NULL)
|
||||||
|
{
|
||||||
|
dtext(1, 0, C_BLACK, "linked_list is initialised correctly");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
elem_t *elem1 = NULL;
|
||||||
|
elem_t *elem2 = NULL;
|
||||||
|
elem_t *elem3 = NULL;
|
||||||
|
elem_t *elem4 = NULL;
|
||||||
|
|
||||||
|
elem1 = elem_create(&linked_list);
|
||||||
|
if(elem1 && elem1->data)
|
||||||
|
{
|
||||||
|
dtext(1, 10, C_BLACK, "elem1 is initalised correctly");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list_push_back_elem(&linked_list, elem1);
|
||||||
|
if(linked_list.first == linked_list.last &&
|
||||||
|
linked_list.first == elem1 &&
|
||||||
|
!linked_list.first->prev &&
|
||||||
|
!linked_list.first->next &&
|
||||||
|
!linked_list.last->prev &&
|
||||||
|
!linked_list.last->next)
|
||||||
|
{
|
||||||
|
dtext(1, 20, C_BLACK, "elem1 is correctly pushed back");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list_pop_back(&linked_list);
|
||||||
|
if(linked_list.first == linked_list.last &&
|
||||||
|
linked_list.first == NULL)
|
||||||
|
{
|
||||||
|
dtext(1, 30, C_BLACK, "elem1 is correctly poped back");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
elem1 = elem_create(&linked_list);
|
||||||
|
elem2 = elem_create(&linked_list);
|
||||||
|
elem3 = elem_create(&linked_list);
|
||||||
|
elem4 = elem_create(&linked_list);
|
||||||
|
|
||||||
|
linked_list_push_back_elem(&linked_list, elem1);
|
||||||
|
linked_list_push_back_elem(&linked_list, elem2);
|
||||||
|
if(linked_list.first == elem1 &&
|
||||||
|
linked_list.last == elem2 &&
|
||||||
|
!linked_list.first->prev &&
|
||||||
|
linked_list.first->next &&
|
||||||
|
linked_list.last->prev &&
|
||||||
|
!linked_list.last->next &&
|
||||||
|
linked_list.first->next == elem2 &&
|
||||||
|
linked_list.last->prev == elem1)
|
||||||
|
{
|
||||||
|
dtext(1, 40, C_BLACK, "elem1 and elem2 are correctly pushed back");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list_push_front_elem(&linked_list, elem3);
|
||||||
|
linked_list_push_front_elem(&linked_list, elem4);
|
||||||
|
if(!linked_list.first->prev &&
|
||||||
|
!linked_list.last->next &&
|
||||||
|
linked_list.first == elem4 &&
|
||||||
|
linked_list.first->next == elem3 &&
|
||||||
|
linked_list.first->next->next == elem1 &&
|
||||||
|
linked_list.first->next->next->next == elem2 &&
|
||||||
|
linked_list.last == elem2 &&
|
||||||
|
linked_list.last->prev == elem1 &&
|
||||||
|
linked_list.last->prev->prev == elem3 &&
|
||||||
|
linked_list.last->prev->prev->prev == elem4)
|
||||||
|
{
|
||||||
|
dtext(1, 50, C_BLACK, "elem3 and elem4 are correctly pushed front");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(linked_list_get_elem(&linked_list, 2) == elem1)
|
||||||
|
{
|
||||||
|
dtext(1, 60, C_BLACK, "elem4 is got correctly");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list_pop_back(&linked_list);
|
||||||
|
if(!linked_list.first->prev &&
|
||||||
|
!linked_list.last->next &&
|
||||||
|
linked_list.first == elem4 &&
|
||||||
|
linked_list.first->next == elem3 &&
|
||||||
|
linked_list.first->next->next == elem1 &&
|
||||||
|
linked_list.last == elem1 &&
|
||||||
|
linked_list.last->prev == elem3 &&
|
||||||
|
linked_list.last->prev->prev == elem4)
|
||||||
|
{
|
||||||
|
dtext(1, 70, C_BLACK, "elem2 is correctly poped back");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list_remove(&linked_list, 1);
|
||||||
|
if(!linked_list.first->prev &&
|
||||||
|
!linked_list.last->next &&
|
||||||
|
linked_list.first == elem4 &&
|
||||||
|
linked_list.first->next == elem1 &&
|
||||||
|
linked_list.last == elem1 &&
|
||||||
|
linked_list.last->prev == elem4)
|
||||||
|
{
|
||||||
|
dtext(1, 80, C_BLACK, "elem3 is correctly removed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list_clear(&linked_list);
|
||||||
|
if(linked_list.first == linked_list.last &&
|
||||||
|
linked_list.first == NULL)
|
||||||
|
{
|
||||||
|
dtext(1, 90, C_BLACK, "linked list is correctly cleared");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
elem1 = elem_create(&linked_list);
|
||||||
|
elem2 = elem_create(&linked_list);
|
||||||
|
elem3 = elem_create(&linked_list);
|
||||||
|
elem4 = elem_create(&linked_list);
|
||||||
|
|
||||||
|
linked_list_push_back_elem(&linked_list, elem1);
|
||||||
|
linked_list_push_back_elem(&linked_list, elem2);
|
||||||
|
linked_list_push_front_elem(&linked_list, elem3);
|
||||||
|
if(linked_list.first == elem3 &&
|
||||||
|
linked_list.last == elem2 &&
|
||||||
|
!linked_list.first->prev &&
|
||||||
|
linked_list.first->next &&
|
||||||
|
linked_list.last->prev &&
|
||||||
|
!linked_list.last->next &&
|
||||||
|
linked_list.first->next == elem1 &&
|
||||||
|
linked_list.first->next->next == elem2 &&
|
||||||
|
linked_list.last->prev == elem1 &&
|
||||||
|
linked_list.last->prev->prev == elem3)
|
||||||
|
{
|
||||||
|
dtext(1, 100, C_BLACK, "elem1, elem2 and elem3 are correctly pushed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list_insert_elem(&linked_list, elem4, 1);
|
||||||
|
if(linked_list.first == elem3 &&
|
||||||
|
linked_list.last == elem2 &&
|
||||||
|
!linked_list.first->prev &&
|
||||||
|
linked_list.first->next &&
|
||||||
|
linked_list.last->prev &&
|
||||||
|
!linked_list.last->next &&
|
||||||
|
linked_list.first->next == elem4 &&
|
||||||
|
linked_list.first->next->next == elem1 &&
|
||||||
|
linked_list.first->next->next->next == elem2 &&
|
||||||
|
linked_list.last->prev == elem1 &&
|
||||||
|
linked_list.last->prev->prev == elem4 &&
|
||||||
|
linked_list.last->prev->prev->prev == elem3)
|
||||||
|
{
|
||||||
|
dtext(1, 110, C_BLACK, "elem3 is correctly inserted");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list_clear(&linked_list);
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
display_update();
|
||||||
|
getkey();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // LINKED_LIST_TEST
|
||||||
Loading…
Reference in New Issue