Implement Crates

Changelog:
- Add new component: container
- Add function to spawn a crate
- Refactor player spawning into level scene init
- Modify tile collision to work on bbox components
- Add actions to switch entity to spawn
- Update spawn system to spawn a crate
scene_man
En Yi 2023-01-10 21:24:50 +08:00
parent af080dbdc8
commit 0b342bb9be
6 changed files with 130 additions and 34 deletions

View File

@ -7,5 +7,7 @@ typedef enum ActionType
ACTION_LEFT,
ACTION_RIGHT,
ACTION_JUMP,
ACTION_NEXT_SPAWN,
ACTION_PREV_SPAWN,
}ActionType_t;
#endif // __ACTIONS_H

View File

@ -4,7 +4,7 @@
#include <stdint.h>
// TODO: Look at sc to use macros to auto generate functions
#define N_COMPONENTS 6
#define N_COMPONENTS 7
enum ComponentEnum
{
CBBOX_COMP_T,
@ -12,7 +12,8 @@ enum ComponentEnum
CTILECOORD_COMP_T,
CMOVEMENTSTATE_T,
CJUMP_COMP_T,
CPLAYERSTATE_T
CPLAYERSTATE_T,
CCONTAINER_T,
};
typedef enum ComponentEnum ComponentEnum_t;
@ -69,6 +70,29 @@ typedef struct _CPlayerState_t
uint8_t is_crouch: 1;
}CPlayerState_t;
typedef enum ContainerItem
{
CONTAINER_EMPTY,
CONTAINER_LEFT_ARROW,
CONTAINER_RIGHT_ARROW,
CONTAINER_UP_ARROW,
CONTAINER_DOWN_ARROW,
CONTAINER_COIN,
CONTAINER_BOMB,
}ContainerItem_t;
typedef enum ContainerMaterial
{
WOODEN_CONTAINER,
METAL_CONTAINER,
}ContainerMaterial_t;
typedef struct _CContainer_t
{
ContainerMaterial_t material;
ContainerItem_t item;
}CContainer_t;
static inline void set_bbox(CBBox_t* p_bbox, unsigned int x, unsigned int y)
{

View File

@ -3,12 +3,13 @@
#include <stdbool.h>
#include "sc/map/sc_map.h"
#define N_TAGS 3
#define N_TAGS 4
enum EntityTag
{
NO_ENT_TAG,
PLAYER_ENT_TAG,
ENEMY_ENT_TAG,
CRATES_ENT_TAG,
};
typedef enum EntityTag EntityTag_t;
typedef struct Entity

View File

@ -10,6 +10,7 @@ static CTileCoord_t ctilecoord_buffer[MAX_COMP_POOL_SIZE];
static CMovementState_t cmstate_buffer[MAX_COMP_POOL_SIZE];
static CJump_t cjump_buffer[1]; // Only player is expected to have this
static CPlayerState_t cplayerstate_buffer[1]; // Only player is expected to have this
static CContainer_t ccontainer_buffer[MAX_COMP_POOL_SIZE];
// Use hashmap as a Set
// Use list will be used to check if an object exist
@ -35,6 +36,7 @@ static MemPool_t comp_mempools[N_COMPONENTS] =
{cmstate_buffer, MAX_COMP_POOL_SIZE, sizeof(CMovementState_t), NULL, {0}},
{cjump_buffer, 1, sizeof(CJump_t), NULL, {0}},
{cplayerstate_buffer, 1, sizeof(CPlayerState_t), NULL, {0}},
{ccontainer_buffer, MAX_COMP_POOL_SIZE, sizeof(CContainer_t), NULL, {0}},
};
static MemPool_t ent_mempool = {entity_buffer, MAX_COMP_POOL_SIZE, sizeof(Entity_t), NULL, {0}};

View File

