Compare commits
2 Commits
dc760bf8db
...
b5e7d8846f
Author | SHA1 | Date |
---|---|---|
|
b5e7d8846f | |
|
36e84d1b75 |
|
@ -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);
|
||||
|
|
|
@ -36,18 +36,32 @@ typedef struct TileArea {
|
|||
typedef struct CollideEntity {
|
||||
unsigned int idx;
|
||||
Rectangle bbox;
|
||||
Rectangle prev_bbox;
|
||||
TileArea_t area;
|
||||
} CollideEntity_t;
|
||||
|
||||
// ------------------------- Collision functions ------------------------------------
|
||||
static bool check_collision(const CollideEntity_t* ent, TileGrid_t* grid, EntityManager_t* p_manager)
|
||||
static bool check_collision(const CollideEntity_t* ent, TileGrid_t* grid, EntityManager_t* p_manager, bool check_oneway)
|
||||
{
|
||||
for(unsigned int tile_y = ent->area.tile_y1; tile_y <= ent->area.tile_y2; tile_y++)
|
||||
{
|
||||
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;
|
||||
|
||||
Vector2 overlap;
|
||||
if (check_oneway && grid->tiles[tile_idx].solid == ONE_WAY)
|
||||
{
|
||||
find_AABB_overlap(
|
||||
(Vector2){ent->bbox.x, ent->bbox.y},
|
||||
(Vector2){ent->bbox.width, ent->bbox.height},
|
||||
(Vector2){tile_x * TILE_SIZE, tile_y * TILE_SIZE}, TILE_SZ, &overlap
|
||||
);
|
||||
|
||||
//For one-way platform, check for vectical collision, only return true for up direction
|
||||
if (overlap.y != 0 && ent->prev_bbox.y + ent->prev_bbox.height - 1 < tile_y * TILE_SIZE) return true;
|
||||
}
|
||||
unsigned int ent_idx;
|
||||
sc_map_foreach_value(&grid->tiles[tile_idx].entities_set, ent_idx)
|
||||
{
|
||||
|
@ -55,7 +69,6 @@ static bool check_collision(const CollideEntity_t* ent, TileGrid_t* grid, Entity
|
|||
Entity_t * p_ent = get_entity(p_manager, ent_idx);
|
||||
CTransform_t *p_ctransform = get_component(p_manager, p_ent, CTRANSFORM_COMP_T);
|
||||
CBBox_t *p_bbox = get_component(p_manager, p_ent, CBBOX_COMP_T);
|
||||
Vector2 overlap;
|
||||
if (p_bbox == NULL || p_ctransform == NULL) continue;
|
||||
//if (p_bbox->solid && !p_bbox->fragile)
|
||||
if (p_bbox->solid)
|
||||
|
@ -77,6 +90,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
|
||||
|
@ -86,6 +101,7 @@ static bool check_collision_at(
|
|||
CollideEntity_t ent = {
|
||||
.idx = ent_idx,
|
||||
.bbox = (Rectangle){new_pos.x, new_pos.y, bbox_sz.x, bbox_sz.y},
|
||||
.prev_bbox = (Rectangle){pos.x, pos.y, bbox_sz.x, bbox_sz.y},
|
||||
.area = (TileArea_t){
|
||||
.tile_x1 = (new_pos.x) / TILE_SIZE,
|
||||
.tile_y1 = (new_pos.y) / TILE_SIZE,
|
||||
|
@ -94,22 +110,35 @@ static bool check_collision_at(
|
|||
}
|
||||
};
|
||||
|
||||
return check_collision(&ent, grid, p_manager);
|
||||
return check_collision(&ent, grid, p_manager, false);
|
||||
}
|
||||
|
||||
static inline bool check_on_ground(
|
||||
unsigned int ent_idx, Vector2 pos, Vector2 bbox_sz,
|
||||
unsigned int ent_idx, Vector2 pos, Vector2 prev_pos, Vector2 bbox_sz,
|
||||
TileGrid_t* grid, EntityManager_t* p_manager
|
||||
)
|
||||
{
|
||||
return check_collision_at(ent_idx, pos, bbox_sz, grid, (Vector2){0, 1}, p_manager);
|
||||
//return check_collision_at(ent_idx, pos, bbox_sz, grid, (Vector2){0, 1}, p_manager);
|
||||
Vector2 new_pos = Vector2Add(pos, (Vector2){0, 1});
|
||||
CollideEntity_t ent = {
|
||||
.idx = ent_idx,
|
||||
.bbox = (Rectangle){new_pos.x, new_pos.y + bbox_sz.y - 1, bbox_sz.x, 1},
|
||||
.prev_bbox = (Rectangle){prev_pos.x, prev_pos.y, bbox_sz.x, bbox_sz.y},
|
||||
.area = (TileArea_t){
|
||||
.tile_x1 = (new_pos.x) / TILE_SIZE,
|
||||
.tile_y1 = (new_pos.y + bbox_sz.y - 1) / TILE_SIZE,
|
||||
.tile_x2 = (new_pos.x + bbox_sz.x - 1) / TILE_SIZE,
|
||||
.tile_y2 = (new_pos.y + bbox_sz.y - 1) / TILE_SIZE
|
||||
}
|
||||
};
|
||||
|
||||
return check_collision(&ent, grid, p_manager, true);
|
||||
}
|
||||
|
||||
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,39 +155,37 @@ 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->prev_position.y + sz.y - 1 < other_pos.y))
|
||||
)
|
||||
{
|
||||
p_ct->position = Vector2Add(p_ct->position, offset);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint8_t check_bbox_edges(
|
||||
EntityManager_t* p_manager, TileGrid_t* tilemap,
|
||||
unsigned int ent_idx, Vector2 pos, Vector2 bbox
|
||||
unsigned int ent_idx, Vector2 pos, Vector2 prev_pos, Vector2 bbox
|
||||
)
|
||||
{
|
||||
uint8_t detected = 0;
|
||||
|
@ -166,6 +193,7 @@ static uint8_t check_bbox_edges(
|
|||
{
|
||||
.idx = ent_idx,
|
||||
.bbox = (Rectangle){pos.x - 1, pos.y, bbox.x, bbox.y},
|
||||
.prev_bbox = (Rectangle){pos.x, pos.y, bbox.x, bbox.y},
|
||||
.area = (TileArea_t){
|
||||
.tile_x1 = (pos.x - 1) / TILE_SIZE,
|
||||
.tile_y1 = (pos.y) / TILE_SIZE,
|
||||
|
@ -173,14 +201,17 @@ static uint8_t check_bbox_edges(
|
|||
.tile_y2 = (pos.y + bbox.y - 1) / TILE_SIZE,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// TODO: Handle one-way platform
|
||||
// Left
|
||||
detected |= (check_collision(&ent, tilemap, p_manager) ? 1 : 0) << 3;
|
||||
detected |= (check_collision(&ent, tilemap, p_manager, false) ? 1 : 0) << 3;
|
||||
|
||||
//Right
|
||||
ent.bbox.x += 2; // 2 to account for the previous subtraction
|
||||
ent.area.tile_x1 = (pos.x + bbox.x) / TILE_SIZE;
|
||||
ent.area.tile_x2 = ent.area.tile_x1;
|
||||
detected |= (check_collision(&ent, tilemap, p_manager) ? 1 : 0) << 2;
|
||||
detected |= (check_collision(&ent, tilemap, p_manager, false) ? 1 : 0) << 2;
|
||||
|
||||
// Up
|
||||
ent.bbox.x -= 2;
|
||||
|
@ -189,13 +220,13 @@ static uint8_t check_bbox_edges(
|
|||
ent.area.tile_x2 = (pos.x + bbox.x - 1) / TILE_SIZE,
|
||||
ent.area.tile_y1 = (pos.y - 1) / TILE_SIZE,
|
||||
ent.area.tile_y2 = ent.area.tile_y1;
|
||||
detected |= (check_collision(&ent, tilemap, p_manager) ? 1 : 0) << 1;
|
||||
detected |= (check_collision(&ent, tilemap, p_manager, false) ? 1 : 0) << 1;
|
||||
|
||||
// Down
|
||||
ent.bbox.y += 2;
|
||||
ent.area.tile_y1 = (pos.y + bbox.y) / TILE_SIZE,
|
||||
ent.area.tile_y2 = ent.area.tile_y1;
|
||||
detected |= (check_collision(&ent, tilemap, p_manager) ? 1 : 0);
|
||||
detected |= (check_collision(&ent, tilemap, p_manager, true) ? 1 : 0);
|
||||
return detected;
|
||||
}
|
||||
|
||||
|
@ -322,7 +353,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 +473,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 +487,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 +508,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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -497,7 +521,7 @@ void tile_collision_system(Scene_t* scene)
|
|||
// Post movement edge check to zero out velocity
|
||||
uint8_t edges = check_bbox_edges(
|
||||
&scene->ent_manager, &data->tilemap, ent_idx,
|
||||
p_ctransform->position, p_bbox->size
|
||||
p_ctransform->position, p_ctransform->prev_position, p_bbox->size
|
||||
);
|
||||
if (edges & (1<<3))
|
||||
{
|
||||
|
@ -659,7 +683,7 @@ void global_external_forces_system(Scene_t* scene)
|
|||
// Zero out acceleration for contacts with sturdy entites and tiles
|
||||
uint8_t edges = check_bbox_edges(
|
||||
&scene->ent_manager, &data->tilemap, ent_idx,
|
||||
p_ctransform->position, p_bbox->size
|
||||
p_ctransform->position, p_ctransform->prev_position, p_bbox->size
|
||||
);
|
||||
if (edges & (1<<3))
|
||||
{
|
||||
|
@ -762,7 +786,7 @@ void state_transition_update_system(Scene_t* scene)
|
|||
if (p_ctransform == NULL || p_bbox == NULL) continue;
|
||||
|
||||
bool on_ground = check_on_ground(
|
||||
ent_idx, p_ctransform->position, p_bbox->size,
|
||||
ent_idx, p_ctransform->position, p_ctransform->prev_position, p_bbox->size,
|
||||
&data->tilemap, &scene->ent_manager
|
||||
);
|
||||
bool in_water = false;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue