Compare commits
No commits in common. "main" and "level_select" have entirely different histories.
main
...
level_sele
|
@ -4,4 +4,3 @@ release/
|
|||
web/
|
||||
compile_commands.json
|
||||
.gdb_history
|
||||
heaptrack.*
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "tracy"]
|
||||
path = tracy
|
||||
url = https://github.com/wolfpld/tracy.git
|
227
CMakeLists.txt
227
CMakeLists.txt
|
@ -2,26 +2,18 @@ set(PROJECT_NAME HATPC_remake)
|
|||
set(CMAKE_C_COMPILER clang)
|
||||
set(CMAKE_C_FLAGS "-Wall -Wextra")
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
project(${PROJECT_NAME} C CXX)
|
||||
project(${PROJECT_NAME} C)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(RAYLIB_DIR /usr/local/lib CACHE FILEPATH "directory to Raylib")
|
||||
set(LIBZSTD_DIR /usr/local/lib CACHE FILEPATH "directory to zstd")
|
||||
option(RUN_PROFILER OFF)
|
||||
option(INCLUDE_ASAN ON)
|
||||
option(EXPORT_MMAP OFF)
|
||||
option(BUILD_EXTRAS OFF)
|
||||
|
||||
# If you want to use Heaptrack to profile the memory
|
||||
# Do not compile in ASAN
|
||||
|
||||
if (EMSCRIPTEN)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_WEB")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -s MIN_WEBGL_VERSION=2 -s MAX_WEBGL_VERSION=2 -s TOTAL_MEMORY=16777216 -s TOTAL_STACK=1048576 --preload-file ./res ")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPLATFORM_WEB")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -s TOTAL_MEMORY=16777216 -s TOTAL_STACK=1048576 --preload-file ./res ")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".html")
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".html")
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_BUILD_TYPE} STREQUAL tile16)
|
||||
|
@ -32,71 +24,164 @@ set(GAME_LIBS
|
|||
lib_scenes
|
||||
)
|
||||
|
||||
if (${RUN_PROFILER})
|
||||
set(GAME_LIBS
|
||||
lib_scenes
|
||||
pthread
|
||||
dl
|
||||
)
|
||||
endif()
|
||||
|
||||
add_subdirectory(engine)
|
||||
add_subdirectory(scenes)
|
||||
if (NOT EMSCRIPTEN)
|
||||
add_subdirectory(res)
|
||||
endif ()
|
||||
|
||||
macro(add_target_exe name)
|
||||
add_executable(${name}
|
||||
${name}.c
|
||||
tracy/public/TracyClient.cpp
|
||||
)
|
||||
target_include_directories(${name}
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
PUBLIC
|
||||
tracy/public/
|
||||
)
|
||||
if (RUN_PROFILER)
|
||||
target_compile_definitions(${name}
|
||||
PUBLIC
|
||||
TRACY_ENABLE
|
||||
TRACY_ON_DEMAND
|
||||
)
|
||||
endif()
|
||||
add_executable(${PROJECT_NAME}
|
||||
main.c
|
||||
)
|
||||
|
||||
if (NOT EMSCRIPTEN)
|
||||
if (INCLUDE_ASAN)
|
||||
target_compile_options(${name} PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_options(${name} PRIVATE -fsanitize=address -gdwarf-4)
|
||||
endif ()
|
||||
if (EXPORT_MMAP)
|
||||
target_link_options(${name} PRIVATE -Xlinker -Map=scene_test.map)
|
||||
endif()
|
||||
endif ()
|
||||
target_link_libraries(${name}
|
||||
PUBLIC
|
||||
${GAME_LIBS}
|
||||
)
|
||||
endmacro()
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
add_target_exe(main)
|
||||
add_target_exe(level_test)
|
||||
add_target_exe(scene_test)
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
${GAME_LIBS}
|
||||
)
|
||||
add_executable(scene_test
|
||||
scene_test.c
|
||||
)
|
||||
|
||||
target_include_directories(scene_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
if (NOT EMSCRIPTEN)
|
||||
if (BUILD_EXTRAS AND NOT RUN_PROFILER)
|
||||
add_target_exe(entManager_test)
|
||||
add_target_exe(water_test)
|
||||
add_target_exe(level_load_test)
|
||||
add_target_exe(menu_test)
|
||||
add_target_exe(assets_test)
|
||||
add_target_exe(particle_test)
|
||||
add_target_exe(scene_man_test)
|
||||
add_target_exe(level_select_test)
|
||||
endif()
|
||||
if (BUILD_TESTING)
|
||||
find_package(cmocka 1.1.0 REQUIRED)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
target_compile_options(scene_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_options(scene_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
endif ()
|
||||
target_link_libraries(scene_test
|
||||
${GAME_LIBS}
|
||||
)
|
||||
|
||||
|
||||
if (NOT EMSCRIPTEN)
|
||||
|
||||
add_executable(EntManager_test
|
||||
entManager_test.c
|
||||
)
|
||||
target_compile_options(EntManager_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_options(EntManager_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_include_directories(EntManager_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_link_libraries(EntManager_test
|
||||
${GAME_LIBS}
|
||||
)
|
||||
|
||||
|
||||
add_executable(scene_test_mem
|
||||
scene_test.c
|
||||
)
|
||||
target_include_directories(scene_test_mem
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_link_options(scene_test_mem PRIVATE -Xlinker -Map=scene_test.map)
|
||||
|
||||
target_link_libraries(scene_test_mem
|
||||
${GAME_LIBS}
|
||||
)
|
||||
|
||||
add_executable(water_test
|
||||
water_test.c
|
||||
)
|
||||
|
||||
target_include_directories(water_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_link_libraries(water_test
|
||||
${GAME_LIBS}
|
||||
)
|
||||
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
|
||||
)
|
||||
target_include_directories(menu_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_compile_options(menu_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_options(menu_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_libraries(menu_test
|
||||
${GAME_LIBS}
|
||||
)
|
||||
|
||||
add_executable(assets_test
|
||||
assets_test.c
|
||||
)
|
||||
target_include_directories(assets_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_compile_options(assets_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_options(assets_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_libraries(assets_test
|
||||
${GAME_LIBS}
|
||||
)
|
||||
|
||||
add_executable(particle_test
|
||||
particle_test.c
|
||||
)
|
||||
target_include_directories(particle_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_compile_options(particle_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_options(particle_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_libraries(particle_test
|
||||
${GAME_LIBS}
|
||||
)
|
||||
|
||||
add_executable(scene_man_test
|
||||
scene_man_test.c
|
||||
)
|
||||
target_include_directories(scene_man_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_compile_options(scene_man_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_options(scene_man_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_libraries(scene_man_test
|
||||
${GAME_LIBS}
|
||||
)
|
||||
add_executable(level_select_test
|
||||
level_select_test.c
|
||||
)
|
||||
target_include_directories(level_select_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
target_compile_options(level_select_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_options(level_select_test PRIVATE -fsanitize=address -gdwarf-4)
|
||||
target_link_libraries(level_select_test
|
||||
${GAME_LIBS}
|
||||
)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
find_package(cmocka 1.1.0 REQUIRED)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
endif()
|
||||
|
|
18
README.md
18
README.md
|
@ -11,13 +11,13 @@ The goal of the project is to make a game similar to Hannah and The Pirate Caves
|
|||
## Implementation Notes
|
||||
As mentioned, this is mostly a learning experience, so certain things are implemented for the sake of learning. However, there are certain things that I didn't bother with because dealing with them will open up another can of worms. Either that or I find it too large of a feature to implement on my own without hating my existance. For these, I will use libraries.
|
||||
|
||||
As this point of time (24/08/2024), these are the things I won't bother for now:
|
||||
As this point of time (23/11/2023), these are the things I won't bother for now:
|
||||
- Game rendering: I remember dealing with OpenGL for a little bit and it being a not-so-pleasant experience. This is also a large topic on its own too.
|
||||
- Camera System: This is an interesting one. I would really like to implement this. However, this is sort of tied to game rendering, so no.
|
||||
- Windows and raw input handling: Not keen on this.
|
||||
- GUI: I'm not about to roll my own GUI library for this. I'll do a lite version, but that's about it.
|
||||
- GUI: I'm not about to roll my own GUI library for this.
|
||||
- Data structures: Will only do it for specific reasons. Otherwise, use a library.
|
||||
- Level editor: ... maybe. I already have a sandbox, so maybe I can turn that into an editor lite??? Won't think too much about it for now.
|
||||
- Level editor: ... no. This is more towards GUI design which I'm not currently keen on.
|
||||
|
||||
Libraries/Tools used:
|
||||
- _raylib_ \[[link](https://github.com/raysan5/raylib)\] + _raygui_ \[[link](https://github.com/raysan5/raygui)\]: MVP of this project. Basically the backbone of the game. I've use it for some past projects and it's always a pleasant experience. Can recommend!
|
||||
|
@ -29,16 +29,14 @@ Libraries/Tools used:
|
|||
- _LDtk_ \[[link](https://ldtk.io/)\]: A nice level editor. I haven't use it to its fullest extent, but definitely having a good experience so far.
|
||||
- _Aseprite_ \[[link](https://www.aseprite.org/)\]: Used it to create sprites. Good tool!
|
||||
- _Emscripten_ \[[link](https://emscripten.org/)\]: For web build. It's really a marvel of technology!
|
||||
- _heaptrack_ \[[link](https://github.com/KDE/heaptrack)\]: For heap profiling. Simple and straightforward to use.
|
||||
|
||||
## Progress
|
||||
The engine features:
|
||||
- An Entity-Component framework with an Entity Manager + memory pool that is specific for this project
|
||||
- AABB collision system + Grid-based Broad phase collision detection
|
||||
- Scene tree management and transition
|
||||
- Scene management and transition
|
||||
- Assets management and sprite transition
|
||||
- Simple level loading
|
||||
- Simple Particle effects management
|
||||
|
||||
Current progress:
|
||||
- Simple main menu + sandbox scene
|
||||
|
@ -49,6 +47,7 @@ Current progress:
|
|||
- Chest and Level Ending
|
||||
- Arrows and dynamites
|
||||
- Water filling
|
||||
- Simple Particle Effects
|
||||
- Sound Effects
|
||||
- Simple Camera Update System
|
||||
- Demo level pack loading
|
||||
|
@ -69,12 +68,5 @@ You may also turn off `BUILD_TESTING` to avoid building the tests.
|
|||
|
||||
There are also other binaries generated for testing purposes. Feel free to try them out if you manage to build them.
|
||||
|
||||
## Debugging && Profiling
|
||||
All binaries except the _main_ one are built with ASAN, which helps to detect memory leakage.
|
||||
|
||||
_Heaptrack_ is used to do so for the main program to keep for memory leakage + heap usage. From my experience, it doesn't work with ASAN.
|
||||
|
||||
I'm looking for runtime profiler. Current candidates are: _Orbit_ and _Tracy_. For small-ish gameplay, the program still runs fine.
|
||||
|
||||
## Note on assets
|
||||
This repository will not contain the assets used in the game, such as fonts, art, and sfx. However, the program should still run without those. Assets are placed in the _res/_ directory.
|
||||
|
|
|
@ -1,43 +1,34 @@
|
|||
add_subdirectory(sc)
|
||||
add_library(lib_assets STATIC
|
||||
add_library(lib_engine STATIC
|
||||
assets.c
|
||||
AABB.c
|
||||
gui.c
|
||||
engine.c
|
||||
collisions.c
|
||||
rres.c
|
||||
mempool.c
|
||||
entManager.c
|
||||
particle_sys.c
|
||||
)
|
||||
target_include_directories(lib_assets
|
||||
target_include_directories(lib_engine
|
||||
PRIVATE
|
||||
${LIBZSTD_DIR}/include
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${RAYLIB_DIR}/include
|
||||
)
|
||||
target_link_directories(lib_assets
|
||||
target_link_directories(lib_engine
|
||||
PUBLIC
|
||||
${RAYLIB_DIR}/lib
|
||||
${LIBZSTD_DIR}/lib
|
||||
)
|
||||
target_link_libraries(lib_assets
|
||||
target_link_libraries(lib_engine
|
||||
PUBLIC
|
||||
zstd
|
||||
raylib
|
||||
sc_queue
|
||||
sc_map
|
||||
m
|
||||
)
|
||||
|
||||
add_library(lib_engine OBJECT
|
||||
AABB.c
|
||||
gui.c
|
||||
engine.c
|
||||
collisions.c
|
||||
mempool.c
|
||||
entManager.c
|
||||
render_queue.c
|
||||
)
|
||||
target_link_libraries(lib_engine
|
||||
PUBLIC
|
||||
lib_assets
|
||||
sc_heap
|
||||
sc_map
|
||||
sc_array
|
||||
m
|
||||
)
|
||||
|
|
247
engine/EC.h
247
engine/EC.h
|
@ -11,39 +11,36 @@
|
|||
typedef struct EntityManager EntityManager_t;
|
||||
typedef struct Entity Entity_t;
|
||||
|
||||
typedef enum AnchorPoint {
|
||||
AP_TOP_LEFT,
|
||||
AP_TOP_CENTER,
|
||||
AP_TOP_RIGHT,
|
||||
AP_MID_LEFT,
|
||||
AP_MID_CENTER,
|
||||
AP_MID_RIGHT,
|
||||
AP_BOT_LEFT,
|
||||
AP_BOT_CENTER,
|
||||
AP_BOT_RIGHT,
|
||||
} AnchorPoint_t;
|
||||
typedef enum ComponentEnum {
|
||||
CBBOX_COMP_T = 0,
|
||||
CTRANSFORM_COMP_T,
|
||||
CTILECOORD_COMP_T,
|
||||
CMOVEMENTSTATE_T,
|
||||
CJUMP_COMP_T,
|
||||
CPLAYERSTATE_T,
|
||||
CCONTAINER_T,
|
||||
CHITBOXES_T,
|
||||
CHURTBOX_T,
|
||||
CSPRITE_T,
|
||||
CMOVEABLE_T,
|
||||
CLIFETIMER_T,
|
||||
CWATERRUNNER_T,
|
||||
CAIRTIMER_T,
|
||||
CEMITTER_T,
|
||||
} ComponentEnum_t;
|
||||
|
||||
typedef enum MovementMode {
|
||||
REGULAR_MOVEMENT = 0,
|
||||
KINEMATIC_MOVEMENT,
|
||||
}MovementMode_t;
|
||||
|
||||
/** Fundamental components:
|
||||
// - Transform
|
||||
// - BBox
|
||||
// - TileCoords
|
||||
**/
|
||||
/** The component enums are purely a index store. Here, there are 3 basic component, that is necessary for the engine to function (mostly collisions)
|
||||
* To extend the component list, define another set of enums as pure integer store and begin the enum at N_BASIC_COMPS
|
||||
* These integers are also used by the component mempool as indices. Thus, the mempool must have the first 3 components as the basic components
|
||||
**/
|
||||
#define N_BASIC_COMPS 3
|
||||
|
||||
enum BasicComponentEnum {
|
||||
CBBOX_COMP_T = 0,
|
||||
CTRANSFORM_COMP_T,
|
||||
CTILECOORD_COMP_T,
|
||||
};
|
||||
typedef struct _CBBox_t {
|
||||
Vector2 size;
|
||||
Vector2 offset;
|
||||
Vector2 half_size;
|
||||
bool solid;
|
||||
bool fragile;
|
||||
} CBBox_t;
|
||||
|
||||
typedef struct _CTransform_t {
|
||||
Vector2 prev_position;
|
||||
|
@ -54,26 +51,17 @@ typedef struct _CTransform_t {
|
|||
Vector2 shape_factor;
|
||||
float grav_delay;
|
||||
float grav_timer;
|
||||
float bounce_coeff;
|
||||
MovementMode_t movement_mode;
|
||||
bool active;
|
||||
} CTransform_t;
|
||||
|
||||
typedef struct _CBBox_t {
|
||||
Vector2 size;
|
||||
Vector2 offset;
|
||||
Vector2 half_size;
|
||||
bool solid;
|
||||
bool fragile;
|
||||
} CBBox_t;
|
||||
typedef struct _CMovementState_t {
|
||||
uint8_t ground_state;
|
||||
uint8_t water_state;
|
||||
uint8_t x_dir;
|
||||
float water_overlap;
|
||||
} CMovementState_t;
|
||||
|
||||
static inline void set_bbox(CBBox_t* p_bbox, unsigned int x, unsigned int y)
|
||||
{
|
||||
p_bbox->size.x = x;
|
||||
p_bbox->size.y = y;
|
||||
p_bbox->half_size.x = (unsigned int)(x / 2);
|
||||
p_bbox->half_size.y = (unsigned int)(y / 2);
|
||||
}
|
||||
// This is to store the occupying tiles
|
||||
// Limits to store 4 tiles at a tile,
|
||||
// Thus the size of the entity cannot be larger than the tile
|
||||
|
@ -82,7 +70,174 @@ typedef struct _CTileCoord_t {
|
|||
unsigned int n_tiles;
|
||||
} CTileCoord_t;
|
||||
|
||||
typedef struct _CJump_t {
|
||||
int jump_speed;
|
||||
uint8_t jumps;
|
||||
uint8_t max_jumps;
|
||||
uint8_t coyote_timer;
|
||||
bool jumped;
|
||||
bool jump_ready;
|
||||
bool short_hop;
|
||||
bool jump_released;
|
||||
} CJump_t;
|
||||
|
||||
typedef enum PlayerState {
|
||||
GROUNDED,
|
||||
AIR,
|
||||
} PlayerState_t;
|
||||
|
||||
typedef struct _CPlayerState_t {
|
||||
Vector2 player_dir;
|
||||
uint8_t jump_pressed;
|
||||
uint8_t is_crouch;
|
||||
bool ladder_state;
|
||||
} CPlayerState_t;
|
||||
|
||||
typedef enum ContainerItem {
|
||||
CONTAINER_EMPTY,
|
||||
CONTAINER_LEFT_ARROW,
|
||||
CONTAINER_RIGHT_ARROW,
|
||||
CONTAINER_UP_ARROW,
|
||||
CONTAINER_DOWN_ARROW,
|
||||
CONTAINER_COIN,
|
||||
CONTAINER_BOMB,
|
||||
CONTAINER_EXPLOSION,
|
||||
} ContainerItem_t;
|
||||
|
||||
typedef enum ContainerMaterial {
|
||||
WOODEN_CONTAINER,
|
||||
METAL_CONTAINER,
|
||||
} ContainerMaterial_t;
|
||||
|
||||
typedef struct _CContainer_t {
|
||||
ContainerMaterial_t material;
|
||||
ContainerItem_t item;
|
||||
} CContainer_t;
|
||||
|
||||
typedef struct _CHitBoxes_t {
|
||||
Rectangle boxes[2];
|
||||
uint8_t n_boxes;
|
||||
uint8_t atk;
|
||||
bool one_hit;
|
||||
} CHitBoxes_t;
|
||||
|
||||
typedef struct _CHurtbox_t {
|
||||
Vector2 offset;
|
||||
Vector2 size;
|
||||
uint8_t def;
|
||||
unsigned int damage_src;
|
||||
} CHurtbox_t;
|
||||
|
||||
typedef struct _CLifeTimer_t {
|
||||
float life_time;
|
||||
} CLifeTimer_t;
|
||||
|
||||
typedef struct _CAirTimer_t {
|
||||
float max_ftimer;
|
||||
float curr_ftimer;
|
||||
float decay_rate;
|
||||
uint8_t max_count;
|
||||
uint8_t curr_count;
|
||||
} CAirTimer_t;
|
||||
|
||||
typedef struct _BFSTile {
|
||||
int32_t to;
|
||||
int32_t from;
|
||||
bool reachable;
|
||||
}BFSTile_t;
|
||||
|
||||
typedef struct _BFSTileMap {
|
||||
BFSTile_t* tilemap;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t len;
|
||||
}BFSTileMap_t;
|
||||
|
||||
typedef enum _WaterRunnerState
|
||||
{
|
||||
BFS_RESET = 0,
|
||||
BFS_START,
|
||||
LOWEST_POINT_SEARCH,
|
||||
LOWEST_POINT_MOVEMENT,
|
||||
REACHABILITY_SEARCH,
|
||||
SCANLINE_FILL,
|
||||
FILL_COMPLETE,
|
||||
}WaterRunerState_t;
|
||||
|
||||
typedef struct _CWaterRunner {
|
||||
BFSTileMap_t bfs_tilemap;
|
||||
WaterRunerState_t state;
|
||||
struct sc_queue_32 bfs_queue;
|
||||
bool* visited;
|
||||
int32_t current_tile;
|
||||
int32_t target_tile;
|
||||
int32_t fill_idx;
|
||||
int16_t fill_range[2];
|
||||
uint8_t movement_delay;
|
||||
int8_t movement_speed;
|
||||
int16_t counter;
|
||||
float fractional;
|
||||
}CWaterRunner_t;
|
||||
|
||||
// Credits to bedroomcoders.co.uk for this
|
||||
typedef struct Sprite {
|
||||
Texture2D* texture;
|
||||
Vector2 frame_size;
|
||||
Vector2 origin; // TL of the frame
|
||||
Vector2 anchor; // Where transformation anchors on
|
||||
uint8_t frame_per_row;
|
||||
int frame_count;
|
||||
int speed;
|
||||
char* name;
|
||||
} Sprite_t;
|
||||
|
||||
typedef unsigned int (*sprite_transition_func_t)(Entity_t *ent); // Transition requires knowledge of the entity
|
||||
typedef struct _SpriteRenderInfo
|
||||
{
|
||||
Sprite_t* sprite;
|
||||
Vector2 offset;
|
||||
} SpriteRenderInfo_t;
|
||||
|
||||
typedef struct _CSprite_t {
|
||||
SpriteRenderInfo_t* sprites;
|
||||
sprite_transition_func_t transition_func;
|
||||
unsigned int current_idx;
|
||||
bool flip_x;
|
||||
bool flip_y;
|
||||
bool pause;
|
||||
int current_frame;
|
||||
float fractional;
|
||||
float rotation; // Degree
|
||||
float rotation_speed; // Degree / s
|
||||
int elapsed;
|
||||
Vector2 offset;
|
||||
Color colour;
|
||||
} CSprite_t;
|
||||
|
||||
typedef struct _CMoveable_t {
|
||||
uint16_t move_speed;
|
||||
Vector2 prev_pos;
|
||||
Vector2 target_pos;
|
||||
bool gridmove;
|
||||
} CMoveable_t;
|
||||
|
||||
typedef uint16_t EmitterHandle;
|
||||
typedef struct _CEmitter_t
|
||||
{
|
||||
EmitterHandle handle;
|
||||
Vector2 offset;
|
||||
} CEmitter_t;
|
||||
|
||||
static inline void set_bbox(CBBox_t* p_bbox, unsigned int x, unsigned int y)
|
||||
{
|
||||
p_bbox->size.x = x;
|
||||
p_bbox->size.y = y;
|
||||
p_bbox->half_size.x = (unsigned int)(x / 2);
|
||||
p_bbox->half_size.y = (unsigned int)(y / 2);
|
||||
}
|
||||
|
||||
struct Entity {
|
||||
Vector2 spawn_pos;
|
||||
Vector2 position;
|
||||
unsigned long m_id;
|
||||
unsigned int m_tag;
|
||||
|
@ -101,7 +256,7 @@ enum EntityUpdateEvent
|
|||
struct EntityUpdateEventInfo
|
||||
{
|
||||
unsigned long e_id;
|
||||
unsigned int comp_type;
|
||||
ComponentEnum_t comp_type;
|
||||
unsigned long c_id;
|
||||
enum EntityUpdateEvent evt_type;
|
||||
};
|
||||
|
@ -129,8 +284,8 @@ Entity_t* add_entity(EntityManager_t* p_manager, unsigned int tag);
|
|||
void remove_entity(EntityManager_t* p_manager, unsigned long id);
|
||||
Entity_t *get_entity(EntityManager_t* p_manager, unsigned long id);
|
||||
|
||||
void* add_component(Entity_t *entity, unsigned int comp_type);
|
||||
void* get_component(Entity_t *entity, unsigned int comp_type);
|
||||
void remove_component(Entity_t* entity, unsigned int comp_type);
|
||||
void* add_component(Entity_t *entity, ComponentEnum_t comp_type);
|
||||
void* get_component(Entity_t *entity, ComponentEnum_t comp_type);
|
||||
void remove_component(Entity_t* entity, ComponentEnum_t comp_type);
|
||||
|
||||
#endif // __ENTITY_H
|
||||
|
|
|
@ -23,6 +23,5 @@ typedef enum ActionType
|
|||
ACTION_SPAWN_TILE,
|
||||
ACTION_REMOVE_TILE,
|
||||
ACTION_SWITCH_TILESET,
|
||||
ACTION_LOOKAHEAD,
|
||||
}ActionType_t;
|
||||
#endif // __ACTIONS_H
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "assets.h"
|
||||
#include "assert.h"
|
||||
#include "engine_conf.h"
|
||||
#include "raymath.h"
|
||||
|
||||
#define RRES_RAYLIB_IMPLEMENTATION
|
||||
#include "rres.h"
|
||||
|
@ -275,7 +274,7 @@ static LevelPack_t* add_level_pack_zst(Assets_t* assets, const char* name, const
|
|||
for (lvls = 0; lvls < n_levels; ++lvls)
|
||||
{
|
||||
printf("Parsing level %u\n", lvls);
|
||||
output.size = 40;
|
||||
output.size = 36;
|
||||
output.pos = 0;
|
||||
|
||||
do
|
||||
|
@ -310,8 +309,6 @@ static LevelPack_t* add_level_pack_zst(Assets_t* assets, const char* name, const
|
|||
memcpy(pack_info->pack.levels[lvls].level_name, level_decompressor.out_buffer, 32);
|
||||
memcpy(&pack_info->pack.levels[lvls].width, level_decompressor.out_buffer + 32, 2);
|
||||
memcpy(&pack_info->pack.levels[lvls].height, level_decompressor.out_buffer + 34, 2);
|
||||
memcpy(&pack_info->pack.levels[lvls].n_chests, level_decompressor.out_buffer + 36, 2);
|
||||
memcpy(&pack_info->pack.levels[lvls].flags, level_decompressor.out_buffer + 38, 2);
|
||||
pack_info->pack.levels[lvls].level_name[31] = '\0';
|
||||
printf("Level name: %s\n", pack_info->pack.levels[lvls].level_name);
|
||||
printf("WxH: %u %u\n", pack_info->pack.levels[lvls].width, pack_info->pack.levels[lvls].height);
|
||||
|
@ -554,20 +551,15 @@ void draw_sprite_pro(Sprite_t* spr, int frame_num, Vector2 pos, float rotation,
|
|||
spr->frame_size.x * ((flip & 1) ? -1 : 1),
|
||||
spr->frame_size.y * ((flip & 2) ? -1 : 1),
|
||||
};
|
||||
|
||||
// The anchor here is only for rotation and scaling.
|
||||
// Translational anchor is expected to be accounted for
|
||||
// So need to offset render position with anchor position
|
||||
Vector2 anchor = spr->anchor;
|
||||
anchor.x *= scale.x;
|
||||
anchor.y *= scale.y;
|
||||
|
||||
Rectangle dest = {
|
||||
.x = pos.x + anchor.x,
|
||||
.y = pos.y + anchor.y,
|
||||
.x = pos.x,
|
||||
.y = pos.y,
|
||||
.width = spr->frame_size.x * scale.x,
|
||||
.height = spr->frame_size.y * scale.y
|
||||
};
|
||||
Vector2 anchor = spr->anchor;
|
||||
anchor.x *= scale.x;
|
||||
anchor.y *= scale.y;
|
||||
DrawTexturePro(
|
||||
*spr->texture,
|
||||
rec,
|
||||
|
@ -576,73 +568,3 @@ void draw_sprite_pro(Sprite_t* spr, int frame_num, Vector2 pos, float rotation,
|
|||
rotation, colour
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static Vector2 internal_get_anchor_offset(Vector2 bbox, AnchorPoint_t anchor)
|
||||
{
|
||||
Vector2 offset = {0};
|
||||
switch (anchor)
|
||||
{
|
||||
case AP_TOP_LEFT:
|
||||
break;
|
||||
case AP_TOP_CENTER:
|
||||
offset.x = bbox.x / 2;
|
||||
break;
|
||||
case AP_TOP_RIGHT:
|
||||
offset.x = bbox.x;
|
||||
break;
|
||||
case AP_MID_LEFT:
|
||||
offset.x = 0;
|
||||
offset.y = bbox.y / 2;
|
||||
break;
|
||||
case AP_MID_CENTER:
|
||||
offset.x = bbox.x / 2;
|
||||
offset.y = bbox.y / 2;
|
||||
break;
|
||||
case AP_MID_RIGHT:
|
||||
offset.x = bbox.x;
|
||||
offset.y = bbox.y / 2;
|
||||
break;
|
||||
case AP_BOT_LEFT:
|
||||
offset.x = 0;
|
||||
offset.y = bbox.y;
|
||||
break;
|
||||
case AP_BOT_CENTER:
|
||||
offset.x = bbox.x / 2;
|
||||
offset.y = bbox.y;
|
||||
break;
|
||||
case AP_BOT_RIGHT:
|
||||
offset.x = bbox.x;
|
||||
offset.y = bbox.y;
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
Vector2 shift_bbox(Vector2 bbox, Vector2 new_bbox, AnchorPoint_t anchor)
|
||||
{
|
||||
Vector2 p1 = internal_get_anchor_offset(bbox, anchor);
|
||||
Vector2 p2 = internal_get_anchor_offset(new_bbox, anchor);
|
||||
|
||||
return Vector2Subtract(p1, p2);
|
||||
}
|
||||
|
||||
Vector2 get_anchor_offset(Vector2 bbox, AnchorPoint_t anchor, bool flip_x)
|
||||
{
|
||||
if (flip_x)
|
||||
{
|
||||
switch(anchor)
|
||||
{
|
||||
case AP_TOP_LEFT: anchor = AP_TOP_RIGHT; break;
|
||||
case AP_TOP_RIGHT: anchor = AP_TOP_LEFT; break;
|
||||
case AP_MID_LEFT: anchor = AP_MID_RIGHT; break;
|
||||
case AP_MID_RIGHT: anchor = AP_MID_LEFT; break;
|
||||
case AP_BOT_LEFT: anchor = AP_BOT_RIGHT; break;
|
||||
case AP_BOT_RIGHT: anchor = AP_BOT_LEFT; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return internal_get_anchor_offset(bbox, anchor);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "EC.h"
|
||||
#include "raylib.h"
|
||||
#include "rres.h"
|
||||
|
||||
#include "particle_sys.h"
|
||||
#define N_ASSETS_TYPE 6
|
||||
typedef enum AssetType
|
||||
{
|
||||
|
@ -16,24 +16,6 @@ typedef enum AssetType
|
|||
AST_EMITTER_CONF,
|
||||
}AssetType_t;
|
||||
|
||||
typedef enum PartEmitterType
|
||||
{
|
||||
EMITTER_UNKNOWN = 0,
|
||||
EMITTER_BURST,
|
||||
EMITTER_STREAM,
|
||||
} PartEmitterType_t;
|
||||
|
||||
typedef struct EmitterConfig
|
||||
{
|
||||
float launch_range[2];
|
||||
float speed_range[2];
|
||||
float angle_range[2];
|
||||
float rotation_range[2];
|
||||
float particle_lifetime[2];
|
||||
float initial_spawn_delay;
|
||||
PartEmitterType_t type;
|
||||
bool one_shot;
|
||||
}EmitterConfig_t;
|
||||
|
||||
typedef struct Assets
|
||||
{
|
||||
|
@ -58,8 +40,6 @@ typedef struct LevelMap
|
|||
char level_name[32];
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t n_chests;
|
||||
uint16_t flags; // In case of extras
|
||||
LevelTileInfo_t* tiles;
|
||||
}LevelMap_t;
|
||||
|
||||
|
@ -69,18 +49,6 @@ typedef struct LevelPack
|
|||
LevelMap_t* levels;
|
||||
}LevelPack_t;
|
||||
|
||||
// Credits to bedroomcoders.co.uk for this
|
||||
typedef struct Sprite {
|
||||
Texture2D* texture;
|
||||
Vector2 frame_size;
|
||||
Vector2 origin; // TL of the frame
|
||||
Vector2 anchor; // Where transformation anchors on
|
||||
uint8_t frame_per_row;
|
||||
int frame_count;
|
||||
int speed;
|
||||
char* name;
|
||||
} Sprite_t;
|
||||
|
||||
typedef struct RresFileInfo
|
||||
{
|
||||
rresCentralDir dir;
|
||||
|
@ -115,8 +83,6 @@ LevelPack_t* get_level_pack(Assets_t* assets, const char* name);
|
|||
|
||||
void draw_sprite(Sprite_t* spr, int frame_num, Vector2 pos, float rotation, bool flip_x);
|
||||
void draw_sprite_pro(Sprite_t* spr, int frame_num, Vector2 pos, float rotation, uint8_t flip, Vector2 scale, Color colour);
|
||||
Vector2 get_anchor_offset(Vector2 bbox, AnchorPoint_t anchor, bool flip_x);
|
||||
Vector2 shift_bbox(Vector2 bbox, Vector2 new_bbox, AnchorPoint_t anchor);
|
||||
|
||||
typedef struct SFX
|
||||
{
|
||||
|
|
|
@ -160,7 +160,7 @@ uint8_t check_collision_at(Entity_t* p_ent, Vector2 pos, Vector2 bbox_sz, TileGr
|
|||
CollideEntity_t ent = {
|
||||
.p_ent = p_ent,
|
||||
.bbox = (Rectangle){pos.x, pos.y, bbox_sz.x, bbox_sz.y},
|
||||
.prev_bbox = (Rectangle){p_ent->position.x, p_ent->position.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 = (pos.x) / grid->tile_size,
|
||||
.tile_y1 = (pos.y) / grid->tile_size,
|
||||
|
@ -169,7 +169,7 @@ uint8_t check_collision_at(Entity_t* p_ent, Vector2 pos, Vector2 bbox_sz, TileGr
|
|||
}
|
||||
};
|
||||
|
||||
return check_collision(&ent, grid, true);
|
||||
return check_collision(&ent, grid, false);
|
||||
}
|
||||
|
||||
bool check_on_ground(Entity_t* p_ent, Vector2 prev_pos, Vector2 bbox_sz, TileGrid_t* grid)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef __COLLISION_FUNCS_H
|
||||
#define __COLLISION_FUNCS_H
|
||||
#include "EC.h"
|
||||
#include "render_queue.h"
|
||||
|
||||
typedef enum SolidType
|
||||
{
|
||||
|
@ -43,7 +42,6 @@ typedef struct TileGrid
|
|||
unsigned int max_tiles;
|
||||
unsigned int tile_size;
|
||||
Tile_t* tiles;
|
||||
RenderInfoNode* render_nodes;
|
||||
}TileGrid_t;
|
||||
|
||||
typedef struct TileArea {
|
||||
|
|
|
@ -15,7 +15,6 @@ void init_engine(GameEngine_t* engine, Vector2 starting_win_size)
|
|||
init_assets(&engine->assets);
|
||||
engine->intended_window_size = starting_win_size;
|
||||
InitWindow(starting_win_size.x, starting_win_size.y, "raylib");
|
||||
engine->base_canvas = LoadRenderTexture(starting_win_size.x, starting_win_size.y);
|
||||
}
|
||||
|
||||
void deinit_engine(GameEngine_t* engine)
|
||||
|
@ -25,7 +24,6 @@ void deinit_engine(GameEngine_t* engine)
|
|||
sc_queue_term(&engine->key_buffer);
|
||||
sc_queue_term(&engine->scene_stack);
|
||||
sc_heap_term(&engine->scenes_render_order);
|
||||
UnloadRenderTexture(engine->base_canvas);
|
||||
CloseAudioDevice();
|
||||
CloseWindow();
|
||||
}
|
||||
|
@ -91,10 +89,10 @@ void process_inputs(GameEngine_t* engine, Scene_t* scene)
|
|||
}
|
||||
}
|
||||
|
||||
Scene_t* change_scene(GameEngine_t* engine, unsigned int idx)
|
||||
void change_scene(GameEngine_t* engine, unsigned int idx)
|
||||
{
|
||||
// Backwards compat
|
||||
return change_active_scene(engine, idx);
|
||||
change_active_scene(engine, idx);
|
||||
}
|
||||
|
||||
bool load_sfx(GameEngine_t* engine, const char* snd_name, uint32_t tag_idx)
|
||||
|
@ -118,7 +116,7 @@ void play_sfx_pitched(GameEngine_t* engine, unsigned int tag_idx, float pitch)
|
|||
//if (sfx->snd != NULL)
|
||||
{
|
||||
PlaySound(*sfx->snd);
|
||||
//sfx->plays++;
|
||||
sfx->plays++;
|
||||
}
|
||||
//SetSoundPitch(*sfx->snd, 0.0f);
|
||||
}
|
||||
|
@ -152,20 +150,13 @@ void update_sfx_list(GameEngine_t* engine)
|
|||
engine->sfx_list.played_sfx = 0;
|
||||
}
|
||||
|
||||
void init_scene(Scene_t* scene, action_func_t action_func, uint32_t subsystem_init)
|
||||
void init_scene(Scene_t* scene, action_func_t action_func)
|
||||
{
|
||||
sc_map_init_64(&scene->action_map, 32, 0);
|
||||
sc_array_init(&scene->systems);
|
||||
if (subsystem_init & ENABLE_ENTITY_MANAGEMENT_SYSTEM)
|
||||
{
|
||||
init_entity_manager(&scene->ent_manager);
|
||||
}
|
||||
if (subsystem_init & ENABLE_PARTICLE_SYSTEM)
|
||||
{
|
||||
init_particle_system(&scene->part_sys);
|
||||
}
|
||||
init_entity_manager(&scene->ent_manager);
|
||||
init_particle_system(&scene->part_sys);
|
||||
|
||||
scene->subsystem_init = subsystem_init;
|
||||
//scene->scene_type = scene_type;
|
||||
scene->layers.n_layers = 0;
|
||||
scene->bg_colour = WHITE;
|
||||
|
@ -193,16 +184,8 @@ void free_scene(Scene_t* scene)
|
|||
{
|
||||
UnloadRenderTexture(scene->layers.render_layers[i].layer_tex);
|
||||
}
|
||||
|
||||
if (scene->subsystem_init & ENABLE_ENTITY_MANAGEMENT_SYSTEM)
|
||||
{
|
||||
free_entity_manager(&scene->ent_manager);
|
||||
}
|
||||
|
||||
if (scene->subsystem_init & ENABLE_PARTICLE_SYSTEM)
|
||||
{
|
||||
deinit_particle_system(&scene->part_sys);
|
||||
}
|
||||
free_entity_manager(&scene->ent_manager);
|
||||
deinit_particle_system(&scene->part_sys);
|
||||
}
|
||||
|
||||
inline void update_scene(Scene_t* scene, float delta_time)
|
||||
|
@ -215,10 +198,7 @@ inline void update_scene(Scene_t* scene, float delta_time)
|
|||
{
|
||||
sys(scene);
|
||||
}
|
||||
if (scene->subsystem_init & ENABLE_PARTICLE_SYSTEM)
|
||||
{
|
||||
update_particle_system(&scene->part_sys, scene->delta_time);
|
||||
}
|
||||
update_particle_system(&scene->part_sys, scene->delta_time);
|
||||
}
|
||||
|
||||
static void _internal_render_scene(Scene_t* scene)
|
||||
|
@ -253,43 +233,8 @@ static void _internal_render_scene(Scene_t* scene)
|
|||
|
||||
inline void render_scene(Scene_t* scene)
|
||||
{
|
||||
BeginTextureMode(scene->engine->base_canvas);
|
||||
_internal_render_scene(scene);
|
||||
EndTextureMode();
|
||||
|
||||
int curr_width = GetRenderWidth();
|
||||
int curr_height = GetRenderHeight();
|
||||
Vector2 original_size = scene->engine->intended_window_size;
|
||||
float wscale = (curr_width / original_size.x);
|
||||
float hscale = (curr_height / original_size.y);
|
||||
float min_dim = (wscale > hscale) ? hscale : wscale;
|
||||
Vector2 offset = {
|
||||
scene->engine->intended_window_size.x * (wscale - min_dim) / 2,
|
||||
scene->engine->intended_window_size.y * (hscale - min_dim) / 2
|
||||
};
|
||||
wscale = min_dim;
|
||||
hscale = min_dim;
|
||||
|
||||
|
||||
Rectangle draw_rec = {
|
||||
0,0,
|
||||
scene->engine->intended_window_size.x,
|
||||
scene->engine->intended_window_size.y
|
||||
};
|
||||
Rectangle draw_pos = {
|
||||
draw_rec.x * wscale + offset.x, draw_rec.y * hscale + offset.y,
|
||||
draw_rec.width * wscale, draw_rec.height * hscale
|
||||
};
|
||||
draw_rec.height *= -1;
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground((Color){0,0,0,255});
|
||||
DrawTexturePro(
|
||||
scene->engine->base_canvas.texture,
|
||||
draw_rec,
|
||||
draw_pos,
|
||||
(Vector2){0,0}, 0.0, WHITE
|
||||
);
|
||||
_internal_render_scene(scene);
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
|
@ -416,13 +361,11 @@ void remove_child_scene(GameEngine_t* engine, unsigned int idx)
|
|||
child->parent_scene = NULL;
|
||||
}
|
||||
|
||||
Scene_t* change_active_scene(GameEngine_t* engine, unsigned int idx)
|
||||
void change_active_scene(GameEngine_t* engine, unsigned int idx)
|
||||
{
|
||||
engine->scenes[engine->curr_scene]->state = 0;
|
||||
engine->curr_scene = idx;
|
||||
engine->scenes[engine->curr_scene]->state = SCENE_COMPLETE_ACTIVE;
|
||||
sc_queue_clear(&engine->key_buffer);
|
||||
return engine->scenes[engine->curr_scene];
|
||||
}
|
||||
|
||||
void change_focused_scene(GameEngine_t* engine, unsigned int idx)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "sc/heap/sc_heap.h"
|
||||
#include "assets.h"
|
||||
#include "particle_sys.h"
|
||||
#include "render_queue.h"
|
||||
|
||||
typedef struct Scene Scene_t;
|
||||
|
||||
|
@ -38,7 +37,6 @@ typedef struct GameEngine {
|
|||
// This is in case of window scaling, where there needs to be
|
||||
// an absolute reference
|
||||
Vector2 intended_window_size;
|
||||
RenderTexture2D base_canvas;
|
||||
} GameEngine_t;
|
||||
|
||||
#define SCENE_ACTIVE_BIT (1 << 0) // Systems Active
|
||||
|
@ -62,7 +60,6 @@ typedef struct SceneRenderLayers {
|
|||
struct Scene {
|
||||
// Not all scene needs an entity manager
|
||||
// but too late to change this
|
||||
uint32_t subsystem_init;
|
||||
EntityManager_t ent_manager;
|
||||
Scene_t* parent_scene;
|
||||
struct sc_map_64 action_map; // key -> actions
|
||||
|
@ -89,8 +86,8 @@ void process_active_scene_inputs(GameEngine_t* engine);
|
|||
void update_curr_scene(GameEngine_t* engine);
|
||||
void render_curr_scene(GameEngine_t* engine);
|
||||
|
||||
Scene_t* change_scene(GameEngine_t* engine, unsigned int idx);
|
||||
Scene_t* change_active_scene(GameEngine_t* engine, unsigned int idx);
|
||||
void change_scene(GameEngine_t* engine, unsigned int idx);
|
||||
void change_active_scene(GameEngine_t* engine, unsigned int idx);
|
||||
void change_focused_scene(GameEngine_t* engine, unsigned int idx);
|
||||
bool load_sfx(GameEngine_t* engine, const char* snd_name, uint32_t tag_idx);
|
||||
void play_sfx(GameEngine_t* engine, unsigned int tag_idx);
|
||||
|
@ -102,10 +99,7 @@ extern void update_scene(Scene_t* scene, float delta_time);
|
|||
extern void render_scene(Scene_t* scene);
|
||||
extern void do_action(Scene_t* scene, ActionType_t action, bool pressed);
|
||||
|
||||
//void init_scene(Scene_t* scene, action_func_t action_func);
|
||||
#define ENABLE_ENTITY_MANAGEMENT_SYSTEM (1)
|
||||
#define ENABLE_PARTICLE_SYSTEM (1 << 1)
|
||||
void init_scene(Scene_t* scene, action_func_t action_func, uint32_t subsystem_init);
|
||||
void init_scene(Scene_t* scene, action_func_t action_func);
|
||||
bool add_scene_layer(Scene_t* scene, int width, int height, Rectangle render_area);
|
||||
void free_scene(Scene_t* scene);
|
||||
void add_child_scene(GameEngine_t* engine, unsigned int child_idx, unsigned int parent_idx);
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
#ifndef _ENGINE_CONF_H
|
||||
#define _ENGINE_CONF_H
|
||||
|
||||
// Take care tuning these params. Web build doesn't work
|
||||
// if memory used too high
|
||||
#define MAX_SCENES_TO_RENDER 8
|
||||
#define MAX_SCENES_TO_RENDER 16
|
||||
#define MAX_RENDER_LAYERS 4
|
||||
#define MAX_RENDERMANAGER_DEPTH 4
|
||||
#define MAX_ENTITIES 2047
|
||||
#define MAX_ENTITIES 2048
|
||||
#define MAX_TEXTURES 16
|
||||
#define MAX_SPRITES 127
|
||||
#define MAX_SPRITES 64
|
||||
#define MAX_SOUNDS 32
|
||||
#define MAX_FONTS 4
|
||||
#define MAX_N_TILES 16384
|
||||
#define MAX_N_TILES 4096
|
||||
#define MAX_NAME_LEN 32
|
||||
#define MAX_LEVEL_PACK 4
|
||||
#define N_SFX 32
|
||||
#define MAX_EMITTER_CONF 8
|
||||
//#define MAX_PARTICLE_EMITTER 8
|
||||
#define MAX_ACTIVE_PARTICLE_EMITTER 255
|
||||
#define MAX_PARTICLES 32
|
||||
#define MAX_ACTIVE_PARTICLE_EMITTER 512
|
||||
#define MAX_PARTICLES 64
|
||||
|
||||
#define MAX_TILE_TYPES 16
|
||||
#define N_TAGS 10
|
||||
|
|
|
@ -115,6 +115,7 @@ Entity_t *add_entity(EntityManager_t* p_manager, unsigned int tag)
|
|||
Entity_t* p_ent = new_entity_from_mempool(&e_idx);
|
||||
if (p_ent == NULL) return NULL;
|
||||
|
||||
p_ent->spawn_pos = (Vector2){0, 0};
|
||||
p_ent->m_tag = tag;
|
||||
sc_queue_add_last(&p_manager->to_add, e_idx);
|
||||
p_ent->manager = p_manager;
|
||||
|
@ -144,7 +145,7 @@ Entity_t* get_entity(EntityManager_t* p_manager, unsigned long id)
|
|||
return p_entity;
|
||||
}
|
||||
|
||||
void* add_component(Entity_t* p_entity, unsigned int comp_type)
|
||||
void* add_component(Entity_t* p_entity, ComponentEnum_t comp_type)
|
||||
{
|
||||
if (p_entity->components[comp_type] == MAX_COMP_POOL_SIZE)
|
||||
{
|
||||
|
@ -163,7 +164,7 @@ void* add_component(Entity_t* p_entity, unsigned int comp_type)
|
|||
return get_component(p_entity, comp_type);
|
||||
}
|
||||
|
||||
void* get_component(Entity_t *p_entity, unsigned int comp_type)
|
||||
void* get_component(Entity_t *p_entity, ComponentEnum_t comp_type)
|
||||
{
|
||||
unsigned long comp_type_idx = (unsigned long)comp_type;
|
||||
unsigned long c_idx = p_entity->components[comp_type_idx];
|
||||
|
@ -171,7 +172,7 @@ void* get_component(Entity_t *p_entity, unsigned int comp_type)
|
|||
return get_component_wtih_id(comp_type, c_idx);
|
||||
}
|
||||
|
||||
void remove_component(Entity_t *p_entity, unsigned int comp_type)
|
||||
void remove_component(Entity_t *p_entity, ComponentEnum_t comp_type)
|
||||
{
|
||||
if (p_entity->components[comp_type] == MAX_COMP_POOL_SIZE) return;
|
||||
struct EntityUpdateEventInfo evt = (struct EntityUpdateEventInfo){p_entity->m_id, comp_type, p_entity->components[comp_type] , COMP_DELETION};
|
||||
|
|
404
engine/gui.c
404
engine/gui.c
|
@ -1,7 +1,5 @@
|
|||
#include "gui.h"
|
||||
#include "raylib.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define RAYGUI_MAX_CONTROLS 16 // Maximum number of standard controls
|
||||
#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of standard properties
|
||||
|
@ -11,11 +9,6 @@
|
|||
static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 };
|
||||
static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization
|
||||
static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib)
|
||||
//
|
||||
// Check if two rectangles are equal, used to validate a slider bounds as an id
|
||||
#ifndef CHECK_BOUNDS_ID
|
||||
#define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height))
|
||||
#endif
|
||||
|
||||
typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement;
|
||||
|
||||
|
@ -376,403 +369,6 @@ void UI_button(const UIComp_t* comp, const char* text)
|
|||
|
||||
}
|
||||
|
||||
void hover_text(const UIComp_t* comp, Font font, const char* text, Vector2 pos, int font_size, int spacing, Color colour) {
|
||||
if (comp->state == STATE_FOCUSED) {
|
||||
DrawTextEx(font, text, pos, font_size, spacing, Fade(colour, 0.1));
|
||||
pos.y -= font_size >> 2;
|
||||
}
|
||||
DrawTextEx(font, text, pos, font_size, spacing, colour);
|
||||
}
|
||||
|
||||
|
||||
// Slider control with pro parameters
|
||||
// NOTE: Other GuiSlider*() controls use this one
|
||||
int GuiSliderPro(const UIComp_t* comp, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth)
|
||||
{
|
||||
Rectangle bounds = comp->bbox;
|
||||
int result = 0;
|
||||
GuiState state = comp->state;
|
||||
|
||||
float temp = (maxValue - minValue)/2.0f;
|
||||
if (value == NULL) value = &temp;
|
||||
|
||||
int sliderValue = (int)(((*value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH)));
|
||||
|
||||
Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
|
||||
0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
|
||||
|
||||
if (sliderWidth > 0) // Slider
|
||||
{
|
||||
slider.x += (sliderValue - (sliderWidth >> 1));
|
||||
slider.width = (float)sliderWidth;
|
||||
}
|
||||
else if (sliderWidth == 0) // SliderBar
|
||||
{
|
||||
slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
slider.width = (float)sliderValue;
|
||||
}
|
||||
|
||||
// Update control
|
||||
//--------------------------------------------------------------------
|
||||
//if ((state != STATE_DISABLED) && !guiLocked)
|
||||
if (state != STATE_DISABLED)
|
||||
{
|
||||
Vector2 mousePoint = GetMousePosition();
|
||||
|
||||
if (comp->pressed) // Keep dragging outside of bounds
|
||||
{
|
||||
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
|
||||
{
|
||||
//if (CHECK_BOUNDS_ID(bounds, guiSliderActive))
|
||||
{
|
||||
state = STATE_PRESSED;
|
||||
|
||||
// Get equivalent value and slider position from mousePosition.x
|
||||
*value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
|
||||
}
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// guiSliderDragging = false;
|
||||
// guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
|
||||
//}
|
||||
}
|
||||
else if (CheckCollisionPointRec(mousePoint, bounds))
|
||||
{
|
||||
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
|
||||
{
|
||||
state = STATE_PRESSED;
|
||||
//guiSliderDragging = true;
|
||||
//guiSliderActive = bounds; // Store bounds as an identifier when dragging starts
|
||||
|
||||
if (!CheckCollisionPointRec(mousePoint, slider))
|
||||
{
|
||||
// Get equivalent value and slider position from mousePosition.x
|
||||
*value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + (sliderWidth >> 1) )))/(float)(bounds.width - sliderWidth) + minValue;
|
||||
|
||||
if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider
|
||||
else if (sliderWidth == 0) slider.width = (float)sliderValue; // SliderBar
|
||||
}
|
||||
}
|
||||
else state = STATE_FOCUSED;
|
||||
}
|
||||
|
||||
if (*value > maxValue) *value = maxValue;
|
||||
else if (*value < minValue) *value = minValue;
|
||||
}
|
||||
|
||||
// Bar limits check
|
||||
if (sliderWidth > 0) // Slider
|
||||
{
|
||||
if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
}
|
||||
else if (sliderWidth == 0) // SliderBar
|
||||
{
|
||||
if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Draw control
|
||||
//--------------------------------------------------------------------
|
||||
GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)));
|
||||
|
||||
// Draw slider internal bar (depends on state)
|
||||
if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
|
||||
else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)));
|
||||
else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED)));
|
||||
|
||||
// Draw left/right text if provided
|
||||
if (textLeft != NULL)
|
||||
{
|
||||
Rectangle textBounds = { 0 };
|
||||
textBounds.width = (float)GetTextWidth(textLeft);
|
||||
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
|
||||
textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
|
||||
textBounds.y = bounds.y + bounds.height/2 - (GuiGetStyle(DEFAULT, TEXT_SIZE) >> 1);
|
||||
|
||||
GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
|
||||
}
|
||||
|
||||
if (textRight != NULL)
|
||||
{
|
||||
Rectangle textBounds = { 0 };
|
||||
textBounds.width = (float)GetTextWidth(textRight);
|
||||
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
|
||||
textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING);
|
||||
textBounds.y = bounds.y + bounds.height/2 - (GuiGetStyle(DEFAULT, TEXT_SIZE) >> 1);
|
||||
|
||||
GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
return result;
|
||||
}
|
||||
//------------------------------------------------------------------------------------
|
||||
// Controls Functions Definitions (local)
|
||||
//------------------------------------------------------------------------------------
|
||||
float GuiVerticalSliderPro(const UIComp_t* comp, const char *textTop, const char *textBottom, float* in_value, float minValue, float maxValue, int sliderHeight)
|
||||
{
|
||||
float value = *in_value;
|
||||
GuiState state = comp->state;
|
||||
Rectangle bounds = comp->bbox;
|
||||
|
||||
int sliderValue = (int)(((value - minValue)/(maxValue - minValue)) * (bounds.height - 2 * GuiGetStyle(SLIDER, BORDER_WIDTH)));
|
||||
|
||||
Rectangle slider = {
|
||||
bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
|
||||
bounds.y + bounds.height - sliderValue,
|
||||
bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING),
|
||||
0.0f,
|
||||
};
|
||||
|
||||
if (sliderHeight > 0) // Slider
|
||||
{
|
||||
slider.y -= sliderHeight >> 1;
|
||||
slider.height = (float)sliderHeight;
|
||||
}
|
||||
else if (sliderHeight == 0) // SliderBar
|
||||
{
|
||||
slider.y -= GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
slider.height = (float)sliderValue;
|
||||
}
|
||||
// Update control
|
||||
//--------------------------------------------------------------------
|
||||
//if ((state != STATE_DISABLED) && !guiLocked)
|
||||
if (state != STATE_DISABLED)
|
||||
{
|
||||
Vector2 mousePoint = GetMousePosition();
|
||||
|
||||
if (CheckCollisionPointRec(mousePoint, bounds))
|
||||
{
|
||||
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
|
||||
{
|
||||
state = STATE_PRESSED;
|
||||
|
||||
// Get equivalent value and slider position from mousePoint.x
|
||||
float normalizedValue = (bounds.y + bounds.height - mousePoint.y - (float)(sliderHeight >> 1)) / (bounds.height - (float)sliderHeight);
|
||||
value = (maxValue - minValue) * normalizedValue + minValue;
|
||||
|
||||
if (sliderHeight > 0) slider.y = mousePoint.y - slider.height / 2; // Slider
|
||||
else if (sliderHeight == 0) // SliderBar
|
||||
{
|
||||
slider.y = mousePoint.y;
|
||||
slider.height = bounds.y + bounds.height - slider.y - GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
}
|
||||
}
|
||||
else state = STATE_FOCUSED;
|
||||
}
|
||||
|
||||
if (value > maxValue) value = maxValue;
|
||||
else if (value < minValue) value = minValue;
|
||||
}
|
||||
|
||||
|
||||
// Bar limits check
|
||||
if (sliderHeight > 0) // Slider
|
||||
{
|
||||
if (slider.y < (bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.y = bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
else if ((slider.y + slider.height) >= (bounds.y + bounds.height)) slider.y = bounds.y + bounds.height - slider.height - GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
}
|
||||
else if (sliderHeight == 0) // SliderBar
|
||||
{
|
||||
if (slider.y < (bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH)))
|
||||
{
|
||||
slider.y = bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
slider.height = bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Draw control
|
||||
//--------------------------------------------------------------------
|
||||
GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), comp->alpha), Fade(GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), comp->alpha));
|
||||
|
||||
// Draw slider internal bar (depends on state)
|
||||
if ((state == STATE_NORMAL) || (state == STATE_PRESSED)) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)), comp->alpha));
|
||||
else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)), comp->alpha));
|
||||
|
||||
// Draw top/bottom text if provided
|
||||
if (textTop != NULL)
|
||||
{
|
||||
Rectangle textBounds = { 0 };
|
||||
textBounds.width = (float)GetTextWidth(textTop);
|
||||
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
|
||||
textBounds.x = bounds.x + bounds.width/2 - textBounds.width/2;
|
||||
textBounds.y = bounds.y - textBounds.height - GuiGetStyle(SLIDER, TEXT_PADDING);
|
||||
|
||||
GuiDrawText(textTop, textBounds, TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), comp->alpha));
|
||||
}
|
||||
|
||||
if (textBottom != NULL)
|
||||
{
|
||||
Rectangle textBounds = { 0 };
|
||||
textBounds.width = (float)GetTextWidth(textBottom);
|
||||
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
|
||||
textBounds.x = bounds.x + bounds.width/2 - textBounds.width/2;
|
||||
textBounds.y = bounds.y + bounds.height + GuiGetStyle(SLIDER, TEXT_PADDING);
|
||||
|
||||
GuiDrawText(textBottom, textBounds, TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), comp->alpha));
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
*in_value = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
float UI_vert_slider(const UIComp_t* comp, const char *textTop, const char *textBottom, float* value, float minValue, float maxValue)
|
||||
{
|
||||
return GuiVerticalSliderPro(comp, textTop, textBottom, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Slider control extended, returns selected value and has text
|
||||
float UI_slider(const UIComp_t* comp, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
|
||||
{
|
||||
return GuiSliderPro(comp, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH));
|
||||
}
|
||||
|
||||
void vert_scrollarea_init(VertScrollArea_t* scroll_area, Rectangle display_area, Vector2 canvas_dims)
|
||||
{
|
||||
scroll_area->comp.font = GetFontDefault();
|
||||
scroll_area->canvas = LoadRenderTexture(canvas_dims.x, canvas_dims.y);
|
||||
scroll_area->scroll_pos = canvas_dims.y - display_area.height;
|
||||
scroll_area->scroll_bounds = (Vector2){
|
||||
0, scroll_area->scroll_pos
|
||||
};
|
||||
|
||||
vert_scrollarea_set_item_dims(scroll_area, 12, 3);
|
||||
scroll_area->curr_selection = 0;
|
||||
|
||||
scroll_area->display_area = display_area;
|
||||
scroll_area->scroll_bar.alpha = 1;
|
||||
scroll_area->scroll_bar.bbox = (Rectangle){
|
||||
display_area.width + display_area.x, display_area.y,
|
||||
0.1f * display_area.width, display_area.height,
|
||||
};
|
||||
scroll_area->scroll_bar.state = STATE_NORMAL;
|
||||
|
||||
scroll_area->comp.alpha = 1;
|
||||
scroll_area->comp.bbox = display_area;
|
||||
scroll_area->comp.bbox.width *= 1.1f;
|
||||
scroll_area->scroll_bar.state = STATE_NORMAL;
|
||||
|
||||
}
|
||||
|
||||
void vert_scrollarea_set_item_dims(VertScrollArea_t* scroll_area, unsigned int item_height, unsigned int item_padding)
|
||||
{
|
||||
scroll_area->item_height = item_height;
|
||||
scroll_area->item_padding = item_padding;
|
||||
scroll_area->max_items = (scroll_area->canvas.texture.height - scroll_area->item_padding) / (scroll_area->item_height + scroll_area->item_padding);
|
||||
}
|
||||
|
||||
bool vert_scrollarea_n_items(VertScrollArea_t* scroll_area, unsigned int n_items) {
|
||||
if (n_items >= scroll_area->max_items) return false;
|
||||
|
||||
// Due to OpenGL convention where y is -1 downwards,
|
||||
// The scroll bar is set to decreases the scroll_pos when going down
|
||||
// This value is used as the offset when rendering, which results in correctly
|
||||
// give the illusion of 'scrolling down'
|
||||
// So, adjust the minimum bound which is the height of the items that are not shown
|
||||
scroll_area->n_items = n_items;
|
||||
scroll_area->scroll_bounds.x =
|
||||
(scroll_area->max_items - n_items)* (scroll_area->item_height + scroll_area->item_padding) + scroll_area->item_padding;
|
||||
if (scroll_area->scroll_bounds.x > scroll_area->scroll_bounds.y) {
|
||||
scroll_area->scroll_bounds.x = scroll_area->scroll_bounds.y;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void vert_scrollarea_insert_item(VertScrollArea_t* scroll_area, char* str, unsigned int item_idx)
|
||||
{
|
||||
if (item_idx >= scroll_area->max_items) return;
|
||||
|
||||
DrawTextEx(
|
||||
scroll_area->comp.font,
|
||||
str,
|
||||
(Vector2){0, scroll_area->item_padding + (scroll_area->item_height + scroll_area->item_padding) * item_idx}
|
||||
, scroll_area->item_height, 0, BLACK);
|
||||
}
|
||||
|
||||
unsigned int vert_scrollarea_set_pos(VertScrollArea_t* scroll_area, Vector2 pos)
|
||||
{
|
||||
float x = pos.x - scroll_area->display_area.x;
|
||||
float y = pos.y - scroll_area->display_area.y;
|
||||
|
||||
if (x >= scroll_area->display_area.width || x < 0) return scroll_area->max_items;
|
||||
if (y >= scroll_area->display_area.height || y < 0) return scroll_area->max_items;
|
||||
|
||||
// How much have scroll down
|
||||
float canvas_offset = (scroll_area->scroll_bounds.y - scroll_area->scroll_pos);
|
||||
|
||||
scroll_area->curr_selection = (y + canvas_offset - scroll_area->item_padding) / (scroll_area->item_height + scroll_area->item_padding);
|
||||
|
||||
return scroll_area->curr_selection;
|
||||
}
|
||||
|
||||
void vert_scrollarea_refocus(VertScrollArea_t* scroll_area)
|
||||
{
|
||||
float canvas_offset = (scroll_area->scroll_bounds.y - scroll_area->scroll_pos);
|
||||
// Reverse from item selection to y in display area
|
||||
float selection_y = scroll_area->curr_selection * (scroll_area->item_height + scroll_area->item_padding) + scroll_area->item_padding - canvas_offset;
|
||||
|
||||
// Auto adjust scroll based on selection
|
||||
if (selection_y < 0)
|
||||
{
|
||||
scroll_area->scroll_pos -= selection_y;
|
||||
}
|
||||
else if (selection_y + scroll_area->item_height + scroll_area->item_padding > scroll_area->display_area.height)
|
||||
{
|
||||
scroll_area->scroll_pos -= selection_y + scroll_area->item_height + scroll_area->item_padding - scroll_area->display_area.height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void vert_scrollarea_render(VertScrollArea_t* scroll_area)
|
||||
{
|
||||
BeginScissorMode(scroll_area->comp.bbox.x, scroll_area->comp.bbox.y, scroll_area->comp.bbox.width, scroll_area->comp.bbox.height);
|
||||
UI_vert_slider(&scroll_area->scroll_bar,
|
||||
NULL,
|
||||
NULL,
|
||||
&scroll_area->scroll_pos,
|
||||
scroll_area->scroll_bounds.x,
|
||||
scroll_area->scroll_bounds.y
|
||||
);
|
||||
Rectangle draw_rec = (Rectangle){
|
||||
0, scroll_area->scroll_pos,
|
||||
scroll_area->display_area.width,
|
||||
scroll_area->display_area.height
|
||||
};
|
||||
|
||||
float canvas_offset = (scroll_area->scroll_bounds.y - scroll_area->scroll_pos);
|
||||
float selection_y = scroll_area->curr_selection * (scroll_area->item_height + scroll_area->item_padding) + scroll_area->item_padding - canvas_offset;
|
||||
|
||||
DrawRectangle(
|
||||
scroll_area->display_area.x,
|
||||
scroll_area->display_area.y + selection_y,
|
||||
scroll_area->canvas.texture.width, scroll_area->item_height,
|
||||
Fade(BLUE, 0.7)
|
||||
);
|
||||
|
||||
Vector2 draw_pos = {scroll_area->display_area.x, scroll_area->display_area.y};
|
||||
draw_rec.height *= -1;
|
||||
DrawTextureRec(
|
||||
scroll_area->canvas.texture,
|
||||
draw_rec,
|
||||
draw_pos,
|
||||
WHITE
|
||||
);
|
||||
EndScissorMode();
|
||||
}
|
||||
|
||||
void vert_scrollarea_free(VertScrollArea_t* scroll_area)
|
||||
{
|
||||
UnloadRenderTexture(scroll_area->canvas);
|
||||
}
|
||||
|
||||
|
||||
void init_UI(void)
|
||||
{
|
||||
GuiLoadStyleDefault();
|
||||
|
|
39
engine/gui.h
39
engine/gui.h
|
@ -3,52 +3,13 @@
|
|||
#include "raylib.h"
|
||||
#include "raygui.h"
|
||||
|
||||
// Generic Component
|
||||
typedef struct UIComp {
|
||||
Rectangle bbox;
|
||||
GuiState state;
|
||||
float alpha;
|
||||
bool pressed;
|
||||
Font font;
|
||||
} UIComp_t;
|
||||
|
||||
typedef struct VertScrollArea {
|
||||
UIComp_t comp; // Display area + scrollbar
|
||||
Rectangle display_area; // Display dimension
|
||||
|
||||
RenderTexture2D canvas; // Complete canvas
|
||||
|
||||
unsigned int n_items;
|
||||
unsigned int max_items;
|
||||
unsigned int curr_selection;
|
||||
unsigned int item_height;
|
||||
unsigned int item_padding;
|
||||
|
||||
float scroll_pos;
|
||||
Vector2 scroll_bounds;
|
||||
|
||||
UIComp_t scroll_bar;
|
||||
|
||||
} VertScrollArea_t;
|
||||
|
||||
void init_UI(void);
|
||||
void vert_scrollarea_init(VertScrollArea_t* scroll_area, Rectangle display_area, Vector2 canvas_dims);
|
||||
void vert_scrollarea_set_item_dims(VertScrollArea_t* scroll_area, unsigned int item_height, unsigned int item_padding);
|
||||
bool vert_scrollarea_n_items(VertScrollArea_t* scroll_area, unsigned int n_items);
|
||||
void vert_scrollarea_insert_item(VertScrollArea_t* scroll_area, char* str, unsigned int item_idx);
|
||||
unsigned int vert_scrollarea_set_pos(VertScrollArea_t* scroll_area, Vector2 pos);
|
||||
void vert_scrollarea_refocus(VertScrollArea_t* scroll_area);
|
||||
void vert_scrollarea_render(VertScrollArea_t* scroll_area);
|
||||
void vert_scrollarea_free(VertScrollArea_t* scroll_area);
|
||||
|
||||
static inline void ScrollAreaRenderBegin(VertScrollArea_t* scroll)
|
||||
{
|
||||
BeginTextureMode(scroll->canvas);
|
||||
}
|
||||
#define ScrollAreaRenderEnd() EndTextureMode()
|
||||
|
||||
void UI_button(const UIComp_t* bbox, const char* text);
|
||||
float UI_slider(const UIComp_t* comp, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue);
|
||||
float UI_vert_slider(const UIComp_t* comp, const char *textTop, const char *textBottom, float* value, float minValue, float maxValue);
|
||||
void hover_text(const UIComp_t* comp, Font font, const char* text, Vector2 pos, int font_size, int spacing, Color colour);
|
||||
#endif
|
||||
|
|
143
engine/mempool.c
143
engine/mempool.c
|
@ -1,11 +1,102 @@
|
|||
#include "mempool.h"
|
||||
//#include "sc/queue/sc_queue.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct ULongCircBuffer {
|
||||
unsigned long* buffer; // data buffer
|
||||
unsigned long* buffer_end; // end of data buffer
|
||||
uint32_t capacity; // maximum number of items in the buffer
|
||||
uint32_t count; // number of items in the buffer
|
||||
unsigned long* head; // pointer to head
|
||||
unsigned long* tail; // pointer to tail
|
||||
}ULongCircBuffer_t;
|
||||
|
||||
static void cb_init(ULongCircBuffer_t* cb, size_t capacity)
|
||||
{
|
||||
cb->buffer = (unsigned long*)malloc(capacity * sizeof(unsigned long));
|
||||
assert(cb->buffer != NULL);
|
||||
|
||||
cb->buffer_end = cb->buffer + capacity;
|
||||
cb->capacity = capacity;
|
||||
cb->count = 0;
|
||||
cb->head = cb->buffer;
|
||||
cb->tail = cb->buffer;
|
||||
}
|
||||
|
||||
static void cb_free(ULongCircBuffer_t* cb)
|
||||
{
|
||||
free(cb->buffer);
|
||||
// clear out other fields too, just to be safe
|
||||
}
|
||||
|
||||
static bool cb_pop_front(ULongCircBuffer_t* cb, unsigned long* item)
|
||||
{
|
||||
if (cb->count == 0) return false;
|
||||
|
||||
*item = *cb->tail;
|
||||
cb->tail++;
|
||||
if(cb->tail == cb->buffer_end) cb->tail = cb->buffer;
|
||||
cb->count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cb_push_back(ULongCircBuffer_t* cb, unsigned long item)
|
||||
{
|
||||
if(cb->count == cb->capacity) return false;
|
||||
*(cb->head) = item;
|
||||
cb->head++;
|
||||
if(cb->head == cb->buffer_end) cb->head = cb->buffer;
|
||||
cb->count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct MemPool {
|
||||
void * const buffer;
|
||||
const unsigned long max_size;
|
||||
const unsigned long elem_size;
|
||||
bool *use_list;
|
||||
ULongCircBuffer_t free_list;
|
||||
} MemPool_t;
|
||||
|
||||
// Static allocate buffers
|
||||
static Entity_t entity_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CBBox_t bbox_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CTransform_t ctransform_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CTileCoord_t ctilecoord_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CMovementState_t cmstate_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CJump_t cjump_buffer[8]; // Only player is expected to have this
|
||||
static CPlayerState_t cplayerstate_buffer[8]; // Only player is expected to have this
|
||||
static CContainer_t ccontainer_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CHitBoxes_t chitboxes_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CHurtbox_t churtbox_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CSprite_t csprite_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CMoveable_t cmoveable_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CLifeTimer_t clifetimer_buffer[MAX_COMP_POOL_SIZE];
|
||||
static CWaterRunner_t cwaterrunner_buffer[32];
|
||||
static CAirTimer_t cairtimer_buffer[8]; // Only player is expected to have this
|
||||
static CEmitter_t cemitter_buffer[MAX_COMP_POOL_SIZE]; // Only player is expected to have this
|
||||
|
||||
// Static allocate mempools
|
||||
static MemPool_t comp_mempools[N_COMPONENTS] = {
|
||||
{bbox_buffer, MAX_COMP_POOL_SIZE, sizeof(CBBox_t), NULL, {0}},
|
||||
{ctransform_buffer, MAX_COMP_POOL_SIZE, sizeof(CTransform_t), NULL, {0}},
|
||||
{ctilecoord_buffer, MAX_COMP_POOL_SIZE, sizeof(CTileCoord_t), NULL, {0}},
|
||||
{cmstate_buffer, MAX_COMP_POOL_SIZE, sizeof(CMovementState_t), NULL, {0}},
|
||||
{cjump_buffer, 8, sizeof(CJump_t), NULL, {0}},
|
||||
{cplayerstate_buffer, 8, sizeof(CPlayerState_t), NULL, {0}},
|
||||
{ccontainer_buffer, MAX_COMP_POOL_SIZE, sizeof(CContainer_t), NULL, {0}},
|
||||
{chitboxes_buffer, MAX_COMP_POOL_SIZE, sizeof(CHitBoxes_t), NULL, {0}},
|
||||
{churtbox_buffer, MAX_COMP_POOL_SIZE, sizeof(CHurtbox_t), NULL, {0}},
|
||||
{csprite_buffer, MAX_COMP_POOL_SIZE, sizeof(CSprite_t), NULL, {0}},
|
||||
{cmoveable_buffer, MAX_COMP_POOL_SIZE, sizeof(CMoveable_t), NULL, {0}},
|
||||
{clifetimer_buffer, MAX_COMP_POOL_SIZE, sizeof(CLifeTimer_t), NULL, {0}},
|
||||
{cwaterrunner_buffer, 32, sizeof(CWaterRunner_t), NULL, {0}},
|
||||
{cairtimer_buffer, 8, sizeof(CAirTimer_t), NULL, {0}},
|
||||
{cemitter_buffer, MAX_COMP_POOL_SIZE, sizeof(CEmitter_t), NULL, {0}},
|
||||
};
|
||||
static MemPool_t ent_mempool = {
|
||||
.buffer = entity_buffer,
|
||||
.max_size = MAX_COMP_POOL_SIZE,
|
||||
|
@ -24,21 +115,23 @@ void init_memory_pools(void)
|
|||
memset(comp_mempools[i].buffer, 0, comp_mempools[i].elem_size * comp_mempools[i].max_size);
|
||||
comp_mempools[i].use_list = (bool*)calloc(comp_mempools[i].max_size, sizeof(bool));
|
||||
assert(comp_mempools[i].use_list != NULL);
|
||||
sc_queue_init(&comp_mempools[i].free_list);
|
||||
cb_init(&comp_mempools[i].free_list, comp_mempools[i].max_size);
|
||||
for (size_t j = 0; j < comp_mempools[i].max_size; ++j)
|
||||
{
|
||||
sc_queue_add_last(&comp_mempools[i].free_list, j);
|
||||
comp_mempools[i].free_list.buffer[j] = j;
|
||||
}
|
||||
comp_mempools[i].free_list.count = comp_mempools[i].max_size;
|
||||
}
|
||||
|
||||
memset(ent_mempool.buffer, 0, ent_mempool.elem_size*ent_mempool.max_size);
|
||||
sc_queue_init(&ent_mempool.free_list);
|
||||
cb_init(&ent_mempool.free_list, ent_mempool.max_size);
|
||||
ent_mempool.use_list = (bool *)calloc(ent_mempool.max_size, sizeof(bool));
|
||||
for (size_t i = 0; i < ent_mempool.max_size; ++i)
|
||||
{
|
||||
entity_buffer[i].m_id = i;
|
||||
sc_queue_add_last(&ent_mempool.free_list, i);
|
||||
ent_mempool.free_list.buffer[i] = i;
|
||||
}
|
||||
ent_mempool.free_list.count = ent_mempool.max_size;
|
||||
pool_inited = true;
|
||||
}
|
||||
}
|
||||
|
@ -50,10 +143,10 @@ void free_memory_pools(void)
|
|||
for (size_t i = 0; i < N_COMPONENTS; ++i)
|
||||
{
|
||||
free(comp_mempools[i].use_list);
|
||||
sc_queue_term(&comp_mempools[i].free_list);
|
||||
cb_free(&comp_mempools[i].free_list);
|
||||
}
|
||||
free(ent_mempool.use_list);
|
||||
sc_queue_term(&ent_mempool.free_list);
|
||||
cb_free(&ent_mempool.free_list);
|
||||
|
||||
pool_inited = false;
|
||||
}
|
||||
|
@ -61,9 +154,8 @@ void free_memory_pools(void)
|
|||
|
||||
Entity_t* new_entity_from_mempool(unsigned long* e_idx_ptr)
|
||||
{
|
||||
if (sc_queue_empty(&ent_mempool.free_list)) return NULL;
|
||||
|
||||
unsigned long e_idx = sc_queue_del_first(&ent_mempool.free_list);
|
||||
unsigned long e_idx;
|
||||
if (!cb_pop_front(&ent_mempool.free_list, &e_idx)) return NULL;
|
||||
|
||||
*e_idx_ptr = e_idx;
|
||||
ent_mempool.use_list[e_idx] = true;
|
||||
|
@ -88,25 +180,24 @@ void free_entity_to_mempool(unsigned long idx)
|
|||
if (ent_mempool.use_list[idx])
|
||||
{
|
||||
ent_mempool.use_list[idx] = false;
|
||||
sc_queue_add_first(&ent_mempool.free_list, idx);
|
||||
cb_push_back(&ent_mempool.free_list, idx);
|
||||
}
|
||||
}
|
||||
|
||||
void* new_component_from_mempool(unsigned int comp_type, unsigned long* idx)
|
||||
void* new_component_from_mempool(ComponentEnum_t comp_type, unsigned long* idx)
|
||||
{
|
||||
void* comp = NULL;
|
||||
assert(comp_type < N_COMPONENTS);
|
||||
|
||||
if (sc_queue_empty(&comp_mempools[comp_type].free_list)) return NULL;
|
||||
|
||||
*idx = sc_queue_del_first(&comp_mempools[comp_type].free_list);
|
||||
comp_mempools[comp_type].use_list[*idx] = true;
|
||||
|
||||
void* comp = comp_mempools[comp_type].buffer + (*idx * comp_mempools[comp_type].elem_size);
|
||||
memset(comp, 0, comp_mempools[comp_type].elem_size);
|
||||
if (cb_pop_front(&comp_mempools[comp_type].free_list, idx))
|
||||
{
|
||||
comp_mempools[comp_type].use_list[*idx] = true;
|
||||
comp = comp_mempools[comp_type].buffer + (*idx * comp_mempools[comp_type].elem_size);
|
||||
memset(comp, 0, comp_mempools[comp_type].elem_size);
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
void* get_component_wtih_id(unsigned int comp_type, unsigned long idx)
|
||||
void* get_component_wtih_id(ComponentEnum_t comp_type, unsigned long idx)
|
||||
{
|
||||
void * comp = NULL;
|
||||
assert(comp_type < N_COMPONENTS);
|
||||
|
@ -117,30 +208,30 @@ void* get_component_wtih_id(unsigned int comp_type, unsigned long idx)
|
|||
return comp;
|
||||
}
|
||||
|
||||
void free_component_to_mempool(unsigned int comp_type, unsigned long idx)
|
||||
void free_component_to_mempool(ComponentEnum_t comp_type, unsigned long idx)
|
||||
{
|
||||
assert(comp_type < N_COMPONENTS);
|
||||
// This just free the component from the memory pool
|
||||
if (comp_mempools[comp_type].use_list[idx])
|
||||
{
|
||||
comp_mempools[comp_type].use_list[idx] = false;
|
||||
sc_queue_add_first(&comp_mempools[comp_type].free_list, idx);
|
||||
cb_push_back(&comp_mempools[comp_type].free_list, idx);
|
||||
}
|
||||
}
|
||||
|
||||
void print_mempool_stats(char* buffer)
|
||||
{
|
||||
buffer += sprintf(buffer, "Entity free: %lu\n", sc_queue_size(&ent_mempool.free_list));
|
||||
buffer += sprintf(buffer, "Entity free: %u\n", ent_mempool.free_list.count);
|
||||
for (size_t i = 0; i < N_COMPONENTS; ++i)
|
||||
{
|
||||
buffer += sprintf(
|
||||
buffer, "%lu: %lu/%lu\n",
|
||||
i, sc_queue_size(&comp_mempools[i].free_list), comp_mempools[i].free_list.cap
|
||||
buffer, "%lu: %u/%u\n",
|
||||
i, comp_mempools[i].free_list.count, comp_mempools[i].free_list.capacity
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t get_num_of_free_entities(void)
|
||||
{
|
||||
return sc_queue_size(&ent_mempool.free_list);
|
||||
return ent_mempool.free_list.count;
|
||||
}
|
||||
|
|
|
@ -1,48 +1,17 @@
|
|||
#ifndef __MEMPOOL_H
|
||||
#define __MEMPOOL_H
|
||||
#include "EC.h"
|
||||
#include "sc/queue/sc_queue.h"
|
||||
void init_memory_pools(void);
|
||||
void free_memory_pools(void);
|
||||
|
||||
typedef struct MemPool {
|
||||
void * const buffer;
|
||||
const unsigned long max_size;
|
||||
const unsigned long elem_size;
|
||||
bool *use_list;
|
||||
struct sc_queue_32 free_list;
|
||||
} MemPool_t;
|
||||
|
||||
// Game needs to implement this somewhere
|
||||
extern MemPool_t comp_mempools[N_COMPONENTS];
|
||||
|
||||
Entity_t* new_entity_from_mempool(unsigned long* e_idx_ptr);
|
||||
Entity_t* get_entity_wtih_id(unsigned long idx);
|
||||
void free_entity_to_mempool(unsigned long idx);
|
||||
|
||||
void* new_component_from_mempool(unsigned int comp_type, unsigned long* idx);
|
||||
void* get_component_wtih_id(unsigned int comp_type, unsigned long idx);
|
||||
void free_component_to_mempool(unsigned int comp_type, unsigned long idx);
|
||||
void* new_component_from_mempool(ComponentEnum_t comp_type, unsigned long* idx);
|
||||
void* get_component_wtih_id(ComponentEnum_t comp_type, unsigned long idx);
|
||||
void free_component_to_mempool(ComponentEnum_t comp_type, unsigned long idx);
|
||||
|
||||
void print_mempool_stats(char* buffer);
|
||||
uint32_t get_num_of_free_entities(void);
|
||||
|
||||
#define DEFINE_COMP_MEMPOOL_BUF(type, n) \
|
||||
static type type##_buf[n]; \
|
||||
const unsigned long type##_CNT = n; \
|
||||
|
||||
#define ADD_COMP_MEMPOOL(type) \
|
||||
{type##_buf, type##_CNT, sizeof(type), NULL, {0}}, \
|
||||
|
||||
#define BEGIN_DEFINE_COMP_MEMPOOL \
|
||||
DEFINE_COMP_MEMPOOL_BUF(CBBox_t, MAX_COMP_POOL_SIZE); \
|
||||
DEFINE_COMP_MEMPOOL_BUF(CTransform_t, MAX_COMP_POOL_SIZE); \
|
||||
DEFINE_COMP_MEMPOOL_BUF(CTileCoord_t, MAX_COMP_POOL_SIZE); \
|
||||
MemPool_t comp_mempools[N_COMPONENTS] = { \
|
||||
ADD_COMP_MEMPOOL(CBBox_t) \
|
||||
ADD_COMP_MEMPOOL(CTransform_t) \
|
||||
ADD_COMP_MEMPOOL(CTileCoord_t) \
|
||||
|
||||
#define END_DEFINE_COMP_MEMPOOL };
|
||||
|
||||
#endif //__MEMPOOL_H
|
||||
|
|
|
@ -3,11 +3,16 @@
|
|||
#include "raylib.h"
|
||||
#include "engine_conf.h"
|
||||
#include "sc_queue.h"
|
||||
#include "assets.h"
|
||||
#include "EC.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef uint16_t EmitterHandle;
|
||||
typedef enum PartEmitterType
|
||||
{
|
||||
EMITTER_UNKNOWN = 0,
|
||||
EMITTER_BURST,
|
||||
EMITTER_STREAM,
|
||||
} PartEmitterType_t;
|
||||
|
||||
typedef struct Particle
|
||||
{
|
||||
|
@ -27,6 +32,18 @@ typedef struct ParticleEmitter ParticleEmitter_t;
|
|||
typedef void (*particle_update_func_t)(Particle_t* part, void* user_data, float delta_time);
|
||||
typedef bool (*emitter_check_func_t)(const ParticleEmitter_t* emitter, float delta_time);
|
||||
|
||||
typedef struct EmitterConfig
|
||||
{
|
||||
float launch_range[2];
|
||||
float speed_range[2];
|
||||
float angle_range[2];
|
||||
float rotation_range[2];
|
||||
float particle_lifetime[2];
|
||||
float initial_spawn_delay;
|
||||
PartEmitterType_t type;
|
||||
bool one_shot;
|
||||
}EmitterConfig_t;
|
||||
|
||||
struct ParticleEmitter
|
||||
{
|
||||
const EmitterConfig_t* config;
|
||||
|
|
|
@ -539,7 +539,7 @@ RAYGUIAPI bool GuiSpinner(Rectangle bounds, const char *text, int *value, int mi
|
|||
RAYGUIAPI bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers
|
||||
RAYGUIAPI bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text
|
||||
RAYGUIAPI bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control with multiple lines
|
||||
RAYGUIAPI float GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue);
|
||||
RAYGUIAPI float GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Slider control, returns selected value
|
||||
RAYGUIAPI float GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Slider Bar control, returns selected value
|
||||
RAYGUIAPI float GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Progress Bar control, shows current progress value
|
||||
RAYGUIAPI void GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
#include "render_queue.h"
|
||||
#include "raylib.h"
|
||||
|
||||
void init_render_manager(RenderManager *manager)
|
||||
{
|
||||
memset(manager, 0, sizeof(*manager));
|
||||
}
|
||||
|
||||
bool add_render_node(RenderManager *manager, RenderInfoNode *node, uint8_t layer_num)
|
||||
{
|
||||
if (node->next != NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (node->spr == NULL) {
|
||||
return false;
|
||||
}
|
||||
layer_num = (layer_num >= MAX_RENDERMANAGER_DEPTH) ? MAX_RENDERMANAGER_DEPTH - 1 : layer_num;
|
||||
|
||||
node->next = manager->layers[layer_num];
|
||||
manager->layers[layer_num] = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
void execute_render(RenderManager *manager) {
|
||||
for (uint8_t depth = 0; depth < MAX_RENDERMANAGER_DEPTH; ++depth)
|
||||
{
|
||||
RenderInfoNode* curr = manager->layers[depth];
|
||||
while (curr != NULL)
|
||||
{
|
||||
draw_sprite_pro(
|
||||
curr->spr, curr->frame_num, curr->pos,
|
||||
curr->rotation, curr->flip, curr->scale,
|
||||
curr->colour
|
||||
);
|
||||
RenderInfoNode* next = curr->next;
|
||||
curr->next = NULL;
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
reset_render_manager(manager);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#ifndef RENDER_QUEUE_H
|
||||
#define RENDER_QUEUE_H
|
||||
#include "assets.h"
|
||||
#include "engine_conf.h"
|
||||
|
||||
typedef struct RenderInfoNode RenderInfoNode;
|
||||
struct RenderInfoNode {
|
||||
// Intrusive Linked-list Node
|
||||
RenderInfoNode* next;
|
||||
|
||||
Sprite_t* spr;
|
||||
Vector2 pos;
|
||||
int frame_num;
|
||||
float rotation;
|
||||
Vector2 scale;
|
||||
Color colour;
|
||||
uint8_t flip;
|
||||
};
|
||||
|
||||
typedef struct RenderManager {
|
||||
RenderInfoNode* layers[MAX_RENDERMANAGER_DEPTH];
|
||||
} RenderManager;
|
||||
|
||||
void init_render_manager(RenderManager* manager);
|
||||
#define reset_render_manager init_render_manager
|
||||
|
||||
bool add_render_node(RenderManager* manager, RenderInfoNode* node, uint8_t layer_num);
|
||||
void execute_render(RenderManager* manager);
|
||||
#endif
|
|
@ -1,6 +1,5 @@
|
|||
#include "mempool.h"
|
||||
#include "scene_impl.h"
|
||||
#include "gui.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
|
@ -15,15 +14,12 @@ int main(void)
|
|||
InitWindow(1280, 640, "raylib");
|
||||
SetTargetFPS(60);
|
||||
init_memory_pools();
|
||||
init_UI();
|
||||
LevelSelectScene_t scene;
|
||||
init_level_select_scene(&scene);
|
||||
scene.scene.bg_colour = RAYWHITE;
|
||||
while(true)
|
||||
{
|
||||
|
||||
Vector2 raw_mouse_pos = GetMousePosition();
|
||||
scene.scene.mouse_pos = raw_mouse_pos;
|
||||
// This entire key processing relies on the assumption that a pressed key will
|
||||
// appear in the polling of raylib
|
||||
|
||||
|
@ -54,18 +50,6 @@ int main(void)
|
|||
do_action(&scene.scene, action, true);
|
||||
sc_queue_add_last(&key_buffer, button);
|
||||
}
|
||||
ActionType_t action = sc_map_get_64(&scene.scene.action_map, MOUSE_BUTTON_LEFT);
|
||||
if (sc_map_found(&scene.scene.action_map))
|
||||
{
|
||||
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT))
|
||||
{
|
||||
do_action(&scene.scene, action, true);
|
||||
}
|
||||
else if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
|
||||
{
|
||||
do_action(&scene.scene, action, false);
|
||||
}
|
||||
}
|
||||
|
||||
float frame_time = GetFrameTime();
|
||||
float delta_time = fminf(frame_time, DT);
|
||||
|
|
128
level_test.c
128
level_test.c
|
@ -1,128 +0,0 @@
|
|||
#include "raylib.h"
|
||||
#include "assets_loader.h"
|
||||
#include "scene_impl.h"
|
||||
#include "ent_impl.h"
|
||||
#include "mempool.h"
|
||||
#include "constants.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tracy/TracyC.h"
|
||||
#define N_SCENES 1
|
||||
|
||||
Scene_t *scenes[N_SCENES];
|
||||
static GameEngine_t engine = {
|
||||
.scenes = scenes,
|
||||
.max_scenes = 1,
|
||||
.curr_scene = 0,
|
||||
.assets = {0}
|
||||
};
|
||||
|
||||
const int screenWidth = VIEWABLE_MAP_WIDTH * TILE_SIZE;
|
||||
const int screenHeight = VIEWABLE_MAP_HEIGHT * TILE_SIZE;
|
||||
|
||||
// Maintain own queue to handle key presses
|
||||
struct sc_queue_32 key_buffer;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||
init_engine(&engine, (Vector2){screenWidth, screenHeight});
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
load_from_infofile("res/assets.info.raw", &engine.assets);
|
||||
init_player_creation("res/player_spr.info", &engine.assets);
|
||||
init_item_creation(&engine.assets);
|
||||
|
||||
load_sfx(&engine, "snd_jump", PLAYER_JMP_SFX);
|
||||
load_sfx(&engine, "snd_land", PLAYER_LAND_SFX);
|
||||
load_sfx(&engine, "snd_wdrop", WATER_IN_SFX);
|
||||
load_sfx(&engine, "snd_bland", BOULDER_LAND_SFX);
|
||||
load_sfx(&engine, "snd_bubble", BUBBLE_SFX);
|
||||
load_sfx(&engine, "snd_step", PLAYER_STEP_SFX);
|
||||
load_sfx(&engine, "snd_dead", PLAYER_DEAD_SFX);
|
||||
load_sfx(&engine, "snd_drwg", PLAYER_DROWNING_SFX);
|
||||
load_sfx(&engine, "snd_mdestroy", METAL_DESTROY_SFX);
|
||||
load_sfx(&engine, "snd_wdestroy", WOOD_DESTROY_SFX);
|
||||
load_sfx(&engine, "snd_cland", WOOD_LAND_SFX);
|
||||
load_sfx(&engine, "snd_explsn", EXPLOSION_SFX);
|
||||
load_sfx(&engine, "snd_coin", COIN_SFX);
|
||||
load_sfx(&engine, "snd_arrhit", ARROW_DESTROY_SFX);
|
||||
load_sfx(&engine, "snd_launch", ARROW_RELEASE_SFX);
|
||||
load_sfx(&engine, "snd_launch", BOMB_RELEASE_SFX);
|
||||
|
||||
LevelScene_t level_scene;
|
||||
level_scene.scene.engine = &engine;
|
||||
init_game_scene(&level_scene);
|
||||
level_scene.data.tile_sprites[ONEWAY_TILE] = get_sprite(&engine.assets, "tl_owp");
|
||||
level_scene.data.tile_sprites[LADDER] = get_sprite(&engine.assets, "tl_ldr");
|
||||
level_scene.data.tile_sprites[SPIKES] = get_sprite(&engine.assets, "d_spikes");
|
||||
level_scene.data.tile_sprites[SPIKES + TILE_90CWROT] = get_sprite(&engine.assets, "l_spikes");
|
||||
level_scene.data.tile_sprites[SPIKES + TILE_90CCWROT] = get_sprite(&engine.assets, "r_spikes");
|
||||
level_scene.data.tile_sprites[SPIKES + TILE_180ROT] = get_sprite(&engine.assets, "u_spikes");
|
||||
Texture2D* tex = get_texture(&engine.assets, "bg_tex");
|
||||
SetTextureWrap(*tex, TEXTURE_WRAP_REPEAT);
|
||||
sc_map_del_64(&level_scene.scene.action_map, ACTION_EXIT);
|
||||
|
||||
// Load level
|
||||
LevelPack_t* pack = get_level_pack(&engine.assets, "DefLevels");
|
||||
if (pack == NULL)
|
||||
{
|
||||
puts("Default level pack not found!");
|
||||
return 1;
|
||||
}
|
||||
unsigned int selected_level = 0;
|
||||
if (argc == 2) {
|
||||
selected_level = strtoul(argv[1], NULL, 10);
|
||||
printf("Selected level: %u", selected_level);
|
||||
}
|
||||
if (selected_level >= pack->n_levels) {
|
||||
printf("Level numbers out of bound. Picking 0");
|
||||
selected_level = 0;
|
||||
}
|
||||
level_scene.data.level_pack = pack;
|
||||
level_scene.data.current_level = selected_level;
|
||||
scenes[0] = &level_scene.scene;
|
||||
reload_level_tilemap(&level_scene);
|
||||
change_scene(&engine, 0);
|
||||
|
||||
const float DT = 1.0f/60.0f;
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
TracyCFrameMark;
|
||||
// This entire key processing relies on the assumption that a pressed key will
|
||||
// appear in the polling of raylib
|
||||
Scene_t* curr_scene = engine.scenes[engine.curr_scene];
|
||||
|
||||
if (curr_scene->state == 0 && engine.curr_scene == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
process_inputs(&engine, curr_scene);
|
||||
|
||||
|
||||
float frame_time = GetFrameTime();
|
||||
float delta_time = fminf(frame_time, DT);
|
||||
|
||||
{
|
||||
TracyCZoneN(ctx, "Update", true)
|
||||
update_scene(curr_scene, delta_time);
|
||||
update_entity_manager(&curr_scene->ent_manager);
|
||||
update_sfx_list(&engine);
|
||||
TracyCZoneEnd(ctx)
|
||||
}
|
||||
|
||||
// This is needed to advance time delta
|
||||
render_scene(curr_scene);
|
||||
|
||||
if (curr_scene->state != 0)
|
||||
{
|
||||
sc_queue_clear(&key_buffer);
|
||||
}
|
||||
}
|
||||
free_game_scene(&level_scene);
|
||||
deinit_engine(&engine);
|
||||
}
|
31
main.c
31
main.c
|
@ -3,7 +3,6 @@
|
|||
#include "scene_impl.h"
|
||||
#include "ent_impl.h"
|
||||
#include "mempool.h"
|
||||
#include "constants.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#define N_SCENES 4
|
||||
|
@ -11,13 +10,13 @@
|
|||
Scene_t *scenes[N_SCENES];
|
||||
static GameEngine_t engine = {
|
||||
.scenes = scenes,
|
||||
.max_scenes = 4,
|
||||
.max_scenes = 3,
|
||||
.curr_scene = 0,
|
||||
.assets = {0}
|
||||
};
|
||||
|
||||
const int screenWidth = VIEWABLE_MAP_WIDTH * TILE_SIZE;
|
||||
const int screenHeight = VIEWABLE_MAP_HEIGHT * TILE_SIZE;
|
||||
const int screenWidth = 1280;
|
||||
const int screenHeight = 640;
|
||||
|
||||
// Maintain own queue to handle key presses
|
||||
struct sc_queue_32 key_buffer;
|
||||
|
@ -26,7 +25,6 @@ int main(void)
|
|||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||
init_engine(&engine, (Vector2){screenWidth, screenHeight});
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
#ifndef NDEBUG
|
||||
|
@ -65,30 +63,21 @@ int main(void)
|
|||
level_scene.data.tile_sprites[SPIKES + TILE_90CWROT] = get_sprite(&engine.assets, "l_spikes");
|
||||
level_scene.data.tile_sprites[SPIKES + TILE_90CCWROT] = get_sprite(&engine.assets, "r_spikes");
|
||||
level_scene.data.tile_sprites[SPIKES + TILE_180ROT] = get_sprite(&engine.assets, "u_spikes");
|
||||
Texture2D* tex = get_texture(&engine.assets, "bg_tex");
|
||||
SetTextureWrap(*tex, TEXTURE_WRAP_REPEAT);
|
||||
|
||||
LevelPack_t* pack = get_level_pack(&engine.assets, "DefLevels");
|
||||
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);
|
||||
|
||||
LevelSelectScene_t level_sel_scene;
|
||||
level_sel_scene.scene.engine = &engine;
|
||||
level_sel_scene.data.level_pack = pack;
|
||||
init_level_select_scene(&level_sel_scene);
|
||||
|
||||
scenes[MAIN_MENU_SCENE] = &menu_scene.scene;
|
||||
scenes[LEVEL_SELECT_SCENE] = &level_sel_scene.scene;
|
||||
scenes[GAME_SCENE] = &level_scene.scene;
|
||||
scenes[SANDBOX_SCENE] = &sandbox_scene.scene;
|
||||
change_scene(&engine, MAIN_MENU_SCENE);
|
||||
scenes[0] = &menu_scene.scene;
|
||||
scenes[1] = &level_scene.scene;
|
||||
scenes[2] = &sandbox_scene.scene;
|
||||
change_scene(&engine, 0);
|
||||
|
||||
const float DT = 1.0f/60.0f;
|
||||
while (!WindowShouldClose())
|
||||
|
@ -118,10 +107,10 @@ int main(void)
|
|||
{
|
||||
sc_queue_clear(&key_buffer);
|
||||
}
|
||||
|
||||
}
|
||||
free_sandbox_scene(&sandbox_scene);
|
||||
free_game_scene(&level_scene);
|
||||
free_level_select_scene(&level_sel_scene);
|
||||
free_menu_scene(&menu_scene);
|
||||
deinit_engine(&engine);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
*
|
||||
!.gitignore
|
||||
!CMakeLists.txt
|
||||
!*.py
|
||||
!pack_ldtk.sh
|
||||
!pack_resources.sh
|
||||
!ldtk_repacker.py
|
||||
!test_assets.info
|
||||
!testLevels.lvldata.zst
|
||||
!rres_packer.c
|
||||
!requirements.txt
|
||||
|
|
|
@ -8,6 +8,6 @@ set_target_properties(rres_packer
|
|||
|
||||
target_link_libraries(rres_packer
|
||||
PRIVATE
|
||||
lib_assets
|
||||
lib_engine
|
||||
)
|
||||
|
||||
|
|
|
@ -37,11 +37,12 @@ ENUMIDS_TILETYPE_MAPPING = {
|
|||
'Boulder': 20,
|
||||
'Runner': 21,
|
||||
'Player': 22,
|
||||
'Chest': 23,
|
||||
'Exit': 24,
|
||||
'Urchin': 25,
|
||||
}
|
||||
|
||||
#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"]
|
||||
|
@ -58,18 +59,8 @@ if not ids_tiletype_map:
|
|||
|
||||
pprint.pprint(ids_tiletype_map)
|
||||
|
||||
def get_level_order(lvl) -> int:
|
||||
order = 65535;
|
||||
for data in lvl['fieldInstances']:
|
||||
if data["__identifier"] == "Order" and data["realEditorValues"]:
|
||||
order = data["__value"]
|
||||
return order
|
||||
|
||||
all_levels = level_pack_data["levels"]
|
||||
all_levels.sort(key=get_level_order)
|
||||
|
||||
# Number of levels is the length of the levels
|
||||
n_levels = len(all_levels)
|
||||
n_levels = len(level_pack_data["levels"])
|
||||
print("Number of levels:", n_levels)
|
||||
|
||||
fileparts = args.filename.split('.')
|
||||
|
@ -83,21 +74,12 @@ converted_filename = '.'.join(fileparts)
|
|||
with open(converted_filename, 'wb+') as out_file:
|
||||
out_file.write(struct.pack("<I", n_levels))
|
||||
# Then loop the levels. Read the layerIndstances
|
||||
for level in all_levels:
|
||||
n_chests : int = 0
|
||||
for level in level_pack_data["levels"]:
|
||||
# Search for __identifier for the level layout
|
||||
level_name = ""
|
||||
|
||||
level_metadata = level['fieldInstances']
|
||||
level_tileset = 0;
|
||||
for data in level_metadata:
|
||||
if data["__identifier"] == "TileSet":
|
||||
level_tileset = data["__value"]
|
||||
if data["__identifier"] == "Name":
|
||||
level_name = data["__value"]
|
||||
|
||||
level_name = level["identifier"]
|
||||
print("Parsing level", level_name)
|
||||
|
||||
|
||||
level_layout = {}
|
||||
entity_layout = {}
|
||||
water_layout = {}
|
||||
|
@ -112,20 +94,13 @@ with open(converted_filename, 'wb+') as out_file:
|
|||
# Dimensions of each level is obtained via __cWid and __cHei. Get the __gridSize as well
|
||||
width = level_layout["__cWid"]
|
||||
height = level_layout["__cHei"]
|
||||
print(f"Dim.: {width}x{height}. N Tiles: {width * height}")
|
||||
print(f"Dim.: {width}x{height}")
|
||||
# Create a W x H array of tile information
|
||||
n_tiles = width * height
|
||||
tiles_info = [[0,0,0] for _ in range(n_tiles)]
|
||||
# Loop through gridTiles, get "d" as the index to fill the info
|
||||
for i, tile in enumerate(level_layout["gridTiles"]):
|
||||
try:
|
||||
tiles_info[tile["d"][0]][0] = ids_tiletype_map[tile["t"]]
|
||||
if tiles_info[tile["d"][0]][0] == ENUMIDS_TILETYPE_MAPPING ["Chest"]:
|
||||
n_chests += 1
|
||||
except Exception as e:
|
||||
print("Error on tile", i, i % width, i // height)
|
||||
print(e)
|
||||
tiles_info[tile["d"][0]][0] = 0
|
||||
for tile in level_layout["gridTiles"]:
|
||||
tiles_info[tile["d"][0]][0] = ids_tiletype_map[tile["t"]]
|
||||
|
||||
for i, water_level in enumerate(water_layout["intGridCsv"]):
|
||||
tiles_info[i][2] = water_level
|
||||
|
@ -134,23 +109,14 @@ with open(converted_filename, 'wb+') as out_file:
|
|||
for ent in entity_layout["entityInstances"]:
|
||||
x,y = ent["__grid"]
|
||||
tiles_info[y*width + x][0] = ENUMIDS_TILETYPE_MAPPING[ent["__identifier"]]
|
||||
if ent["__identifier"] == "Urchin":
|
||||
spd_encoding = 0
|
||||
for urchin_data in ent['fieldInstances']:
|
||||
if urchin_data["__identifier"] == "Direction":
|
||||
spd_encoding |= urchin_data["__value"] << 2
|
||||
elif urchin_data["__identifier"] == "SpeedLevel":
|
||||
spd_encoding |= urchin_data["__value"]
|
||||
|
||||
tiles_info[y*width + x][0] += spd_encoding
|
||||
|
||||
out_file.write(struct.pack("<32s4H", level_name.encode('utf-8'), width, height, n_chests, level_tileset))
|
||||
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))
|
||||
|
||||
|
||||
#for y in range(height):
|
||||
# for x in range(width):
|
||||
# print(tiles_info[y*width + x], end=" ")
|
||||
# print()
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
print(tiles_info[y*width + x], end=" ")
|
||||
print()
|
||||
|
||||
|
|
|
@ -1,257 +0,0 @@
|
|||
import sys
|
||||
import argparse
|
||||
import pprint
|
||||
import json
|
||||
import struct
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('filename')
|
||||
args = parser.parse_args()
|
||||
|
||||
print("Rendering", args.filename)
|
||||
|
||||
with open(args.filename, 'r') as f:
|
||||
level_pack_data = json.load(f)
|
||||
|
||||
#pprint.pprint(level_pack_data)
|
||||
ENUMIDS_TILETYPE_MAPPING = {
|
||||
'Solid': 1,
|
||||
'WoodenPlat': 2,
|
||||
'Ladder': 3,
|
||||
'LSpike': 4,
|
||||
'RSpike': 5,
|
||||
'USpike': 6,
|
||||
'DSpike': 7,
|
||||
'EmptyWCrate': 8,
|
||||
'LArrowWCrate': 9,
|
||||
'RArrowWCrate': 10,
|
||||
'UArrowWCrate': 11,
|
||||
'DArrowWCrate': 12,
|
||||
'BombWCrate': 13,
|
||||
'EmptyMCrate': 14,
|
||||
'LArrowMCrate': 15,
|
||||
'RArrowMCrate': 16,
|
||||
'UArrowMCrate': 17,
|
||||
'DArrowMCrate': 18,
|
||||
'BombMCrate': 19,
|
||||
'Boulder': 20,
|
||||
'Runner': 21,
|
||||
'Player': 22,
|
||||
'Chest': 23,
|
||||
'Exit': 24,
|
||||
'Urchin': 25,
|
||||
}
|
||||
|
||||
DANGER_COLOUR = (239,79,81,255)
|
||||
WCRATE_COLOUR = (160,117,48,255)
|
||||
MCRATE_COLOUR = (110,110,110,255)
|
||||
WATER_COLOUR = (0,0,128,64)
|
||||
|
||||
REC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s-1, y+s-1)), c)
|
||||
RECLINE_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s-1, y+s-1)), fill=None, outline=c)
|
||||
UPHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s-1, y+s//2-1)), c)
|
||||
DOWNHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x, y+s//2), (x+s-1,y+s-1)), c)
|
||||
LEFTHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s//2-1, y+s-1)), c)
|
||||
RIGHTHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x+s//2,y), (x+s-1, y+s-1)), c)
|
||||
CIRCLE_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.circle((x+s//2, y+s//2), s//2, c)
|
||||
TRIANGLE_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.regular_polygon(((x+s//2, y+s//2), s//2), 3, 0, c)
|
||||
|
||||
def draw_bomb_tile(ctx, x, y, s, c):
|
||||
REC_DRAW_FUNCTION(ctx, x, y, s, c)
|
||||
ctx.line((x,y,x+s-1,y+s-1), DANGER_COLOUR, 1)
|
||||
ctx.line((x,y+s-1,x+s-1,y), DANGER_COLOUR, 1)
|
||||
|
||||
def draw_arrow_tile(ctx, x, y, s, c, d):
|
||||
REC_DRAW_FUNCTION(ctx, x, y, s, c)
|
||||
if d == 0:
|
||||
ctx.line((x+s//2,y+s//2,x+s//2,y), DANGER_COLOUR, 1)
|
||||
elif d == 1:
|
||||
ctx.line((x+s//2,y+s//2,x+s-1,y+s//2), DANGER_COLOUR, 1)
|
||||
elif d == 2:
|
||||
ctx.line((x+s//2,y+s//2,x+s//2,y+s-1), DANGER_COLOUR, 1)
|
||||
elif d == 3:
|
||||
ctx.line((x+s//2,y+s//2,x,y+s//2), DANGER_COLOUR, 1)
|
||||
|
||||
def draw_urchin_tile(ctx, x, y, s, c):
|
||||
ctx.line((x,y,x+s-1,y+s-1), c, 1)
|
||||
ctx.line((x,y+s-1,x+s-1,y), c, 1)
|
||||
ctx.line((x+(s-1)//2,y,x+(s-1)//2,y+s-1), c, 1)
|
||||
ctx.line((x,y+(s-1)//2,x+s-1,y+(s-1)//2), c, 1)
|
||||
|
||||
TILETYPE_SHAPE_MAP = {
|
||||
'Solid': (REC_DRAW_FUNCTION, (0,0,0,255)),
|
||||
'WoodenPlat': (UPHALFREC_DRAW_FUNCTION, (128,64,0,255)),
|
||||
'Ladder': (RECLINE_DRAW_FUNCTION, (214,141,64,255)),
|
||||
'LSpike': (LEFTHALFREC_DRAW_FUNCTION, DANGER_COLOUR),
|
||||
'RSpike': (RIGHTHALFREC_DRAW_FUNCTION, DANGER_COLOUR),
|
||||
'USpike': (UPHALFREC_DRAW_FUNCTION, DANGER_COLOUR),
|
||||
'DSpike': (DOWNHALFREC_DRAW_FUNCTION, DANGER_COLOUR),
|
||||
'EmptyWCrate': (REC_DRAW_FUNCTION, WCRATE_COLOUR),
|
||||
'LArrowWCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,3), WCRATE_COLOUR),
|
||||
'RArrowWCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,1), WCRATE_COLOUR),
|
||||
'UArrowWCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,0), WCRATE_COLOUR),
|
||||
'DArrowWCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,2), WCRATE_COLOUR),
|
||||
'BombWCrate': (draw_bomb_tile, WCRATE_COLOUR),
|
||||
'EmptyMCrate': (REC_DRAW_FUNCTION, MCRATE_COLOUR),
|
||||
'LArrowMCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,3), MCRATE_COLOUR),
|
||||
'RArrowMCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,1), MCRATE_COLOUR),
|
||||
'UArrowMCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,0), MCRATE_COLOUR),
|
||||
'DArrowMCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,2), MCRATE_COLOUR),
|
||||
'BombMCrate': (draw_bomb_tile, MCRATE_COLOUR),
|
||||
'Boulder': (CIRCLE_DRAW_FUNCTION, (45,45,45,255)),
|
||||
'Runner': (TRIANGLE_DRAW_FUNCTION, (0,0,128,255)),
|
||||
'Player': (REC_DRAW_FUNCTION, (255,0,255,255)),
|
||||
'Chest': (REC_DRAW_FUNCTION, (255,255,0,255)),
|
||||
'Exit': (REC_DRAW_FUNCTION, (0,255,0,255)),
|
||||
'Urchin': (draw_urchin_tile, DANGER_COLOUR),
|
||||
}
|
||||
|
||||
# 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"]
|
||||
|
||||
for ts_def in tileset_defs:
|
||||
if ts_def["identifier"] != "Items_spritesheet":
|
||||
continue
|
||||
for tag in ts_def["enumTags"]:
|
||||
ids_tiletype_map[tag["tileIds"][0]] = tag["enumValueId"]
|
||||
|
||||
if not ids_tiletype_map:
|
||||
print("No tileset definition")
|
||||
sys.exit(1)
|
||||
|
||||
pprint.pprint(ids_tiletype_map)
|
||||
|
||||
def get_level_order(lvl) -> int:
|
||||
order = 65535;
|
||||
for data in lvl['fieldInstances']:
|
||||
if data["__identifier"] == "Order" and data["realEditorValues"]:
|
||||
order = data["__value"]
|
||||
return order
|
||||
|
||||
all_levels = level_pack_data["levels"]
|
||||
all_levels.sort(key=get_level_order)
|
||||
|
||||
# Number of levels is the length of the levels
|
||||
n_levels = len(all_levels)
|
||||
print("Number of levels:", n_levels)
|
||||
|
||||
fileparts = args.filename.split('.')
|
||||
if len(fileparts) == 1:
|
||||
fileparts.append("lvldat")
|
||||
else:
|
||||
fileparts[-1] = "lvldata"
|
||||
converted_filename = '.'.join(fileparts)
|
||||
|
||||
# First run the entire level pack to figure out the largest dimensions required.
|
||||
|
||||
# tile size needs to be dynamic. Fix the output dimensions (and therefore aspect ratio)
|
||||
# figure out width and height of level
|
||||
# Get the tile size that fit within the dimensions
|
||||
# Error out if tile size is zero
|
||||
# Figure out the offset to center the render
|
||||
LEVELS_PER_ROW = 5
|
||||
N_ROWS = n_levels // LEVELS_PER_ROW
|
||||
if n_levels % LEVELS_PER_ROW != 0:
|
||||
N_ROWS += 1
|
||||
|
||||
IMG_WIDTH = 400
|
||||
IMG_HEIGHT = 400
|
||||
|
||||
FULL_IMG_WIDTH = LEVELS_PER_ROW * IMG_WIDTH
|
||||
FULL_IMG_HEIGHT = N_ROWS * IMG_HEIGHT
|
||||
# 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]...
|
||||
# Then loop the levels. Read the layerIndstances
|
||||
|
||||
lvl_render = Image.new("RGBA", (FULL_IMG_WIDTH, FULL_IMG_HEIGHT), (255,255,255,0))
|
||||
water_render = Image.new("RGBA", (FULL_IMG_WIDTH, FULL_IMG_HEIGHT), (255,255,255,0))
|
||||
render_ctx = ImageDraw.Draw(lvl_render)
|
||||
water_render_ctx = ImageDraw.Draw(water_render)
|
||||
for l, level in enumerate(all_levels):
|
||||
lx = (l % LEVELS_PER_ROW) * IMG_WIDTH
|
||||
ly = (l // LEVELS_PER_ROW) * IMG_HEIGHT
|
||||
n_chests : int = 0
|
||||
# Search for __identifier for the level layout
|
||||
level_name = ""
|
||||
|
||||
level_metadata = level['fieldInstances']
|
||||
level_tileset = 0;
|
||||
for data in level_metadata:
|
||||
if data["__identifier"] == "TileSet":
|
||||
level_tileset = data["__value"]
|
||||
if data["__identifier"] == "Name":
|
||||
level_name = data["__value"]
|
||||
|
||||
print("Parsing level", level_name)
|
||||
|
||||
level_layout = {}
|
||||
entity_layout = {}
|
||||
water_layout = {}
|
||||
for layer in level['layerInstances']:
|
||||
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"]
|
||||
height = level_layout["__cHei"]
|
||||
print(f"Dim.: {width}x{height}. N Tiles: {width * height}")
|
||||
|
||||
TILE_SIZE = 400 // max(width, height)
|
||||
TILE_SIZE = max(TILE_SIZE,1)
|
||||
|
||||
# Create a W x H array of tile information
|
||||
n_tiles = width * height
|
||||
|
||||
LVL_SIZE = (width*TILE_SIZE-1, height*TILE_SIZE-1)
|
||||
OFFSET = ((IMG_WIDTH - LVL_SIZE[0]) // 2 + lx, (IMG_HEIGHT - LVL_SIZE[1])//2 + ly)
|
||||
|
||||
render_ctx.rectangle((OFFSET, (OFFSET[0]+width*TILE_SIZE-1, OFFSET[1] + height*TILE_SIZE-1)), (64,64,64,255))
|
||||
# Loop through gridTiles, get "d" as the index to fill the info
|
||||
for i, tile in enumerate(level_layout["gridTiles"]):
|
||||
x, y= (tile["d"][0] % width * TILE_SIZE + OFFSET[0], tile["d"][0] // width * TILE_SIZE + OFFSET[1])
|
||||
try:
|
||||
if ids_tiletype_map[tile["t"]] in TILETYPE_SHAPE_MAP:
|
||||
draw_func, colour = TILETYPE_SHAPE_MAP[ids_tiletype_map[tile["t"]]]
|
||||
draw_func(render_ctx, x, y, TILE_SIZE, colour)
|
||||
else:
|
||||
print(ids_tiletype_map[tile["t"]], "is not mapped");
|
||||
except Exception as e:
|
||||
print("Error on tile", x, y)
|
||||
render_ctx.circle((x,y), 2,(255,0,0,255))
|
||||
print(e)
|
||||
|
||||
## Subject to change
|
||||
for ent in entity_layout["entityInstances"]:
|
||||
x,y = ent["__grid"]
|
||||
x *= TILE_SIZE
|
||||
x += OFFSET[0]
|
||||
y *= TILE_SIZE
|
||||
y += OFFSET[1]
|
||||
ent = ent["__identifier"]
|
||||
try:
|
||||
if ent in TILETYPE_SHAPE_MAP:
|
||||
draw_func, colour = TILETYPE_SHAPE_MAP[ent]
|
||||
draw_func(render_ctx, x, y, TILE_SIZE, colour)
|
||||
else:
|
||||
print(ent, "is not mapped");
|
||||
except Exception as e:
|
||||
print("Error on tile", x, y)
|
||||
render_ctx.circle((x,y), 2,(255,0,0,255))
|
||||
print(e)
|
||||
|
||||
for i, water_level in enumerate(water_layout["intGridCsv"]):
|
||||
if water_level == 0:
|
||||
continue
|
||||
x, y = (i % width * TILE_SIZE + OFFSET[0], i // width * TILE_SIZE + OFFSET[1])
|
||||
height = TILE_SIZE * water_level / 4
|
||||
water_render_ctx.rectangle(((x,y+TILE_SIZE-height), (x+TILE_SIZE-1, y+TILE_SIZE-1)), WATER_COLOUR)
|
||||
|
||||
lvl_render = Image.alpha_composite(lvl_render, water_render)
|
||||
lvl_render.save("preview.png")
|
||||
lvl_render.show()
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
source venv/bin/activate
|
||||
python ldtk_repacker.py $1.ldtk && zstd $1.lvldata && python level_render.py $1.ldtk
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
sed 's|res/||g' assets.info.raw > assets.info
|
||||
./rres_packer
|
||||
mv ../web/res/myresources.rres ../web/res/myresources.rres.old
|
||||
cp ./myresources.rres ../web/res/
|
|
@ -1 +0,0 @@
|
|||
Pillow
|
|
@ -109,7 +109,7 @@ int main(void)
|
|||
for (uint8_t i = 0; i < 6; ++i)
|
||||
{
|
||||
scenes[i] = &dummy_scenes[i].scene;
|
||||
init_scene(&dummy_scenes[i].scene, &level_do_action, 0);
|
||||
init_scene(&dummy_scenes[i].scene, &level_do_action);
|
||||
dummy_scenes[i].scene.engine = &engine;
|
||||
dummy_scenes[i].number = i;
|
||||
add_scene_layer(
|
||||
|
|
18
scene_test.c
18
scene_test.c
|
@ -1,6 +1,3 @@
|
|||
#ifdef TRACY_ENABLE
|
||||
#include "tracy/TracyC.h"
|
||||
#endif
|
||||
#include "scene_impl.h"
|
||||
#include "ent_impl.h"
|
||||
#include "assets_loader.h"
|
||||
|
@ -64,9 +61,6 @@ int main(void)
|
|||
load_sfx(&engine, "snd_cland", WOOD_LAND_SFX);
|
||||
load_sfx(&engine, "snd_explsn", EXPLOSION_SFX);
|
||||
load_sfx(&engine, "snd_coin", COIN_SFX);
|
||||
load_sfx(&engine, "snd_step", PLAYER_STEP_SFX);
|
||||
load_sfx(&engine, "snd_dead", PLAYER_DEAD_SFX);
|
||||
load_sfx(&engine, "snd_drwg", PLAYER_DROWNING_SFX);
|
||||
load_sfx(&engine, "snd_arrhit", ARROW_DESTROY_SFX);
|
||||
load_sfx(&engine, "snd_launch", ARROW_RELEASE_SFX);
|
||||
load_sfx(&engine, "snd_launch", BOMB_RELEASE_SFX);
|
||||
|
@ -95,22 +89,10 @@ int main(void)
|
|||
float frame_time = GetFrameTime();
|
||||
float delta_time = fminf(frame_time, DT);
|
||||
|
||||
#ifdef TRACY_ENABLE
|
||||
TracyCZoneN(ctx, "Overall", true)
|
||||
#endif
|
||||
#ifdef TRACY_ENABLE
|
||||
TracyCZoneN(ctx1, "Update", true)
|
||||
#endif
|
||||
update_scene(&scene.scene, delta_time);
|
||||
update_entity_manager(&scene.scene.ent_manager);
|
||||
#ifdef TRACY_ENABLE
|
||||
TracyCZoneEnd(ctx1)
|
||||
#endif
|
||||
// This is needed to advance time delta
|
||||
render_scene(&scene.scene);
|
||||
#ifdef TRACY_ENABLE
|
||||
TracyCZoneEnd(ctx)
|
||||
#endif
|
||||
update_sfx_list(&engine);
|
||||
if (WindowShouldClose()) break;
|
||||
}
|
||||
|
|
|
@ -9,23 +9,11 @@ add_library(lib_scenes STATIC
|
|||
game_scene.c
|
||||
game_systems.c
|
||||
scene_systems.c
|
||||
camera_systems.c
|
||||
engine_impl.c
|
||||
)
|
||||
target_include_directories(lib_scenes
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../tracy/public/
|
||||
)
|
||||
|
||||
if (${RUN_PROFILER})
|
||||
target_compile_definitions(lib_scenes
|
||||
PUBLIC
|
||||
TRACY_ENABLE
|
||||
TRACY_ON_DEMAND
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(lib_scenes
|
||||
PUBLIC
|
||||
lib_engine
|
||||
|
|
|
@ -7,7 +7,6 @@ typedef enum AssetInfoType
|
|||
TEXTURE_INFO,
|
||||
SPRITE_INFO,
|
||||
SOUND_INFO,
|
||||
FONT_INFO,
|
||||
EMITTER_INFO,
|
||||
LEVELPACK_INFO,
|
||||
INVALID_INFO
|
||||
|
@ -81,8 +80,6 @@ static inline AssetInfoType_t get_asset_type(const char* str)
|
|||
|
||||
if (strcmp(str, "LevelPack") == 0) return LEVELPACK_INFO;
|
||||
|
||||
if (strcmp(str, "Font") == 0) return FONT_INFO;
|
||||
|
||||
return INVALID_INFO;
|
||||
}
|
||||
|
||||
|
@ -275,22 +272,12 @@ bool load_from_infofile(const char* file, Assets_t* assets)
|
|||
{
|
||||
if (add_sound(assets, name, info_str) == NULL)
|
||||
{
|
||||
printf("Unable to add sound at line %lu\n", line_num);
|
||||
printf("Unable to add texture at line %lu\n", line_num);
|
||||
break;
|
||||
}
|
||||
printf("Added sound %s as %s\n", info_str, name);
|
||||
}
|
||||
break;
|
||||
case FONT_INFO:
|
||||
{
|
||||
if (add_font(assets, name, info_str) == NULL)
|
||||
{
|
||||
printf("Unable to add font at line %lu\n", line_num);
|
||||
break;
|
||||
}
|
||||
printf("Added font %s as %s\n", info_str, name);
|
||||
}
|
||||
break;
|
||||
case LEVELPACK_INFO:
|
||||
{
|
||||
//if (add_level_pack(assets, name, info_str) == NULL)
|
||||
|
|
|
@ -11,7 +11,6 @@ typedef enum EntityTag {
|
|||
LEVEL_END_TAG,
|
||||
DESTRUCTABLE_ENT_TAG,
|
||||
DYNMEM_ENT_TAG,
|
||||
URCHIN_ENT_TAG,
|
||||
} EntityTag_t;
|
||||
|
||||
typedef enum SFXTag {
|
||||
|
@ -20,9 +19,6 @@ typedef enum SFXTag {
|
|||
PLAYER_RUN_SFX,
|
||||
PLAYER_LADDER_SFX,
|
||||
PLAYER_WATER_RUN_SFX,
|
||||
PLAYER_STEP_SFX,
|
||||
PLAYER_DEAD_SFX,
|
||||
PLAYER_DROWNING_SFX,
|
||||
WATER_IN_SFX,
|
||||
WATER_OUT_SFX,
|
||||
WOOD_LAND_SFX,
|
||||
|
@ -39,11 +35,9 @@ typedef enum SFXTag {
|
|||
COIN_SFX,
|
||||
} SFXTag_t;
|
||||
|
||||
typedef enum SceneType {
|
||||
MAIN_MENU_SCENE = 0,
|
||||
LEVEL_SELECT_SCENE,
|
||||
GAME_SCENE,
|
||||
SANDBOX_SCENE,
|
||||
}SceneType_t;
|
||||
//typedef enum SceneType {
|
||||
// LEVEL_SCENE = 0,
|
||||
// MENU_SCENE,
|
||||
//}SceneType_t;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
#include "game_systems.h"
|
||||
#include "ent_impl.h"
|
||||
#include "raymath.h"
|
||||
|
||||
void camera_update_system(Scene_t* scene)
|
||||
{
|
||||
LevelSceneData_t* data = &CONTAINER_OF(scene, LevelScene_t, scene)->data;
|
||||
Entity_t* p_player;
|
||||
const int width = data->game_rec.width;
|
||||
const int height =data->game_rec.height;
|
||||
data->camera.cam.offset = (Vector2){ width/2.0f, height/2.0f };
|
||||
|
||||
if (data->camera.mode == CAMERA_FOLLOW_PLAYER)
|
||||
{
|
||||
Vector2 target_vel = {0};
|
||||
sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_player)
|
||||
{
|
||||
CTransform_t* p_ctransform = get_component(p_player, CTRANSFORM_COMP_T);
|
||||
data->camera.target_pos.x = p_player->position.x;
|
||||
target_vel = p_ctransform->velocity;
|
||||
CMovementState_t* p_movement = get_component(p_player, CMOVEMENTSTATE_T);
|
||||
CPlayerState_t* p_pstate = get_component(p_player, CPLAYERSTATE_T);
|
||||
data->camera.target_pos.x += (p_movement->x_dir == 1) ? width/6: -width/6;
|
||||
|
||||
if (p_movement->ground_state == 0b01
|
||||
|| (p_movement->water_state & 1)
|
||||
|| (p_pstate->ladder_state & 1)
|
||||
)
|
||||
{
|
||||
data->camera.base_y = p_player->position.y;
|
||||
}
|
||||
if (p_player->position.y >= data->camera.base_y)
|
||||
{
|
||||
data->camera.target_pos.y = p_player->position.y;
|
||||
data->camera.target_pos.y += p_ctransform->velocity.y * 0.2;
|
||||
}
|
||||
}
|
||||
data->camera.target_pos.x = Clamp(data->camera.target_pos.x, data->game_rec.width / 2,
|
||||
fmax(data->tilemap.width * data->tilemap.tile_size, data->game_rec.width) - data->game_rec.width / 2);
|
||||
data->camera.target_pos.y = Clamp(data->camera.target_pos.y, data->game_rec.height / 2,
|
||||
fmax(data->tilemap.height * data->tilemap.tile_size, data->game_rec.width) - data->game_rec.height / 2);
|
||||
|
||||
// Mass-Spring damper update in x direction
|
||||
float x = data->camera.target_pos.x - data->camera.cam.target.x;
|
||||
float v = data->camera.current_vel.x - target_vel.x;
|
||||
float F = data->camera.k * x - data->camera.c * v;
|
||||
// Kinematics update
|
||||
const float dt = scene->delta_time;
|
||||
float a_dt = F * dt / data->camera.mass;
|
||||
data->camera.cam.target.x += (data->camera.current_vel.x + a_dt * 0.5) * dt;
|
||||
|
||||
data->camera.current_vel.x += a_dt;
|
||||
|
||||
// Simple lerp for y direction
|
||||
float dy = (data->camera.target_pos.y - data->camera.cam.target.y);
|
||||
data->camera.cam.target.y += dy * 0.1f;
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_player)
|
||||
//{
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
|
||||
// Bound camera within level limits
|
||||
Vector2 max = GetWorldToScreen2D(
|
||||
(Vector2){
|
||||
fmax(data->tilemap.width * data->tilemap.tile_size, data->game_rec.width),
|
||||
fmax(data->tilemap.height * data->tilemap.tile_size, data->game_rec.height)
|
||||
},
|
||||
data->camera.cam
|
||||
);
|
||||
Vector2 min = GetWorldToScreen2D((Vector2){0, 0}, data->camera.cam);
|
||||
if (max.x < width)
|
||||
{
|
||||
//data->camera.cam.offset.x = width - (max.x - width/2.0f);
|
||||
data->camera.cam.target.x = fmax(data->tilemap.width * data->tilemap.tile_size, data->game_rec.width) - (width >> 1);
|
||||
data->camera.current_vel.x = 0;
|
||||
}
|
||||
if (min.x > 0)
|
||||
{
|
||||
//data->camera.cam.offset.x = (width >> 1) - min.x;
|
||||
data->camera.cam.target.x = (width >> 1);
|
||||
data->camera.current_vel.x = 0;
|
||||
}
|
||||
|
||||
if (max.y < height)
|
||||
{
|
||||
//data->camera.cam.offset.y = height - (max.y - height/2.0f);
|
||||
data->camera.cam.target.y = fmax(data->tilemap.height * data->tilemap.tile_size, data->game_rec.height) - (height >> 1);
|
||||
data->camera.current_vel.y = 0;
|
||||
}
|
||||
if (min.y > 0)
|
||||
{
|
||||
//data->camera.cam.offset.y = (height >> 1) - min.y;
|
||||
data->camera.cam.target.y = (height >> 1);
|
||||
data->camera.current_vel.y = 0;
|
||||
}
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
#include "EC.h"
|
||||
#include "engine.h"
|
||||
#include "render_queue.h"
|
||||
#include "particle_sys.h" // includes assets
|
||||
|
||||
enum ComponentEnum {
|
||||
CMOVEMENTSTATE_T = N_BASIC_COMPS,
|
||||
CJUMP_COMP_T,
|
||||
CPLAYERSTATE_T,
|
||||
CCONTAINER_T,
|
||||
CHITBOXES_T,
|
||||
CHURTBOX_T,
|
||||
CSPRITE_T,
|
||||
CMOVEABLE_T,
|
||||
CLIFETIMER_T,
|
||||
CWATERRUNNER_T,
|
||||
CAIRTIMER_T,
|
||||
CEMITTER_T,
|
||||
CSQUISHABLE_T
|
||||
};
|
||||
|
||||
typedef struct _CMovementState_t {
|
||||
uint8_t ground_state;
|
||||
uint8_t water_state;
|
||||
uint8_t x_dir;
|
||||
float water_overlap;
|
||||
} CMovementState_t;
|
||||
|
||||
typedef struct _CJump_t {
|
||||
int jump_speed;
|
||||
uint8_t jumps;
|
||||
uint8_t max_jumps;
|
||||
uint8_t coyote_timer;
|
||||
bool jumped;
|
||||
bool jump_ready;
|
||||
bool short_hop;
|
||||
bool jump_released;
|
||||
} CJump_t;
|
||||
|
||||
typedef enum PlayerState {
|
||||
GROUNDED,
|
||||
AIR,
|
||||
} PlayerState_t;
|
||||
|
||||
typedef struct _CPlayerState_t {
|
||||
Vector2 player_dir;
|
||||
uint8_t jump_pressed;
|
||||
uint8_t is_crouch;
|
||||
bool ladder_state;
|
||||
bool locked; // Whether to respond to inputs
|
||||
} CPlayerState_t;
|
||||
|
||||
typedef enum ContainerItem {
|
||||
CONTAINER_EMPTY,
|
||||
CONTAINER_LEFT_ARROW,
|
||||
CONTAINER_RIGHT_ARROW,
|
||||
CONTAINER_UP_ARROW,
|
||||
CONTAINER_DOWN_ARROW,
|
||||
CONTAINER_COIN,
|
||||
CONTAINER_BOMB,
|
||||
CONTAINER_EXPLOSION,
|
||||
} ContainerItem_t;
|
||||
|
||||
typedef enum ContainerMaterial {
|
||||
WOODEN_CONTAINER,
|
||||
METAL_CONTAINER,
|
||||
} ContainerMaterial_t;
|
||||
|
||||
typedef struct _CContainer_t {
|
||||
ContainerMaterial_t material;
|
||||
ContainerItem_t item;
|
||||
} CContainer_t;
|
||||
|
||||
typedef struct _CHitBoxes_t {
|
||||
Rectangle boxes[2];
|
||||
uint8_t n_boxes;
|
||||
uint8_t atk;
|
||||
bool one_hit;
|
||||
} CHitBoxes_t;
|
||||
|
||||
typedef struct _CHurtbox_t {
|
||||
Vector2 offset;
|
||||
Vector2 size;
|
||||
uint8_t def;
|
||||
unsigned int damage_src;
|
||||
} CHurtbox_t;
|
||||
|
||||
typedef struct _CLifeTimer_t {
|
||||
float life_time;
|
||||
} CLifeTimer_t;
|
||||
|
||||
typedef struct _CAirTimer_t {
|
||||
float max_ftimer;
|
||||
float curr_ftimer;
|
||||
float decay_rate;
|
||||
uint8_t max_count;
|
||||
uint8_t curr_count;
|
||||
} CAirTimer_t;
|
||||
|
||||
typedef struct _BFSTile {
|
||||
int32_t to;
|
||||
int32_t from;
|
||||
bool reachable;
|
||||
}BFSTile_t;
|
||||
|
||||
typedef struct _BFSTileMap {
|
||||
BFSTile_t* tilemap;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t len;
|
||||
}BFSTileMap_t;
|
||||
|
||||
typedef enum _WaterRunnerState
|
||||
{
|
||||
BFS_RESET = 0,
|
||||
BFS_START,
|
||||
LOWEST_POINT_SEARCH,
|
||||
LOWEST_POINT_MOVEMENT,
|
||||
REACHABILITY_SEARCH,
|
||||
SCANLINE_FILL,
|
||||
FILL_COMPLETE,
|
||||
}WaterRunerState_t;
|
||||
|
||||
typedef struct _CWaterRunner {
|
||||
BFSTileMap_t bfs_tilemap;
|
||||
WaterRunerState_t state;
|
||||
struct sc_queue_32 bfs_queue;
|
||||
bool* visited;
|
||||
int32_t current_tile;
|
||||
int32_t target_tile;
|
||||
int32_t fill_idx;
|
||||
int16_t fill_range[2];
|
||||
uint8_t movement_delay;
|
||||
int8_t movement_speed;
|
||||
int16_t counter;
|
||||
float fractional;
|
||||
}CWaterRunner_t;
|
||||
|
||||
typedef unsigned int (*sprite_transition_func_t)(Entity_t *ent); // Transition requires knowledge of the entity
|
||||
typedef void (*sprite_sfx_func_t)(GameEngine_t*, Entity_t *ent); // Transition requires knowledge of the entity
|
||||
|
||||
typedef struct _SpriteRenderInfo
|
||||
{
|
||||
Sprite_t* sprite;
|
||||
Vector2 offset;
|
||||
AnchorPoint_t src_anchor;
|
||||
AnchorPoint_t dest_anchor;
|
||||
} SpriteRenderInfo_t;
|
||||
|
||||
typedef struct _CSprite_t {
|
||||
RenderInfoNode node;
|
||||
SpriteRenderInfo_t* sprites;
|
||||
sprite_transition_func_t transition_func;
|
||||
sprite_sfx_func_t sfx_func;
|
||||
unsigned int current_idx;
|
||||
int current_frame;
|
||||
float fractional;
|
||||
float rotation_speed; // Degree / s
|
||||
int elapsed;
|
||||
Vector2 offset;
|
||||
uint8_t depth;
|
||||
bool pause;
|
||||
} CSprite_t;
|
||||
|
||||
typedef struct _CMoveable_t {
|
||||
uint16_t move_speed;
|
||||
Vector2 prev_pos;
|
||||
Vector2 target_pos;
|
||||
bool gridmove;
|
||||
} CMoveable_t;
|
||||
|
||||
typedef struct _CEmitter_t
|
||||
{
|
||||
EmitterHandle handle;
|
||||
Vector2 offset;
|
||||
} CEmitter_t;
|
||||
|
||||
typedef struct _CSquishable_t {
|
||||
bool active; //< Dummy variable
|
||||
} CSquishable_t;
|
|
@ -1,16 +1,12 @@
|
|||
// Constants to be used in game
|
||||
#ifndef __CONSTANTS_H
|
||||
#define __CONSTANTS_H
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef TILE16_SIZE
|
||||
#define TILE_SIZE 32
|
||||
#define DEFAULT_MAP_WIDTH 48
|
||||
#define DEFAULT_MAP_HEIGHT 32
|
||||
#define VIEWABLE_EDITOR_MAP_WIDTH 32
|
||||
#define VIEWABLE_EDITOR_MAP_HEIGHT 16
|
||||
#define VIEWABLE_MAP_WIDTH 25
|
||||
#define VIEWABLE_MAP_HEIGHT 14
|
||||
#define VIEWABLE_MAP_WIDTH 32
|
||||
#define VIEWABLE_MAP_HEIGHT 16
|
||||
#else
|
||||
#define TILE_SIZE 16
|
||||
#define DEFAULT_MAP_WIDTH 64
|
||||
|
@ -21,13 +17,13 @@
|
|||
|
||||
#define DELTA_T 0.017
|
||||
#define GRAV_ACCEL 1500
|
||||
#define JUMP_SPEED 600
|
||||
#define JUMP_SPEED 70
|
||||
#define MOVE_ACCEL 1300
|
||||
|
||||
#ifndef TILE16_SIZE
|
||||
#define PLAYER_WIDTH 22
|
||||
#define PLAYER_WIDTH 28
|
||||
#define PLAYER_HEIGHT 42
|
||||
#define PLAYER_C_WIDTH 30
|
||||
#define PLAYER_C_WIDTH 28
|
||||
#define PLAYER_C_HEIGHT 26
|
||||
#else
|
||||
#define PLAYER_WIDTH 14
|
||||
|
@ -43,17 +39,12 @@
|
|||
#define GROUND_X_FRICTION 6.1
|
||||
#define GROUND_Y_FRICTION 1.0
|
||||
|
||||
#define ARROW_SPEED 400
|
||||
#define ARROW_SPEED 350
|
||||
|
||||
#define MAX_WATER_LEVEL 4
|
||||
#define WATER_BBOX_STEP (TILE_SIZE / MAX_WATER_LEVEL)
|
||||
|
||||
#define MAX_LEVEL_NUM 50
|
||||
#define MAX_N_TILES 4096
|
||||
|
||||
static const uint8_t CONNECTIVITY_TILE_MAPPING[16] = {
|
||||
0,3,15,14,
|
||||
1,2,12,13,
|
||||
7,6,11,10,
|
||||
4,5,8 ,9 ,
|
||||
};
|
||||
#endif // __CONSTANTS_H
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,35 +0,0 @@
|
|||
#include "mempool.h"
|
||||
#include "components.h"
|
||||
/** This file is supposed to implement any required engine functions
|
||||
*/
|
||||
|
||||
DEFINE_COMP_MEMPOOL_BUF(CMovementState_t, MAX_COMP_POOL_SIZE)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CJump_t, 8)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CPlayerState_t, 8)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CContainer_t, MAX_COMP_POOL_SIZE)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CHitBoxes_t, MAX_COMP_POOL_SIZE)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CHurtbox_t, MAX_COMP_POOL_SIZE)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CSprite_t, MAX_COMP_POOL_SIZE)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CMoveable_t, MAX_COMP_POOL_SIZE)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CLifeTimer_t, MAX_COMP_POOL_SIZE)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CWaterRunner_t, 32)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CAirTimer_t, 8)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CEmitter_t, 32)
|
||||
DEFINE_COMP_MEMPOOL_BUF(CSquishable_t, MAX_COMP_POOL_SIZE)
|
||||
|
||||
// Component mempools are added in the order of the component enums
|
||||
BEGIN_DEFINE_COMP_MEMPOOL
|
||||
ADD_COMP_MEMPOOL(CMovementState_t)
|
||||
ADD_COMP_MEMPOOL(CJump_t)
|
||||
ADD_COMP_MEMPOOL(CPlayerState_t)
|
||||
ADD_COMP_MEMPOOL(CContainer_t)
|
||||
ADD_COMP_MEMPOOL(CHitBoxes_t)
|
||||
ADD_COMP_MEMPOOL(CHurtbox_t)
|
||||
ADD_COMP_MEMPOOL(CSprite_t)
|
||||
ADD_COMP_MEMPOOL(CMoveable_t)
|
||||
ADD_COMP_MEMPOOL(CLifeTimer_t)
|
||||
ADD_COMP_MEMPOOL(CWaterRunner_t)
|
||||
ADD_COMP_MEMPOOL(CAirTimer_t)
|
||||
ADD_COMP_MEMPOOL(CEmitter_t)
|
||||
ADD_COMP_MEMPOOL(CSquishable_t)
|
||||
END_DEFINE_COMP_MEMPOOL
|
|
@ -1,13 +1,12 @@
|
|||
#ifndef __ENT_IMPL_H
|
||||
#define __ENT_IMPL_H
|
||||
#include "assets.h"
|
||||
#include "assets_tag.h"
|
||||
#include "components.h"
|
||||
|
||||
bool init_player_creation(const char* info_file, Assets_t* assets);
|
||||
bool init_player_creation_rres(const char* rres_file, const char* file, Assets_t* assets);
|
||||
Entity_t* create_player(EntityManager_t* ent_manager);
|
||||
Entity_t* create_dead_player(EntityManager_t* ent_manager);
|
||||
Entity_t* create_player_finish(EntityManager_t* ent_manager);
|
||||
|
||||
|
||||
bool init_item_creation(Assets_t* assets);
|
||||
|
@ -16,7 +15,6 @@ Entity_t* create_boulder(EntityManager_t* ent_manager);
|
|||
Entity_t* create_arrow(EntityManager_t* ent_manager, uint8_t dir);
|
||||
Entity_t* create_bomb(EntityManager_t* ent_manager, Vector2 launch_dir);
|
||||
Entity_t* create_explosion(EntityManager_t* ent_manager);
|
||||
Entity_t* create_urchin(EntityManager_t* ent_manager);
|
||||
Entity_t* create_chest(EntityManager_t* ent_manager);
|
||||
Entity_t* create_level_end(EntityManager_t* ent_manager);
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include "tracy/TracyC.h"
|
||||
|
||||
#include "scene_impl.h"
|
||||
#include "game_systems.h"
|
||||
#include "water_flow.h"
|
||||
|
@ -11,7 +9,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
static Tile_t all_tiles[MAX_N_TILES] = {0};
|
||||
static RenderInfoNode all_tile_rendernodes[MAX_N_TILES] = {0};
|
||||
|
||||
#define GAME_LAYER 0
|
||||
#define CONTROL_LAYER 1
|
||||
|
@ -23,77 +20,33 @@ static void level_scene_render_func(Scene_t* scene)
|
|||
BeginTextureMode(scene->layers.render_layers[CONTROL_LAYER].layer_tex);
|
||||
ClearBackground(BLANK);
|
||||
|
||||
if (data->camera.mode == CAMERA_RANGED_MOVEMENT)
|
||||
{
|
||||
// TL
|
||||
DrawLineEx((Vector2){32,32},
|
||||
(Vector2){64,32}, 5, WHITE);
|
||||
DrawLineEx((Vector2){32,32},
|
||||
(Vector2){32,64}, 5, WHITE);
|
||||
//TR
|
||||
DrawLineEx((Vector2){data->game_rec.width - 64,32},
|
||||
(Vector2){data->game_rec.width - 32, 32}, 5, WHITE);
|
||||
DrawLineEx((Vector2){data->game_rec.width - 32,32},
|
||||
(Vector2){data->game_rec.width - 32, 64}, 5, WHITE);
|
||||
//BL
|
||||
DrawLineEx((Vector2){32,data->game_rec.height-32},
|
||||
(Vector2){64,data->game_rec.height - 32}, 5, WHITE);
|
||||
DrawLineEx((Vector2){32,data->game_rec.height-64},
|
||||
(Vector2){32, data->game_rec.height - 32}, 5, WHITE);
|
||||
//BR
|
||||
DrawLineEx((Vector2){data->game_rec.width - 64,data->game_rec.height-32},
|
||||
(Vector2){data->game_rec.width - 32,data->game_rec.height - 32}, 5, WHITE);
|
||||
DrawLineEx((Vector2){data->game_rec.width - 32,data->game_rec.height-64},
|
||||
(Vector2){data->game_rec.width - 32, data->game_rec.height - 32}, 5, WHITE);
|
||||
}
|
||||
|
||||
Entity_t* p_ent;
|
||||
sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_ent)
|
||||
{
|
||||
CAirTimer_t* p_air = get_component(p_ent, CAIRTIMER_T);
|
||||
|
||||
Sprite_t* spr = get_sprite(&scene->engine->assets, "p_bigbubble");
|
||||
Vector2 air_pos = {data->game_rec.width - 32, data->game_rec.height - 32};
|
||||
Vector2 air_pos = {data->game_rec.x + data->game_rec.width - 16, data->game_rec.y + data->game_rec.height - 16};
|
||||
for (uint8_t i = 0; i < p_air->curr_count; i++)
|
||||
{
|
||||
draw_sprite(spr, 0, air_pos, 0, false);
|
||||
//DrawCircleV(air_pos, 16, BLUE);
|
||||
DrawCircleV(air_pos, 16, BLUE);
|
||||
air_pos.x -= 32;
|
||||
}
|
||||
}
|
||||
// For DEBUG
|
||||
int gui_x = 5;
|
||||
sprintf(buffer, "%u %u", sc_map_size_64v(&scene->ent_manager.entities), GetFPS());
|
||||
DrawText(buffer, gui_x, data->game_rec.height - 12, 12, WHITE);
|
||||
const int gui_x = data->game_rec.x + data->game_rec.width + 10;
|
||||
//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, 70, 12, BLACK);
|
||||
sprintf(buffer, "FPS: %u", GetFPS());
|
||||
DrawText(buffer, gui_x, 120, 12, BLACK);
|
||||
|
||||
DrawRectangle(0, 0, data->game_rec.width, 32, (Color){0,0,0,128});
|
||||
{
|
||||
DrawText("Z", 300, 5, 24, RED);
|
||||
Sprite_t* spr = get_sprite(&scene->engine->assets, "eye");
|
||||
if (data->camera.mode == CAMERA_RANGED_MOVEMENT)
|
||||
{
|
||||
draw_sprite(spr, 1, (Vector2){332, 0}, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
draw_sprite(spr, 0, (Vector2){332, 0}, 0, false);
|
||||
}
|
||||
}
|
||||
DrawText(data->level_pack->levels[data->current_level].level_name, 5, 5, 24, WHITE);
|
||||
{
|
||||
sprintf(buffer, "%u / %u", data->coins.current, data->coins.total);
|
||||
gui_x = data->game_rec.width - MeasureText(buffer, 24) - 5;
|
||||
// TODO: Use the chest sprite
|
||||
Sprite_t* spr = get_sprite(&scene->engine->assets, "chest");
|
||||
draw_sprite_pro(spr, 0, (Vector2){gui_x-32, 8}, 0, 0, (Vector2){0.5,0.5}, WHITE);
|
||||
DrawText(buffer, gui_x, 5, 24, RED);
|
||||
}
|
||||
print_mempool_stats(buffer);
|
||||
DrawText(buffer, gui_x, 150, 12, BLACK);
|
||||
EndTextureMode();
|
||||
}
|
||||
|
||||
static void level_do_action(Scene_t* scene, ActionType_t action, bool pressed)
|
||||
{
|
||||
LevelSceneData_t* data = &(CONTAINER_OF(scene, LevelScene_t, scene)->data);
|
||||
CPlayerState_t* p_playerstate;
|
||||
sc_map_foreach_value(&scene->ent_manager.component_map[CPLAYERSTATE_T], p_playerstate)
|
||||
{
|
||||
|
@ -101,27 +54,19 @@ static void level_do_action(Scene_t* scene, ActionType_t action, bool pressed)
|
|||
{
|
||||
case ACTION_UP:
|
||||
p_playerstate->player_dir.y = (pressed)? -1 : 0;
|
||||
if (data->camera.mode == CAMERA_RANGED_MOVEMENT) data->camera.cam.target.y -= 20;
|
||||
break;
|
||||
case ACTION_DOWN:
|
||||
p_playerstate->player_dir.y = (pressed)? 1 : 0;
|
||||
if (data->camera.mode == CAMERA_RANGED_MOVEMENT) data->camera.cam.target.y += 20;
|
||||
break;
|
||||
case ACTION_LEFT:
|
||||
p_playerstate->player_dir.x = (pressed)? -1 : 0;
|
||||
if (data->camera.mode == CAMERA_RANGED_MOVEMENT) data->camera.cam.target.x -= 20;
|
||||
break;
|
||||
case ACTION_RIGHT:
|
||||
p_playerstate->player_dir.x = (pressed)? 1 : 0;
|
||||
if (data->camera.mode == CAMERA_RANGED_MOVEMENT) data->camera.cam.target.x += 20;
|
||||
break;
|
||||
case ACTION_JUMP:
|
||||
p_playerstate->jump_pressed = pressed;
|
||||
break;
|
||||
case ACTION_LOOKAHEAD:
|
||||
p_playerstate->locked = pressed;
|
||||
data->camera.mode = pressed ? CAMERA_RANGED_MOVEMENT : CAMERA_FOLLOW_PLAYER;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -144,7 +89,7 @@ static void level_do_action(Scene_t* scene, ActionType_t action, bool pressed)
|
|||
case ACTION_EXIT:
|
||||
if(scene->engine != NULL)
|
||||
{
|
||||
change_scene(scene->engine, MAIN_MENU_SCENE);
|
||||
change_scene(scene->engine, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -155,18 +100,17 @@ static void level_do_action(Scene_t* scene, ActionType_t action, bool pressed)
|
|||
|
||||
static void render_regular_game_scene(Scene_t* scene)
|
||||
{
|
||||
TracyCZoneN(ctx, "GameRender", true)
|
||||
// This function will render the game scene outside of the intended draw function
|
||||
// Just for clarity and separation of logic
|
||||
LevelSceneData_t* data = &(CONTAINER_OF(scene, LevelScene_t, scene)->data);
|
||||
TileGrid_t tilemap = data->tilemap;
|
||||
|
||||
Entity_t* p_ent;
|
||||
Vector2 min = GetScreenToWorld2D((Vector2){0, 0}, data->camera.cam);
|
||||
Vector2 min = GetScreenToWorld2D((Vector2){data->game_rec.x, data->game_rec.y}, data->camera.cam);
|
||||
Vector2 max = GetScreenToWorld2D(
|
||||
(Vector2){
|
||||
data->game_rec.width,
|
||||
data->game_rec.height
|
||||
data->game_rec.x + data->game_rec.width,
|
||||
data->game_rec.y + data->game_rec.height
|
||||
},
|
||||
data->camera.cam
|
||||
);
|
||||
|
@ -177,95 +121,10 @@ static void render_regular_game_scene(Scene_t* scene)
|
|||
max.x = (int)fmin(tilemap.width, max.x + 1);
|
||||
max.y = (int)fmin(tilemap.height, max.y + 1);
|
||||
|
||||
// Queue TileMap rendering
|
||||
for (int tile_y = min.y; tile_y < max.y; tile_y++)
|
||||
{
|
||||
for (int tile_x = min.x; tile_x < max.x; tile_x++)
|
||||
{
|
||||
|
||||
int i = tile_x + tile_y * tilemap.width;
|
||||
// Tile render nodes is static on load and is not dynamically updated.
|
||||
// We exploit the fact that all tiles can only change into an empty
|
||||
// tile.
|
||||
// This won't work if a tile can change into something else
|
||||
if (tilemap.tiles[i].tile_type == EMPTY_TILE) continue;
|
||||
|
||||
uint8_t depth = 2;
|
||||
if (tilemap.tiles[i].tile_type == LADDER)
|
||||
{
|
||||
depth = 0;
|
||||
}
|
||||
add_render_node(&data->render_manager, all_tile_rendernodes + i, depth);
|
||||
}
|
||||
}
|
||||
|
||||
// Queue Sprite rendering
|
||||
unsigned int ent_idx;
|
||||
CSprite_t* p_cspr;
|
||||
sc_map_foreach(&scene->ent_manager.component_map[CSPRITE_T], ent_idx, p_cspr)
|
||||
{
|
||||
Entity_t* p_ent = get_entity(&scene->ent_manager, ent_idx);
|
||||
if (!p_ent->m_alive) continue;
|
||||
|
||||
const SpriteRenderInfo_t spr = p_cspr->sprites[p_cspr->current_idx];
|
||||
if (spr.sprite == NULL) continue;
|
||||
|
||||
Vector2 pos = p_ent->position;
|
||||
CBBox_t* p_bbox = get_component(p_ent, CBBOX_COMP_T);
|
||||
if (p_bbox != NULL)
|
||||
{
|
||||
pos = Vector2Add(
|
||||
pos,
|
||||
get_anchor_offset(p_bbox->size, spr.dest_anchor, p_cspr->node.flip & 1)
|
||||
);
|
||||
}
|
||||
pos = Vector2Subtract(
|
||||
pos,
|
||||
get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->node.flip & 1)
|
||||
);
|
||||
|
||||
Vector2 offset = spr.offset;
|
||||
if (p_cspr->node.flip & 1) offset.x *= -1;
|
||||
|
||||
pos = Vector2Add(pos, offset);
|
||||
// Entity culling
|
||||
if (
|
||||
pos.x + spr.sprite->frame_size.x < min.x * tilemap.tile_size
|
||||
|| pos.x > max.x * tilemap.tile_size
|
||||
|| pos.y + spr.sprite->frame_size.y < min.y * tilemap.tile_size
|
||||
|| pos.y > max.y * tilemap.tile_size
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_ent->m_tag == LEVEL_END_TAG)
|
||||
{
|
||||
p_cspr->current_frame = 2 * data->selected_solid_tilemap + (
|
||||
(data->coins.current < data->coins.total) ? 0 : 1);
|
||||
}
|
||||
|
||||
p_cspr->node.spr = spr.sprite;
|
||||
p_cspr->node.frame_num = p_cspr->current_frame;
|
||||
p_cspr->node.pos = pos;
|
||||
add_render_node(&data->render_manager, &p_cspr->node, p_cspr->depth);
|
||||
}
|
||||
|
||||
Texture2D* bg = get_texture(&scene->engine->assets, "bg_tex");
|
||||
|
||||
BeginTextureMode(scene->layers.render_layers[GAME_LAYER].layer_tex);
|
||||
ClearBackground(WHITE);
|
||||
DrawTexturePro(*bg,
|
||||
//(Rectangle){0,0,64,64},
|
||||
(Rectangle){min.x,0, data->game_rec.width, data->game_rec.height},
|
||||
(Rectangle){0,0, data->game_rec.width, data->game_rec.height},
|
||||
//(Rectangle){0,0,game_rec.width, game_rec.height},
|
||||
(Vector2){0,0}, 0.0f, WHITE
|
||||
);
|
||||
|
||||
BeginMode2D(data->camera.cam);
|
||||
|
||||
#ifdef ENABLE_RENDER_FALLBACK
|
||||
for (int tile_y = min.y; tile_y < max.y; tile_y++)
|
||||
{
|
||||
for (int tile_x = min.x; tile_x < max.x; tile_x++)
|
||||
|
@ -274,15 +133,66 @@ static void render_regular_game_scene(Scene_t* scene)
|
|||
int x = tile_x * TILE_SIZE;
|
||||
int y = tile_y * TILE_SIZE;
|
||||
|
||||
if (tilemap.tiles[i].tile_type == LADDER)
|
||||
if (data->tile_sprites[tilemap.tiles[i].tile_type] != NULL)
|
||||
{
|
||||
if (data->tile_sprites[tilemap.tiles[i].tile_type] == NULL)
|
||||
draw_sprite(data->tile_sprites[tilemap.tiles[i].tile_type], 0, (Vector2){x,y}, 0.0f, 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;
|
||||
unsigned 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)
|
||||
{
|
||||
DrawRectangle(x, y, TILE_SIZE, TILE_SIZE, ORANGE);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
if (tilemap.tiles[i].max_water_level < MAX_WATER_LEVEL)
|
||||
{
|
||||
DrawRectangleLinesEx((Rectangle){x, y, TILE_SIZE, TILE_SIZE}, 2.0, ColorAlpha(BLUE, 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sc_map_foreach_value(&scene->ent_manager.entities, p_ent)
|
||||
{
|
||||
CBBox_t* p_bbox = get_component(p_ent, CBBOX_COMP_T);
|
||||
|
@ -297,8 +207,18 @@ static void render_regular_game_scene(Scene_t* scene)
|
|||
|| p_ent->position.y > max.y * tilemap.tile_size
|
||||
) continue;
|
||||
|
||||
// Render Sprite only
|
||||
CSprite_t* p_cspr = get_component(p_ent, CSPRITE_T);
|
||||
if (p_cspr != NULL) continue;
|
||||
if (p_cspr != NULL)
|
||||
{
|
||||
const SpriteRenderInfo_t spr = p_cspr->sprites[p_cspr->current_idx];
|
||||
if (spr.sprite != NULL)
|
||||
{
|
||||
Vector2 pos = Vector2Add(p_ent->position, spr.offset);
|
||||
draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->flip_x);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Continue here only if no sprite
|
||||
Color colour;
|
||||
|
@ -318,12 +238,6 @@ static void render_regular_game_scene(Scene_t* scene)
|
|||
break;
|
||||
}
|
||||
|
||||
if (p_ent->m_tag == LEVEL_END_TAG)
|
||||
{
|
||||
DrawCircleV(p_ent->position, tilemap.tile_size >> 1, (data->coins.current < data->coins.total)? RED : GREEN);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p_bbox != NULL)
|
||||
{
|
||||
if (p_ent->m_tag == BOULDER_ENT_TAG)
|
||||
|
@ -388,92 +302,27 @@ static void render_regular_game_scene(Scene_t* scene)
|
|||
}
|
||||
}
|
||||
}
|
||||
for (int tile_y = min.y; tile_y < max.y; tile_y++)
|
||||
|
||||
|
||||
sc_map_foreach_value(&scene->ent_manager.entities_map[DYNMEM_ENT_TAG], p_ent)
|
||||
{
|
||||
for (int tile_x = min.x; tile_x < max.x; tile_x++)
|
||||
{
|
||||
int i = tile_x + tile_y * tilemap.width;
|
||||
int x = tile_x * TILE_SIZE;
|
||||
int y = tile_y * TILE_SIZE;
|
||||
CWaterRunner_t* p_runner = get_component(p_ent, CWATERRUNNER_T);
|
||||
|
||||
if (tilemap.tiles[i].tile_type != LADDER)
|
||||
{
|
||||
uint8_t tile_sprite_idx = tilemap.tiles[i].tile_type + tilemap.tiles[i].rotation;
|
||||
if (tilemap.tiles[i].tile_type == SOLID_TILE)
|
||||
{
|
||||
if (data->solid_tile_sprites == NULL) {
|
||||
DrawRectangle(x, y, TILE_SIZE, TILE_SIZE, BLACK);
|
||||
}
|
||||
}
|
||||
else if (data->tile_sprites[tile_sprite_idx] == NULL)
|
||||
{
|
||||
if (tilemap.tiles[i].tile_type == ONEWAY_TILE)
|
||||
{
|
||||
DrawRectangle(x, y, TILE_SIZE, TILE_SIZE, MAROON);
|
||||
}
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
#endif //ENABLE_RENDER_FALLBACK
|
||||
|
||||
execute_render(&data->render_manager);
|
||||
|
||||
// Particle effect will always be in front of everything except water
|
||||
draw_particle_system(&scene->part_sys);
|
||||
|
||||
// Render water
|
||||
// Draw water tile
|
||||
for (int tile_y = min.y; tile_y < max.y; tile_y++)
|
||||
{
|
||||
for (int tile_x = min.x; tile_x < max.x; tile_x++)
|
||||
{
|
||||
int i = tile_x + tile_y * tilemap.width;
|
||||
if (!tilemap.tiles[i].wet && tilemap.tiles[i].water_level == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int x = tile_x * TILE_SIZE;
|
||||
int y = tile_y * TILE_SIZE;
|
||||
|
||||
// Draw water flow
|
||||
#define SURFACE_THICKNESS 4
|
||||
int up = i - tilemap.width;
|
||||
unsigned 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));
|
||||
}
|
||||
}
|
||||
|
||||
//if (tilemap.tiles[i].max_water_level < MAX_WATER_LEVEL)
|
||||
//{
|
||||
// DrawRectangleLinesEx((Rectangle){x, y, TILE_SIZE, TILE_SIZE}, 2.0, ColorAlpha(BLUE, 0.5));
|
||||
//}
|
||||
|
||||
uint32_t water_height = tilemap.tiles[i].water_level * WATER_BBOX_STEP;
|
||||
Color water_colour = ColorAlpha(BLUE, 0.5);
|
||||
DrawRectangle(
|
||||
|
@ -485,64 +334,31 @@ static void render_regular_game_scene(Scene_t* scene)
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw Border
|
||||
DrawLine(0, 0, 0, tilemap.height * tilemap.tile_size, BLACK);
|
||||
DrawLine(0, 0, tilemap.width * TILE_SIZE, 0, BLACK);
|
||||
int val = (tilemap.width) * tilemap.tile_size;
|
||||
DrawLine(val, 0, val, tilemap.height * tilemap.tile_size, BLACK);
|
||||
val = (tilemap.height) * tilemap.tile_size;
|
||||
DrawLine(0, val, tilemap.width * TILE_SIZE, val, BLACK);
|
||||
EndMode2D();
|
||||
EndTextureMode();
|
||||
TracyCZoneEnd(ctx)
|
||||
}
|
||||
|
||||
static void at_level_start(Scene_t* scene)
|
||||
{
|
||||
LevelSceneData_t* data = &(CONTAINER_OF(scene, LevelScene_t, scene)->data);
|
||||
data->sm.state = LEVEL_STATE_RUNNING;
|
||||
}
|
||||
|
||||
static void at_level_complete(Scene_t* scene)
|
||||
{
|
||||
LevelSceneData_t* data = &(CONTAINER_OF(scene, LevelScene_t, scene)->data);
|
||||
data->sm.fractional += scene->delta_time;
|
||||
if (data->sm.fractional > 1.0f)
|
||||
{
|
||||
data->sm.fractional -= 1.0f;
|
||||
data->sm.counter++;
|
||||
}
|
||||
if (data->sm.counter >= 1)
|
||||
{
|
||||
do_action(scene, ACTION_NEXTLEVEL, false);
|
||||
data->sm.state = LEVEL_STATE_STARTING;
|
||||
}
|
||||
}
|
||||
|
||||
void init_game_scene(LevelScene_t* scene)
|
||||
{
|
||||
init_scene(&scene->scene, &level_do_action, ENABLE_ENTITY_MANAGEMENT_SYSTEM | ENABLE_PARTICLE_SYSTEM);
|
||||
init_scene(&scene->scene, &level_do_action);
|
||||
init_entity_tag_map(&scene->scene.ent_manager, PLAYER_ENT_TAG, 4);
|
||||
init_entity_tag_map(&scene->scene.ent_manager, BOULDER_ENT_TAG, MAX_COMP_POOL_SIZE);
|
||||
init_entity_tag_map(&scene->scene.ent_manager, LEVEL_END_TAG, 16);
|
||||
init_entity_tag_map(&scene->scene.ent_manager, DYNMEM_ENT_TAG, 16);
|
||||
|
||||
scene->data.tilemap.tiles = all_tiles;
|
||||
scene->data.tilemap.render_nodes = all_tile_rendernodes;
|
||||
init_level_scene_data(
|
||||
&scene->data, MAX_N_TILES, all_tiles,
|
||||
(Rectangle){
|
||||
0,0,
|
||||
VIEWABLE_MAP_WIDTH*TILE_SIZE, VIEWABLE_MAP_HEIGHT*TILE_SIZE
|
||||
}
|
||||
(Rectangle){25, 25, 32*TILE_SIZE, 18*TILE_SIZE}
|
||||
);
|
||||
for (size_t i = 0; i < MAX_N_TILES; i++)
|
||||
{
|
||||
memset(all_tile_rendernodes + i, 0, sizeof(RenderInfoNode));
|
||||
all_tile_rendernodes[i].pos = (Vector2){
|
||||
(i % scene->data.tilemap.width) * TILE_SIZE,
|
||||
(i / scene->data.tilemap.width) * TILE_SIZE,
|
||||
};
|
||||
all_tile_rendernodes[i].scale = (Vector2){1,1};
|
||||
all_tile_rendernodes[i].colour = WHITE;
|
||||
}
|
||||
scene->data.sm.state_functions[LEVEL_STATE_STARTING] = at_level_start;
|
||||
scene->data.sm.state_functions[LEVEL_STATE_RUNNING] = NULL;
|
||||
scene->data.sm.state_functions[LEVEL_STATE_DEAD] = NULL;
|
||||
scene->data.sm.state_functions[LEVEL_STATE_COMPLETE] = at_level_complete;
|
||||
|
||||
scene->scene.bg_colour = LIGHTGRAY;
|
||||
add_scene_layer(
|
||||
|
@ -550,17 +366,18 @@ void init_game_scene(LevelScene_t* scene)
|
|||
scene->data.game_rec
|
||||
);
|
||||
add_scene_layer(
|
||||
&scene->scene,
|
||||
scene->data.game_rec.width, scene->data.game_rec.height,
|
||||
scene->data.game_rec
|
||||
&scene->scene, scene->scene.engine->intended_window_size.x,
|
||||
scene->scene.engine->intended_window_size.y,
|
||||
(Rectangle){
|
||||
0, 0,
|
||||
scene->scene.engine->intended_window_size.x,
|
||||
scene->scene.engine->intended_window_size.y
|
||||
}
|
||||
);
|
||||
|
||||
create_player(&scene->scene.ent_manager);
|
||||
update_entity_manager(&scene->scene.ent_manager);
|
||||
|
||||
// Set up textures
|
||||
scene->data.solid_tile_sprites = get_sprite(&scene->scene.engine->assets, "stile0");
|
||||
|
||||
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);
|
||||
|
@ -576,6 +393,7 @@ void init_game_scene(LevelScene_t* scene)
|
|||
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, &edge_velocity_check_system);
|
||||
sc_array_add(&scene->scene.systems, &state_transition_update_system);
|
||||
sc_array_add(&scene->scene.systems, &update_entity_emitter_system);
|
||||
sc_array_add(&scene->scene.systems, &player_ground_air_transition_system);
|
||||
|
@ -585,10 +403,8 @@ void init_game_scene(LevelScene_t* scene)
|
|||
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);
|
||||
sc_array_add(&scene->scene.systems, &check_player_dead_system);
|
||||
sc_array_add(&scene->scene.systems, &level_end_detection_system);
|
||||
sc_array_add(&scene->scene.systems, &level_state_management_system);
|
||||
sc_array_add(&scene->scene.systems, &render_regular_game_scene);
|
||||
sc_array_add(&scene->scene.systems, &level_scene_render_func);
|
||||
// This avoid graphical glitch, not essential
|
||||
|
@ -603,13 +419,11 @@ void init_game_scene(LevelScene_t* scene)
|
|||
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);
|
||||
sc_map_put_64(&scene->scene.action_map, KEY_Z, ACTION_LOOKAHEAD);
|
||||
|
||||
}
|
||||
|
||||
void free_game_scene(LevelScene_t* scene)
|
||||
{
|
||||
clear_all_game_entities(scene);
|
||||
free_scene(&scene->scene);
|
||||
term_level_scene_data(&scene->data);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,16 +16,16 @@ void state_transition_update_system(Scene_t* scene);
|
|||
void update_entity_emitter_system(Scene_t* scene);
|
||||
void update_tilemap_system(Scene_t* scene);
|
||||
void hitbox_update_system(Scene_t* scene);
|
||||
void edge_velocity_check_system(Scene_t* scene);
|
||||
void sprite_animation_system(Scene_t* scene);
|
||||
void boulder_destroy_wooden_tile_system(Scene_t* scene);
|
||||
void camera_update_system(Scene_t* scene);
|
||||
void container_destroy_system(Scene_t* scene);
|
||||
void player_dir_reset_system(Scene_t* scene);
|
||||
void check_player_dead_system(Scene_t* scene);
|
||||
void player_respawn_system(Scene_t* scene);
|
||||
void lifetimer_update_system(Scene_t* scene);
|
||||
void airtimer_update_system(Scene_t* scene);
|
||||
void spike_collision_system(Scene_t* scene);
|
||||
void level_end_detection_system(Scene_t* scene);
|
||||
void level_state_management_system(Scene_t* scene);
|
||||
|
||||
#endif // __GAME_SYSTEMS_H
|
||||
|
|
|
@ -1,31 +1,20 @@
|
|||
#include "EC.h"
|
||||
#include "assets_tag.h"
|
||||
#include "ent_impl.h"
|
||||
#include "constants.h"
|
||||
#include "raymath.h"
|
||||
|
||||
static SpriteRenderInfo_t item_sprite_map[22] = {0};
|
||||
#define URCHIN_OFFSET 6
|
||||
static SpriteRenderInfo_t item_sprite_map[20] = {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, "r_arrow");
|
||||
//item_sprite_map[2].offset = (Vector2){-8, 6};
|
||||
item_sprite_map[2].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[2].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[2].offset = (Vector2){-8, 4};
|
||||
item_sprite_map[3].sprite = get_sprite(assets, "u_arrow");
|
||||
item_sprite_map[3].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[3].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[4].sprite = get_sprite(assets, "l_arrow");
|
||||
item_sprite_map[4].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[4].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[5].sprite = get_sprite(assets, "d_arrow");
|
||||
item_sprite_map[5].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[5].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[6].sprite = get_sprite(assets, "bomb");
|
||||
item_sprite_map[6].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[6].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[6].offset = (Vector2){0, -4};
|
||||
item_sprite_map[7].sprite = get_sprite(assets, "w_ra_crate");
|
||||
item_sprite_map[8].sprite = get_sprite(assets, "m_ra_crate");
|
||||
item_sprite_map[9].sprite = get_sprite(assets, "w_ua_crate");
|
||||
|
@ -37,16 +26,9 @@ bool init_item_creation(Assets_t* assets)
|
|||
item_sprite_map[15].sprite = get_sprite(assets, "w_b_crate");
|
||||
item_sprite_map[16].sprite = get_sprite(assets, "m_b_crate");
|
||||
item_sprite_map[17].sprite = get_sprite(assets, "explode");
|
||||
item_sprite_map[17].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[17].src_anchor = AP_MID_CENTER;
|
||||
item_sprite_map[17].offset = (Vector2){-12, -12};
|
||||
item_sprite_map[18].sprite = get_sprite(assets, "chest");
|
||||
item_sprite_map[19].sprite = get_sprite(assets, "boulder");
|
||||
item_sprite_map[20].sprite = get_sprite(assets, "exit");
|
||||
item_sprite_map[20].src_anchor = AP_BOT_CENTER;
|
||||
item_sprite_map[20].src_anchor = AP_BOT_CENTER;
|
||||
item_sprite_map[20].offset = (Vector2){0, TILE_SIZE >> 1};
|
||||
item_sprite_map[21].sprite = get_sprite(assets, "urchin");
|
||||
item_sprite_map[21].offset = (Vector2){-URCHIN_OFFSET, -URCHIN_OFFSET};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -62,7 +44,7 @@ Entity_t* create_crate(EntityManager_t* ent_manager, bool metal, ContainerItem_t
|
|||
p_bbox->fragile = false;
|
||||
|
||||
CTransform_t* p_ctransform = add_component(p_crate, CTRANSFORM_COMP_T);
|
||||
p_ctransform->grav_delay = 0.10f;
|
||||
p_ctransform->grav_delay = 0.20f;
|
||||
p_ctransform->shape_factor = metal ? (Vector2){0.7,0.7} : (Vector2){0.8,0.8} ;
|
||||
add_component(p_crate, CMOVEMENTSTATE_T);
|
||||
|
||||
|
@ -74,9 +56,6 @@ Entity_t* create_crate(EntityManager_t* ent_manager, bool metal, ContainerItem_t
|
|||
|
||||
CSprite_t* p_cspr = add_component(p_crate, CSPRITE_T);
|
||||
p_cspr->sprites = item_sprite_map;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->node.colour = WHITE;
|
||||
|
||||
{
|
||||
CContainer_t* p_container = add_component(p_crate, CCONTAINER_T);
|
||||
p_container->material = metal? METAL_CONTAINER : WOODEN_CONTAINER;
|
||||
|
@ -125,9 +104,6 @@ Entity_t* create_boulder(EntityManager_t* ent_manager)
|
|||
CSprite_t* p_cspr = add_component(p_boulder, CSPRITE_T);
|
||||
p_cspr->sprites = item_sprite_map;
|
||||
p_cspr->current_idx = 19;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->node.colour = WHITE;
|
||||
p_cspr->depth = 2;
|
||||
|
||||
return p_boulder;
|
||||
}
|
||||
|
@ -151,32 +127,26 @@ Entity_t* create_arrow(EntityManager_t* ent_manager, uint8_t dir)
|
|||
CSprite_t* p_cspr = add_component(p_arrow, CSPRITE_T);
|
||||
p_cspr->sprites = item_sprite_map;
|
||||
p_cspr->current_idx = 2;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->node.colour = WHITE;
|
||||
//p_hitbox->boxes[0] = (Rectangle){TILE_SIZE - 5, TILE_SIZE / 2 - 5, 5, 5};
|
||||
const int HITBOX_LONG_SIDE = 10;
|
||||
const int HITBOX_SHORT_SIDE = 4;
|
||||
const int CENTER_POSITION = (TILE_SIZE - HITBOX_SHORT_SIDE) >> 1;
|
||||
const int HITBOX_CENTER = (HITBOX_SHORT_SIDE >> 1);
|
||||
switch(dir)
|
||||
{
|
||||
case 0:
|
||||
p_hitbox->boxes[0] = (Rectangle){10, TILE_SIZE / 2 - 5, 10, 5};
|
||||
p_ctransform->velocity.x = -ARROW_SPEED;
|
||||
p_cspr->current_idx += 2;
|
||||
p_hitbox->boxes[0] = (Rectangle){-CENTER_POSITION, -HITBOX_CENTER, HITBOX_LONG_SIDE, HITBOX_SHORT_SIDE};
|
||||
break;
|
||||
case 2:
|
||||
p_hitbox->boxes[0] = (Rectangle){-HITBOX_CENTER, -CENTER_POSITION, HITBOX_SHORT_SIDE, HITBOX_LONG_SIDE};
|
||||
p_hitbox->boxes[0] = (Rectangle){TILE_SIZE / 2 - 5, 10, 5, 10};
|
||||
p_ctransform->velocity.y = -ARROW_SPEED;
|
||||
p_cspr->current_idx += 1;
|
||||
break;
|
||||
case 3:
|
||||
p_hitbox->boxes[0] = (Rectangle){-HITBOX_CENTER, CENTER_POSITION - HITBOX_LONG_SIDE, HITBOX_SHORT_SIDE, HITBOX_LONG_SIDE};
|
||||
p_hitbox->boxes[0] = (Rectangle){TILE_SIZE / 2 - 5, 10, 5, 10};
|
||||
p_ctransform->velocity.y = ARROW_SPEED;
|
||||
p_cspr->current_idx += 3;
|
||||
break;
|
||||
default:
|
||||
p_hitbox->boxes[0] = (Rectangle){CENTER_POSITION - HITBOX_LONG_SIDE, -HITBOX_CENTER, HITBOX_LONG_SIDE, HITBOX_SHORT_SIDE};
|
||||
p_hitbox->boxes[0] = (Rectangle){10, TILE_SIZE / 2 - 5, 10, 5};
|
||||
p_ctransform->velocity.x = ARROW_SPEED;
|
||||
break;
|
||||
}
|
||||
|
@ -189,12 +159,22 @@ Entity_t* create_bomb(EntityManager_t* ent_manager, Vector2 launch_dir)
|
|||
Entity_t* p_bomb = add_entity(ent_manager, DESTRUCTABLE_ENT_TAG);
|
||||
if (p_bomb == NULL) return NULL;
|
||||
|
||||
p_bomb->position.x += (TILE_SIZE - 25) / 2;
|
||||
p_bomb->position.y += (TILE_SIZE - 25) / 2;
|
||||
if (launch_dir.x > 0)
|
||||
{
|
||||
p_bomb->position.x += TILE_SIZE/ 2;
|
||||
}
|
||||
else if (launch_dir.x < 0)
|
||||
{
|
||||
p_bomb->position.x -= TILE_SIZE / 2;
|
||||
}
|
||||
|
||||
add_component(p_bomb, CTILECOORD_COMP_T);
|
||||
add_component(p_bomb, CMOVEMENTSTATE_T);
|
||||
CHitBoxes_t* p_hitbox = add_component(p_bomb, CHITBOXES_T);
|
||||
p_hitbox->n_boxes = 1;
|
||||
p_hitbox->boxes[0] = (Rectangle){-13, -13, 26, 26};
|
||||
p_hitbox->boxes[0] = (Rectangle){0, 0, 25, 25};
|
||||
|
||||
p_hitbox->atk = 0;
|
||||
p_hitbox->one_hit = true;
|
||||
|
@ -205,8 +185,6 @@ Entity_t* create_bomb(EntityManager_t* ent_manager, Vector2 launch_dir)
|
|||
CSprite_t* p_cspr = add_component(p_bomb, CSPRITE_T);
|
||||
p_cspr->sprites = item_sprite_map;
|
||||
p_cspr->current_idx = 6;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->node.colour = WHITE;
|
||||
|
||||
CTransform_t* p_ctransform = add_component(p_bomb, CTRANSFORM_COMP_T);
|
||||
p_ctransform->active = true;
|
||||
|
@ -223,8 +201,8 @@ Entity_t* create_explosion(EntityManager_t* ent_manager)
|
|||
Entity_t* p_explosion = add_entity(ent_manager, DESTRUCTABLE_ENT_TAG);
|
||||
if (p_explosion == NULL) return NULL;
|
||||
|
||||
//p_explosion->position.x -= 16;
|
||||
//p_explosion->position.y -= 16;
|
||||
p_explosion->position.x -= 16;
|
||||
p_explosion->position.y -= 16;
|
||||
add_component(p_explosion, CTILECOORD_COMP_T);
|
||||
CHitBoxes_t* p_hitbox = add_component(p_explosion, CHITBOXES_T);
|
||||
p_hitbox->n_boxes = 1;
|
||||
|
@ -234,63 +212,17 @@ Entity_t* create_explosion(EntityManager_t* ent_manager)
|
|||
CTransform_t* p_ctransform = add_component(p_explosion, CTRANSFORM_COMP_T);
|
||||
p_ctransform->movement_mode = KINEMATIC_MOVEMENT;
|
||||
p_ctransform->active = true;
|
||||
const int hitbox_sz = (TILE_SIZE << 1) + (TILE_SIZE >> 1);
|
||||
p_hitbox->boxes[0] = (Rectangle){-(hitbox_sz >> 1), -(hitbox_sz >> 1), hitbox_sz, hitbox_sz};
|
||||
p_hitbox->boxes[0] = (Rectangle){0, 0, TILE_SIZE + 32, TILE_SIZE + 32};
|
||||
|
||||
CSprite_t* p_cspr = add_component(p_explosion, CSPRITE_T);
|
||||
p_cspr->sprites = item_sprite_map;
|
||||
p_cspr->current_idx = 17;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->node.colour = WHITE;
|
||||
p_cspr->depth = 3;
|
||||
|
||||
CLifeTimer_t* p_clifetimer = add_component(p_explosion, CLIFETIMER_T);
|
||||
p_clifetimer->life_time = 0.05f;
|
||||
return p_explosion;
|
||||
}
|
||||
|
||||
Entity_t* create_urchin(EntityManager_t* ent_manager)
|
||||
{
|
||||
// The hit box is larger than the bbox
|
||||
// Unfortunately, it's too late to incorporate the offset for the bbox component
|
||||
// So, offset the hitbox instead and external reposition it.
|
||||
Entity_t* p_urchin = add_entity(ent_manager, URCHIN_ENT_TAG);
|
||||
if (p_urchin == NULL) return NULL;
|
||||
|
||||
CBBox_t* p_bbox = add_component(p_urchin, CBBOX_COMP_T);
|
||||
set_bbox(p_bbox, TILE_SIZE-(URCHIN_OFFSET<<1), TILE_SIZE-(URCHIN_OFFSET<<1));
|
||||
|
||||
CTransform_t* p_ctransform = add_component(p_urchin, CTRANSFORM_COMP_T);
|
||||
p_ctransform->movement_mode = KINEMATIC_MOVEMENT;
|
||||
p_ctransform->bounce_coeff = 1.0f;
|
||||
p_ctransform->velocity.x = -100;
|
||||
p_ctransform->active = true;
|
||||
|
||||
add_component(p_urchin, CTILECOORD_COMP_T);
|
||||
add_component(p_urchin, CMOVEMENTSTATE_T);
|
||||
|
||||
CHurtbox_t* p_hurtbox = add_component(p_urchin, CHURTBOX_T);
|
||||
p_hurtbox->size = p_bbox->size;
|
||||
p_hurtbox->def = 2;
|
||||
p_hurtbox->damage_src = -1;
|
||||
|
||||
CHitBoxes_t* p_hitbox = add_component(p_urchin, CHITBOXES_T);
|
||||
p_hitbox->n_boxes = 1;
|
||||
p_hitbox->boxes[0] = (Rectangle) {-(URCHIN_OFFSET>>1),-(URCHIN_OFFSET>>1),TILE_SIZE-URCHIN_OFFSET,TILE_SIZE-URCHIN_OFFSET};
|
||||
p_hitbox->atk = 2;
|
||||
|
||||
CSprite_t* p_cspr = add_component(p_urchin, CSPRITE_T);
|
||||
p_cspr->sprites = item_sprite_map;
|
||||
p_cspr->current_idx = 21;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->node.colour = WHITE;
|
||||
p_cspr->depth = 2;
|
||||
|
||||
add_component(p_urchin, CSQUISHABLE_T);
|
||||
|
||||
return p_urchin;
|
||||
}
|
||||
|
||||
Entity_t* create_chest(EntityManager_t* ent_manager)
|
||||
{
|
||||
Entity_t* p_chest = add_entity(ent_manager, CHEST_ENT_TAG);
|
||||
|
@ -299,7 +231,7 @@ Entity_t* create_chest(EntityManager_t* ent_manager)
|
|||
CBBox_t* p_bbox = add_component(p_chest, CBBOX_COMP_T);
|
||||
set_bbox(p_bbox, TILE_SIZE, TILE_SIZE);
|
||||
p_bbox->solid = true;
|
||||
p_bbox->fragile = false;
|
||||
p_bbox->fragile = true;
|
||||
|
||||
CTransform_t* p_ctransform = add_component(p_chest, CTRANSFORM_COMP_T);
|
||||
p_ctransform->grav_delay = 0.3f;
|
||||
|
@ -314,9 +246,6 @@ Entity_t* create_chest(EntityManager_t* ent_manager)
|
|||
CSprite_t* p_cspr = add_component(p_chest, CSPRITE_T);
|
||||
p_cspr->sprites = item_sprite_map;
|
||||
p_cspr->current_idx = 18;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->node.colour = WHITE;
|
||||
p_cspr->depth = 2;
|
||||
|
||||
|
||||
return p_chest;
|
||||
|
@ -327,12 +256,6 @@ Entity_t* create_level_end(EntityManager_t* ent_manager)
|
|||
Entity_t* p_flag = add_entity(ent_manager, LEVEL_END_TAG);
|
||||
if (p_flag == NULL) return NULL;
|
||||
|
||||
CSprite_t* p_cspr = add_component(p_flag, CSPRITE_T);
|
||||
p_cspr->sprites = item_sprite_map;
|
||||
p_cspr->current_idx = 20;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->node.colour = WHITE;
|
||||
|
||||
add_component(p_flag, CTILECOORD_COMP_T);
|
||||
add_component(p_flag, CTRANSFORM_COMP_T);
|
||||
return p_flag;
|
||||
}
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
#include "scene_impl.h"
|
||||
#include "assets_tag.h"
|
||||
#include "gui.h"
|
||||
#include "raymath.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static void level_select_render_func(Scene_t* scene)
|
||||
{
|
||||
LevelSelectSceneData_t* data = &(CONTAINER_OF(scene, LevelSelectScene_t, scene)->data);
|
||||
Sprite_t* level_board = get_sprite(&scene->engine->assets, "lvl_board");
|
||||
Sprite_t* level_select = get_sprite(&scene->engine->assets, "lvl_select");
|
||||
Sprite_t* preview = get_sprite(&scene->engine->assets, "lvlprvw");
|
||||
Font* menu_font = get_font(&scene->engine->assets, "MenuFont");
|
||||
BeginTextureMode(scene->layers.render_layers[0].layer_tex);
|
||||
ClearBackground(BLANK);
|
||||
draw_sprite(level_select, 0, (Vector2){0,0},0, false);
|
||||
draw_sprite(level_board, 0, (Vector2){level_select->frame_size.x,0},0, false);
|
||||
|
||||
draw_sprite(preview, data->scroll_area.curr_selection, (Vector2){
|
||||
level_select->frame_size.x + (level_board->frame_size.x - preview->frame_size.x) / 2,
|
||||
(level_board->frame_size.y - preview->frame_size.y) / 2,
|
||||
},0, false);
|
||||
DrawTextEx(*menu_font, "Level Select", (Vector2){60, 20}, 40, 4, BLACK);
|
||||
vert_scrollarea_render(&data->scroll_area);
|
||||
ClearBackground(RAYWHITE);
|
||||
Rectangle draw_rec = (Rectangle){
|
||||
0, data->scroll,
|
||||
scene->layers.render_layers[0].render_area.width,
|
||||
scene->layers.render_layers[0].render_area.height
|
||||
};
|
||||
Vector2 draw_pos = {50, 50};
|
||||
draw_rec.height *= -1;
|
||||
DrawTextureRec(
|
||||
data->level_display.texture,
|
||||
draw_rec,
|
||||
draw_pos,
|
||||
WHITE
|
||||
);
|
||||
EndTextureMode();
|
||||
}
|
||||
|
||||
|
@ -31,70 +29,17 @@ static void level_select_do_action(Scene_t* scene, ActionType_t action, bool pre
|
|||
switch(action)
|
||||
{
|
||||
case ACTION_UP:
|
||||
if (!pressed)
|
||||
if (pressed)
|
||||
{
|
||||
if (data->scroll_area.curr_selection > 0)
|
||||
{
|
||||
data->scroll_area.curr_selection--;
|
||||
vert_scrollarea_refocus(&data->scroll_area);
|
||||
}
|
||||
data->scroll += 3;
|
||||
data->scroll = Clamp(data->scroll, 0, 400);
|
||||
}
|
||||
break;
|
||||
case ACTION_DOWN:
|
||||
if (!pressed)
|
||||
if (pressed)
|
||||
{
|
||||
if (data->scroll_area.curr_selection < data->level_pack->n_levels - 1)
|
||||
{
|
||||
data->scroll_area.curr_selection++;
|
||||
vert_scrollarea_refocus(&data->scroll_area);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_EXIT:
|
||||
if (!pressed)
|
||||
{
|
||||
if(scene->engine != NULL)
|
||||
{
|
||||
change_scene(scene->engine, MAIN_MENU_SCENE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_NEXT_SPAWN:
|
||||
if (!pressed)
|
||||
{
|
||||
unsigned int prev_sel = data->scroll_area.curr_selection;
|
||||
// TODO: Add scene offset to scroll area calculation
|
||||
if (vert_scrollarea_set_pos(&data->scroll_area, scene->mouse_pos) != data->scroll_area.max_items)
|
||||
{
|
||||
vert_scrollarea_refocus(&data->scroll_area);
|
||||
|
||||
if (prev_sel == data->scroll_area.curr_selection)
|
||||
{
|
||||
if (data->level_pack != NULL && data->scroll_area.curr_selection < data->level_pack->n_levels)
|
||||
{
|
||||
// TODO: Need to load the current level
|
||||
LevelScene_t* level_scene = (LevelScene_t*)change_scene(scene->engine, GAME_SCENE);
|
||||
level_scene->data.level_pack = data->level_pack;
|
||||
level_scene->data.current_level = data->scroll_area.curr_selection;
|
||||
reload_level_tilemap(level_scene);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_CONFIRM:
|
||||
if (!pressed)
|
||||
{
|
||||
if (data->level_pack != NULL && data->scroll_area.curr_selection < data->level_pack->n_levels)
|
||||
{
|
||||
// TODO: Need to load the current level
|
||||
LevelScene_t* level_scene = (LevelScene_t*)change_scene(scene->engine, GAME_SCENE);
|
||||
level_scene->data.level_pack = data->level_pack;
|
||||
level_scene->data.current_level = data->scroll_area.curr_selection;
|
||||
reload_level_tilemap(level_scene);
|
||||
|
||||
}
|
||||
data->scroll -= 3;
|
||||
data->scroll = Clamp(data->scroll, 0, 400);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -102,64 +47,31 @@ static void level_select_do_action(Scene_t* scene, ActionType_t action, bool pre
|
|||
}
|
||||
}
|
||||
|
||||
#define FONT_SIZE 22
|
||||
#define TEXT_PADDING 3
|
||||
#define SCROLL_TOTAL_HEIGHT 800
|
||||
void init_level_select_scene(LevelSelectScene_t* scene)
|
||||
{
|
||||
init_scene(&scene->scene, &level_select_do_action, 0);
|
||||
init_scene(&scene->scene, &level_select_do_action);
|
||||
add_scene_layer(
|
||||
&scene->scene, scene->scene.engine->intended_window_size.x,
|
||||
scene->scene.engine->intended_window_size.y,
|
||||
(Rectangle){
|
||||
0, 0,
|
||||
scene->scene.engine->intended_window_size.x,
|
||||
scene->scene.engine->intended_window_size.y
|
||||
}
|
||||
&scene->scene, 300, 400,
|
||||
(Rectangle){0, 0, 300, 400}
|
||||
);
|
||||
scene->scene.bg_colour = BLACK;
|
||||
Sprite_t* level_select = get_sprite(&scene->scene.engine->assets, "lvl_select");
|
||||
vert_scrollarea_init(&scene->data.scroll_area, (Rectangle){50, 75, level_select->frame_size.x * 0.6, level_select->frame_size.y * 3 / 4}, (Vector2){level_select->frame_size.x * 0.6, SCROLL_TOTAL_HEIGHT});
|
||||
vert_scrollarea_set_item_dims(&scene->data.scroll_area, FONT_SIZE, TEXT_PADDING);
|
||||
Font* menu_font = get_font(&scene->scene.engine->assets, "MenuFont");
|
||||
if (menu_font != NULL) {
|
||||
scene->data.scroll_area.comp.font = *menu_font;
|
||||
}
|
||||
char buf[32];
|
||||
ScrollAreaRenderBegin(&scene->data.scroll_area);
|
||||
ClearBackground(BLANK);
|
||||
if (scene->data.level_pack != NULL)
|
||||
scene->data.scroll = 400;
|
||||
scene->data.level_display = LoadRenderTexture(300, 800);
|
||||
const unsigned int n_elems = 800 / (12+3);
|
||||
BeginTextureMode(scene->data.level_display);
|
||||
ClearBackground(GRAY);
|
||||
for (unsigned int i = 0; i < n_elems; ++i)
|
||||
{
|
||||
vert_scrollarea_n_items(&scene->data.scroll_area, scene->data.level_pack->n_levels);
|
||||
for (unsigned int i = 0; i < scene->data.level_pack->n_levels; ++i)
|
||||
{
|
||||
vert_scrollarea_insert_item(&scene->data.scroll_area, scene->data.level_pack->levels[i].level_name, i);
|
||||
}
|
||||
for (unsigned int i = scene->data.level_pack->n_levels; i < scene->data.scroll_area.max_items; ++i)
|
||||
{
|
||||
vert_scrollarea_insert_item(&scene->data.scroll_area, "---", i);
|
||||
}
|
||||
char buf[32];
|
||||
sprintf(buf, "Level %u", i);
|
||||
DrawText(buf, 0, (12+3) * i, 12, BLACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < scene->data.scroll_area.max_items; ++i)
|
||||
{
|
||||
sprintf(buf, "Level %u", i);
|
||||
vert_scrollarea_insert_item(&scene->data.scroll_area, buf, i);
|
||||
}
|
||||
}
|
||||
ScrollAreaRenderEnd();
|
||||
EndTextureMode();
|
||||
|
||||
sc_array_add(&scene->scene.systems, &level_select_render_func);
|
||||
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_Q, ACTION_EXIT);
|
||||
sc_map_put_64(&scene->scene.action_map, KEY_ENTER, ACTION_CONFIRM);
|
||||
sc_map_put_64(&scene->scene.action_map, MOUSE_LEFT_BUTTON, ACTION_NEXT_SPAWN); // Abuse an unused action
|
||||
}
|
||||
void free_level_select_scene(LevelSelectScene_t* scene)
|
||||
{
|
||||
|
||||
vert_scrollarea_free(&scene->data.scroll_area);
|
||||
free_scene(&scene->scene);
|
||||
}
|
||||
|
|
|
@ -1,50 +1,18 @@
|
|||
#include "scene_impl.h"
|
||||
#include "assets_tag.h"
|
||||
#include "raymath.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static void menu_scene_render_func(Scene_t* scene)
|
||||
{
|
||||
MenuSceneData_t* data = &(CONTAINER_OF(scene, MenuScene_t, scene)->data);
|
||||
|
||||
Sprite_t* spr = get_sprite(&scene->engine->assets, "title_spr");
|
||||
Sprite_t* title_spr = get_sprite(&scene->engine->assets, "title_board");
|
||||
Sprite_t* title_select = get_sprite(&scene->engine->assets, "title_select");
|
||||
Rectangle render_rec = scene->layers.render_layers[0].render_area;
|
||||
Font* menu_font = get_font(&scene->engine->assets, "MenuFont");
|
||||
BeginTextureMode(scene->layers.render_layers[0].layer_tex);
|
||||
ClearBackground(RAYWHITE);
|
||||
draw_sprite(spr, 0, (Vector2){0, 0}, 0, false);
|
||||
draw_sprite(title_spr, 0, (Vector2){32, 10}, 0, false);
|
||||
Vector2 font_sz = MeasureTextEx(*menu_font, "Bunny's Spelunking Adventure", 56, 0);
|
||||
Vector2 title_pos = {
|
||||
.x = (render_rec.width - font_sz.x) / 2,
|
||||
.y = 32 + (title_spr->frame_size.y - font_sz.y) / 2
|
||||
};
|
||||
DrawTextEx(*menu_font, "Bunny's Spelunking Adventure", title_pos, 56, 0, BLACK);
|
||||
|
||||
const char* OPTIONS[3] = {"Start", "Credits", "Exit"};
|
||||
for (uint8_t i = 0; i < 3; ++i)
|
||||
{
|
||||
Vector2 pos = (Vector2){data->buttons[i].bbox.x, data->buttons[i].bbox.y};
|
||||
pos = Vector2Add(
|
||||
pos,
|
||||
shift_bbox(
|
||||
(Vector2){
|
||||
data->buttons[i].bbox.width,data->buttons[i].bbox.height
|
||||
},
|
||||
title_select->frame_size,
|
||||
AP_MID_CENTER
|
||||
)
|
||||
);
|
||||
draw_sprite(title_select, 0, pos, 0, false);
|
||||
font_sz = MeasureTextEx(*menu_font, OPTIONS[i], 32, 6);
|
||||
Vector2 title_pos = {
|
||||
.x = pos.x + (title_select->frame_size.x - font_sz.x) / 2,
|
||||
.y = pos.y + (title_spr->frame_size.y) / 2 - font_sz.y
|
||||
};
|
||||
hover_text(data->buttons + i, *menu_font, OPTIONS[i], title_pos, 32, 6, BLACK);
|
||||
}
|
||||
DrawText("This is a game", 25, 220, 12, BLACK);
|
||||
UI_button(data->buttons, "Start");
|
||||
UI_button(data->buttons + 1, "Sandbox");
|
||||
UI_button(data->buttons + 2, "Continue");
|
||||
UI_button(data->buttons + 3, "Exit");
|
||||
EndTextureMode();
|
||||
}
|
||||
|
||||
|
@ -53,9 +21,12 @@ static void exec_component_function(Scene_t* scene, int sel)
|
|||
switch(sel)
|
||||
{
|
||||
case 0:
|
||||
change_scene(scene->engine, LEVEL_SELECT_SCENE);
|
||||
change_scene(scene->engine, 1);
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
change_scene(scene->engine, 2);
|
||||
break;
|
||||
case 3:
|
||||
scene->state = 0;
|
||||
break;
|
||||
default:
|
||||
|
@ -161,31 +132,28 @@ static void gui_loop(Scene_t* scene)
|
|||
|
||||
void init_menu_scene(MenuScene_t* scene)
|
||||
{
|
||||
init_scene(&scene->scene, &menu_do_action, 0);
|
||||
init_scene(&scene->scene, &menu_do_action);
|
||||
|
||||
sc_array_add(&scene->scene.systems, &gui_loop);
|
||||
sc_array_add(&scene->scene.systems, &menu_scene_render_func);
|
||||
|
||||
int button_x = scene->scene.engine->intended_window_size.x / 8;
|
||||
int button_y = scene->scene.engine->intended_window_size.y / 3;
|
||||
int spacing = 100;
|
||||
scene->data.buttons[0] = (UIComp_t) {
|
||||
.bbox = {button_x,button_y,125,30},
|
||||
.bbox = {25,255,125,30},
|
||||
.state = STATE_NORMAL,
|
||||
.alpha = 1.0
|
||||
};
|
||||
scene->data.buttons[1] = (UIComp_t) {
|
||||
.bbox = {button_x,button_y+spacing,125,30},
|
||||
.bbox = {25,300,125,30},
|
||||
.state = STATE_NORMAL,
|
||||
.alpha = 1.0
|
||||
};
|
||||
scene->data.buttons[2] = (UIComp_t) {
|
||||
.bbox = {button_x,button_y+spacing * 2,125,30},
|
||||
.bbox = {25,345,125,30},
|
||||
.state = STATE_NORMAL,
|
||||
.alpha = 1.0
|
||||
};
|
||||
scene->data.buttons[3] = (UIComp_t) {
|
||||
.bbox = {button_x,button_y+spacing * 3,125,30},
|
||||
.bbox = {25,390,125,30},
|
||||
.state = STATE_NORMAL,
|
||||
.alpha = 1.0
|
||||
};
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#include "engine.h"
|
||||
#include "ent_impl.h"
|
||||
#include "constants.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "raymath.h"
|
||||
|
||||
#define N_PLAYER_SPRITES 12
|
||||
#define N_PLAYER_SPRITES 9
|
||||
enum PlayerSpriteEnum
|
||||
{
|
||||
SPR_PLAYER_STAND = 0,
|
||||
|
@ -16,10 +15,7 @@ enum PlayerSpriteEnum
|
|||
SPR_PLAYER_CROUCH,
|
||||
SPR_PLAYER_CRMOVE,
|
||||
SPR_PLAYER_SWIM,
|
||||
SPR_PLAYER_USWIM,
|
||||
SPR_PLAYER_DSWIM,
|
||||
SPR_PLAYER_DEAD,
|
||||
SPR_PLAYER_ENTER,
|
||||
};
|
||||
|
||||
static SpriteRenderInfo_t player_sprite_map[N_PLAYER_SPRITES] = {0};
|
||||
|
@ -31,13 +27,8 @@ static unsigned int player_sprite_transition_func(Entity_t* ent)
|
|||
CSprite_t* p_spr = get_component(ent, CSPRITE_T);
|
||||
CPlayerState_t* p_plr = get_component(ent, CPLAYERSTATE_T);
|
||||
|
||||
if (p_ctrans->velocity.x > 0) {
|
||||
p_spr->node.flip |= 1;
|
||||
}
|
||||
else if (p_ctrans->velocity.x < 0)
|
||||
{
|
||||
p_spr->node.flip &= ~1;
|
||||
}
|
||||
if (p_ctrans->velocity.x > 0) p_spr->flip_x = true;
|
||||
else if (p_ctrans->velocity.x < 0) p_spr->flip_x = false;
|
||||
|
||||
p_spr->pause = false;
|
||||
|
||||
|
@ -59,29 +50,11 @@ static unsigned int player_sprite_transition_func(Entity_t* ent)
|
|||
}
|
||||
else if (p_move->water_state & 1)
|
||||
{
|
||||
if (p_ctrans->velocity.y > 50) return SPR_PLAYER_DSWIM;
|
||||
|
||||
if (p_ctrans->velocity.y < -50) return SPR_PLAYER_USWIM;
|
||||
|
||||
return SPR_PLAYER_SWIM;
|
||||
}
|
||||
return (p_ctrans->velocity.y < 0) ? SPR_PLAYER_JUMP : SPR_PLAYER_FALL;
|
||||
}
|
||||
|
||||
static void player_sfx_func(GameEngine_t* engine, Entity_t* ent) {
|
||||
CSprite_t* p_spr = get_component(ent, CSPRITE_T);
|
||||
if (p_spr->current_idx == SPR_PLAYER_RUN) {
|
||||
if (p_spr->current_frame % 3 == 0) {
|
||||
play_sfx_pitched(engine, PLAYER_STEP_SFX, p_spr->current_frame == 0?1.0f : 0.75f );
|
||||
}
|
||||
}
|
||||
if (p_spr->current_idx == SPR_PLAYER_CRMOVE) {
|
||||
if (p_spr->current_frame % 2 == 0) {
|
||||
play_sfx(engine, PLAYER_STEP_SFX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Entity_t* create_player(EntityManager_t* ent_manager)
|
||||
{
|
||||
Entity_t* p_ent = add_entity(ent_manager, PLAYER_ENT_TAG);
|
||||
|
@ -95,7 +68,7 @@ Entity_t* create_player(EntityManager_t* ent_manager)
|
|||
p_ct->shape_factor = (Vector2){1, 1};
|
||||
|
||||
CJump_t* p_cjump = add_component(p_ent, CJUMP_COMP_T);
|
||||
p_cjump->jump_speed = JUMP_SPEED;
|
||||
p_cjump->jump_speed = 680;
|
||||
p_cjump->jumps = 1;
|
||||
p_cjump->max_jumps = 1;
|
||||
p_cjump->jump_ready = true;
|
||||
|
@ -125,22 +98,16 @@ Entity_t* create_player(EntityManager_t* ent_manager)
|
|||
CAirTimer_t* p_air = add_component(p_ent, CAIRTIMER_T);
|
||||
p_air->max_count = 10;
|
||||
p_air->curr_count = 10;
|
||||
p_air->max_ftimer = 0.9f;
|
||||
p_air->max_ftimer = 1.0f;
|
||||
p_air->decay_rate = 1.0f;
|
||||
|
||||
CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T);
|
||||
p_cspr->sprites = player_sprite_map;
|
||||
p_cspr->transition_func = &player_sprite_transition_func;
|
||||
p_cspr->sfx_func = &player_sfx_func;
|
||||
p_cspr->node.colour = WHITE;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->depth = 1;
|
||||
|
||||
CEmitter_t* p_emitter = add_component(p_ent, CEMITTER_T);
|
||||
p_emitter->offset = (Vector2){7,0};
|
||||
|
||||
add_component(p_ent, CSQUISHABLE_T);
|
||||
|
||||
return p_ent;
|
||||
}
|
||||
|
||||
|
@ -157,69 +124,12 @@ Entity_t* create_dead_player(EntityManager_t* ent_manager)
|
|||
CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T);
|
||||
p_cspr->sprites = player_sprite_map;
|
||||
p_cspr->current_idx = SPR_PLAYER_DEAD;
|
||||
p_cspr->node.colour = WHITE;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->depth = 3;
|
||||
|
||||
add_component(p_ent, CMOVEMENTSTATE_T);
|
||||
|
||||
return p_ent;
|
||||
}
|
||||
|
||||
static unsigned int player_finish_transition_func(Entity_t* ent)
|
||||
{
|
||||
CSprite_t* p_spr = get_component(ent, CSPRITE_T);
|
||||
// Due to index-from-0
|
||||
if (p_spr->current_frame == p_spr->sprites[p_spr->current_idx].sprite->frame_count - 1)
|
||||
{
|
||||
p_spr->pause = true;
|
||||
//remove_entity(ent->manager, ent->m_id);
|
||||
}
|
||||
return p_spr->current_idx;
|
||||
}
|
||||
|
||||
Entity_t* create_player_finish(EntityManager_t* ent_manager)
|
||||
{
|
||||
Entity_t* p_ent = add_entity(ent_manager, NO_ENT_TAG);
|
||||
if (p_ent == NULL) return NULL;
|
||||
|
||||
CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T);
|
||||
p_cspr->sprites = player_sprite_map;
|
||||
p_cspr->current_idx = SPR_PLAYER_ENTER;
|
||||
p_cspr->transition_func = &player_finish_transition_func;
|
||||
p_cspr->node.colour = WHITE;
|
||||
p_cspr->node.scale = (Vector2){1, 1};
|
||||
p_cspr->depth = 1;
|
||||
|
||||
CLifeTimer_t* p_clifetimer = add_component(p_ent, CLIFETIMER_T);
|
||||
p_clifetimer->life_time = 0.9f;
|
||||
return p_ent;
|
||||
}
|
||||
|
||||
static AnchorPoint_t parse_anchor_symbol(const char symbol[2])
|
||||
{
|
||||
if (symbol[0] == 't')
|
||||
{
|
||||
if (symbol[1] == 'l') return AP_TOP_LEFT;
|
||||
if (symbol[1] == 'c') return AP_TOP_CENTER;
|
||||
if (symbol[1] == 'r') return AP_TOP_RIGHT;
|
||||
}
|
||||
else if (symbol[0] == 'm')
|
||||
{
|
||||
if (symbol[1] == 'l') return AP_MID_LEFT;
|
||||
if (symbol[1] == 'c') return AP_MID_CENTER;
|
||||
if (symbol[1] == 'r') return AP_MID_RIGHT;
|
||||
}
|
||||
else if (symbol[0] == 'b')
|
||||
{
|
||||
if (symbol[1] == 'l') return AP_BOT_LEFT;
|
||||
if (symbol[1] == 'c') return AP_BOT_CENTER;
|
||||
if (symbol[1] == 'r') return AP_BOT_RIGHT;
|
||||
}
|
||||
|
||||
return AP_TOP_LEFT;
|
||||
}
|
||||
|
||||
static bool init_player_file(FILE* in_file, Assets_t* assets)
|
||||
{
|
||||
static bool already_init = false;
|
||||
|
@ -246,23 +156,18 @@ static bool init_player_file(FILE* in_file, Assets_t* assets)
|
|||
while(*info_str == ' ' || *info_str == '\t') info_str++;
|
||||
|
||||
Vector2 offset;
|
||||
char src_ap_symbol[3];
|
||||
char dest_ap_symbol[3];
|
||||
int data_count = sscanf(
|
||||
info_str, "%f,%f,%2s,%2s",
|
||||
&offset.x, &offset.y, src_ap_symbol, dest_ap_symbol
|
||||
info_str, "%f,%f",
|
||||
&offset.x, &offset.y
|
||||
);
|
||||
if (data_count != 4)
|
||||
if (data_count !=2)
|
||||
{
|
||||
printf("Unable to parse info for player at line %lu\n", line_num);
|
||||
return false;
|
||||
}
|
||||
Sprite_t* spr = get_sprite(assets, name);
|
||||
spr->anchor = Vector2Scale(spr->frame_size, 0.5f);
|
||||
player_sprite_map[i].sprite = spr;
|
||||
player_sprite_map[i].offset = offset;
|
||||
player_sprite_map[i].src_anchor = parse_anchor_symbol(src_ap_symbol);
|
||||
player_sprite_map[i].dest_anchor = parse_anchor_symbol(dest_ap_symbol);
|
||||
i++;
|
||||
}
|
||||
already_init = true;
|
||||
|
|
|
@ -27,14 +27,8 @@ typedef struct CoinCounter
|
|||
uint16_t total;
|
||||
}CoinCounter_t;
|
||||
|
||||
typedef enum CameraMode {
|
||||
CAMERA_FOLLOW_PLAYER = 0,
|
||||
CAMERA_RANGED_MOVEMENT,
|
||||
} CameraMode_t;
|
||||
|
||||
typedef struct LevelCamera {
|
||||
Camera2D cam;
|
||||
CameraMode_t mode;
|
||||
Vector2 target_pos;
|
||||
float base_y;
|
||||
//Vector2 prev_pos;
|
||||
|
@ -42,25 +36,8 @@ typedef struct LevelCamera {
|
|||
float mass;
|
||||
float c; // damping factor
|
||||
float k; // spring constant
|
||||
float range_limit;
|
||||
}LevelCamera_t;
|
||||
|
||||
typedef enum LevelSceneState {
|
||||
LEVEL_STATE_STARTING = 0,
|
||||
LEVEL_STATE_RUNNING,
|
||||
LEVEL_STATE_DEAD,
|
||||
LEVEL_STATE_COMPLETE,
|
||||
} LevelSceneState_t;
|
||||
|
||||
typedef struct LevelSceneStateMachine {
|
||||
LevelSceneState_t state;
|
||||
system_func_t state_functions[4];
|
||||
|
||||
// Engine has no timeline support, so make a pseudo timeline implementation
|
||||
float fractional;
|
||||
uint32_t counter;
|
||||
} LevelSceneStateMachine_t;
|
||||
|
||||
typedef struct LevelSceneData {
|
||||
TileGrid_t tilemap;
|
||||
// TODO: game_rec is actually obsolete since this is in the scene game layer
|
||||
|
@ -73,18 +50,8 @@ typedef struct LevelSceneData {
|
|||
unsigned int current_level;
|
||||
CoinCounter_t coins;
|
||||
bool show_grid;
|
||||
Vector2 player_spawn;
|
||||
LevelSceneStateMachine_t sm;
|
||||
RenderManager render_manager;
|
||||
}LevelSceneData_t;
|
||||
|
||||
static inline void change_level_state(LevelSceneData_t* data, LevelSceneState_t state)
|
||||
{
|
||||
data->sm.state = state;
|
||||
data->sm.counter = 0;
|
||||
data->sm.fractional = 0;
|
||||
}
|
||||
|
||||
typedef struct LevelScene {
|
||||
Scene_t scene;
|
||||
LevelSceneData_t data;
|
||||
|
@ -95,8 +62,6 @@ 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 clear_an_entity(Scene_t* scene, TileGrid_t* tilemap, Entity_t* p_ent);
|
||||
void clear_all_game_entities(LevelScene_t* scene);
|
||||
void term_level_scene_data(LevelSceneData_t* data);
|
||||
void reload_level_tilemap(LevelScene_t* scene);
|
||||
void load_next_level_tilemap(LevelScene_t* scene);
|
||||
|
@ -122,8 +87,8 @@ typedef struct MenuScene {
|
|||
} MenuScene_t;
|
||||
|
||||
typedef struct LevelSelectSceneData {
|
||||
VertScrollArea_t scroll_area;
|
||||
LevelPack_t* level_pack;
|
||||
RenderTexture2D level_display;
|
||||
float scroll;
|
||||
} LevelSelectSceneData_t;
|
||||
|
||||
typedef struct LevelSelectScene {
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
#include "collisions.h"
|
||||
#include "scene_impl.h"
|
||||
#include "water_flow.h"
|
||||
#include "ent_impl.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include "raymath.h"
|
||||
|
||||
void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* tiles, Rectangle view_zone)
|
||||
{
|
||||
init_render_manager(&data->render_manager);
|
||||
|
||||
data->game_rec = view_zone;
|
||||
memset(&data->camera, 0, sizeof(LevelCamera_t));
|
||||
data->camera.cam.rotation = 0.0f;
|
||||
|
@ -17,7 +12,6 @@ void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* t
|
|||
data->camera.mass = 0.2f;
|
||||
data->camera.k = 6.2f;
|
||||
data->camera.c = 2.2f;
|
||||
data->camera.range_limit = 200.0f;
|
||||
|
||||
data->tilemap.max_tiles = max_tiles;
|
||||
if (tiles != NULL)
|
||||
|
@ -46,9 +40,6 @@ void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* t
|
|||
}
|
||||
memset(&data->coins, 0, sizeof(data->coins));
|
||||
data->show_grid = false;
|
||||
|
||||
memset(&data->sm, 0, sizeof(data->sm));
|
||||
|
||||
}
|
||||
|
||||
void term_level_scene_data(LevelSceneData_t* data)
|
||||
|
@ -59,44 +50,6 @@ void term_level_scene_data(LevelSceneData_t* data)
|
|||
}
|
||||
}
|
||||
|
||||
void clear_an_entity(Scene_t* scene, TileGrid_t* tilemap, Entity_t* p_ent)
|
||||
{
|
||||
/* Use the helper function to remove any entity
|
||||
* This is because some components may have deinit steps
|
||||
* This function will also take care of the tilemap collision handling
|
||||
* */
|
||||
|
||||
CEmitter_t* p_emitter = get_component(p_ent, CEMITTER_T);
|
||||
if (p_emitter != NULL)
|
||||
{
|
||||
unload_emitter_handle(&scene->part_sys, p_emitter->handle);
|
||||
}
|
||||
if (get_component(p_ent, CWATERRUNNER_T)!= NULL)
|
||||
{
|
||||
free_water_runner(p_ent, &scene->ent_manager);
|
||||
}
|
||||
|
||||
remove_entity_from_tilemap(&scene->ent_manager, tilemap, p_ent);
|
||||
}
|
||||
|
||||
void clear_all_game_entities(LevelScene_t* scene)
|
||||
{
|
||||
Entity_t* ent;
|
||||
sc_map_foreach_value(&scene->scene.ent_manager.entities, ent)
|
||||
{
|
||||
clear_an_entity(&scene->scene, &scene->data.tilemap, ent);
|
||||
}
|
||||
|
||||
// This is unnecessary as the first pass should clear everything
|
||||
// For now, leave it in. This is not expected to call all the time
|
||||
// so not too bad
|
||||
clear_entity_manager(&scene->scene.ent_manager);
|
||||
for (size_t i = 0; i < scene->data.tilemap.n_tiles;i++)
|
||||
{
|
||||
sc_map_clear_64v(&scene->data.tilemap.tiles[i].entities_set);
|
||||
}
|
||||
}
|
||||
|
||||
bool load_level_tilemap(LevelScene_t* scene, unsigned int level_num)
|
||||
{
|
||||
if (level_num >= scene->data.level_pack->n_levels) return false;
|
||||
|
@ -109,61 +62,27 @@ bool load_level_tilemap(LevelScene_t* scene, unsigned int level_num)
|
|||
scene->data.tilemap.width = lvl_map.width;
|
||||
scene->data.tilemap.height = lvl_map.height;
|
||||
scene->data.tilemap.n_tiles = n_tiles;
|
||||
scene->data.coins.current = 0;
|
||||
scene->data.coins.total = lvl_map.n_chests;
|
||||
|
||||
#define N_SOLID_TILESETS 3
|
||||
static const char* SOLID_TILE_SELECTIONS[N_SOLID_TILESETS] = {
|
||||
"stile0", "stile1", "stile2"
|
||||
};
|
||||
scene->data.selected_solid_tilemap = lvl_map.flags;
|
||||
scene->data.solid_tile_sprites = get_sprite(&scene->scene.engine->assets, SOLID_TILE_SELECTIONS[lvl_map.flags]);
|
||||
|
||||
clear_all_game_entities(scene);
|
||||
|
||||
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].rotation = TILE_NOROTATE;
|
||||
scene->data.tilemap.tiles[i].connectivity = 0;
|
||||
scene->data.tilemap.tiles[i].moveable = true;
|
||||
scene->data.tilemap.tiles[i].offset = (Vector2){0, 0};
|
||||
scene->data.tilemap.tiles[i].size = (Vector2){TILE_SIZE, TILE_SIZE};
|
||||
scene->data.tilemap.tiles[i].def = 0;
|
||||
|
||||
memset(scene->data.tilemap.render_nodes + i, 0, sizeof(RenderInfoNode));
|
||||
scene->data.tilemap.render_nodes[i].pos = (Vector2){
|
||||
(i % scene->data.tilemap.width) * TILE_SIZE,
|
||||
(i / scene->data.tilemap.width) * TILE_SIZE,
|
||||
};
|
||||
scene->data.tilemap.render_nodes[i].scale = (Vector2){1,1};
|
||||
scene->data.tilemap.render_nodes[i].colour = WHITE;
|
||||
|
||||
if (lvl_map.tiles[i].tile_type == SOLID_TILE)
|
||||
sc_map_clear_64v(&scene->data.tilemap.tiles[i].entities_set);
|
||||
|
||||
if (lvl_map.tiles[i].tile_type == 1)
|
||||
{
|
||||
change_a_tile(&scene->data.tilemap, i, SOLID_TILE);
|
||||
change_a_tile(&scene->data.tilemap, i, SOLID_TILE);
|
||||
}
|
||||
|
||||
if (lvl_map.tiles[i].water > MAX_WATER_LEVEL) {
|
||||
scene->data.tilemap.tiles[i].max_water_level = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scene->data.tilemap.tiles[i].max_water_level = 4;
|
||||
scene->data.tilemap.tiles[i].water_level = lvl_map.tiles[i].water;
|
||||
scene->data.tilemap.tiles[i].wet = scene->data.tilemap.tiles[i].water_level > 0;
|
||||
}
|
||||
scene->data.tilemap.tiles[i].water_level = lvl_map.tiles[i].water;
|
||||
}
|
||||
|
||||
// Two pass, because some tile depends on the solidity of the tiles
|
||||
// Two pass
|
||||
for (size_t i = 0; i < scene->data.tilemap.n_tiles;i++)
|
||||
{
|
||||
if (lvl_map.tiles[i].tile_type == SOLID_TILE)
|
||||
{
|
||||
change_a_tile(&scene->data.tilemap, i, SOLID_TILE);
|
||||
}
|
||||
if (lvl_map.tiles[i].tile_type >= 8 && lvl_map.tiles[i].tile_type < 20)
|
||||
{
|
||||
uint32_t tmp_idx = lvl_map.tiles[i].tile_type - 8;
|
||||
|
@ -217,74 +136,12 @@ bool load_level_tilemap(LevelScene_t* scene, unsigned int level_num)
|
|||
Entity_t* ent = create_player(&scene->scene.ent_manager);
|
||||
ent->position.x = (i % scene->data.tilemap.width) * scene->data.tilemap.tile_size;
|
||||
ent->position.y = (i / scene->data.tilemap.width) * scene->data.tilemap.tile_size;
|
||||
scene->data.camera.target_pos.x = ent->position.x;
|
||||
scene->data.camera.target_pos.y = ent->position.y;
|
||||
scene->data.camera.cam.target.x = ent->position.x;
|
||||
scene->data.camera.cam.target.y = ent->position.y;
|
||||
ent->spawn_pos = ent->position;
|
||||
}
|
||||
break;
|
||||
case 23:
|
||||
{
|
||||
Entity_t* ent = create_chest(&scene->scene.ent_manager);
|
||||
ent->position.x = (i % scene->data.tilemap.width) * scene->data.tilemap.tile_size;
|
||||
ent->position.y = (i / scene->data.tilemap.width) * scene->data.tilemap.tile_size;
|
||||
CTransform_t* p_ctransform = get_component(ent, CTRANSFORM_COMP_T);
|
||||
p_ctransform->active = true;
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
{
|
||||
Entity_t* ent = create_level_end(&scene->scene.ent_manager);
|
||||
if (ent != NULL)
|
||||
{
|
||||
ent->position.x = (i % scene->data.tilemap.width) * scene->data.tilemap.tile_size;
|
||||
ent->position.y = (i / scene->data.tilemap.width) * scene->data.tilemap.tile_size + (scene->data.tilemap.tile_size >> 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (lvl_map.tiles[i].tile_type >= 25)
|
||||
{
|
||||
Entity_t* ent = create_urchin(&scene->scene.ent_manager);
|
||||
if (ent != NULL)
|
||||
{
|
||||
CBBox_t* p_bbox = get_component(ent, CBBOX_COMP_T);
|
||||
ent->position.x = (i % scene->data.tilemap.width) * scene->data.tilemap.tile_size + (scene->data.tilemap.tile_size >> 1) - p_bbox->half_size.x;
|
||||
|
||||
ent->position.y = (int)(i / scene->data.tilemap.width) * scene->data.tilemap.tile_size + (scene->data.tilemap.tile_size >> 1) - p_bbox->half_size.y;
|
||||
|
||||
uint8_t spd_encoding = lvl_map.tiles[i].tile_type - 25;
|
||||
float angle = 45.0f / 180.0f * PI * ((spd_encoding >> 2) & 7);
|
||||
float mag = 75 * (spd_encoding & 3);
|
||||
|
||||
CTransform_t* p_ct = get_component(ent, CTRANSFORM_COMP_T);
|
||||
p_ct->velocity = Vector2Scale(
|
||||
(Vector2){cosf(angle), sinf(angle)}, mag
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This only works for static loading.
|
||||
// If a tilemap change change to some other arbitrary tile.
|
||||
// Then this should be done while changing a tile.
|
||||
if (lvl_map.tiles[i].tile_type == SOLID_TILE)
|
||||
{
|
||||
scene->data.tilemap.render_nodes[i].spr = scene->data.solid_tile_sprites;
|
||||
scene->data.tilemap.render_nodes[i].frame_num = CONNECTIVITY_TILE_MAPPING[
|
||||
scene->data.tilemap.tiles[i].connectivity
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t tile_sprite_idx = scene->data.tilemap.tiles[i].tile_type + scene->data.tilemap.tiles[i].rotation;
|
||||
scene->data.tilemap.render_nodes[i].spr = scene->data.tile_sprites[
|
||||
tile_sprite_idx
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,20 +188,20 @@ void change_a_tile(TileGrid_t* tilemap, unsigned int tile_idx, TileType_t new_ty
|
|||
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
|
||||
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;
|
||||
}
|
||||
//unsigned 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;
|
||||
//}
|
||||
unsigned 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:
|
||||
|
@ -360,39 +217,37 @@ void change_a_tile(TileGrid_t* tilemap, unsigned int tile_idx, TileType_t new_ty
|
|||
unsigned 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 = NOT_SOLID;
|
||||
tilemap->tiles[down_tile].solid = ONE_WAY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tilemap->tiles[tile_idx].rotation = TILE_NOROTATE;
|
||||
|
||||
const int SPIKE_HITBOX_LONGSIDE = 30;
|
||||
const int SPIKE_HITBOX_SHORTSIDE = 12;
|
||||
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,tilemap->tile_size - SPIKE_HITBOX_SHORTSIDE};
|
||||
tilemap->tiles[tile_idx].size = (Vector2){SPIKE_HITBOX_LONGSIDE, SPIKE_HITBOX_SHORTSIDE};
|
||||
tilemap->tiles[tile_idx].offset = (Vector2){0,16};
|
||||
tilemap->tiles[tile_idx].size = (Vector2){32,16};
|
||||
}
|
||||
else if (tile_idx >= tilemap->width && tilemap->tiles[tile_idx - tilemap->width].tile_type == SOLID_TILE)
|
||||
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){SPIKE_HITBOX_LONGSIDE, SPIKE_HITBOX_SHORTSIDE};
|
||||
tilemap->tiles[tile_idx].size = (Vector2){32,16};
|
||||
tilemap->tiles[tile_idx].rotation = TILE_180ROT;
|
||||
}
|
||||
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){SPIKE_HITBOX_SHORTSIDE, SPIKE_HITBOX_LONGSIDE};
|
||||
tilemap->tiles[tile_idx].size = (Vector2){16,32};
|
||||
tilemap->tiles[tile_idx].rotation = TILE_90CWROT;
|
||||
}
|
||||
else if ((tile_idx + 1) % tilemap->width != 0 && tilemap->tiles[tile_idx + 1].tile_type == SOLID_TILE)
|
||||
{
|
||||
tilemap->tiles[tile_idx].offset = (Vector2){tilemap->tile_size - SPIKE_HITBOX_SHORTSIDE,0};
|
||||
tilemap->tiles[tile_idx].size = (Vector2){SPIKE_HITBOX_SHORTSIDE, SPIKE_HITBOX_LONGSIDE};
|
||||
tilemap->tiles[tile_idx].offset = (Vector2){16,0};
|
||||
tilemap->tiles[tile_idx].size = (Vector2){16,32};
|
||||
tilemap->tiles[tile_idx].rotation = TILE_90CCWROT;
|
||||
}
|
||||
else
|
||||
|
@ -415,7 +270,6 @@ void change_a_tile(TileGrid_t* tilemap, unsigned int tile_idx, TileType_t new_ty
|
|||
tilemap->tiles[tile_idx].moveable = (
|
||||
tilemap->tiles[tile_idx].tile_type == EMPTY_TILE
|
||||
|| tilemap->tiles[tile_idx].tile_type == SPIKES
|
||||
|| tilemap->tiles[tile_idx].tile_type == LADDER
|
||||
);
|
||||
tilemap->tiles[tile_idx].def = (tilemap->tiles[tile_idx].tile_type == SOLID_TILE) ? 5: 2;
|
||||
|
||||
|
|
|
@ -289,10 +289,11 @@ void update_water_runner_system(Scene_t* scene)
|
|||
break;
|
||||
case SCANLINE_FILL:
|
||||
{
|
||||
const float FILL_RATE = 1.0f/22;
|
||||
const float FILL_RATE = 1.0f/24;
|
||||
p_crunner->fractional += scene->delta_time;
|
||||
if (p_crunner->fractional < FILL_RATE) break;
|
||||
|
||||
p_crunner->fractional -= FILL_RATE;
|
||||
// Unsigned usage here is okay
|
||||
unsigned int start_tile =
|
||||
(p_crunner->current_tile / p_crunner->bfs_tilemap.width) * p_crunner->bfs_tilemap.width;
|
||||
|
@ -307,7 +308,6 @@ void update_water_runner_system(Scene_t* scene)
|
|||
if (curr_tile->water_level < curr_tile->max_water_level)
|
||||
{
|
||||
curr_tile->water_level++;
|
||||
p_crunner->fractional -= FILL_RATE;
|
||||
}
|
||||
if (curr_tile->water_level < curr_tile->max_water_level)
|
||||
{
|
||||
|
|
1
tracy
1
tracy
|
@ -1 +0,0 @@
|
|||
Subproject commit 5d542dc09f3d9378d005092a4ad446bd405f819a
|
|
@ -110,7 +110,7 @@ static void level_scene_render_func(Scene_t* scene)
|
|||
if (spr.sprite != NULL)
|
||||
{
|
||||
Vector2 pos = Vector2Add(p_ent->position, spr.offset);
|
||||
draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->node.flip & 1);
|
||||
draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->flip_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +400,7 @@ int main(void)
|
|||
|
||||
LevelScene_t scene;
|
||||
scene.scene.engine = &engine;
|
||||
init_scene(&scene.scene, &level_do_action, ENABLE_ENTITY_MANAGEMENT_SYSTEM);
|
||||
init_scene(&scene.scene, &level_do_action);
|
||||
init_entity_tag_map(&scene.scene.ent_manager, PLAYER_ENT_TAG, 4);
|
||||
init_entity_tag_map(&scene.scene.ent_manager, DYNMEM_ENT_TAG, 16);
|
||||
init_level_scene_data(
|
||||
|
|
Loading…
Reference in New Issue