Add one way tile

Changelog:
- Add new enums for tile and solidity
- Modify check_collsion_and_move function to account for one way
  collision
  - Also remove the collision value as it is not used
- Add spawning for oneway tile
scene_man
En Yi 2023-05-02 21:54:29 +08:00
parent dc760bf8db
commit 36e84d1b75
3 changed files with 70 additions and 32 deletions

View File

@ -11,10 +11,11 @@ static Tile_t all_tiles[MAX_N_TILES] = {0};
enum EntitySpawnSelection {
TOGGLE_TILE = 0,
TOGGLE_ONEWAY,
SPAWN_CRATE,
SPAWN_METAL_CRATE,
};
#define MAX_SPAWN_TYPE 3
#define MAX_SPAWN_TYPE 4
static unsigned int current_spawn_selection = 0;
static inline unsigned int get_tile_idx(int x, int y, unsigned int tilemap_width)
@ -38,10 +39,14 @@ static void level_scene_render_func(Scene_t* scene)
int y = (i / tilemap.width) * TILE_SIZE;
sprintf(buffer, "%u", sc_map_size_64(&tilemap.tiles[i].entities_set));
if (tilemap.tiles[i].solid)
if (tilemap.tiles[i].tile_type == SOLID_TILE)
{
DrawRectangle(x, y, TILE_SIZE, TILE_SIZE, BLACK);
}
else if (tilemap.tiles[i].tile_type == ONEWAY_TILE)
{
DrawRectangle(x, y, TILE_SIZE, TILE_SIZE, BROWN);
}
else if (tilemap.tiles[i].water_level > 0)
{
// Draw water tile
@ -106,7 +111,7 @@ static void level_scene_render_func(Scene_t* scene)
int y = (i / tilemap.width) * TILE_SIZE;
sprintf(buffer, "%u", sc_map_size_64(&tilemap.tiles[i].entities_set));
if (tilemap.tiles[i].solid)
if (tilemap.tiles[i].solid > 0)
{
DrawText(buffer, x, y, 10, WHITE);
}
@ -233,8 +238,30 @@ static void toggle_block_system(Scene_t* scene)
switch (sel)
{
case TOGGLE_TILE:
tilemap.tiles[tile_idx].solid = !tilemap.tiles[tile_idx].solid;
tilemap.tiles[tile_idx].water_level = 0;
if (tilemap.tiles[tile_idx].tile_type == SOLID_TILE)
{
tilemap.tiles[tile_idx].tile_type = EMPTY_TILE;
tilemap.tiles[tile_idx].solid = NOT_SOLID;
}
else
{
tilemap.tiles[tile_idx].tile_type = SOLID_TILE;
tilemap.tiles[tile_idx].solid = SOLID;
}
tilemap.tiles[tile_idx].water_level = 0;
break;
case TOGGLE_ONEWAY:
if (tilemap.tiles[tile_idx].tile_type == ONEWAY_TILE)
{
tilemap.tiles[tile_idx].tile_type = EMPTY_TILE;
tilemap.tiles[tile_idx].solid = NOT_SOLID;
}
else
{
tilemap.tiles[tile_idx].tile_type = ONEWAY_TILE;
tilemap.tiles[tile_idx].solid = ONE_WAY;
}
tilemap.tiles[tile_idx].water_level = 0;
break;
case SPAWN_CRATE:
spawn_crate(scene, tile_idx, false);
@ -361,13 +388,15 @@ void init_level_scene(LevelScene_t* scene)
scene->data.tilemap.tiles = all_tiles;
for (size_t i = 0; i < MAX_N_TILES;i++)
{
all_tiles[i].solid = 0;
all_tiles[i].solid = NOT_SOLID;
all_tiles[i].tile_type = EMPTY_TILE;
sc_map_init_64(&all_tiles[i].entities_set, 16, 0);
}
for (size_t i = 0; i < scene->data.tilemap.width; ++i)
{
unsigned int tile_idx = (scene->data.tilemap.height - 1) * scene->data.tilemap.width + i;
all_tiles[tile_idx].solid = true; // for testing
all_tiles[tile_idx].solid = SOLID; // for testing
all_tiles[tile_idx].tile_type = SOLID_TILE; // for testing
}
spawn_player(&scene->scene);

View File

@ -47,7 +47,8 @@ static bool check_collision(const CollideEntity_t* ent, TileGrid_t* grid, Entity
for(unsigned int tile_x = ent->area.tile_x1; tile_x <= ent->area.tile_x2; tile_x++)
{
unsigned int tile_idx = tile_y*grid->width + tile_x;
if (grid->tiles[tile_idx].solid) return true;
if (grid->tiles[tile_idx].solid == SOLID) return true;
//TODO: For one-way platform, check for collision, only return true for up direction
unsigned int ent_idx;
sc_map_foreach_value(&grid->tiles[tile_idx].entities_set, ent_idx)
{
@ -77,6 +78,8 @@ static bool check_collision(const CollideEntity_t* ent, TileGrid_t* grid, Entity
return false;
}
// TODO: This should be a point collision check, not an AABB check
static bool check_collision_at(
unsigned int ent_idx, Vector2 pos, Vector2 bbox_sz,
TileGrid_t* grid, Vector2 point, EntityManager_t* p_manager
@ -108,8 +111,7 @@ static inline bool check_on_ground(
static bool check_collision_and_move(
EntityManager_t* p_manager, TileGrid_t* tilemap,
unsigned int ent_idx, CTransform_t* p_ct, Vector2 sz,
Vector2 other_pos, Vector2 other_sz, bool other_solid,
uint32_t* collision_value
Vector2 other_pos, Vector2 other_sz, SolidType_t other_solid
)
{
Vector2 overlap = {0,0};
@ -126,32 +128,30 @@ static bool check_collision_and_move(
if (fabs(prev_overlap.y) > fabs(prev_overlap.x))
{
offset.x = overlap.x;
*collision_value = (((overlap.x > 0?1:0)<< 14) | ( (uint16_t)(fabs(overlap.x)) ));
}
else if (fabs(prev_overlap.x) > fabs(prev_overlap.y))
{
offset.y = overlap.y;
*collision_value = (((overlap.y > 0?3:2)<< 14) | ( (uint16_t)(fabs(overlap.y)) ));
}
else if (fabs(overlap.x) < fabs(overlap.y))
{
offset.x = overlap.x;
*collision_value = (((overlap.x > 0?1:0)<< 14) | ( (uint16_t)(fabs(overlap.x)) ));
}
else
{
offset.y = overlap.y;
*collision_value = (((overlap.y > 0?3:2)<< 14) | ( (uint16_t)(fabs(overlap.y)) ));
}
// Resolve collision via moving player by the overlap amount only if other is solid
// also check for empty to prevent creating new collision. Not fool-proof, but good enough
//if (other_solid && !check_collision_at(ent_idx, p_ct->position, sz, tilemap, offset, p_manager))
if (other_solid)
if ( other_solid == SOLID
|| (other_solid == ONE_WAY && offset.y < 0)
)
{
p_ct->position = Vector2Add(p_ct->position, offset);
return true;
}
return true;
}
return false;
}
@ -322,7 +322,7 @@ void player_movement_input_system(Scene_t* scene)
for(unsigned int tile_x = tile_x1; tile_x <= tile_x2; tile_x++)
{
hit |= tilemap.tiles[tile_y * tilemap.width + tile_x].solid;
hit |= tilemap.tiles[tile_y * tilemap.width + tile_x].tile_type == SOLID_TILE;
}
if (hit)
{
@ -442,13 +442,12 @@ void tile_collision_system(Scene_t* scene)
unsigned int tile_x2 = (p_ctransform->position.x + p_bbox->size.x) / TILE_SIZE;
unsigned int tile_y2 = (p_ctransform->position.y + p_bbox->size.y) / TILE_SIZE;
uint32_t collision_value;
for (unsigned int tile_y = tile_y1; tile_y <= tile_y2; tile_y++)
{
for (unsigned int tile_x = tile_x1; tile_x <= tile_x2; tile_x++)
{
unsigned int tile_idx = tile_y * tilemap.width + tile_x;
if(tilemap.tiles[tile_idx].solid)
if(tilemap.tiles[tile_idx].tile_type != EMPTY_TILE)
{
Vector2 other;
other.x = (tile_idx % tilemap.width) * TILE_SIZE;
@ -457,7 +456,7 @@ void tile_collision_system(Scene_t* scene)
check_collision_and_move(
&scene->ent_manager, &tilemap, ent_idx,
p_ctransform, p_bbox->size, other,
TILE_SZ, true, &collision_value
TILE_SZ, tilemap.tiles[tile_idx].solid
);
}
@ -478,17 +477,11 @@ void tile_collision_system(Scene_t* scene)
if (p_other_bbox == NULL) continue;
CTransform_t *p_other_ct = get_component(&scene->ent_manager, p_other_ent, CTRANSFORM_COMP_T);
if (
check_collision_and_move(
&scene->ent_manager, &tilemap, ent_idx,
p_ctransform, p_bbox->size, p_other_ct->position,
p_other_bbox->size, p_other_bbox->solid, &collision_value
)
)
{
uint32_t collision_key = ((ent_idx << 16) | other_ent_idx);
sc_map_put_32(&data->collision_events, collision_key, collision_value);
}
check_collision_and_move(
&scene->ent_manager, &tilemap, ent_idx,
p_ctransform, p_bbox->size, p_other_ct->position,
p_other_bbox->size, p_other_bbox->solid? SOLID : NOT_SOLID
);
}
}
}

View File

@ -7,8 +7,24 @@
#include "engine.h"
#include "gui.h"
typedef enum TileType {
EMPTY_TILE = 0,
SOLID_TILE,
ONEWAY_TILE,
LADDER
} TileType_t;
typedef enum SolidType
{
NOT_SOLID = 0,
SOLID,
ONE_WAY,
}SolidType_t;
typedef struct Tile {
bool solid;
TileType_t tile_type;
SolidType_t solid;
unsigned int water_level;
struct sc_map_64 entities_set;
}Tile_t;