@ -11,6 +11,14 @@ static Tile_t all_tiles[MAX_N_TILES] = {0};
static const Vector2 GRAVITY = {0, GRAV_ACCEL};
static const Vector2 UPTHRUST = {0, -GRAV_ACCEL * 1.1};
enum EntitySpawnSelection
{
TOGGLE_TILE = 0,
SPAWN_CRATE,
};
#define MAX_SPAWN_TYPE 2
static unsigned int current_spawn_selection = 0;
static inline unsigned int get_tile_idx(int x, int y, unsigned int tilemap_width)
{
unsigned int tile_x = x / TILE_SIZE;
@ -179,6 +187,26 @@ static void level_scene_render_func(Scene_t* scene)
LevelSceneData_t *data = (LevelSceneData_t *)scene->scene_data;
TileGrid_t tilemap = data->tilemap;
Entity_t *p_ent;
sc_map_foreach_value(&scene->ent_manager.entities, p_ent)
{
CTransform_t* p_ct = get_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T);
CBBox_t* p_bbox = get_component(&scene->ent_manager, p_ent, CBBOX_COMP_T);
Color colour;
switch(p_ent->m_tag)
{
case PLAYER_ENT_TAG:
colour = RED;
break;
case CRATES_ENT_TAG:
colour = BROWN;
break;
default:
colour = BLACK;
}
DrawRectangle(p_ct->position.x, p_ct->position.y, p_bbox->size.x, p_bbox->size.y, colour);
}
for (size_t i=0; i<tilemap.n_tiles;++i)
{
char buffer[6] = {0};
@ -202,14 +230,6 @@ static void level_scene_render_func(Scene_t* scene)
}
}
Entity_t *p_ent;
sc_map_foreach_value(&scene->ent_manager.entities, p_ent)
{
CTransform_t* p_ct = get_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T);
CBBox_t* p_bbox = get_component(&scene->ent_manager, p_ent, CBBOX_COMP_T);
DrawRectangle(p_ct->position.x, p_ct->position.y, p_bbox->size.x, p_bbox->size.y, RED);
}
// Draw tile grid
for (size_t i=0; i<tilemap.width;++i)
{
@ -240,6 +260,8 @@ static void level_scene_render_func(Scene_t* scene)
DrawText(buffer, tilemap.width * TILE_SIZE + 1, 90, 12, BLACK);
sprintf(buffer, "Water: %s", p_mstate->water_state & 1? "YES":"NO");
DrawText(buffer, tilemap.width * TILE_SIZE + 1, 120, 12, BLACK);
sprintf(buffer, "Spawn Entity: %u", current_spawn_selection);
DrawText(buffer, tilemap.width * TILE_SIZE + 1, 240, 12, BLACK);
}
}
@ -509,17 +531,19 @@ static void player_ground_air_transition_system(Scene_t* scene)
}
}
static void player_collision_system(Scene_t *scene)
static void tile_collision_system(Scene_t *scene)
{
LevelSceneData_t *data = (LevelSceneData_t *)scene->scene_data;
TileGrid_t tilemap = data->tilemap;
Entity_t *p_player;
sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_player)
unsigned int ent_idx;
CBBox_t* p_bbox;
//sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_player)
sc_map_foreach(&scene->ent_manager.component_map[CBBOX_COMP_T], ent_idx, p_bbox)
{
CTransform_t* p_ctransform = get_component(&scene->ent_manager, p_player, CTRANSFORM_COMP_T);
CBBox_t* p_bbox = get_component(&scene->ent_manager, p_player, CBBOX_COMP_T);
Entity_t *p_ent = get_entity(&scene->ent_manager, ent_idx);
CTransform_t* p_ctransform = get_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T);
// Get the occupied tiles
// For each tile, loop through the entities and find overlaps
// exclude self
@ -543,7 +567,6 @@ static void player_collision_system(Scene_t *scene)
Vector2 other;
if(tilemap.tiles[tile_idx].solid)
{
other.x = (tile_idx % tilemap.width) * TILE_SIZE;
other.y = (tile_idx / tilemap.width) * TILE_SIZE; // Precision loss is intentional
if (find_AABB_overlap(p_ctransform->position, p_bbox->size, other, TILE_SZ, &overlap))
@ -714,6 +737,35 @@ static void update_tilemap_system(Scene_t *scene)
}
}
static void spawn_crate(Scene_t *scene, unsigned int tile_idx)
{
LevelSceneData_t *data = (LevelSceneData_t *)scene->scene_data;
Entity_t *p_crate = add_entity(&scene->ent_manager, CRATES_ENT_TAG);
CBBox_t *p_bbox = add_component(&scene->ent_manager, p_crate, CBBOX_COMP_T);
set_bbox(p_bbox, TILE_SIZE, TILE_SIZE);
CTransform_t *p_ctransform = add_component(&scene->ent_manager, p_crate, CTRANSFORM_COMP_T);
p_ctransform->position.x = (tile_idx % data->tilemap.width) * TILE_SIZE;
p_ctransform->position.y = (tile_idx / data->tilemap.width) * TILE_SIZE;
add_component(&scene->ent_manager, p_crate, CMOVEMENTSTATE_T);
add_component(&scene->ent_manager, p_crate, CTILECOORD_COMP_T);
}
static void spawn_player(Scene_t *scene)
{
Entity_t *p_ent = add_entity(&scene->ent_manager, PLAYER_ENT_TAG);
CBBox_t *p_bbox = add_component(&scene->ent_manager, p_ent, CBBOX_COMP_T);
set_bbox(p_bbox, 30, 45);
add_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T);
CJump_t *p_cjump = add_component(&scene->ent_manager, p_ent, CJUMP_COMP_T);
p_cjump->jump_speed = 680;
p_cjump->jumps = 1;
p_cjump->max_jumps = 1;
add_component(&scene->ent_manager, p_ent, CPLAYERSTATE_T);
add_component(&scene->ent_manager, p_ent, CTILECOORD_COMP_T);
add_component(&scene->ent_manager, p_ent, CMOVEMENTSTATE_T);
}
static void toggle_block_system(Scene_t *scene)
{
// TODO: This system is not good as the interface between raw input and actions is broken
@ -724,10 +776,19 @@ static void toggle_block_system(Scene_t *scene)
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
unsigned int tile_idx = get_tile_idx(GetMouseX(), GetMouseY(), tilemap.width);
enum EntitySpawnSelection sel = (enum EntitySpawnSelection)current_spawn_selection;
if (tile_idx != last_tile_idx)
{
tilemap.tiles[tile_idx].solid = !tilemap.tiles[tile_idx].solid;
tilemap.tiles[tile_idx].water_level = 0;
switch (sel)
{
case TOGGLE_TILE:
tilemap.tiles[tile_idx].solid = !tilemap.tiles[tile_idx].solid;
tilemap.tiles[tile_idx].water_level = 0;
break;
case SPAWN_CRATE:
spawn_crate(scene, tile_idx);
break;
}
last_tile_idx = tile_idx;
}
}
@ -777,6 +838,20 @@ void level_do_action(Scene_t *scene, ActionType_t action, bool pressed)
case ACTION_JUMP:
p_playerstate->jump_pressed = pressed;
break;
case ACTION_NEXT_SPAWN:
if (!pressed)
{
current_spawn_selection++;
current_spawn_selection &= 1;
}
break;
case ACTION_PREV_SPAWN:
if (!pressed)
{
current_spawn_selection--;
current_spawn_selection &= 1;
}
break;
}
}
}
@ -791,8 +866,8 @@ void init_level_scene(LevelScene_t *scene)
sc_array_add(&scene->scene.systems, &player_bbox_update_system);
sc_array_add(&scene->scene.systems, &global_external_forces_system);
sc_array_add(&scene->scene.systems, &movement_update_system);
sc_array_add(&scene->scene.systems, &tile_collision_system);
sc_array_add(&scene->scene.systems, &update_tilemap_system);
sc_array_add(&scene->scene.systems, &player_collision_system);
sc_array_add(&scene->scene.systems, &state_transition_update_system);
sc_array_add(&scene->scene.systems, &player_ground_air_transition_system);
sc_array_add(&scene->scene.systems, &toggle_block_system);
@ -805,6 +880,8 @@ void init_level_scene(LevelScene_t *scene)
sc_map_put_64(&scene->scene.action_map, KEY_LEFT, ACTION_LEFT);
sc_map_put_64(&scene->scene.action_map, KEY_RIGHT, ACTION_RIGHT);
sc_map_put_64(&scene->scene.action_map, KEY_SPACE, ACTION_JUMP);
sc_map_put_64(&scene->scene.action_map, KEY_O, ACTION_PREV_SPAWN);
sc_map_put_64(&scene->scene.action_map, KEY_P, ACTION_NEXT_SPAWN);
scene->data.tilemap.width = 32;
scene->data.tilemap.height = 16;
@ -820,6 +897,9 @@ void init_level_scene(LevelScene_t *scene)
{
all_tiles[15*32+i].solid = true; // for testing
}
spawn_player(&scene->scene);
update_entity_manager(&scene->scene.ent_manager);
}
void free_level_scene(LevelScene_t *scene)

View File

@ -14,20 +14,6 @@ int main(void)
init_memory_pools();
LevelScene_t scene;
init_level_scene(&scene);
Entity_t *p_ent = add_entity(&scene.scene.ent_manager, PLAYER_ENT_TAG);
CBBox_t *p_bbox = add_component(&scene.scene.ent_manager, p_ent, CBBOX_COMP_T);
set_bbox(p_bbox, 30, 45);
add_component(&scene.scene.ent_manager, p_ent, CTRANSFORM_COMP_T);
CJump_t *p_cjump = add_component(&scene.scene.ent_manager, p_ent, CJUMP_COMP_T);
p_cjump->jump_speed = 680;
p_cjump->jumps = 1;
p_cjump->max_jumps = 1;
add_component(&scene.scene.ent_manager, p_ent, CPLAYERSTATE_T);
add_component(&scene.scene.ent_manager, p_ent, CTILECOORD_COMP_T);
add_component(&scene.scene.ent_manager, p_ent, CMOVEMENTSTATE_T);
update_entity_manager(&scene.scene.ent_manager);
//for (size_t step = 0; step < 6000; step++)
while(true)
{
@ -63,6 +49,7 @@ int main(void)
}
update_scene(&scene.scene);
update_entity_manager(&scene.scene.ent_manager);
// This is needed to advance time delta
BeginDrawing();
render_scene(&scene.scene);