Compare commits

..

10 Commits

Author SHA1 Message Date
En Yi 70d7fda22c Add game scene
This is slightly different from the sandbox
- No editting tiles and spawnning
- Can switch levels
2023-08-14 18:37:29 +08:00
En Yi e0ea01a4de Add level switching
Changelog:
- Water is now on a separate layer in LDtk
- Update water loading in assets functions
- Add actions to switch levels
2023-08-14 17:05:43 +08:00
En Yi ca392a0efd Remove loop when loading level pack 2023-08-14 16:01:10 +08:00
En Yi f6f3214dc1 Add levelpack loading in asset loader
Changelog:
- Update main code to use assets loader
- Update level load test as well
2023-08-14 15:40:48 +08:00
En Yi 9387189927 Refactor out level loading function 2023-08-14 15:03:11 +08:00
En Yi 8e9efc622d Refactor out level tilemap initialisation
- Rename sandbox scene initialisation, which is just a convenience
  function
- Also refactor out tilemap related functions to a new file
2023-08-14 13:51:20 +08:00
En Yi 5de188c503 Implement level pack loading and testing 2023-08-14 12:16:15 +08:00
En Yi 5dbe2cc4d0 Add struct for loading in a level pack 2023-08-13 15:02:20 +08:00
En Yi 87c415d52c Parse entity layer in ldtk script 2023-08-13 15:02:20 +08:00
En Yi 62703c0317 Add arrow sprite 2023-08-13 15:02:20 +08:00
20 changed files with 965 additions and 218 deletions

View File

@ -85,6 +85,19 @@ target_link_libraries(water_test
target_compile_options(water_test PRIVATE -fsanitize=address -gdwarf-4)
target_link_options(water_test PRIVATE -fsanitize=address -gdwarf-4)
add_executable(level_load_test
level_load_test.c
)
target_include_directories(level_load_test
PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(level_load_test
${GAME_LIBS}
)
target_compile_options(level_load_test PRIVATE -fsanitize=address -gdwarf-4)
target_link_options(level_load_test PRIVATE -fsanitize=address -gdwarf-4)
add_executable(menu_test
menu_test.c
)

102
level_load_test.c 100644
View File

@ -0,0 +1,102 @@
#include "constants.h"
#include "mempool.h"
#include "raymath.h"
#include "scene_impl.h"
#include "ent_impl.h"
#include "water_flow.h"
#include "game_systems.h"
#include "assets_loader.h"
#include <stdio.h>
#include <unistd.h>
// Maintain own queue to handle key presses
struct sc_queue_32 key_buffer;
Scene_t* scenes[1];
static GameEngine_t engine =
{
.scenes = scenes,
.max_scenes = 1,
.curr_scene = 0,
.assets = {0}
};
int main(void)
{
sc_queue_init(&key_buffer);
InitWindow(1280, 640, "raylib");
SetTargetFPS(60);
init_memory_pools();
init_assets(&engine.assets);
load_from_infofile("res/assets.info", &engine.assets);
init_player_creation("res/player_spr.info", &engine.assets);
LevelPack_t* pack = get_level_pack(&engine.assets, "TestLevels");
assert(pack != NULL);
LevelScene_t scene;
scene.scene.engine = &engine;
scene.data.level_pack = pack;
scene.data.current_level = 0;
init_game_scene(&scene);
assert(load_level_tilemap(&scene, 0) == true);
scene.data.tile_sprites[ONEWAY_TILE] = get_sprite(&engine.assets, "tl_owp");
scene.data.tile_sprites[LADDER] = get_sprite(&engine.assets, "tl_ldr");
scenes[0] = &scene.scene;
change_scene(&engine, 0);
while(true)
{
// This entire key processing relies on the assumption that a pressed key will
// appear in the polling of raylib
unsigned int sz = sc_queue_size(&key_buffer);
// Process any existing pressed key
for (size_t i = 0; i < sz; i++)
{
int button = sc_queue_del_first(&key_buffer);
ActionType_t action = sc_map_get_64(&scene.scene.action_map, button);
if (IsKeyReleased(button))
{
do_action(&scene.scene, action, false);
}
else
{
do_action(&scene.scene, action, true);
sc_queue_add_last(&key_buffer, button);
}
}
// Detect new key presses
while(true)
{
int button = GetKeyPressed();
if (button == 0) break;
ActionType_t action = sc_map_get_64(&scene.scene.action_map, button);
if (!sc_map_found(&scene.scene.action_map)) continue;
do_action(&scene.scene, action, true);
sc_queue_add_last(&key_buffer, button);
}
update_scene(&scene.scene);
update_entity_manager(&scene.scene.ent_manager);
// This is needed to advance time delta
render_scene(&scene.scene);
if (WindowShouldClose()) break;
}
unsigned int m_id;
Entity_t* ent;
sc_map_foreach(&scene.scene.ent_manager.entities_map[DYNMEM_ENT_TAG], m_id, ent)
{
free_water_runner(ent, &scene.scene.ent_manager);
}
free_scene(&scene.scene);
term_level_scene_data(&scene.data);
sc_queue_term(&key_buffer);
term_assets(&engine.assets);
CloseWindow();
}

31
main.c
View File

@ -1,5 +1,7 @@
#include "raylib.h"
#include "assets_loader.h"
#include "scene_impl.h"
#include "ent_impl.h"
#include "mempool.h"
#include <stdio.h>
#define N_SCENES 3
@ -15,20 +17,6 @@ static GameEngine_t engine = {
const int screenWidth = 1280;
const int screenHeight = 640;
static void load_assets(void)
{
Texture2D* tex = add_texture(&engine.assets, "plr_tex", "res/test_tex.png");
Sprite_t* spr = add_sprite(&engine.assets, "plr_stand", tex);
spr->origin = (Vector2){0, 0};
spr->frame_size = (Vector2){32, 32};
spr = add_sprite(&engine.assets, "plr_run", tex);
spr->frame_count = 4;
spr->origin = (Vector2){0, 0};
spr->frame_size = (Vector2){32, 32};
spr->speed = 15;
}
// Maintain own queue to handle key presses
struct sc_queue_32 key_buffer;
@ -42,11 +30,20 @@ int main(void)
init_memory_pools();
init_assets(&engine.assets);
load_assets();
load_from_infofile("res/assets.info", &engine.assets);
init_player_creation("res/player_spr.info", &engine.assets);
LevelScene_t level_scene;
level_scene.scene.engine = &engine;
init_level_scene(&level_scene);
init_sandbox_scene(&level_scene);
LevelPack_t* pack = get_level_pack(&engine.assets, "TestLevels");
if (pack != NULL)
{
level_scene.data.level_pack = pack;
level_scene.data.current_level = 0;
load_level_tilemap(&level_scene, 0);
}
MenuScene_t menu_scene;
menu_scene.scene.engine = &engine;
init_menu_scene(&menu_scene);
@ -102,7 +99,7 @@ int main(void)
sc_queue_clear(&key_buffer);
}
}
free_level_scene(&level_scene);
free_sandbox_scene(&level_scene);
free_menu_scene(&menu_scene);
sc_queue_term(&key_buffer);
term_assets(&engine.assets);

View File

@ -19,6 +19,10 @@ ENUMIDS_TILETYPE_MAPPING = {
'Water': 2
}
ENTID_MAPPING = {
'Player': 1
}
# First go to tilesets and find Simple_tiles identifier, then find enumTags to identifier which tile type is what tileid
ids_tiletype_map = {}
tileset_defs = level_pack_data["defs"]["tilesets"]
@ -48,7 +52,7 @@ converted_filename = '.'.join(fileparts)
# Each level should be packed as: [width, 2 bytes][height, 2 bytes][tile_type,entity,water,padding 1,1,1,1 bytes][tile_type,entity,water,padding 1,1,1,1 bytes]...
with open(converted_filename, 'wb+') as out_file:
out_file.write(struct.pack("I", n_levels))
out_file.write(struct.pack("<I", n_levels))
# Then loop the levels. Read the layerIndstances
for level in level_pack_data["levels"]:
# Search for __identifier for the level layout
@ -57,11 +61,15 @@ with open(converted_filename, 'wb+') as out_file:
level_layout = {}
entity_layout = {}
water_layout = {}
for layer in level['layerInstances']:
if layer["__identifier"] != "Tiles":
continue
level_layout = layer
if layer["__identifier"] == "Tiles":
level_layout = layer
elif layer["__identifier"] == "Entities":
entity_layout = layer
elif layer["__identifier"] == "Water":
water_layout = layer
# Dimensions of each level is obtained via __cWid and __cHei. Get the __gridSize as well
width = level_layout["__cWid"]
@ -74,9 +82,17 @@ with open(converted_filename, 'wb+') as out_file:
for tile in level_layout["gridTiles"]:
tiles_info[tile["d"][0]][0] = ids_tiletype_map[tile["t"]]
out_file.write(struct.pack("32s2H", level_name.encode('utf-8'), width, height))
for i, water_level in enumerate(water_layout["intGridCsv"]):
tiles_info[i][2] = water_level
for ent in entity_layout["entityInstances"]:
if ent["__identifier"] in ENTID_MAPPING:
x,y = ent["__grid"]
tiles_info[y*width + x][1] = ENTID_MAPPING[ent["__identifier"]]
out_file.write(struct.pack("<32s2H", level_name.encode('utf-8'), width, height))
for tile in tiles_info:
out_file.write(struct.pack("3Bx", *tile))
out_file.write(struct.pack("<3Bx", *tile))
for y in range(height):

View File

@ -31,7 +31,7 @@ int main(void)
LevelScene_t scene;
scene.scene.engine = &engine;
init_level_scene(&scene);
init_sandbox_scene(&scene);
scene.data.tile_sprites[ONEWAY_TILE] = get_sprite(&engine.assets, "tl_owp");
scene.data.tile_sprites[LADDER] = get_sprite(&engine.assets, "tl_ldr");
scenes[0] = &scene.scene;
@ -78,7 +78,7 @@ int main(void)
render_scene(&scene.scene);
if (WindowShouldClose()) break;
}
free_level_scene(&scene);
free_sandbox_scene(&scene);
sc_queue_term(&key_buffer);
term_assets(&engine.assets);
CloseWindow();

