refactor: seperate engine and game

This commit is contained in:
2026-07-16 21:44:34 +01:00
parent a408094d95
commit 7cf3427a97
41 changed files with 873 additions and 1243 deletions
View File
-187
View File
@@ -1,187 +0,0 @@
#include <algorithm>
#include <asset/asset.hpp>
#include <asset/raylib_asset.hpp>
#include <raylib.h>
#include <asset_packer/asset.hpp>
#include <string>
#include <iostream>
#include <filesystem>
#include <variant>
#include <ranges>
namespace fs = std::filesystem;
// Helper to determine if the asset path implies streaming music
bool should_stream_as_music(const std::filesystem::path& asset_path) {
for (const auto& part : asset_path) {
if (part == "music" || part == "bgm") {
return true;
}
}
return false;
}
AssetLoader::AssetLoader(std::string asset_data) : asset_reader(asset_data){
if (!asset_reader.load_index()){
std::cerr << "Failed to load assets!!!" << std::endl;
}
}
AssetReader AssetLoader::get_reader(){
return asset_reader;
}
RaylibAssetLoader::RaylibAssetLoader(std::string asset_data) : AssetLoader(asset_data) {
}
RaylibAssetLoader::~RaylibAssetLoader(){
unload_all_assets();
}
void RaylibAssetLoader::load_asset(std::string path){
fs::path file_path(path);
Asset new_asset;
new_asset.name = file_path.filename().string() ;
// std::cout << file_path.extension() << std::endl;
auto bytes = get_reader().extract_asset(path);
if (file_path.extension() == ".png"){
Image img = LoadImageFromMemory(".png", bytes.data(), bytes.size());
auto texture = LoadTextureFromImage(img);
UnloadImage(img);
new_asset.data = ImageData { new Texture(texture)};
}else if(file_path.extension() == ".ogg"){
if (should_stream_as_music(file_path)){
auto music = LoadMusicStreamFromMemory(".ogg",bytes.data(),bytes.size());
new_asset.data = MusicData{new Music(music)};
}else{
auto wave = LoadWaveFromMemory(".ogg", bytes.data(),bytes.size());
auto sound = LoadSoundFromWave(wave);
UnloadWave(wave);
new_asset.data = SoundData{new Sound(sound)};
}
}
else if(file_path.extension() == ".mp3"){
if (should_stream_as_music(file_path)){
auto music = LoadMusicStreamFromMemory(".mp3",bytes.data(),bytes.size());
new_asset.data = MusicData{new Music(music)};
}else{
auto wave = LoadWaveFromMemory(".mp3", bytes.data(),bytes.size());
auto sound = LoadSoundFromWave(wave);
UnloadWave(wave);
new_asset.data = SoundData{new Sound(sound)};
}
}
else if(file_path.extension() == ".wav"){
if (should_stream_as_music(file_path)){
auto music = LoadMusicStreamFromMemory(".wav",bytes.data(),bytes.size());
new_asset.data = MusicData{new Music(music)};
}else{
auto wave = LoadWaveFromMemory(".wav", bytes.data(),bytes.size());
auto sound = LoadSoundFromWave(wave);
UnloadWave(wave);
new_asset.data = SoundData{new Sound(sound)};
}
}
else if(file_path.extension() == ".json"){
auto json = std::string(bytes.begin(),bytes.end());
new_asset.data = JsonData {json};
}
assets[path] = new_asset;
}
void RaylibAssetLoader::unload_asset(std::string path){
if (!assets.contains(path)) return;
Asset asset = assets[path];
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ImageData>) {
Texture* tex = static_cast<Texture*>(arg.texture);
UnloadTexture(*tex);
delete tex;
arg.texture = nullptr;
}
else if constexpr (std::is_same_v<T, SoundData>) {
Sound* sound = static_cast<Sound*>(arg.sound);
UnloadSound(*sound);
delete sound;
arg.sound = nullptr;
}
else if constexpr (std::is_same_v<T, MusicData>) {
Music* music = static_cast<Music*>(arg.music);
UnloadMusicStream(*music);
delete music;
arg.music = nullptr;
}
// JsonData requires no manual step because std::string cleans itself up!
}, asset.data);
assets.erase(path);
}
void RaylibAssetLoader::unload_all_assets(){
std::vector<std::string> assets_to_unload;
std::ranges::copy(std::views::keys(assets),std::back_inserter(assets_to_unload));
for (const auto &path : assets_to_unload){
unload_asset(path);
}
}
Asset RaylibAssetLoader::get_asset(std::string path){
if (assets.contains(path)){
return assets[path];
}else{
return {};
}
}
Texture* RaylibAssetLoader::get_texture(std::string path){
Asset asset = get_asset(path);
if (auto* ptr = std::get_if<ImageData>(&asset.data)) {
return (Texture*)ptr->texture;
}
return nullptr;
}
Sound* RaylibAssetLoader::get_sound(std::string path){
Asset asset = get_asset(path);
if (auto* ptr = std::get_if<SoundData>(&asset.data)) {
return (Sound*)ptr->sound;
}
return nullptr;
}
Music* RaylibAssetLoader::get_music(std::string path){
Asset asset = get_asset(path);
if (auto* ptr = std::get_if<MusicData>(&asset.data)) {
return (Music*)ptr->music;
}
return nullptr;
}
std::string RaylibAssetLoader::get_json(std::string path){
Asset asset = get_asset(path);
if (auto* ptr = std::get_if<JsonData>(&asset.data)) {
return ptr->json;
}
return "{}";
}
+189
View File
@@ -0,0 +1,189 @@
#include "engine/asset/asset.hpp"
#include "engine/asset/raylib-asset.hpp"
#include <algorithm>
#include <raylib.h>
#include <asset_packer/asset.hpp>
#include <string>
#include <iostream>
#include <filesystem>
#include <variant>
#include <ranges>
namespace fs = std::filesystem;
// Helper to determine if the asset path implies streaming music
bool should_stream_as_music(const std::filesystem::path& asset_path) {
for (const auto& part : asset_path) {
if (part == "music" || part == "bgm") {
return true;
}
}
return false;
}
namespace varicle {
AssetLoader::AssetLoader(std::string asset_data) : asset_reader(asset_data){
if (!asset_reader.load_index()){
std::cerr << "Failed to load assets!!!" << std::endl;
}
}
AssetReader AssetLoader::get_reader(){
return asset_reader;
}
RaylibAssetLoader::RaylibAssetLoader(std::string asset_data) : AssetLoader(asset_data) {
}
RaylibAssetLoader::~RaylibAssetLoader(){
unload_all_assets();
}
void RaylibAssetLoader::load_asset(std::string path){
fs::path file_path(path);
Asset new_asset;
new_asset.name = file_path.filename().string() ;
// std::cout << file_path.extension() << std::endl;
auto bytes = get_reader().extract_asset(path);
if (file_path.extension() == ".png"){
Image img = LoadImageFromMemory(".png", bytes.data(), bytes.size());
auto texture = LoadTextureFromImage(img);
UnloadImage(img);
new_asset.data = ImageData { new Texture(texture)};
}else if(file_path.extension() == ".ogg"){
if (should_stream_as_music(file_path)){
auto music = LoadMusicStreamFromMemory(".ogg",bytes.data(),bytes.size());
new_asset.data = MusicData{new Music(music)};
}else{
auto wave = LoadWaveFromMemory(".ogg", bytes.data(),bytes.size());
auto sound = LoadSoundFromWave(wave);
UnloadWave(wave);
new_asset.data = SoundData{new Sound(sound)};
}
}
else if(file_path.extension() == ".mp3"){
if (should_stream_as_music(file_path)){
auto music = LoadMusicStreamFromMemory(".mp3",bytes.data(),bytes.size());
new_asset.data = MusicData{new Music(music)};
}else{
auto wave = LoadWaveFromMemory(".mp3", bytes.data(),bytes.size());
auto sound = LoadSoundFromWave(wave);
UnloadWave(wave);
new_asset.data = SoundData{new Sound(sound)};
}
}
else if(file_path.extension() == ".wav"){
if (should_stream_as_music(file_path)){
auto music = LoadMusicStreamFromMemory(".wav",bytes.data(),bytes.size());
new_asset.data = MusicData{new Music(music)};
}else{
auto wave = LoadWaveFromMemory(".wav", bytes.data(),bytes.size());
auto sound = LoadSoundFromWave(wave);
UnloadWave(wave);
new_asset.data = SoundData{new Sound(sound)};
}
}
else if(file_path.extension() == ".json"){
auto json = std::string(bytes.begin(),bytes.end());
new_asset.data = JsonData {json};
}
assets[path] = new_asset;
}
void RaylibAssetLoader::unload_asset(std::string path){
if (!assets.contains(path)) return;
Asset asset = assets[path];
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ImageData>) {
Texture* tex = static_cast<Texture*>(arg.texture);
UnloadTexture(*tex);
delete tex;
arg.texture = nullptr;
}
else if constexpr (std::is_same_v<T, SoundData>) {
Sound* sound = static_cast<Sound*>(arg.sound);
UnloadSound(*sound);
delete sound;
arg.sound = nullptr;
}
else if constexpr (std::is_same_v<T, MusicData>) {
Music* music = static_cast<Music*>(arg.music);
UnloadMusicStream(*music);
delete music;
arg.music = nullptr;
}
// JsonData requires no manual step because std::string cleans itself up!
}, asset.data);
assets.erase(path);
}
void RaylibAssetLoader::unload_all_assets(){
std::vector<std::string> assets_to_unload;
std::ranges::copy(std::views::keys(assets),std::back_inserter(assets_to_unload));
for (const auto &path : assets_to_unload){
unload_asset(path);
}
}
Asset RaylibAssetLoader::get_asset(std::string path){
if (assets.contains(path)){
return assets[path];
}else{
return {};
}
}
Texture* RaylibAssetLoader::get_texture(std::string path){
Asset asset = get_asset(path);
if (auto* ptr = std::get_if<ImageData>(&asset.data)) {
return (Texture*)ptr->texture;
}
return nullptr;
}
Sound* RaylibAssetLoader::get_sound(std::string path){
Asset asset = get_asset(path);
if (auto* ptr = std::get_if<SoundData>(&asset.data)) {
return (Sound*)ptr->sound;
}
return nullptr;
}
Music* RaylibAssetLoader::get_music(std::string path){
Asset asset = get_asset(path);
if (auto* ptr = std::get_if<MusicData>(&asset.data)) {
return (Music*)ptr->music;
}
return nullptr;
}
std::string RaylibAssetLoader::get_json(std::string path){
Asset asset = get_asset(path);
if (auto* ptr = std::get_if<JsonData>(&asset.data)) {
return ptr->json;
}
return "{}";
}
}
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <asset_packer/asset.hpp>
#include <string>
#include <variant>
#include <unordered_map>
namespace varicle {
struct ImageData {
void* texture;
};
struct SoundData {
void* sound;
};
struct MusicData {
void* music;
};
struct JsonData {
std::string json;
};
struct Asset {
std::string name;
std::variant<ImageData, SoundData, MusicData, JsonData> data;
};
class AssetLoader{
private:
AssetReader asset_reader;
protected:
std::unordered_map<std::string,Asset> assets;
virtual void load_all_assets(std::string data_path) = 0;
virtual void unload_all_assets() = 0;
public:
AssetLoader(std::string asset_data);
~AssetLoader() = default;
virtual void load_asset(std::string path) = 0;
virtual void unload_asset(std::string path) = 0;
virtual Asset get_asset(std::string path) = 0;;
AssetReader get_reader();
};
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
// #include "asset_packer/asset.hpp"
#include "engine/asset/asset.hpp"
#include <raylib.h>
namespace varicle {
class RaylibAssetLoader : public AssetLoader{
protected:
void load_all_assets(std::string asset_list) override {};
void unload_all_assets() override;
public:
RaylibAssetLoader(std::string asset_data = "data.dat");
~RaylibAssetLoader();
void load_asset(std::string path) override;
void unload_asset(std::string path) override;
Asset get_asset(std::string path) override;
Texture* get_texture(std::string path);
Sound* get_sound(std::string path);
Music* get_music(std::string path);
std::string get_json(std::string path);
};
// extern RaylibAssetLoader asset_loader;
}
+85
View File
@@ -0,0 +1,85 @@
// src/engine/core/application.cpp
#include "engine/core/application.hpp"
#include "engine/core/service-locator.hpp"
#include "engine/asset/raylib-asset.hpp"
#include "engine/scene/scene.hpp"
#include "raylib.h"
#include "rlImGui.h"
#include <memory>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
namespace varicle {
void game_loop(void){
auto& scene_manager = ServiceLocator::get<SceneManager>();
float dt = GetFrameTime();
// Update
scene_manager.update(dt);
// Draw
BeginDrawing();
ClearBackground(RAYWHITE); // Or a configurable engine default color
scene_manager.render();
rlImGuiBegin();
rlImGuiEnd();
EndDrawing();
scene_manager.process_scene_switch();
}
void Application::run() {
// 1. Initialize Raylib
SetTraceLogLevel(LOG_NONE);
SetConfigFlags(FLAG_VSYNC_HINT);
InitWindow(m_window_width, m_window_height, m_window_title);
SetTargetFPS(60);
rlImGuiSetup(true); // initialize gui
ServiceLocator::provide(std::make_unique<RaylibAssetLoader>());
ServiceLocator::provide(std::make_unique<SceneManager>());
// 2. Call game-specific startup (where the game creates its first scene)
on_init();
auto& scene_manager = ServiceLocator::get<SceneManager>();
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(game_loop, 0, 1);
#else
while (!scene_manager.should_game_close()){
game_loop();
}
#endif
// 4. Call game-specific cleanup
on_shutdown();
ServiceLocator::shutdown(); // Clean up services
// 5. Close Raylib
rlImGuiShutdown();
CloseWindow();
}
void Application::change_scene(std::string scene_id) {
ServiceLocator::get<SceneManager>().switch_to_scene(scene_id);
}
void Application::quit() {
ServiceLocator::get<SceneManager>().quit();
}
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "engine/scene/scene.hpp"
#include "raylib.h"
namespace varicle {
class Application{
// Window configuration variables that a derived game can tweak in its constructor
int m_window_width = 1280;
int m_window_height = 720;
const char* m_window_title = "My Raylib Engine Game";
public:
Application() = default;
virtual ~Application() = default;
virtual void on_init() = 0;
virtual void on_shutdown() = 0;
void run();
void change_scene(std::string scene_id);
void quit();
};
}
+66
View File
@@ -0,0 +1,66 @@
#pragma once
#include <cassert>
#include <memory>
#include <typeindex>
#include <unordered_map>
namespace varicle{
class ServiceLocator{
private:
// generic storage
struct ServiceContainerBase {
virtual ~ServiceContainerBase() = default;
};
template <typename T>
struct ServiceContainer : public ServiceContainerBase {
std::unique_ptr<T> instance;
ServiceContainer(std::unique_ptr<T> inst) : instance(std::move(inst)) {}
};
static inline std::unordered_map<std::type_index, std::unique_ptr<ServiceContainerBase>> s_services;
// Track registration order to ensure safe LIFO destruction
static inline std::vector<std::type_index> s_registration_order;
public:
// Wrap and pass ownership of a unique_ptr to the locator
template <typename T>
static void provide(std::unique_ptr<T> service) {
s_services[typeid(T)] = std::make_unique<ServiceContainer<T>>(std::move(service));
}
template <typename T>
static T& get(){
auto it = s_services.find(typeid(T));
assert( it != s_services.end() && "Requested service was never provided!");
// Cast the container back, take a peek inside the container and send the address of the reference
// auto container = static_cast <ServiceContainer<T>>(it->second);
auto* container = static_cast<ServiceContainer<T>*>(it->second.get());
return *(container->instance);
}
// Explicitly destroy a specific service
template <typename T>
static void remove() {
s_services.erase(typeid(T)); // Automatically calls the destructor of T!
auto it = std::find(s_registration_order.begin(), s_registration_order.end(), typeid(T));
if (it != s_registration_order.end()) s_registration_order.erase(it);
}
static inline void shutdown(){
for (auto it = s_registration_order.rbegin(); it != s_registration_order.rend(); ++it) {
s_services.erase(*it);
}
s_registration_order.clear();
s_services.clear();
}
};
};
+26
View File
@@ -0,0 +1,26 @@
#include <raylib.h>
namespace varicle{
struct Position{
float x;
float y;
};
struct Velocity{
float dx;
float dy;
};
struct Sprite{
Texture *texture;
float offset_x;
float offset_y;
float width;
float height;
bool flip_h;
bool flip_v;
float rotation;
};
}
+50
View File
@@ -0,0 +1,50 @@
#include "engine/render/render-system.hpp"
#include "engine/ecs/components.hpp"
#include<raylib.h>
#include <entt/entt.hpp>
namespace varicle {
void update_render_system(entt::registry &registry){
auto view = registry.view<const Sprite, const Position>();
for (entt::entity entity : view){
const Sprite &sprite = view.get<Sprite>(entity);
const Position &pos = view.get<Position>(entity);
if (sprite.texture){
DrawTexturePro(
*(sprite.texture),
Rectangle{
0,
0,
(float)sprite.texture->width,
(float)sprite.texture->height,
},
Rectangle {
sprite.offset_x + pos.x,
sprite.offset_y + pos.y,
sprite.width,
sprite.height
},
Vector2 {sprite.width * 0.5f, sprite.height*0.5f},
sprite.rotation,
WHITE);
}else{
DrawRectanglePro(Rectangle {
sprite.offset_x + pos.x,
sprite.offset_y + pos.y,
sprite.width,
sprite.height
},
Vector2 {sprite.width * 0.5f, sprite.height*0.5f},
sprite.rotation,
PURPLE
);
}
}
}
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <entt/entt.hpp>
#include <raylib.h>
namespace varicle {
void update_render_system(entt::registry &registry);
}
+65
View File
@@ -0,0 +1,65 @@
#include "raylib.h"
#include "engine/scene/scene.hpp"
namespace varicle {
SceneManager::SceneManager(){
// current_scene = std::make_unique<MenuScene>();
}
SceneManager::~SceneManager(){
// delete current_scene;
}
Scene& SceneManager::get_current_scene(){
return *current_scene;
}
void SceneManager::process_scene_switch(){
if (next_scene_id.empty()) return;
auto it = scene_registry.find(next_scene_id);
if (it != scene_registry.end()){
current_scene.reset();
current_scene = it->second();
current_scene->init();
}
next_scene_id.clear();
}
void SceneManager::update(float dt){
if (!current_scene) return;
current_scene->update(dt);
}
void SceneManager::render(){
if (!current_scene) return;
current_scene->render();
}
void SceneManager::ui(){
if (!current_scene) return;
current_scene->ui();
}
bool SceneManager::should_game_close(){
return should_quit || WindowShouldClose();
}
void SceneManager::switch_to_scene(std::string scene_id){
next_scene_id = scene_id;
}
void SceneManager::register_scene(std::string scene_id, SceneFactory factory){
scene_registry[std::string(scene_id)] = factory;
}
void SceneManager::quit(){
should_quit = true;
}
}
+82
View File
@@ -0,0 +1,82 @@
#pragma once
#include <functional>
#include <entt/entt.hpp>
#include <memory>
namespace varicle {
// enum class SceneType{
// MENU,
// GAMEPLAY
// };
//
class Scene{
public:
Scene() = default;
virtual ~Scene() = default;
virtual void init() = 0;
virtual void update(float dt) = 0;
virtual void render() = 0;
virtual void ui() = 0;
};
// class GamePlayScene : public Scene{
//
// private:
// entt::registry registry;
//
// public:
// GamePlayScene();
// ~GamePlayScene();
//
// void update(float dt) override;
// void render() override;
// void ui() override;
//
// };
//
// class MenuScene : public Scene{
//
// public:
// MenuScene();
// ~MenuScene() = default;
//
// void update(float dt) override;
// void render() override;
// void ui() override;
//
// };
class SceneManager{
private:
using SceneFactory = std::function<std::unique_ptr<Scene>()>;
std::unordered_map<std::string, SceneFactory> scene_registry;
std::unique_ptr<Scene> current_scene = nullptr;
std::string next_scene_id;
bool pending_switch = false;
bool should_quit = false;
public:
SceneManager();
~SceneManager();
void update(float dt);
void render();
void ui();
void process_scene_switch();
bool should_game_close();
void switch_to_scene(std::string scene_id);
void register_scene(std::string scene_id, SceneFactory factory);
void quit();
Scene& get_current_scene();
};
}
-50
View File
@@ -1,50 +0,0 @@
// src\fruit.cpp
#include <fruit.hpp>
#include <components.hpp>
#include <cstdlib>
#include <math_util.hpp>
#include <engine_variant.hpp>
#include <raylib.h>
#include <entt/entt.hpp>
// #include <iostream>
entt::entity fruit;
// File Base Helper Function
Position get_player_position(entt::registry& registry){
auto player_view = registry.view<const Player>();
if (player_view.empty()) return {};
entt::entity player_entity = player_view.front();
return registry.get<Position>(player_entity);
}
void change_position(Position& pos){
pos.x = Math::RandomRange(30, GetScreenWidth()-30);
pos.y = Math::RandomRange(30, GetScreenHeight()-30);
};
void create_fruit(entt::registry& registry,Texture* texture){
const auto entity = registry.create();
registry.emplace<Position>(entity,100.0f,0.0f);
registry.emplace<Fruit>(entity);
registry.emplace<Sprite>(entity,texture,0.0f,0.0f,30.f,30.0f,false,false,0.0f);
}
void update_fruit_system(entt::registry& registry,float dt){
auto view = registry.view<const Fruit, Position>();
const Position player_pos = get_player_position(registry);
for (entt::entity entity : view){
Position& pos = view.get<Position>(entity);
if (abs(pos.x - player_pos.x) < 35 && abs(pos.y - player_pos.y) < 35 ){
change_position(pos);
}
}
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
struct Player{};
+31
View File
@@ -0,0 +1,31 @@
#include "engine/core/application.hpp"
#include "engine/core/service-locator.hpp"
#include "engine/scene/scene.hpp"
#include "game/scenes/main-scene/main-scene.hpp"
#include <raylib.h>
class Game : public varicle::Application{
public:
void on_init() override {
auto& scene_manager = varicle::ServiceLocator::get<varicle::SceneManager>();
scene_manager.register_scene("menu", []() { return std::make_unique<MainScene>(); });
change_scene("menu");
}
void on_shutdown() override {
}
};
int main(){
Game game;
game.run();
return 0;
}
+100
View File
@@ -0,0 +1,100 @@
#include "main-scene.hpp"
#include "engine/asset/raylib-asset.hpp"
#include "engine/core/service-locator.hpp"
#include "engine/render/render-system.hpp"
#include "engine/ecs/components.hpp"
#include "game/ecs/components.hpp"
#include "raylib.h"
namespace v = varicle;
const float SPEED = 300.0f;
void create_player(entt::registry &registry);
void update_player_system(entt::registry& registry,float dt);
void update_movement_system(entt::registry& registry, float dt);
void MainScene::init() {
auto& asset_loader = v::ServiceLocator::get<v::RaylibAssetLoader>();
asset_loader.load_asset("assets/snake_head.png");
create_player(registry);
}
void MainScene::update(float dt) {
update_player_system(registry,dt);
update_movement_system(registry,dt);
}
void MainScene::render() {
v::update_render_system(registry);
}
void MainScene::ui() {
}
////////////////////////////////////////////////
void create_player(entt::registry &registry){
using namespace v;
auto& asset_loader = ServiceLocator::get<RaylibAssetLoader>();
auto player_texture = asset_loader.get_texture("assets/snake_head.png");
const auto entity = registry.create();
registry.emplace<Position>(entity,100.0f,100.0f);
registry.emplace<Velocity>(entity,SPEED,0.0f);
registry.emplace<Sprite>(entity,player_texture,0.0f,0.0f,70.0f,70.0f,false,false,0.0f);
registry.emplace<Player>(entity);
}
void update_movement_system(entt::registry& registry, float dt) {
using namespace varicle;
// We get Position and Velocity, but EXCLUDE entities that have the Player tag
auto view = registry.view<Position, Velocity>();
view.each([dt](Position &position, Velocity &velocity) {
// This will only run for pipes, enemies, or particles!
position.x += velocity.dx * dt;
position.y += velocity.dy * dt;
});
}
void update_player_system(entt::registry& registry,float dt){
using namespace varicle;
auto view = registry.view<const Position,Velocity,Sprite>();
// for (entt::entity entity : view){
view.each([](const auto entity, const Position& pos, Velocity& vel, Sprite& sprite){
if (IsKeyPressed(KEY_W) && vel.dy <= 0.0f){
vel.dx = 0;
vel.dy = -SPEED;
} else if (IsKeyPressed(KEY_S) && vel.dy >= 0.0f){
vel.dx = 0;
vel.dy = SPEED;
} else if (IsKeyPressed(KEY_A) && vel.dx <= 0.0f){
vel.dx = -SPEED;
vel.dy = 0;
} else if (IsKeyPressed(KEY_D) && vel.dx >= 0.0f){
vel.dx = SPEED;
vel.dy = 0;
}
if (vel.dx != 0.0f || vel.dy != 0.0f) {
// atan2 returns radians. Convert to degrees if your renderer expects it!
float radians = std::atan2(vel.dy, vel.dx);
sprite.rotation = radians * (180.0f / 3.14159265f);
}
});
}
+15
View File
@@ -0,0 +1,15 @@
#include "engine/scene/scene.hpp"
#include <entt/entt.hpp>
class MainScene : public varicle::Scene {
private:
entt::registry registry;
public:
void init() override;
void update(float dt) override;
void render() override;
void ui() override ;
};
-22
View File
@@ -1,22 +0,0 @@
#pragma once
#include <string>
class AnimationManager{
private:
unsigned int glboal_id;
public:
};
// Component attacked to an object for playing animation
struct AnimationComponent{
unsigned int id;
std::string track_key;
float elapsed_time;
bool is_playing;
bool is_completed;
float speed_scale;
std::string group_name;
};
-54
View File
@@ -1,54 +0,0 @@
#pragma once
#include <asset_packer/asset.hpp>
#include <string>
#include <variant>
#include <unordered_map>
struct ImageData {
void* texture;
};
struct SoundData {
void* sound;
};
struct MusicData {
void* music;
};
struct JsonData {
std::string json;
};
struct Asset {
std::string name;
std::variant<ImageData, SoundData, MusicData, JsonData> data;
};
class AssetLoader{
private:
AssetReader asset_reader;
protected:
std::unordered_map<std::string,Asset> assets;
virtual void load_all_assets(std::string data_path) = 0;
virtual void unload_all_assets() = 0;
public:
AssetLoader(std::string asset_data);
~AssetLoader() = default;
virtual void load_asset(std::string path) = 0;
virtual void unload_asset(std::string path) = 0;
virtual Asset get_asset(std::string path) = 0;;
AssetReader get_reader();
};
-31
View File
@@ -1,31 +0,0 @@
#pragma once
#include "asset_packer/asset.hpp"
#include <asset/asset.hpp>
#include <raylib.h>
class RaylibAssetLoader : public AssetLoader{
protected:
void load_all_assets(std::string asset_list) override {};
void unload_all_assets() override;
public:
RaylibAssetLoader(std::string asset_data = "data.dat");
~RaylibAssetLoader();
void load_asset(std::string path) override;
void unload_asset(std::string path) override;
Asset get_asset(std::string path) override;
Texture* get_texture(std::string path);
Sound* get_sound(std::string path);
Music* get_music(std::string path);
std::string get_json(std::string path);
};
// extern RaylibAssetLoader asset_loader;
-30
View File
@@ -1,30 +0,0 @@
#pragma once
#include<raylib.h>
struct Position{
float x;
float y;
};
struct Velocity{
float dx;
float dy;
};
struct Player{};
struct PlayerBody{
unsigned int part_idx;
};
struct Fruit{};
struct Sprite{
Texture *texture;
float offset_x;
float offset_y;
float width;
float height;
bool flip_h;
bool flip_v;
float rotation;
};
-109
View File
@@ -1,109 +0,0 @@
#pragma once
#include <variant>
#include <string>
#include <mutex>
#include <iostream>
struct Vec2 {
float x = 0.0f;
float y = 0.0f;
bool operator==(const Vec2& o) const { return x == o.x && y == o.y; }
bool operator!=(const Vec2& o) const { return !(*this == o); }
Vec2 operator+(const Vec2& o) const { return { x + o.x, y + o.y }; }
Vec2 operator-(const Vec2& o) const { return { x - o.x, y - o.y }; }
Vec2 operator*(float scalar) const { return { x * scalar, y * scalar }; }
};
struct Vec3 {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
bool operator==(const Vec3& o) const { return x == o.x && y == o.y && z == o.z; }
bool operator!=(const Vec3& o) const { return !(*this == o); }
Vec3 operator+(const Vec3& o) const { return { x + o.x, y + o.y, z + o.z }; }
Vec3 operator-(const Vec3& o) const { return { x - o.x, y - o.y, z - o.z }; }
Vec3 operator*(float scalar) const { return { x * scalar, y * scalar, z * scalar }; }
};
struct Vec4 {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
float w = 1.0f;
bool operator==(const Vec4& o) const { return x == o.x && y == o.y && z == o.z && w == o.w; }
bool operator!=(const Vec4& o) const { return !(*this == o); }
Vec4 operator+(const Vec4& o) const { return { x + o.x, y + o.y, z + o.z, w + o.w }; }
Vec4 operator-(const Vec4& o) const { return { x - o.x, y - o.y, z - o.z, w - o.w }; }
Vec4 operator*(float scalar) const { return { x * scalar, y * scalar, z * scalar, w * scalar }; }
};
// Standalone Interpolation Helpers
inline Vec2 Vec2Lerp(const Vec2& s, const Vec2& e, float a) { return { s.x + (e.x - s.x) * a, s.y + (e.y - s.y) * a }; }
inline Vec3 Vec3Lerp(const Vec3& s, const Vec3& e, float a) { return { s.x + (e.x - s.x) * a, s.y + (e.y - s.y) * a, s.z + (e.z - s.z) * a }; }
inline Vec4 Vec4Lerp(const Vec4& s, const Vec4& e, float a) { return { s.x + (e.x - s.x) * a, s.y + (e.y - s.y) * a, s.z + (e.z - s.z) * a, s.w + (e.w - s.w) * a }; }
enum class VariantType { Null, Float, Vector2, Vector3, Vector4, String };
class EngineVariant{
public:
using InternalVariant = std::variant<std::monostate,float,Vec2,Vec3,Vec4,std::string>;
EngineVariant() : data(std::monostate{}), type(VariantType::Null){}
EngineVariant(float v) : data(v), type(VariantType::Float){}
EngineVariant(Vec2 v) : data(v), type(VariantType::Vector2){}
EngineVariant(Vec3 v) : data(v), type(VariantType::Vector3){}
EngineVariant(Vec4 v) : data(v), type(VariantType::Vector4){}
EngineVariant(std::string v) : data(v), type(VariantType::String){}
VariantType GetType() const { return type; }
template<typename T>
T Get() const {
std::lock_guard<std::mutex> lock(v_mutex);
return std::get<T>(data);
}
void Print() const {
std::lock_guard<std::mutex> lock(v_mutex);
std::cout << "[Variant " << TypeToString(type) << "]: ";
std::visit([](auto &&arg){
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::monostate>) std::cout << "Null";
else if constexpr (std::is_same_v<T, float>) std::cout << arg;
else if constexpr (std::is_same_v<T, Vec2>) std::cout << "(" << arg.x << ", " << arg.y << ")";
else if constexpr (std::is_same_v<T, Vec3>) std::cout << "(" << arg.x << ", " << arg.y << ", " << arg.z << ")";
else if constexpr (std::is_same_v<T, Vec4>) std::cout << "(" << arg.x << ", " << arg.y << ", " << arg.z << ", " << arg.w << ")";
else if constexpr (std::is_same_v<T, std::string>) std::cout << "\"" << arg << "\"";
},data);
std::cout << "\n";
}
private:
InternalVariant data;
VariantType type;
mutable std::mutex v_mutex;
static std::string TypeToString(VariantType t) {
switch(t) {
case VariantType::Float: return "Float";
case VariantType::Vector2: return "Vector2";
case VariantType::Vector3: return "Vector3";
case VariantType::Vector4: return "Vector4";
case VariantType::String: return "String";
default: return "Null";
}
}
friend class VariantOpManager;
};
-74
View File
@@ -1,74 +0,0 @@
#pragma once
#include <engine_variant.hpp>
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
enum class OpType {
Assign, // Replace the old value entirely
Add, // Add to the current value
Multiply, // Add to the current value
Lerp // Smoothly blend toward a value
};
struct VariantOpRequest {
EngineVariant* target; // The variable we want to change
OpType operation; // How we want to change it
EngineVariant operand; // The value we are using to make the change
float alpha; // Used ONLY for Lerp (0.0 to 1.0)
};
class VariantOpManager{
public:
VariantOpManager(){}
void ExecuteOperation(const VariantOpRequest& req) {
if (req.target == nullptr) return;
switch (req.operation){
case OpType::Assign:
req.target->data = req.operand.data;
req.target->type = req.operand.type;
break;
case OpType::Add:
req.target->data = std::visit(
overloaded{
[](float p, float n) -> EngineVariant::InternalVariant {return p + n;},
[](Vec2 p, Vec2 n) -> EngineVariant::InternalVariant {return p + n;},
[](Vec3 p, Vec3 n) -> EngineVariant::InternalVariant {return p + n;},
[](Vec4 p, Vec4 n) -> EngineVariant::InternalVariant {return p + n;},
// Fallback
[](auto p, auto n) -> EngineVariant::InternalVariant {return p;},
},req.target->data,req.operand.data);
break;
case OpType::Lerp:
req.target->data = std::visit(overloaded{
[&](float p, float n) -> EngineVariant::InternalVariant { return p + (n - p) * req.alpha; },
[&](Vec2 p, Vec2 n) -> EngineVariant::InternalVariant { return Vec2Lerp(p, n, req.alpha); },
[&](Vec3 p, Vec3 n) -> EngineVariant::InternalVariant { return Vec3Lerp(p, n, req.alpha); },
[&](Vec4 p, Vec4 n) -> EngineVariant::InternalVariant { return Vec4Lerp(p, n, req.alpha); },
[&](const std::string& p, const std::string& n) -> EngineVariant::InternalVariant {
return req.alpha >= 0.5f ? n : p; // Discrete switch for strings
},
// Fallback
[](auto p, auto n) -> EngineVariant::InternalVariant { return p; }
}, req.target->data, req.operand.data);
break;
case OpType::Multiply:
req.target->data = std::visit(overloaded{
[](float p, float n) -> EngineVariant::InternalVariant { return p * n; },
[](Vec2 p, float n) -> EngineVariant::InternalVariant { return p * n; }, // Scale a vector!
[](auto p, auto n) -> EngineVariant::InternalVariant { return p; }
}, req.target->data, req.operand.data);
break;
}
}
};
-9
View File
@@ -1,9 +0,0 @@
#pragma once
#include<raylib.h>
#include<entt/entt.hpp>
void create_fruit(entt::registry& registry,Texture* texture);
void update_fruit_system(entt::registry& registry,float dt);
-24
View File
@@ -1,24 +0,0 @@
#pragma once
#include <scene.hpp>
#include <asset/raylib_asset.hpp>
// A simple Service Locator
class ServiceLocator {
private:
static inline SceneManager* s_scene_manager = nullptr;
static inline RaylibAssetLoader* s_asset_loader = nullptr;
// static inline Configuration* s_config = nullptr;
// static inline AssetManager* s_assets = nullptr;
public:
static void provide(SceneManager* service) { s_scene_manager = service; }
static void provide(RaylibAssetLoader* service) { s_asset_loader = service; }
static SceneManager& get_scene_manager() { return *s_scene_manager; }
static RaylibAssetLoader& get_asset_loader() { return *s_asset_loader; }
// static SceneManager& get_config() { return *s_config; }
// static AssetManager& GetAssets() { return *s_assets; }
};
-21
View File
@@ -1,21 +0,0 @@
#pragma once
#include <random>
namespace Math {
// Generate a random float between min and max
inline float RandomRange(float min, float max) {
static std::random_device rd;
static std::mt19937 gen(rd());
std::uniform_real_distribution<float> dist(min, max);
return dist(gen);
}
// Generate a random int between min and max
inline int RandomRange(int min, int max) {
static std::random_device rd;
static std::mt19937 gen(rd());
std::uniform_int_distribution<int> dist(min, max);
return dist(gen);
}
}
-4
View File
@@ -1,4 +0,0 @@
#pragma once
#include<entt/entt.hpp>
void update_movement_system(entt::registry& registry, float dt);
-24
View File
@@ -1,24 +0,0 @@
#pragma once
#include <components.hpp>
#include <entt/entt.hpp>
#include<raylib.h>
void create_player(entt::registry& registry,Texture* texture);
void create_player_body(entt::registry& registry,Texture* texture,unsigned int idx);
void update_player_system(entt::registry& registry,float dt);
class BodyManager{
private:
std::vector<Position> parts_position_stack = {};
public:
Texture* body_texture;
BodyManager(Texture* texture) : body_texture(texture){}
void add_body(entt::registry& registry);
void pop_body();
void update_body_positions(Position player_head_position);
Position get_body_position(unsigned int part_idx);
};
-5
View File
@@ -1,5 +0,0 @@
#pragma once
#include <entt/entt.hpp>
void update_render_system(entt::registry &registry);
-73
View File
@@ -1,73 +0,0 @@
#pragma once
#include <functional>
#include <entt/entt.hpp>
#include <memory>
enum class SceneType{
MENU,
GAMEPLAY
};
class Scene{
public:
Scene() = default;
virtual ~Scene() = default;
virtual void update(float dt) = 0;
virtual void render() = 0;
virtual void ui() = 0;
};
class GamePlayScene : public Scene{
private:
entt::registry registry;
public:
GamePlayScene();
~GamePlayScene();
void update(float dt) override;
void render() override;
void ui() override;
};
class MenuScene : public Scene{
public:
MenuScene();
~MenuScene() = default;
void update(float dt) override;
void render() override;
void ui() override;
};
class SceneManager{
private:
std::unique_ptr<Scene> current_scene = nullptr;
SceneType next_scene_type;
bool pending_switch = false;
bool should_quit = false;
public:
SceneManager();
~SceneManager();
void update(float dt);
void render();
void ui();
void process_scene_switch();
bool should_game_close();
void request_switch(SceneType type);
void quit();
Scene& get_current_scene();
};
-94
View File
@@ -1,94 +0,0 @@
#include "locator.hpp"
#include <asset/raylib_asset.hpp>
#include <scene.hpp>
#include <components.hpp>
#include <box2d/box2d.h>
#include <box2d/types.h>
#include <raylib.h>
#include <rlImGui.h>
#include <imgui.h>
#include <entt/entt.hpp>
#include <asset_packer/asset.hpp>
#include <iostream>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
void UpdateDrawFrame(void) {
// Update
float dt = GetFrameTime();
// cap dt just for now
if (dt > 0.1f) dt = 0.1f;
// Draw
ServiceLocator::get_scene_manager().update(dt);
BeginDrawing();
ClearBackground(RAYWHITE);
ServiceLocator::get_scene_manager().render();
rlImGuiBegin();
ServiceLocator::get_scene_manager().ui();
rlImGuiEnd();
EndDrawing();
ServiceLocator::get_scene_manager().process_scene_switch(); // !!! After scene_manager is done with the current loop
}
int main(){
int screen_width = 1280;
int screen_height = 800;
RaylibAssetLoader asset_loader;
SceneManager scene_manager;
ServiceLocator::provide(&asset_loader);
ServiceLocator::provide(&scene_manager); // Depends on asset loader!
rlImGuiSetup(true);
ImGuiStyle& style = ImGui::GetStyle();
// Rounded corners
style.WindowRounding = 6.0f;
style.ChildRounding = 4.0f;
style.FrameRounding = 4.0f;
style.PopupRounding = 4.0f;
style.ScrollbarRounding = 9.0f;
style.GrabRounding = 4.0f;
style.TabRounding = 4.0f;
// Sizes and Spacing
style.WindowPadding = ImVec2(15.0f, 15.0f);
style.FramePadding = ImVec2(6.0f, 6.0f);
style.ItemSpacing = ImVec2(10.0f, 8.0f);
style.ScrollbarSize = 15.0f;
SetTargetFPS(60);
// SetTraceLogLevel(TraceLogLevel::LOG_NONE);
InitWindow(screen_width, screen_height, "Snake");
SetWindowState(FLAG_WINDOW_RESIZABLE);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
#else
while (!ServiceLocator::get_scene_manager().should_game_close()){
UpdateDrawFrame();
}
#endif
CloseWindow();
rlImGuiShutdown();
return 0;
}
-16
View File
@@ -1,16 +0,0 @@
// src\movement.cpp
#include <movement.hpp>
#include <entt/entt.hpp>
#include <components.hpp>
void update_movement_system(entt::registry& registry, float dt) {
// We get Position and Velocity, but EXCLUDE entities that have the Player tag
auto view = registry.view<Position, Velocity>();
view.each([dt](Position &position, Velocity &velocity) {
// This will only run for pipes, enemies, or particles!
position.x += velocity.dx * dt;
position.y += velocity.dy * dt;
});
}
-104
View File
@@ -1,104 +0,0 @@
// src\player.cpp
#include <player.hpp>
#include<raylib.h>
#include<entt/entt.hpp>
#include<components.hpp>
entt::entity player;
const float SPEED = 300.0f;
class BodyManager;
void create_player(entt::registry& registry,Texture* texture){
const auto entity = registry.create();
registry.emplace<Position>(entity,100.0f,0.0f);
registry.emplace<Velocity>(entity,SPEED,0.0f);
registry.emplace<Player>(entity);
registry.emplace<Sprite>(entity,texture,0.0f,0.0f,70.0f,70.0f,false,false,0.0f);
}
void update_player_system(entt::registry& registry,float dt){
auto view = registry.view<const Player, const Position, Velocity,Sprite>();
for (entt::entity entity : view){
const Position& pos = view.get<Position>(entity);
Velocity& vel = view.get<Velocity>(entity);
Sprite& sprite = view.get<Sprite>(entity);
if (IsKeyPressed(KEY_W)){
if (vel.dy > 0)
continue;
vel.dx = 0;
vel.dy = -SPEED;
} else if (IsKeyPressed(KEY_S)){
if (vel.dy < 0)
continue;
vel.dx = 0;
vel.dy = SPEED;
} else if (IsKeyPressed(KEY_A)){
if (vel.dx > 0)
continue;
vel.dx = -SPEED;
vel.dy = 0;
} else if (IsKeyPressed(KEY_D)){
if (vel.dx < 0)
continue;
vel.dx = SPEED;
vel.dy = 0;
}
if (vel.dx != 0.0f || vel.dy != 0.0f) {
// atan2 returns radians. Convert to degrees if your renderer expects it!
float radians = std::atan2(vel.dy, vel.dx);
sprite.rotation = radians * (180.0f / 3.14159265f);
}
}
auto body_view = registry.view<const PlayerBody, Position>();
for (entt::entity entity : body_view){
const PlayerBody& body = body_view.get<PlayerBody>(entity);
Position& pos = body_view.get<Position>(entity);
}
}
void create_player_body(entt::registry& registry,Texture* texture,unsigned int idx){
const auto entity = registry.create();
registry.emplace<Position>(entity,100.0f,0.0f);
registry.emplace<Velocity>(entity,SPEED,0.0f);
registry.emplace<PlayerBody>(entity,idx);
registry.emplace<Sprite>(entity,texture,0.0f,0.0f,70.0f,70.0f,false,false,0.0f);
}
void BodyManager::add_body(entt::registry& registry)
{
create_player_body(registry,body_texture,parts_position_stack.size());
parts_position_stack.push_back( Position{});
}
void BodyManager::pop_body(){
parts_position_stack.pop_back();
}
void BodyManager::update_body_positions(Position player_head_position){
for ( auto i = parts_position_stack.size()-1; i > 0 ;i--){
parts_position_stack[i] = parts_position_stack[i-1];
}
parts_position_stack[0] = player_head_position;
}
Position BodyManager::get_body_position(unsigned int part_idx){
return parts_position_stack[part_idx];
}
-45
View File
@@ -1,45 +0,0 @@
#include <render.hpp>
#include <components.hpp>
#include<raylib.h>
#include <entt/entt.hpp>
void update_render_system(entt::registry &registry){
auto view = registry.view<const Sprite, const Position>();
for (entt::entity entity : view){
const Sprite &sprite = view.get<Sprite>(entity);
const Position &pos = view.get<Position>(entity);
if (sprite.texture){
DrawTexturePro(
*(sprite.texture),
Rectangle{
0,
0,
(float)sprite.texture->width,
(float)sprite.texture->height,
},
Rectangle {
sprite.offset_x + pos.x,
sprite.offset_y + pos.y,
sprite.width,
sprite.height
},
Vector2 {sprite.width * 0.5f, sprite.height*0.5f},
sprite.rotation,
WHITE);
// DrawTexture(
// *(sprite.texture),
// pos.x + sprite.offset_x,
// pos.y + sprite.offset_y,
// WHITE
// );
}else{
DrawRectangle(pos.x,pos.y,100, 100,PURPLE);
}
}
}
-64
View File
@@ -1,64 +0,0 @@
#include "locator.hpp"
#include <player.hpp>
#include <movement.hpp>
#include <scene.hpp>
#include <render.hpp>
#include <fruit.hpp>
#include <asset/raylib_asset.hpp>
#include <imgui.h>
#include <iostream>
#include <format>
GamePlayScene::GamePlayScene() {
registry = entt::registry();
ServiceLocator::get_asset_loader().load_asset("assets/snake_head.png");
ServiceLocator::get_asset_loader().load_asset("assets/fruit.png");
create_player(registry,ServiceLocator::get_asset_loader().get_texture("assets/snake_head.png"));
create_fruit(registry,ServiceLocator::get_asset_loader().get_texture("assets/fruit.png"));
}
void GamePlayScene::update(float dt) {
update_movement_system(registry, dt);
update_player_system(registry, dt);
update_fruit_system(registry, dt);
}
void GamePlayScene::render() {
update_render_system(registry);
}
void GamePlayScene::ui() {
// Get the current screen/viewport size
ImVec2 screen_size = ImGui::GetIO().DisplaySize;
// set next container to be center of the screen
ImVec2 screen_center = ImVec2(screen_size.x * 0.9f, screen_size.y * 0.1f);
ImGui::SetNextWindowPos(screen_center, ImGuiCond_Always,ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize({40.f,40.f});
// remove sub window decoration
ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground;
ImGui::Begin("Exit", nullptr, flags);
if (ImGui::Button("X",{40.f,40.f})){
ServiceLocator::get_scene_manager().request_switch(SceneType::MENU);
}
ImGui::End();
}
GamePlayScene::~GamePlayScene(){
ServiceLocator::get_scene_manager();
ServiceLocator::get_asset_loader();
ServiceLocator::get_asset_loader().unload_asset("assets/snake_head.png");
ServiceLocator::get_asset_loader().unload_asset("assets/fruit.png");
}
-57
View File
@@ -1,57 +0,0 @@
#include "locator.hpp"
#include <player.hpp>
#include <movement.hpp>
#include <scene.hpp>
#include <imgui.h>
// #include <format>
MenuScene::MenuScene() {
}
void MenuScene::update(float dt) {
}
void MenuScene::render() {}
void MenuScene::ui() {
// Get the current screen/viewport size
ImVec2 screen_size = ImGui::GetIO().DisplaySize;
// size of button container
ImVec2 vbox_size = ImVec2(200.0f, 250.0f);
// set next container to be center of the screen
ImVec2 screen_center = ImVec2(screen_size.x * 0.5f, screen_size.y * 0.5f);
ImGui::SetNextWindowPos(screen_center, ImGuiCond_Always,ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(vbox_size);
// remove sub window decoration
ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground;
ImGui::Begin("VBoxContainer", nullptr, flags);
// set button width to be size fill container
ImVec2 button_size = ImVec2(ImGui::GetContentRegionAvail().x, 50.0f);
// ImGui::SetCursorPos(centeredPos);
if (ImGui::Button("Play",button_size)){
ServiceLocator::get_scene_manager().request_switch(SceneType::GAMEPLAY);
}
ImGui::Dummy(ImVec2(0, 10)); // Gap
if (ImGui::Button("Quit",button_size)){
ServiceLocator::get_scene_manager().quit();
}
ImGui::End();
// ImGui::Begin("Debug");
// ImGui::Button("Hello",button_size);
// ImGui::TextUnformatted(std::format("window size: {} {} ", screen_size.x,screen_size.y).c_str());
// ImGui::End();
}
-60
View File
@@ -1,60 +0,0 @@
#include "raylib.h"
#include <scene.hpp>
SceneManager::SceneManager(){
current_scene = std::make_unique<MenuScene>();
}
SceneManager::~SceneManager(){
// delete current_scene;
}
Scene& SceneManager::get_current_scene(){
return *current_scene;
}
void SceneManager::process_scene_switch(){
if (!pending_switch) return;
if (current_scene){
current_scene.reset();
}
switch(next_scene_type){
case SceneType::MENU:
current_scene = std::make_unique<MenuScene>();
break;
case SceneType::GAMEPLAY:
current_scene = std::make_unique<GamePlayScene>();
break;
}
pending_switch = false;
}
void SceneManager::update(float dt){
if (!current_scene) return;
current_scene->update(dt);
}
void SceneManager::render(){
if (!current_scene) return;
current_scene->render();
}
void SceneManager::ui(){
if (!current_scene) return;
current_scene->ui();
}
bool SceneManager::should_game_close(){
return should_quit || WindowShouldClose();
}
void SceneManager::request_switch(SceneType type){
next_scene_type = type;
pending_switch = true;
}
void SceneManager::quit(){
should_quit = true;
}
-58
View File
@@ -1,58 +0,0 @@
#include "engine_variant_operation.hpp"
#include <asset/raylib_asset.hpp>
#include <scene.hpp>
#include <components.hpp>
#include <box2d/box2d.h>
#include <box2d/types.h>
#include <raylib.h>
#include <rlImGui.h>
#include <imgui.h>
#include <entt/entt.hpp>
#include <asset_packer/asset.hpp>
#include <engine_variant.hpp>
// #include <engine_math.hpp>
#include <chrono>
#include <thread>
#include <format>
#include <iostream>
#include <variant>
EngineState g_Engine;
RaylibAssetLoader asset_loader;
class Counter {
public:
int value;
};
int main() {
// std::variant<std::monostate,Counter, int,std::string> v1;
// v1 = "hero";
// std::cout << v1.index();
Vec2 v1(1,2);
EngineVariant position(v1);
VariantOpRequest op{
&position,
OpType::Multiply,
EngineVariant (2),
0.0f
};
VariantOpManager().ExecuteOperation(op);
position.Print();
// std::cout << var.Get<Vec2>();
return 0;
}