View File

@ -6,7 +6,9 @@ add_library(lib_scenes STATIC
water_flow.c
editor_scene.c
menu_scene.c
game_scene.c
game_systems.c
scene_systems.c
)
target_include_directories(lib_scenes
PUBLIC

View File

@ -6,6 +6,7 @@ typedef enum AssetInfoType
{
TEXTURE_INFO,
SPRITE_INFO,
LEVELPACK_INFO,
INVALID_INFO
}AssetInfoType_t;
@ -64,6 +65,10 @@ bool load_from_infofile(const char* file, Assets_t* assets)
{
info_type = SPRITE_INFO;
}
else if (strcmp(tmp, "LevelPack") == 0)
{
info_type = LEVELPACK_INFO;
}
else
{
info_type = INVALID_INFO;
@ -90,6 +95,16 @@ bool load_from_infofile(const char* file, Assets_t* assets)
//strcpy(tmp2, name);
}
break;
case LEVELPACK_INFO:
{
if (add_level_pack(assets, name, info_str) == NULL)
{
printf("Unable to add level pack at line %lu\n", line_num);
break;
}
printf("Added level pack %s as %s\n", info_str, name);
}
break;
case SPRITE_INFO:
{
SpriteInfo_t spr_info = {0};

View File

@ -40,4 +40,8 @@
#define MAX_WATER_LEVEL 4
#define WATER_BBOX_STEP (TILE_SIZE / MAX_WATER_LEVEL)
#define MAX_LEVEL_NUM 50
#define MAX_N_TILES 4096
#endif // __CONSTANTS_H

View File

@ -8,7 +8,6 @@
#include "raymath.h"
#include <stdio.h>
#define MAX_N_TILES 4096
static Tile_t all_tiles[MAX_N_TILES] = {0};
enum EntitySpawnSelection {
@ -777,12 +776,22 @@ void level_do_action(Scene_t* scene, ActionType_t action, bool pressed)
}
}
void init_level_scene(LevelScene_t* scene)
void init_sandbox_scene(LevelScene_t* scene)
{
//init_scene(&scene->scene, LEVEL_SCENE, &level_scene_render_func, &level_do_action);
init_scene(&scene->scene, &level_scene_render_func, &level_do_action);
init_level_scene_data(&scene->data);
scene->data.tilemap.tiles = all_tiles;
init_level_scene_data(&scene->data, MAX_N_TILES, all_tiles);
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;
change_a_tile(&scene->data.tilemap, tile_idx, SOLID_TILE);
}
create_player(&scene->scene.ent_manager, &scene->scene.engine->assets);
update_entity_manager(&scene->scene.ent_manager);
// insert level scene systems
sc_array_add(&scene->scene.systems, &update_tilemap_system);
sc_array_add(&scene->scene.systems, &player_movement_input_system);
@ -825,43 +834,10 @@ void init_level_scene(LevelScene_t* scene)
sc_map_put_64(&scene->scene.action_map, KEY_Q, ACTION_EXIT);
sc_map_put_64(&scene->scene.action_map, KEY_R, ACTION_RESTART);
scene->data.tilemap.width = DEFAULT_MAP_WIDTH;
scene->data.tilemap.height = DEFAULT_MAP_HEIGHT;
scene->data.tilemap.tile_size = TILE_SIZE;
scene->data.tilemap.n_tiles = scene->data.tilemap.width * scene->data.tilemap.height;
assert(scene->data.tilemap.n_tiles <= MAX_N_TILES);
scene->data.tilemap.tiles = all_tiles;
memset(scene->data.tile_sprites, 0, sizeof(scene->data.tile_sprites));
for (size_t i = 0; i < scene->data.tilemap.n_tiles;i++)
{
all_tiles[i].solid = NOT_SOLID;
all_tiles[i].tile_type = EMPTY_TILE;
all_tiles[i].moveable = true;
all_tiles[i].max_water_level = 4;
sc_map_init_64v(&all_tiles[i].entities_set, 16, 0);
all_tiles[i].size = (Vector2){TILE_SIZE, TILE_SIZE};
}
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;
change_a_tile(&scene->data.tilemap, tile_idx, SOLID_TILE);
}
create_player(&scene->scene.ent_manager, &scene->scene.engine->assets);
update_entity_manager(&scene->scene.ent_manager);
}
void free_level_scene(LevelScene_t* scene)
void free_sandbox_scene(LevelScene_t* scene)
{
free_scene(&scene->scene);
for (size_t i = 0; i < scene->data.tilemap.n_tiles;i++)
{
all_tiles[i].solid = 0;
sc_map_term_64v(&all_tiles[i].entities_set);
}
term_level_scene_data(&scene->data);
}
void reload_level_scene(LevelScene_t* scene)
{
}

View File

@ -13,5 +13,7 @@ typedef enum ActionType
ACTION_CONFIRM,
ACTION_EXIT,
ACTION_RESTART,
ACTION_NEXTLEVEL,
ACTION_PREVLEVEL,
}ActionType_t;
#endif // __ACTIONS_H

View File

@ -1,12 +1,16 @@
#include "assets.h"
#include "assert.h"
#include <stdio.h>
#define MAX_TEXTURES 16
#define MAX_SPRITES 16
#define MAX_SPRITES 64
#define MAX_SOUNDS 16
#define MAX_FONTS 4
#define MAX_N_TILES 4096
#define MAX_NAME_LEN 32
uint8_t free_idx[4] = {0};
#define MAX_LEVEL_PACK 4
uint8_t n_loaded[5] = {0};
// Hard limit number of
typedef struct TextureData
@ -29,17 +33,31 @@ typedef struct SoundData
Sound sound;
char name[MAX_NAME_LEN];
}SoundData_t;
typedef struct LevelPackData
{
LevelPack_t pack;
char name[MAX_NAME_LEN];
}LevelPackData_t;
static TextureData_t textures[MAX_TEXTURES];
static FontData_t fonts[MAX_FONTS];
static SoundData_t sfx[MAX_SOUNDS];
static SpriteData_t sprites[MAX_SPRITES];
static LevelPackData_t levelpacks[MAX_LEVEL_PACK];
static void unload_level_pack(LevelPack_t pack)
{
for (uint8_t i = 0; i < pack.n_levels; ++i)
{
free(pack.levels[i].tiles);
}
free(pack.levels);
}
// Maybe need a circular buffer??
Texture2D* add_texture(Assets_t* assets, const char* name, const char* path)
{
uint8_t tex_idx = free_idx[0];
uint8_t tex_idx = n_loaded[0];
assert(tex_idx < MAX_TEXTURES);
Texture2D tex = LoadTexture(path);
if (tex.width == 0 || tex.height == 0) return NULL;
@ -47,59 +65,107 @@ Texture2D* add_texture(Assets_t* assets, const char* name, const char* path)
textures[tex_idx].texture = tex;
strncpy(textures[tex_idx].name, name, MAX_NAME_LEN);
sc_map_put_s64(&assets->m_textures, textures[tex_idx].name, tex_idx);
free_idx[0]++;
n_loaded[0]++;
return &textures[tex_idx].texture;
}
Sprite_t* add_sprite(Assets_t* assets, const char* name, Texture2D* texture)
{
uint8_t spr_idx = free_idx[1];
uint8_t spr_idx = n_loaded[1];
assert(spr_idx < MAX_SPRITES);
memset(sprites + spr_idx, 0, sizeof(Sprite_t));
sprites[spr_idx].sprite.texture = texture;
strncpy(sprites[spr_idx].name, name, MAX_NAME_LEN);
sc_map_put_s64(&assets->m_sprites, sprites[spr_idx].name, spr_idx);
free_idx[1]++;
n_loaded[1]++;
return &sprites[spr_idx].sprite;
}
Sound* add_sound(Assets_t* assets, const char* name, const char* path)
{
uint8_t snd_idx = free_idx[2];
uint8_t snd_idx = n_loaded[2];
assert(snd_idx < MAX_SOUNDS);
sfx[snd_idx].sound = LoadSound(path);
strncpy(sfx[snd_idx].name, name, MAX_NAME_LEN);
sc_map_put_s64(&assets->m_sounds, sfx[snd_idx].name, snd_idx);
free_idx[2]++;
n_loaded[2]++;
return &sfx[snd_idx].sound;
}
Font* add_font(Assets_t* assets, const char* name, const char* path)
{
uint8_t fnt_idx = free_idx[3];
uint8_t fnt_idx = n_loaded[3];
assert(fnt_idx < MAX_FONTS);
fonts[fnt_idx].font = LoadFont(path);
strncpy(fonts[fnt_idx].name, name, MAX_NAME_LEN);
sc_map_put_s64(&assets->m_fonts, fonts[fnt_idx].name, fnt_idx);
free_idx[3]++;
n_loaded[3]++;
return &fonts[fnt_idx].font;
}
LevelPack_t* add_level_pack(Assets_t* assets, const char* name, const char* path)
{
FILE* file = fopen(path, "rb");
if (file == NULL) return NULL;
LevelPackData_t* pack_info = levelpacks + n_loaded[4];
fread(&pack_info->pack.n_levels, sizeof(uint32_t), 1, file);
pack_info->pack.levels = calloc(pack_info->pack.n_levels, sizeof(LevelMap_t));
for (uint8_t i = 0; i < pack_info->pack.n_levels; ++i)
{
fread(pack_info->pack.levels[i].level_name, sizeof(char), 32, file);
fread(&pack_info->pack.levels[i].width, sizeof(uint16_t), 1, file);
fread(&pack_info->pack.levels[i].height, sizeof(uint16_t), 1, file);
uint32_t n_tiles = pack_info->pack.levels[i].width * pack_info->pack.levels[i].height;
pack_info->pack.levels[i].tiles = calloc(n_tiles, sizeof(LevelTileInfo_t));
fread(pack_info->pack.levels[i].tiles, 4, n_tiles, file);
}
fclose(file);
uint8_t pack_idx = n_loaded[4];
strncpy(pack_info->name, name, MAX_NAME_LEN);
sc_map_put_s64(&assets->m_levelpacks, levelpacks[pack_idx].name, pack_idx);
n_loaded[4]++;
return &levelpacks[pack_idx].pack;
}
void init_assets(Assets_t* assets)
{
sc_map_init_s64(&assets->m_fonts, MAX_FONTS, 0);
sc_map_init_s64(&assets->m_sprites, MAX_SPRITES, 0);
sc_map_init_s64(&assets->m_textures, MAX_TEXTURES, 0);
sc_map_init_s64(&assets->m_sounds, MAX_SOUNDS, 0);
sc_map_init_s64(&assets->m_levelpacks, MAX_LEVEL_PACK, 0);
}
void free_all_assets(Assets_t* assets)
{
for (uint8_t i = 0; i < n_loaded[0]; ++i)
{
UnloadTexture(textures[i].texture);
}
for (uint8_t i = 0; i < n_loaded[2]; ++i)
{
UnloadSound(sfx[i].sound);
}
for (uint8_t i = 0; i < n_loaded[3]; ++i)
{
UnloadFont(fonts[i].font);
}
for (uint8_t i = 0; i < n_loaded[4]; ++i)
{
unload_level_pack(levelpacks[i].pack);
}
sc_map_clear_s64(&assets->m_textures);
sc_map_clear_s64(&assets->m_fonts);
sc_map_clear_s64(&assets->m_sounds);
sc_map_clear_s64(&assets->m_sprites);
memset(free_idx, 0, sizeof(free_idx));
sc_map_clear_s64(&assets->m_levelpacks);
memset(n_loaded, 0, sizeof(n_loaded));
}
void term_assets(Assets_t* assets)
@ -109,6 +175,7 @@ void term_assets(Assets_t* assets)
sc_map_term_s64(&assets->m_fonts);
sc_map_term_s64(&assets->m_sounds);
sc_map_term_s64(&assets->m_sprites);
sc_map_term_s64(&assets->m_levelpacks);
}
Texture2D* get_texture(Assets_t* assets, const char* name)
@ -151,6 +218,16 @@ Font* get_font(Assets_t* assets, const char* name)
return NULL;
}
LevelPack_t* get_level_pack(Assets_t* assets, const char* name)
{
uint8_t pack_idx = sc_map_get_s64(&assets->m_levelpacks, name);
if (sc_map_found(&assets->m_levelpacks))
{
return &levelpacks[pack_idx].pack;
}
return NULL;
}
void draw_sprite(Sprite_t* spr, Vector2 pos, bool flip_x)
{
Rectangle rec = {

View File

@ -10,8 +10,30 @@ typedef struct Assets
struct sc_map_s64 m_sounds;
struct sc_map_s64 m_fonts;
struct sc_map_s64 m_sprites;
struct sc_map_s64 m_levelpacks;
}Assets_t;
typedef struct LevelTileInfo
{
uint8_t tile_type;
uint8_t entity_to_spawn;
uint8_t water;
uint8_t dummy[1];
}LevelTileInfo_t;
typedef struct LevelMap
{
char level_name[32];
uint16_t width;
uint16_t height;
LevelTileInfo_t* tiles;
}LevelMap_t;
typedef struct LevelPack
{
uint32_t n_levels;
LevelMap_t* levels;
}LevelPack_t;
void init_assets(Assets_t* assets);
void free_all_assets(Assets_t* assets);
@ -21,12 +43,13 @@ Texture2D* add_texture(Assets_t* assets, const char* name, const char* path);
Sprite_t* add_sprite(Assets_t* assets, const char* name, Texture2D* texture);
Sound* add_sound(Assets_t * assets, const char* name, const char* path);
Font* add_font(Assets_t* assets, const char* name, const char* path);
LevelPack_t* add_level_pack(Assets_t* assets, const char* name, const char* path);
Texture2D* get_texture(Assets_t* assets, const char* name);
Sprite_t* get_sprite(Assets_t* assets, const char* name);
Sound* get_sound(Assets_t* assets, const char* name);
Font* get_font(Assets_t* assets, const char* name);
LevelPack_t* get_level_pack(Assets_t* assets, const char* name);
void draw_sprite(Sprite_t* spr, Vector2 pos, bool flip_x);
#endif // __ASSETS_H

View File

@ -28,6 +28,7 @@ typedef struct TileGrid
unsigned int width;
unsigned int height;
unsigned int n_tiles;
unsigned int max_tiles;
unsigned int tile_size;
Tile_t* tiles;
}TileGrid_t;

421
scenes/game_scene.c 100644
View File

@ -0,0 +1,421 @@
#include "scene_impl.h"
#include "game_systems.h"
#include "water_flow.h"
#include "constants.h"
#include "ent_impl.h"
#include "mempool.h"
#include "raylib.h"
#include "raymath.h"
#include <stdio.h>
static Tile_t all_tiles[MAX_N_TILES] = {0};
static void level_scene_render_func(Scene_t* scene)
{
LevelSceneData_t* data = &(CONTAINER_OF(scene, LevelScene_t, scene)->data);
TileGrid_t tilemap = data->tilemap;
Entity_t* p_ent;
BeginTextureMode(data->game_viewport);
ClearBackground(WHITE);
BeginMode2D(data->cam);
for (size_t i = 0; i < tilemap.n_tiles; ++i)
{
char buffer[6] = {0};
int x = (i % tilemap.width) * TILE_SIZE;
int y = (i / tilemap.width) * TILE_SIZE;
sprintf(buffer, "%u", sc_map_size_64v(&tilemap.tiles[i].entities_set));
if (!tilemap.tiles[i].moveable)
{
// Draw water tile
Color water_colour = ColorAlpha(RED, 0.2);
DrawRectangle(x, y, TILE_SIZE, TILE_SIZE, water_colour);
}
if (data->tile_sprites[tilemap.tiles[i].tile_type] != NULL)
{
draw_sprite(data->tile_sprites[tilemap.tiles[i].tile_type], (Vector2){x,y}, false);
}
else 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, MAROON);
}
else if (tilemap.tiles[i].tile_type == LADDER)
{
DrawRectangle(x, y, TILE_SIZE, TILE_SIZE, ORANGE);
}
else if (tilemap.tiles[i].tile_type == SPIKES)
{
DrawRectangle(
x + tilemap.tiles[i].offset.x, y + tilemap.tiles[i].offset.y,
tilemap.tiles[i].size.x, tilemap.tiles[i].size.y, RED
);
}
if (tilemap.tiles[i].wet)
{
#define SURFACE_THICKNESS 4
int up = i - tilemap.width;
int bot = i + tilemap.width;
int right = i + 1;
int left = i - 1;
int bot_line = y + TILE_SIZE - tilemap.tiles[i].water_level * WATER_BBOX_STEP - SURFACE_THICKNESS / 2;
if (up >= 0 && tilemap.tiles[up].wet)
{
DrawLineEx((Vector2){x + TILE_SIZE / 2, y}, (Vector2){x + TILE_SIZE / 2, y + TILE_SIZE - tilemap.tiles[i].water_level * WATER_BBOX_STEP}, SURFACE_THICKNESS, ColorAlpha(BLUE, 0.7));
}
if (
bot <= tilemap.n_tiles
&& tilemap.tiles[i].water_level == 0
)
{
if (i % tilemap.width != 0 && tilemap.tiles[left].wet && (tilemap.tiles[bot].solid == SOLID || tilemap.tiles[bot-1].solid == SOLID))
{
DrawLineEx((Vector2){x, bot_line}, (Vector2){x + TILE_SIZE / 2, bot_line}, SURFACE_THICKNESS, ColorAlpha(BLUE, 0.7));
}
if (right % tilemap.width != 0 && tilemap.tiles[right].wet && (tilemap.tiles[bot].solid == SOLID || tilemap.tiles[bot+1].solid == SOLID))
{
DrawLineEx((Vector2){x + TILE_SIZE / 2, bot_line}, (Vector2){x + TILE_SIZE, bot_line}, SURFACE_THICKNESS, ColorAlpha(BLUE, 0.7));
}
}
}
// Draw water tile
uint32_t water_height = tilemap.tiles[i].water_level * WATER_BBOX_STEP;
// Draw water tile
Color water_colour = ColorAlpha(BLUE, 0.5);
DrawRectangle(
x,
y + (TILE_SIZE - water_height),
TILE_SIZE,
water_height,
water_colour
);
if (tilemap.tiles[i].max_water_level < MAX_WATER_LEVEL)
{
DrawRectangleLinesEx((Rectangle){x, y, TILE_SIZE, TILE_SIZE}, 2.0, ColorAlpha(BLUE, 0.5));
}
}
char buffer[64] = {0};
sc_map_foreach_value(&scene->ent_manager.entities, p_ent)
{
CTransform_t* p_ct = get_component(p_ent, CTRANSFORM_COMP_T);
CBBox_t* p_bbox = get_component(p_ent, CBBOX_COMP_T);
Color colour;
switch(p_ent->m_tag)
{
case PLAYER_ENT_TAG:
colour = RED;
break;
case CRATES_ENT_TAG:
colour = p_bbox->fragile? BROWN : GRAY;
break;
case BOULDER_ENT_TAG:
colour = GRAY;
break;
default:
colour = BLACK;
break;
}
if (p_bbox != NULL)
{
if (p_ent->m_tag == BOULDER_ENT_TAG)
{
DrawCircleV(Vector2Add(p_ct->position, p_bbox->half_size), p_bbox->half_size.x, colour);
}
else
{
DrawRectangle(p_ct->position.x, p_ct->position.y, p_bbox->size.x, p_bbox->size.y, colour);
}
if (p_ent->m_tag == CRATES_ENT_TAG)
{
CContainer_t* p_container = get_component(p_ent, CCONTAINER_T);
if (p_container != NULL)
{
switch (p_container->item)
{
case CONTAINER_LEFT_ARROW:
DrawLine(
p_ct->position.x,
p_ct->position.y + p_bbox->half_size.y,
p_ct->position.x + p_bbox->half_size.x,
p_ct->position.y + p_bbox->half_size.y,
BLACK
);
break;
case CONTAINER_RIGHT_ARROW:
DrawLine(
p_ct->position.x + p_bbox->half_size.x,
p_ct->position.y + p_bbox->half_size.y,
p_ct->position.x + p_bbox->size.x,
p_ct->position.y + p_bbox->half_size.y,
BLACK
);
break;
case CONTAINER_UP_ARROW:
DrawLine(
p_ct->position.x + p_bbox->half_size.x,
p_ct->position.y,
p_ct->position.x + p_bbox->half_size.x,
p_ct->position.y + p_bbox->half_size.y,
BLACK
);
break;
case CONTAINER_DOWN_ARROW:
DrawLine(
p_ct->position.x + p_bbox->half_size.x,
p_ct->position.y + p_bbox->half_size.y,
p_ct->position.x + p_bbox->half_size.x,
p_ct->position.y + p_bbox->size.y,
BLACK
);
break;
case CONTAINER_BOMB:
DrawCircleV(Vector2Add(p_ct->position, p_bbox->half_size), p_bbox->half_size.x, BLACK);
break;
default:
break;
}
}
}
}
CHurtbox_t* p_hurtbox = get_component(p_ent, CHURTBOX_T);
CHitBoxes_t* p_hitbox = get_component(p_ent, CHITBOXES_T);
if (p_hitbox != NULL)
{
for (uint8_t i = 0;i < p_hitbox->n_boxes; ++i)
{
Rectangle rec = {
.x = p_ct->position.x + p_hitbox->boxes[i].x,
.y = p_ct->position.y + p_hitbox->boxes[i].y,
.width = p_hitbox->boxes[i].width,
.height = p_hitbox->boxes[i].height,
};
DrawRectangleLinesEx(rec, 1.5, ORANGE);
}
}
if (p_hurtbox != NULL)
{
Rectangle rec = {
.x = p_ct->position.x + p_hurtbox->offset.x,
.y = p_ct->position.y + p_hurtbox->offset.y,
.width = p_hurtbox->size.x,
.height = p_hurtbox->size.y,
};
DrawRectangleLinesEx(rec, 1.5, PURPLE);
}
CSprite_t* p_cspr = get_component(p_ent, CSPRITE_T);
if (p_cspr != NULL)
{
const SpriteRenderInfo_t spr = p_cspr->sprites[p_cspr->current_idx];
if (spr.sprite != NULL)
{
Vector2 pos = Vector2Add(p_ct->position, spr.offset);
draw_sprite(spr.sprite, pos, p_cspr->flip_x);
}
}
}
sc_map_foreach_value(&scene->ent_manager.entities_map[DYNMEM_ENT_TAG], p_ent)
{
CWaterRunner_t* p_runner = get_component(p_ent, CWATERRUNNER_T);
unsigned int x = ((p_runner->current_tile) % tilemap.width) * tilemap.tile_size;
unsigned int y = ((p_runner->current_tile) / tilemap.width) * tilemap.tile_size;
DrawCircle(x+16, y+16, 8, ColorAlpha(BLUE, 0.6));
}
for (size_t i = 0; i < tilemap.n_tiles; ++i)
{
int x = (i % tilemap.width) * TILE_SIZE;
int y = (i / tilemap.width) * TILE_SIZE;
sprintf(buffer, "%u", sc_map_size_64v(&tilemap.tiles[i].entities_set));
if (tilemap.tiles[i].solid > 0)
{
DrawText(buffer, x, y, 10, WHITE);
}
else
{
// Draw water tile
DrawText(buffer, x, y, 10, BLACK);
}
}
// Draw tile grid
for (size_t i = 0; i < tilemap.width; ++i)
{
int x = (i+1)*TILE_SIZE;
DrawLine(x, 0, x, tilemap.height * TILE_SIZE, BLACK);
}
for (size_t i = 0; i < tilemap.height;++i)
{
int y = (i+1)*TILE_SIZE;
DrawLine(0, y, tilemap.width * TILE_SIZE, y, BLACK);
}
EndMode2D();
EndTextureMode();
Rectangle draw_rec = data->game_rec;
draw_rec.x = 0;
draw_rec.y = 0;
draw_rec.height *= -1;
BeginDrawing();
ClearBackground(LIGHTGRAY);
DrawTextureRec(
data->game_viewport.texture,
draw_rec,
(Vector2){data->game_rec.x, data->game_rec.y},
WHITE
);
// For DEBUG
const int gui_x = data->game_rec.x + data->game_rec.width + 10;
sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_ent)
{
CTransform_t* p_ct = get_component(p_ent, CTRANSFORM_COMP_T);
CJump_t* p_cjump = get_component(p_ent, CJUMP_COMP_T);
CPlayerState_t* p_pstate = get_component(p_ent, CPLAYERSTATE_T);
CMovementState_t* p_mstate = get_component(p_ent, CMOVEMENTSTATE_T);
sprintf(buffer, "Pos: %.3f\n %.3f", p_ct->position.x, p_ct->position.y);
DrawText(buffer, gui_x, 15, 12, BLACK);
sprintf(buffer, "Vel: %.3f\n %.3f", p_ct->velocity.x, p_ct->velocity.y);
DrawText(buffer, gui_x + 80, 15, 12, BLACK);
//sprintf(buffer, "Accel: %.3f\n %.3f", p_ct->accel.x, p_ct->accel.y);
//DrawText(buffer, tilemap.width * TILE_SIZE + 128, 60, 12, BLACK);
sprintf(buffer, "Jumps: %u", p_cjump->jumps);
DrawText(buffer, gui_x, 60, 12, BLACK);
sprintf(buffer, "Crouch: %u", p_pstate->is_crouch);
DrawText(buffer, gui_x, 90, 12, BLACK);
sprintf(buffer, "Water: %s", p_mstate->water_state & 1? "YES":"NO");
DrawText(buffer, gui_x, 120, 12, BLACK);
sprintf(buffer, "Ladder: %u", p_pstate->ladder_state);
DrawText(buffer, gui_x, 150, 12, BLACK);
}
//sprintf(buffer, "Spawn Entity: %s", get_spawn_selection_string(current_spawn_selection));
//DrawText(buffer, gui_x, 240, 12, BLACK);
sprintf(buffer, "Number of Entities: %u", sc_map_size_64v(&scene->ent_manager.entities));
DrawText(buffer, gui_x, 270, 12, BLACK);
sprintf(buffer, "FPS: %u", GetFPS());
DrawText(buffer, gui_x, 320, 12, BLACK);
static char mempool_stats[512];
print_mempool_stats(mempool_stats);
DrawText(mempool_stats, gui_x, 350, 12, BLACK);
EndDrawing();
}
void level_do_action(Scene_t* scene, ActionType_t action, bool pressed)
{
CPlayerState_t* p_playerstate;
sc_map_foreach_value(&scene->ent_manager.component_map[CPLAYERSTATE_T], p_playerstate)
{
switch(action)
{
case ACTION_UP:
p_playerstate->player_dir.y = (pressed)? -1 : 0;
break;
case ACTION_DOWN:
p_playerstate->player_dir.y = (pressed)? 1 : 0;
break;
case ACTION_LEFT:
p_playerstate->player_dir.x = (pressed)? -1 : 0;
break;
case ACTION_RIGHT:
p_playerstate->player_dir.x = (pressed)? 1 : 0;
break;
case ACTION_JUMP:
p_playerstate->jump_pressed = pressed;
break;
default:
break;
}
}
if (!pressed)
{
switch (action)
{
case ACTION_RESTART:
reload_level_tilemap((LevelScene_t*)scene);
break;
case ACTION_NEXTLEVEL:
load_next_level_tilemap((LevelScene_t*)scene);
break;
case ACTION_PREVLEVEL:
load_prev_level_tilemap((LevelScene_t*)scene);
break;
default:
break;
}
}
}
void init_game_scene(LevelScene_t* scene)
{
//init_scene(&scene->scene, LEVEL_SCENE, &level_scene_render_func, &level_do_action);
init_scene(&scene->scene, &level_scene_render_func, &level_do_action);
scene->data.tilemap.tiles = all_tiles;
init_level_scene_data(&scene->data, MAX_N_TILES, all_tiles);
create_player(&scene->scene.ent_manager, &scene->scene.engine->assets);
update_entity_manager(&scene->scene.ent_manager);
// insert level scene systems
sc_array_add(&scene->scene.systems, &update_tilemap_system);
sc_array_add(&scene->scene.systems, &player_movement_input_system);
sc_array_add(&scene->scene.systems, &player_bbox_update_system);
sc_array_add(&scene->scene.systems, &player_pushing_system);
sc_array_add(&scene->scene.systems, &friction_coefficient_update_system);
sc_array_add(&scene->scene.systems, &global_external_forces_system);
sc_array_add(&scene->scene.systems, &moveable_update_system);
sc_array_add(&scene->scene.systems, &movement_update_system);
sc_array_add(&scene->scene.systems, &boulder_destroy_wooden_tile_system);
sc_array_add(&scene->scene.systems, &update_tilemap_system);
sc_array_add(&scene->scene.systems, &tile_collision_system);
sc_array_add(&scene->scene.systems, &hitbox_update_system);
sc_array_add(&scene->scene.systems, &player_crushing_system);
sc_array_add(&scene->scene.systems, &spike_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, &lifetimer_update_system);
sc_array_add(&scene->scene.systems, &container_destroy_system);
sc_array_add(&scene->scene.systems, &sprite_animation_system);
sc_array_add(&scene->scene.systems, &camera_update_system);
sc_array_add(&scene->scene.systems, &player_dir_reset_system);
sc_array_add(&scene->scene.systems, &player_respawn_system);
sc_array_add(&scene->scene.systems, &update_water_runner_system);
// This avoid graphical glitch, not essential
//sc_array_add(&scene->scene.systems, &update_tilemap_system);
sc_map_put_64(&scene->scene.action_map, KEY_UP, ACTION_UP);
sc_map_put_64(&scene->scene.action_map, KEY_DOWN, ACTION_DOWN);
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_Q, ACTION_EXIT);
sc_map_put_64(&scene->scene.action_map, KEY_R, ACTION_RESTART);
sc_map_put_64(&scene->scene.action_map, KEY_RIGHT_BRACKET, ACTION_NEXTLEVEL);
sc_map_put_64(&scene->scene.action_map, KEY_LEFT_BRACKET, ACTION_PREVLEVEL);
}
void free_game_scene(LevelScene_t* scene)
{
free_scene(&scene->scene);
term_level_scene_data(&scene->data);
}

View File

@ -26,103 +26,6 @@ static inline unsigned int get_tile_idx(int x, int y, unsigned int tilemap_width
return tile_y * tilemap_width + tile_x;
}
void change_a_tile(TileGrid_t* tilemap, unsigned int tile_idx, TileType_t new_type)
{
TileType_t last_type = tilemap->tiles[tile_idx].tile_type;
tilemap->tiles[tile_idx].tile_type = new_type;
switch (new_type)
{
case EMPTY_TILE:
tilemap->tiles[tile_idx].solid = NOT_SOLID;
break;
case ONEWAY_TILE:
tilemap->tiles[tile_idx].solid = ONE_WAY;
break;
case LADDER:
{
int up_tile = tile_idx - tilemap->width;
if (up_tile > 0 && tilemap->tiles[up_tile].tile_type != LADDER)
{
tilemap->tiles[tile_idx].solid = ONE_WAY;
}
else
{
tilemap->tiles[tile_idx].solid = NOT_SOLID;
}
int down_tile = tile_idx + tilemap->width;
if (down_tile < tilemap->n_tiles && tilemap->tiles[down_tile].tile_type == LADDER)
{
tilemap->tiles[down_tile].solid = (tilemap->tiles[tile_idx].tile_type != LADDER)? ONE_WAY : NOT_SOLID;
}
}
break;
case SPIKES:
tilemap->tiles[tile_idx].solid = NOT_SOLID;
break;
case SOLID_TILE:
tilemap->tiles[tile_idx].solid = SOLID;
break;
}
if (last_type == LADDER && new_type != LADDER)
{
int down_tile = tile_idx + tilemap->width;
if (down_tile < tilemap->n_tiles && tilemap->tiles[down_tile].tile_type == LADDER)
{
tilemap->tiles[down_tile].solid = ONE_WAY;
}
}
if (new_type == SPIKES)
{
// Priority: Down, Up, Left, Right
if (tile_idx + tilemap->width < tilemap->n_tiles && tilemap->tiles[tile_idx + tilemap->width].tile_type == SOLID_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){0,16};
tilemap->tiles[tile_idx].size = (Vector2){32,16};
}
else if (tile_idx - tilemap->width >= 0 && tilemap->tiles[tile_idx - tilemap->width].tile_type == SOLID_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){0,0};
tilemap->tiles[tile_idx].size = (Vector2){32,16};
}
else if (tile_idx % tilemap->width != 0 && tilemap->tiles[tile_idx - 1].tile_type == SOLID_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){0,0};
tilemap->tiles[tile_idx].size = (Vector2){16,32};
}
else if ((tile_idx + 1) % tilemap->width != 0 && tilemap->tiles[tile_idx + 1].tile_type == SOLID_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){16,0};
tilemap->tiles[tile_idx].size = (Vector2){16,32};
}
else
{
tilemap->tiles[tile_idx].offset = (Vector2){0,16};
tilemap->tiles[tile_idx].size = (Vector2){32,16};
}
}
else if (new_type == ONEWAY_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){0,0};
tilemap->tiles[tile_idx].size = (Vector2){32,10};
}
else
{
tilemap->tiles[tile_idx].offset = (Vector2){0,0};
tilemap->tiles[tile_idx].size = (Vector2){32,32};
}
tilemap->tiles[tile_idx].moveable = (
tilemap->tiles[tile_idx].tile_type == EMPTY_TILE
|| tilemap->tiles[tile_idx].tile_type == SPIKES
);
tilemap->tiles[tile_idx].def = (tilemap->tiles[tile_idx].tile_type == SOLID_TILE) ? 5: 2;
}
// ------------------------- Collision functions ------------------------------------
// Do not subtract one for the size for any collision check, just pass normally. The extra one is important for AABB test
@ -1758,17 +1661,3 @@ void camera_update_system(Scene_t* scene)
if (min.x > 0) lvl_scene->data.cam.offset.x = width/2.0f - min.x;
if (min.y > 0) lvl_scene->data.cam.offset.y = height/2.0f - min.y;
}
void init_level_scene_data(LevelSceneData_t* data)
{
data->game_viewport = LoadRenderTexture(VIEWABLE_MAP_WIDTH*TILE_SIZE, VIEWABLE_MAP_HEIGHT*TILE_SIZE);
data->game_rec = (Rectangle){25, 25, VIEWABLE_MAP_WIDTH*TILE_SIZE, VIEWABLE_MAP_HEIGHT*TILE_SIZE};
data->cam = (Camera2D){0};
data->cam.rotation = 0.0f;
data->cam.zoom = 1.0f;
}
void term_level_scene_data(LevelSceneData_t* data)
{
UnloadRenderTexture(data->game_viewport); // Unload render texture
}

View File

@ -1,8 +1,6 @@
#ifndef __GAME_SYSTEMS_H
#define __GAME_SYSTEMS_H
#include "scene_impl.h"
void init_level_scene_data(LevelSceneData_t* data);
void term_level_scene_data(LevelSceneData_t* data);
void player_movement_input_system(Scene_t* scene);
void player_bbox_update_system(Scene_t* scene);
@ -26,5 +24,4 @@ void player_respawn_system(Scene_t* scene);
void lifetimer_update_system(Scene_t* scene);
void spike_collision_system(Scene_t* scene);
void change_a_tile(TileGrid_t* tilemap, unsigned int tile_idx, TileType_t new_type);
#endif // __GAME_SYSTEMS_H

View File

@ -2,12 +2,14 @@
#include "constants.h"
#include "raymath.h"
static SpriteRenderInfo_t item_sprite_map[2] = {0};
static SpriteRenderInfo_t item_sprite_map[3] = {0};
bool init_item_creation(Assets_t* assets)
{
item_sprite_map[0].sprite = get_sprite(assets, "w_crate");
item_sprite_map[1].sprite = get_sprite(assets, "m_crate");
item_sprite_map[2].sprite = get_sprite(assets, "arrow");
item_sprite_map[2].offset = (Vector2){-8, 4};
return true;
}
@ -85,6 +87,9 @@ Entity_t* create_arrow(EntityManager_t* ent_manager, Assets_t* assets, uint8_t d
p_ctransform->movement_mode = KINEMATIC_MOVEMENT;
p_ctransform->active = true;
CSprite_t* p_cspr = add_component(p_arrow, CSPRITE_T);
p_cspr->sprites = item_sprite_map;
p_cspr->current_idx = 2;
//p_hitbox->boxes[0] = (Rectangle){TILE_SIZE - 5, TILE_SIZE / 2 - 5, 5, 5};
switch(dir)
{

View File

@ -25,6 +25,8 @@ typedef struct LevelSceneData {
Rectangle game_rec;
Camera2D cam;
Sprite_t* tile_sprites[MAX_TILE_TYPES];
LevelPack_t* level_pack;
unsigned int current_level;
}LevelSceneData_t;
typedef struct LevelScene {
@ -32,9 +34,18 @@ typedef struct LevelScene {
LevelSceneData_t data;
}LevelScene_t;
void init_level_scene(LevelScene_t* scene);
void free_level_scene(LevelScene_t* scene);
void reload_level_scene(LevelScene_t* scene);
void init_game_scene(LevelScene_t* scene);
void free_game_scene(LevelScene_t* scene);
void init_sandbox_scene(LevelScene_t* scene);
void free_sandbox_scene(LevelScene_t* scene);
//void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* tiles, Rectangle view_zone);
void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* tiles);
void term_level_scene_data(LevelSceneData_t* data);
void reload_level_tilemap(LevelScene_t* scene);
void load_next_level_tilemap(LevelScene_t* scene);
void load_prev_level_tilemap(LevelScene_t* scene);
bool load_level_tilemap(LevelScene_t* scene, unsigned int level_num);
void change_a_tile(TileGrid_t* tilemap, unsigned int tile_idx, TileType_t new_type);
typedef enum GuiMode {
KEYBOARD_MODE,
@ -55,4 +66,5 @@ typedef struct MenuScene {
void init_menu_scene(MenuScene_t* scene);
void free_menu_scene(MenuScene_t* scene);
#endif // __SCENE_IMPL_H

View File

@ -0,0 +1,217 @@
#include "scene_impl.h"
#include "ent_impl.h"
#include "constants.h"
void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* tiles)
{
data->game_viewport = LoadRenderTexture(VIEWABLE_MAP_WIDTH*TILE_SIZE, VIEWABLE_MAP_HEIGHT*TILE_SIZE);
data->game_rec = (Rectangle){25, 25, VIEWABLE_MAP_WIDTH*TILE_SIZE, VIEWABLE_MAP_HEIGHT*TILE_SIZE};
data->cam = (Camera2D){0};
data->cam.rotation = 0.0f;
data->cam.zoom = 1.0f;
data->tilemap.max_tiles = max_tiles;
if (tiles != NULL)
{
data->tilemap.tiles = tiles;
}
else
{
data->tilemap.tiles = calloc(max_tiles, sizeof(Tile_t));
}
data->tilemap.width = DEFAULT_MAP_WIDTH;
data->tilemap.height = DEFAULT_MAP_HEIGHT;
data->tilemap.tile_size = TILE_SIZE;
data->tilemap.n_tiles = data->tilemap.width * data->tilemap.height;
memset(data->tile_sprites, 0, sizeof(data->tile_sprites));
for (size_t i = 0; i < max_tiles;i++)
{
data->tilemap.tiles[i].solid = NOT_SOLID;
data->tilemap.tiles[i].tile_type = EMPTY_TILE;
data->tilemap.tiles[i].moveable = true;
data->tilemap.tiles[i].max_water_level = 4;
sc_map_init_64v(&data->tilemap.tiles[i].entities_set, 16, 0);
data->tilemap.tiles[i].size = (Vector2){TILE_SIZE, TILE_SIZE};
}
}
void term_level_scene_data(LevelSceneData_t* data)
{
for (size_t i = 0; i < data->tilemap.max_tiles;i++)
{
sc_map_term_64v(&data->tilemap.tiles[i].entities_set);
}
UnloadRenderTexture(data->game_viewport); // Unload render texture
}
bool load_level_tilemap(LevelScene_t* scene, unsigned int level_num)
{
if (level_num >= scene->data.level_pack->n_levels) return false;
LevelMap_t lvl_map = scene->data.level_pack->levels[level_num];
uint32_t n_tiles = lvl_map.width * lvl_map.height;
if (n_tiles > scene->data.tilemap.max_tiles) return false;
scene->data.current_level = level_num;
scene->data.tilemap.width = lvl_map.width;
scene->data.tilemap.height = lvl_map.height;
scene->data.tilemap.n_tiles = n_tiles;
clear_entity_manager(&scene->scene.ent_manager);
for (size_t i = 0; i < scene->data.tilemap.n_tiles;i++)
{
scene->data.tilemap.tiles[i].max_water_level = 4;
scene->data.tilemap.tiles[i].solid = NOT_SOLID;
scene->data.tilemap.tiles[i].tile_type = EMPTY_TILE;
scene->data.tilemap.tiles[i].moveable = true;
scene->data.tilemap.tiles[i].size = (Vector2){TILE_SIZE, TILE_SIZE};
sc_map_clear_64v(&scene->data.tilemap.tiles[i].entities_set);
switch (lvl_map.tiles[i].tile_type)
{
case 1:
change_a_tile(&scene->data.tilemap, i, SOLID_TILE);
break;
default:
break;
}
switch (lvl_map.tiles[i].entity_to_spawn)
{
case 1:
{
Entity_t* ent = create_player(&scene->scene.ent_manager, &scene->scene.engine->assets);
CTransform_t* p_ct = get_component(ent, CTRANSFORM_COMP_T);
p_ct->position.x = (i % scene->data.tilemap.width) * scene->data.tilemap.tile_size;
p_ct->position.y = (i / scene->data.tilemap.width) * scene->data.tilemap.tile_size;
}
break;
default:
break;
}
scene->data.tilemap.tiles[i].water_level = lvl_map.tiles[i].water;
}
return true;
}
void reload_level_tilemap(LevelScene_t* scene)
{
load_level_tilemap(scene, scene->data.current_level);
}
void load_next_level_tilemap(LevelScene_t* scene)
{
unsigned int lvl = scene->data.current_level;
lvl++;
if (lvl < scene->data.level_pack->n_levels)
{
load_level_tilemap(scene, lvl);
}
}
void load_prev_level_tilemap(LevelScene_t* scene)
{
unsigned int lvl = scene->data.current_level;
lvl--;
if (lvl >= 0)
{
load_level_tilemap(scene, lvl);
}
}
void change_a_tile(TileGrid_t* tilemap, unsigned int tile_idx, TileType_t new_type)
{
TileType_t last_type = tilemap->tiles[tile_idx].tile_type;
tilemap->tiles[tile_idx].tile_type = new_type;
switch (new_type)
{
case EMPTY_TILE:
tilemap->tiles[tile_idx].solid = NOT_SOLID;
break;
case ONEWAY_TILE:
tilemap->tiles[tile_idx].solid = ONE_WAY;
break;
case LADDER:
{
int up_tile = tile_idx - tilemap->width;
if (up_tile > 0 && tilemap->tiles[up_tile].tile_type != LADDER)
{
tilemap->tiles[tile_idx].solid = ONE_WAY;
}
else
{
tilemap->tiles[tile_idx].solid = NOT_SOLID;
}
int down_tile = tile_idx + tilemap->width;
if (down_tile < tilemap->n_tiles && tilemap->tiles[down_tile].tile_type == LADDER)
{
tilemap->tiles[down_tile].solid = (tilemap->tiles[tile_idx].tile_type != LADDER)? ONE_WAY : NOT_SOLID;
}
}
break;
case SPIKES:
tilemap->tiles[tile_idx].solid = NOT_SOLID;
break;
case SOLID_TILE:
tilemap->tiles[tile_idx].solid = SOLID;
break;
}
if (last_type == LADDER && new_type != LADDER)
{
int down_tile = tile_idx + tilemap->width;
if (down_tile < tilemap->n_tiles && tilemap->tiles[down_tile].tile_type == LADDER)
{
tilemap->tiles[down_tile].solid = ONE_WAY;
}
}
if (new_type == SPIKES)
{
// Priority: Down, Up, Left, Right
if (tile_idx + tilemap->width < tilemap->n_tiles && tilemap->tiles[tile_idx + tilemap->width].tile_type == SOLID_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){0,16};
tilemap->tiles[tile_idx].size = (Vector2){32,16};
}
else if (tile_idx - tilemap->width >= 0 && tilemap->tiles[tile_idx - tilemap->width].tile_type == SOLID_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){0,0};
tilemap->tiles[tile_idx].size = (Vector2){32,16};
}
else if (tile_idx % tilemap->width != 0 && tilemap->tiles[tile_idx - 1].tile_type == SOLID_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){0,0};
tilemap->tiles[tile_idx].size = (Vector2){16,32};
}
else if ((tile_idx + 1) % tilemap->width != 0 && tilemap->tiles[tile_idx + 1].tile_type == SOLID_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){16,0};
tilemap->tiles[tile_idx].size = (Vector2){16,32};
}
else
{
tilemap->tiles[tile_idx].offset = (Vector2){0,16};
tilemap->tiles[tile_idx].size = (Vector2){32,16};
}
}
else if (new_type == ONEWAY_TILE)
{
tilemap->tiles[tile_idx].offset = (Vector2){0,0};
tilemap->tiles[tile_idx].size = (Vector2){32,10};
}
else
{
tilemap->tiles[tile_idx].offset = (Vector2){0,0};
tilemap->tiles[tile_idx].size = (Vector2){32,32};
}
tilemap->tiles[tile_idx].moveable = (
tilemap->tiles[tile_idx].tile_type == EMPTY_TILE
|| tilemap->tiles[tile_idx].tile_type == SPIKES
);
tilemap->tiles[tile_idx].def = (tilemap->tiles[tile_idx].tile_type == SOLID_TILE) ? 5: 2;
}

View File

@ -9,7 +9,6 @@
#include <stdio.h>
#include <unistd.h>
#define MAX_N_TILES 4096
static Tile_t all_tiles[MAX_N_TILES] = {0};
// Maintain own queue to handle key presses
@ -193,7 +192,6 @@ static void level_scene_render_func(Scene_t* scene)
);
EndDrawing();
}
#define MAX_N_TILES 4096
static inline unsigned int get_tile_idx(int x, int y, const TileGrid_t* tilemap)
{
@ -421,24 +419,9 @@ int main(void)
LevelScene_t scene;
scene.scene.engine = &engine;
init_scene(&scene.scene, &level_scene_render_func, &level_do_action);
init_level_scene_data(&scene.data);
scene.data.tilemap.width = DEFAULT_MAP_WIDTH;
scene.data.tilemap.height = DEFAULT_MAP_HEIGHT;
scene.data.tilemap.tile_size = TILE_SIZE;
scene.data.tilemap.n_tiles = scene.data.tilemap.width * scene.data.tilemap.height;
init_level_scene_data(&scene.data, MAX_N_TILES, all_tiles);
assert(scene.data.tilemap.n_tiles <= MAX_N_TILES);
scene.data.tilemap.tiles = all_tiles;
memset(scene.data.tile_sprites, 0, sizeof(scene.data.tile_sprites));
for (size_t i = 0; i < scene.data.tilemap.n_tiles;i++)
{
all_tiles[i].solid = NOT_SOLID;
all_tiles[i].tile_type = EMPTY_TILE;
all_tiles[i].moveable = true;
all_tiles[i].max_water_level = 4;
sc_map_init_64v(&all_tiles[i].entities_set, 16, 0);
all_tiles[i].size = (Vector2){TILE_SIZE, TILE_SIZE};
}
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;
@ -519,11 +502,6 @@ int main(void)
free_water_runner(ent, &scene.scene.ent_manager);
}
free_scene(&scene.scene);
for (size_t i = 0; i < scene.data.tilemap.n_tiles;i++)
{
all_tiles[i].solid = 0;
sc_map_term_64v(&all_tiles[i].entities_set);
}
term_level_scene_data(&scene.data);
sc_queue_term(&key_buffer);
term_assets(&engine.assets);