Compare commits
3
Commits
7cf3427a97
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8feb32ae75 | ||
|
|
e7407ce319 | ||
|
|
d307bd5dbe |
@@ -0,0 +1,4 @@
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
@@ -1,5 +1,7 @@
|
||||
assets/
|
||||
bin/
|
||||
web/
|
||||
web*
|
||||
debug/
|
||||
external/
|
||||
compile_commands.json
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Window][Debug##Default]
|
||||
Pos=952,-6
|
||||
Pos=952,0
|
||||
Size=400,400
|
||||
|
||||
[Window][CenterWindow]
|
||||
@@ -8,7 +8,7 @@ Size=1280,800
|
||||
Collapsed=1
|
||||
|
||||
[Window][VBoxContainer]
|
||||
Pos=540,275
|
||||
Pos=540,235
|
||||
Size=200,250
|
||||
|
||||
[Window][Box]
|
||||
|
||||
@@ -31,22 +31,21 @@ DEBUGFLAGS = -std=c++20 -g -O0
|
||||
|
||||
INCLUDES = -I./external/raylib/include \
|
||||
-I./external/entt/single_include \
|
||||
-I./src/include \
|
||||
-I./external/imgui \
|
||||
-I./external/rlImGui \
|
||||
-I./external/box2d/include \
|
||||
-I./external/nhlohmann_json_3.12.0/ \
|
||||
-I./external/asset_packer/bin/include \
|
||||
-I./src \
|
||||
|
||||
WEB_INCLUDES = -I./external/raylib-web/include \
|
||||
-I./external/entt/single_include \
|
||||
-I./src/include \
|
||||
-I./external/imgui \
|
||||
-I./external/rlImGui \
|
||||
-I./external/box2d/include \
|
||||
-I./external/nhlohmann_json_3.12.0/ \
|
||||
-I./external/asset_packer/bin/include \
|
||||
# -I./external/emscripten/include \
|
||||
-I./src \
|
||||
|
||||
IMGUI_SRCS = ./external/imgui/imgui.cpp \
|
||||
./external/imgui/imgui_demo.cpp \
|
||||
@@ -56,38 +55,35 @@ IMGUI_SRCS = ./external/imgui/imgui.cpp \
|
||||
|
||||
IMGUI_BACKEND = ./external/rlImGui/rlImGui.cpp
|
||||
|
||||
# SRC_FILES = ./src/engine/core/application.cpp \
|
||||
# ./src/engine/scene/scene.cpp \
|
||||
# ./src/game/main.cpp
|
||||
|
||||
SRC_FILES := $(shell find ./src -name "*.cpp")
|
||||
|
||||
SRC_FILES = ./src/asset.cpp \
|
||||
./src/movement.cpp \
|
||||
./src/player.cpp \
|
||||
./src/fruit.cpp \
|
||||
./src/render.cpp \
|
||||
./src/scenes/scene.cpp \
|
||||
./src/scenes/game_play_scene.cpp \
|
||||
./src/scenes/menu_scene.cpp
|
||||
|
||||
ENTRY_POINT = ./src/main.cpp
|
||||
TEST_ENTRY_POINT = ./src/test.cpp
|
||||
|
||||
IMGUI_OBJS = $(patsubst ./external/imgui/%.cpp,./bin/%.o,$(IMGUI_SRCS))
|
||||
IMGUI_BACKEND_OBJS = $(patsubst ./external/rlImGui/%.cpp,./bin/%.o,$(IMGUI_BACKEND))
|
||||
OBJS_FILES = $(patsubst ./src/%.cpp,./bin/%.o,$(SRC_FILES))
|
||||
IMGUI_OBJS = $(patsubst ./external/imgui/%.cpp,./bin/external/%.o,$(IMGUI_SRCS))
|
||||
IMGUI_BACKEND_OBJS = $(patsubst ./external/rlImGui/%.cpp,./bin/external/%.o,$(IMGUI_BACKEND))
|
||||
|
||||
DEP_FILES = $(patsubst ./bin/%.o,./bin/%.d,$(OBJS_FILES))
|
||||
OBJS_FILES = $(patsubst ./src/%.cpp,./bin/obj/%.o,$(SRC_FILES))
|
||||
|
||||
DEP_FILES = $(patsubst ./bin/obj/%.o,./bin/obj/%.d,$(OBJS_FILES))
|
||||
|
||||
|
||||
all: build-desktop run-desktop
|
||||
|
||||
./bin/%.o: ./external/imgui/%.cpp
|
||||
./bin/external/%.o: ./external/imgui/%.cpp
|
||||
@mkdir -p bin
|
||||
@mkdir -p $(dir $@)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
./bin/%.o: ./external/rlImGui/%.cpp
|
||||
./bin/external/%.o: ./external/rlImGui/%.cpp
|
||||
@mkdir -p bin
|
||||
@mkdir -p $(dir $@)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
./bin/%.o: ./src/%.cpp
|
||||
./bin/obj/%.o: ./src/%.cpp
|
||||
@mkdir -p bin
|
||||
@mkdir -p $(dir $@)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
|
||||
@@ -114,7 +110,7 @@ build-core: $(OBJS_FILES)
|
||||
|
||||
build-desktop: $(OBJS_FILES) $(IMGUI_OBJS) $(IMGUI_BACKEND_OBJS)
|
||||
@mkdir -p bin
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $(ENTRY_POINT) $(OBJS_FILES) $(IMGUI_OBJS) $(IMGUI_BACKEND_OBJS) $(LDFLAGS) $(LIBS) -o ./bin/main.exe
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $(OBJS_FILES) $(IMGUI_OBJS) $(IMGUI_BACKEND_OBJS) $(LDFLAGS) $(LIBS) -o ./bin/main.exe
|
||||
cp ./assets ./bin -rf
|
||||
|
||||
build-test: $(OBJS_FILES) $(IMGUI_OBJS) $(IMGUI_BACKEND_OBJS)
|
||||
@@ -125,20 +121,31 @@ build-test: $(OBJS_FILES) $(IMGUI_OBJS) $(IMGUI_BACKEND_OBJS)
|
||||
|
||||
build-debug:
|
||||
@mkdir -p debug
|
||||
$(CXX) $(DEBUGFLAGS) $(INCLUDES) $(ENTRY_POINT) $(SRC_FILES) $(IMGUI_OBJS) $(IMGUI_BACKEND_OBJS) $(LDFLAGS) $(LIBS) -o ./debug/d.exe
|
||||
$(CXX) $(DEBUGFLAGS) $(INCLUDES) $(SRC_FILES) $(IMGUI_OBJS) $(IMGUI_BACKEND_OBJS) $(LDFLAGS) $(LIBS) -o ./debug/d.exe
|
||||
cp ./data.dat ./debug -rf
|
||||
|
||||
web:
|
||||
@mkdir -p web
|
||||
$(WEB_CXX) $(CXXFLAGS) $(WEB_INCLUDES) $(ENTRY_POINT) $(SRC_FILES) $(IMGUI_SRCS) $(IMGUI_BACKEND) $(WEB_LDFLAGS) $(WEB_LIBS) -o ./web/index.html
|
||||
$(WEB_CXX) $(CXXFLAGS) $(WEB_INCLUDES) $(SRC_FILES) $(IMGUI_SRCS) $(IMGUI_BACKEND) $(WEB_LDFLAGS) $(WEB_LIBS) -o ./web/index.html
|
||||
|
||||
web-native:
|
||||
@mkdir -p web
|
||||
em++ $(CXXFLAGS) $(WEB_INCLUDES) $(ENTRY_POINT) $(SRC_FILES) $(IMGUI_SRCS) $(IMGUI_BACKEND) $(WEB_LDFLAGS) $(WEB_LIBS) -o ./web/index.html
|
||||
|
||||
clean-desktop:
|
||||
clean-all:
|
||||
@rm -r -f ./bin
|
||||
@rm -f compile_commands.json
|
||||
|
||||
clean-engine:
|
||||
@rm -r -f ./bin/obj/engine
|
||||
@rm -r -f ./bin/main.exe
|
||||
|
||||
clean-game:
|
||||
@rm -r -f ./bin/obj/game
|
||||
@rm -r -f ./bin/main.exe
|
||||
|
||||
clean-desktop:
|
||||
@rm -r -f ./bin/obj
|
||||
@rm -r -f ./bin/main.exe
|
||||
|
||||
clean-debug:
|
||||
@rm -r -f ./debug
|
||||
@@ -170,5 +177,5 @@ run-test: build-test
|
||||
pack-assets:
|
||||
./external/asset_packer/bin/assetpacker.exe assets/
|
||||
|
||||
|
||||
|
||||
list-src-files:
|
||||
@echo $(shell find src -name "*.cpp")
|
||||
|
||||
-187
@@ -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 "{}";
|
||||
}
|
||||
@@ -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 "{}";
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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();
|
||||
scene_manager.ui();
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
@@ -1,109 +1,109 @@
|
||||
#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;
|
||||
};
|
||||
#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
-74
@@ -1,74 +1,74 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include<vector>
|
||||
#include<algorithm>
|
||||
#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();
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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 ®istry){
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <entt/entt.hpp>
|
||||
#include <raylib.h>
|
||||
|
||||
namespace varicle {
|
||||
|
||||
void update_render_system(entt::registry ®istry);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <random>
|
||||
|
||||
|
||||
namespace varicle {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
struct Player{};
|
||||
struct PlayerBody{};
|
||||
|
||||
struct Fruit{};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
#include "engine/core/application.hpp"
|
||||
#include "engine/core/service-locator.hpp"
|
||||
#include "engine/scene/scene.hpp"
|
||||
|
||||
#include "game/scenes/game-over-scene/game-over.hpp"
|
||||
#include "game/scenes/main-scene/main-scene.hpp"
|
||||
#include "game/scenes/menu-scene/menu.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("main", []() { return std::make_unique<MainScene>(); });
|
||||
|
||||
scene_manager.register_scene("menu", []() { return std::make_unique<MenuScene>(); });
|
||||
|
||||
scene_manager.register_scene("game-over", []() { return std::make_unique<GameOverScene>(); });
|
||||
|
||||
|
||||
change_scene("menu");
|
||||
}
|
||||
|
||||
void on_shutdown() override {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main(){
|
||||
Game game;
|
||||
game.run();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "game-over.hpp"
|
||||
|
||||
#include "engine/core/service-locator.hpp"
|
||||
#include "raylib.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
void GameOverScene::init() {}
|
||||
|
||||
void GameOverScene::update(float dt) {
|
||||
}
|
||||
|
||||
void GameOverScene::render() {
|
||||
ClearBackground(BLACK);
|
||||
DrawText("GAME OVER",400,0,48,RED);
|
||||
}
|
||||
|
||||
void GameOverScene::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 Again",button_size)){
|
||||
v::ServiceLocator::get<v::SceneManager>().switch_to_scene("main");
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, 10)); // Gap
|
||||
|
||||
if (ImGui::Button("Menu",button_size)){
|
||||
v::ServiceLocator::get<v::SceneManager>().switch_to_scene("menu");
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, 10)); // Gap
|
||||
if (ImGui::Button("Quit",button_size)){
|
||||
v::ServiceLocator::get<v::SceneManager>().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();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "engine/scene/scene.hpp"
|
||||
|
||||
namespace v = varicle;
|
||||
|
||||
class GameOverScene : public v::Scene{
|
||||
public:
|
||||
void init() override;
|
||||
void update(float dt) override;
|
||||
void render() override;
|
||||
void ui() override ;
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
#include "body.hpp"
|
||||
|
||||
#include "engine/ecs/components.hpp"
|
||||
#include "game/ecs/components.hpp"
|
||||
#include "engine/asset/raylib-asset.hpp"
|
||||
#include "engine/core/service-locator.hpp"
|
||||
|
||||
#include <raylib.h>
|
||||
#include <entt/entt.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace v = varicle;
|
||||
|
||||
entt::entity create_body(entt::registry& registry,unsigned int idx){
|
||||
auto& asset_loader = v::ServiceLocator::get<v::RaylibAssetLoader>();
|
||||
auto& body_manager = v::ServiceLocator::get<BodyManager>();
|
||||
auto body_texture = asset_loader.get_texture("assets/snake_body.png");
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<v::Position>(entity,-10000.0f,-10000.0f);
|
||||
// registry.emplace<v::Position>(entity,100.0f,100.0f);
|
||||
registry.emplace<PlayerBody>(entity);
|
||||
registry.emplace_or_replace<v::Sprite>(entity,body_texture,0.0f,0.0f,70.0f,70.0f,false,false,0.0f);
|
||||
return entity;
|
||||
}
|
||||
|
||||
void BodyManager::add_body(entt::registry& registry)
|
||||
{
|
||||
auto body_entity =create_body(registry,parts_position_stack.size());
|
||||
body_parts.push_back(body_entity);
|
||||
parts_position_stack.push_back( v::Position{});
|
||||
}
|
||||
|
||||
void BodyManager::pop_body(){
|
||||
parts_position_stack.pop_back();
|
||||
}
|
||||
|
||||
void BodyManager::update_body_positions(v::Position player_head_position){
|
||||
if (parts_position_stack.size() >= 2){
|
||||
for ( auto i = parts_position_stack.size()-1; i > 0 ;i--){
|
||||
parts_position_stack[i] = parts_position_stack[i-1];
|
||||
}
|
||||
}
|
||||
|
||||
if (parts_position_stack.size() >= 1){
|
||||
parts_position_stack[0] = player_head_position;
|
||||
}
|
||||
}
|
||||
|
||||
v::Position BodyManager::get_body_position(unsigned int part_idx){
|
||||
return parts_position_stack[part_idx];
|
||||
}
|
||||
bool BodyManager::dectect_collision(entt::registry& registry) {
|
||||
|
||||
auto player_view = registry.view<const Player, v::Position>();
|
||||
float radius = 50;
|
||||
auto player_entity = player_view.front();
|
||||
if (player_entity == entt::null) return false;
|
||||
auto player_head_position = player_view.get<v::Position>(player_entity);
|
||||
|
||||
for (auto body_part_position : parts_position_stack) {
|
||||
float x = abs(player_head_position.x - body_part_position.x);
|
||||
float y = abs(player_head_position.y - body_part_position.y);
|
||||
float distance = x*x + y*y;
|
||||
if (distance < (radius * radius)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BodyManager::update_body_positions(entt::registry& registry) {
|
||||
for (int i = 0; i < body_parts.size() ;i++) {
|
||||
auto body_part = body_parts[i];
|
||||
auto& body_pos = registry.get<v::Position>(body_part);
|
||||
auto new_pos = parts_position_stack[i];
|
||||
body_pos.x = new_pos.x;
|
||||
body_pos.y = new_pos.y;
|
||||
}
|
||||
|
||||
}
|
||||
void update_body_system(entt::registry& registry){
|
||||
|
||||
auto& body_manager = v::ServiceLocator::get<BodyManager>();
|
||||
auto player_view = registry.view<const Player, v::Position>();
|
||||
auto player_entity = player_view.front();
|
||||
if (player_entity == entt::null) return;
|
||||
body_manager.update_body_positions(player_view.get<v::Position>(player_entity));
|
||||
body_manager.update_body_positions(registry);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
// #include "game/ecs/components.hpp"
|
||||
#include "engine/ecs/components.hpp"
|
||||
|
||||
#include <raylib.h>
|
||||
#include <entt/entt.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace v = varicle;
|
||||
class BodyManager{
|
||||
private:
|
||||
std::vector<v::Position> parts_position_stack = {};
|
||||
std::vector<entt::entity> body_parts = {};
|
||||
public:
|
||||
Texture* body_texture;
|
||||
BodyManager() = default;
|
||||
~BodyManager() = default;
|
||||
|
||||
void add_body(entt::registry& registry);
|
||||
void pop_body();
|
||||
void update_body_positions(v::Position player_head_position);
|
||||
void update_body_positions(entt::registry& registry);
|
||||
bool dectect_collision(entt::registry& registry);
|
||||
v::Position get_body_position(unsigned int part_idx);
|
||||
};
|
||||
|
||||
entt::entity create_body(entt::registry& registry,unsigned int idx);
|
||||
void update_body_system(entt::registry& registry);
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "game/ecs/components.hpp"
|
||||
#include "body.hpp"
|
||||
#include "score-system.hpp"
|
||||
|
||||
#include "engine/ecs/components.hpp"
|
||||
#include "engine/util/math_util.hpp"
|
||||
#include "engine/asset/raylib-asset.hpp"
|
||||
#include "engine/core/service-locator.hpp"
|
||||
|
||||
#include <raylib.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
namespace v = varicle ;
|
||||
|
||||
void create_fruit(entt::registry& registry){
|
||||
auto& asset_loader = v::ServiceLocator::get<v::RaylibAssetLoader>();
|
||||
auto fruit_texture = asset_loader.get_texture("assets/fruit.png");
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<v::Position>(entity,640.0f,400.0f);
|
||||
registry.emplace<v::Sprite>(entity,fruit_texture,0.0f,0.0f,30.f,30.0f,false,false,0.0f);
|
||||
registry.emplace<Fruit>(entity);
|
||||
}
|
||||
|
||||
v::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<v::Position>(player_entity);
|
||||
}
|
||||
|
||||
void change_position(v::Position& pos){
|
||||
pos.x = varicle::RandomRange(30, GetScreenWidth()-30);
|
||||
pos.y = varicle::RandomRange(30, GetScreenHeight()-30);
|
||||
};
|
||||
|
||||
|
||||
void update_fruit_system(entt::registry& registry,float dt){
|
||||
|
||||
auto view = registry.view<const Fruit, v::Position>();
|
||||
const v::Position player_pos = get_player_position(registry);
|
||||
|
||||
for (entt::entity entity : view){
|
||||
v::Position& pos = view.get<v::Position>(entity);
|
||||
if (abs(pos.x - player_pos.x) < 35 && abs(pos.y - player_pos.y) < 35 ){
|
||||
|
||||
auto& score_system = v::ServiceLocator::get<ScoreSystem>();
|
||||
auto& body_manager = v::ServiceLocator::get<BodyManager>();
|
||||
body_manager.add_body(registry);
|
||||
score_system.add_points(1);
|
||||
|
||||
change_position(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <raylib.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
void create_fruit(entt::registry& registry);
|
||||
void update_fruit_system(entt::registry& registry,float dt);
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "main-scene.hpp"
|
||||
#include "fruit.hpp"
|
||||
#include "player.hpp"
|
||||
#include "body.hpp"
|
||||
|
||||
#include "score-system.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 <raylib.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <format>
|
||||
|
||||
const float TICK_INTERVAL = 0.2f;
|
||||
|
||||
namespace v = varicle;
|
||||
|
||||
|
||||
void MainScene::init() {
|
||||
v::ServiceLocator::provide(std::make_unique<ScoreSystem>());
|
||||
v::ServiceLocator::provide(std::make_unique<BodyManager>());
|
||||
|
||||
auto& asset_loader = v::ServiceLocator::get<v::RaylibAssetLoader>();
|
||||
asset_loader.load_asset("assets/snake_head.png");
|
||||
asset_loader.load_asset("assets/snake_body.png");
|
||||
asset_loader.load_asset("assets/fruit.png");
|
||||
|
||||
create_player(registry);
|
||||
create_fruit(registry);
|
||||
}
|
||||
|
||||
void MainScene::update(float dt) {
|
||||
update_player_system(registry,dt);
|
||||
update_fruit_system(registry, dt);
|
||||
|
||||
tick_timer += dt;
|
||||
if (tick_timer >= TICK_INTERVAL) {
|
||||
tick_timer -= TICK_INTERVAL;
|
||||
update_body_system(registry);
|
||||
update_movement_system(registry,dt);
|
||||
auto bm = v::ServiceLocator::get<BodyManager>();
|
||||
if (bm.dectect_collision(registry)) {
|
||||
v::ServiceLocator::get<v::SceneManager>().switch_to_scene("game-over");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainScene::render() {
|
||||
v::update_render_system(registry);
|
||||
|
||||
auto& score_system = v::ServiceLocator::get<ScoreSystem>();
|
||||
DrawText(std::format("Score: {}",score_system.get_current_score()).c_str(),40,40,24,BLACK);
|
||||
}
|
||||
|
||||
void MainScene::ui() {
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
position.y += velocity.dy;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "engine/scene/scene.hpp"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
class MainScene : public varicle::Scene {
|
||||
private:
|
||||
entt::registry registry;
|
||||
float tick_timer = 0.0f;
|
||||
|
||||
public:
|
||||
void init() override;
|
||||
void update(float dt) override;
|
||||
void render() override;
|
||||
void ui() override ;
|
||||
};
|
||||
|
||||
void update_movement_system(entt::registry& registry, float dt);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
#include "engine/ecs/components.hpp"
|
||||
#include "engine/core/service-locator.hpp"
|
||||
#include "engine/asset/raylib-asset.hpp"
|
||||
#include "game/ecs/components.hpp"
|
||||
#include "raylib.h"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
const float SPEED = 60.0f;
|
||||
|
||||
void create_player(entt::registry ®istry){
|
||||
using namespace varicle;
|
||||
|
||||
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_player_system(entt::registry& registry,float dt){
|
||||
using namespace varicle;
|
||||
|
||||
auto view = registry.view<Position,Velocity,Sprite>();
|
||||
|
||||
// for (entt::entity entity : view){
|
||||
view.each([](const auto entity, 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);
|
||||
}
|
||||
|
||||
if (pos.x > GetScreenWidth()) {
|
||||
pos.x = 45;
|
||||
} else if (pos.x < 0) {
|
||||
pos.x = GetScreenWidth() - 45;
|
||||
}
|
||||
|
||||
if (pos.y > GetScreenHeight()) {
|
||||
pos.y = 45;
|
||||
} else if (pos.y < 0) {
|
||||
pos.y = GetScreenHeight() - 45;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
void create_player(entt::registry ®istry);
|
||||
void update_player_system(entt::registry& registry,float dt);
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
class ScoreSystem{
|
||||
private:
|
||||
unsigned int current_score;
|
||||
unsigned int high_score;
|
||||
|
||||
public:
|
||||
ScoreSystem() :current_score(0), high_score(0){}
|
||||
int get_current_score(){return current_score;}
|
||||
int get_high_score(){return high_score;}
|
||||
void reset_score(){current_score = 0;}
|
||||
void reset_high_score(){high_score = 0;}
|
||||
void add_points(unsigned int points){ current_score +=points;}
|
||||
};
|
||||
@@ -1,57 +1,54 @@
|
||||
#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();
|
||||
}
|
||||
#include "menu.hpp"
|
||||
|
||||
#include "engine/core/service-locator.hpp"
|
||||
#include "raylib.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
void MenuScene::init() {}
|
||||
|
||||
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)){
|
||||
v::ServiceLocator::get<v::SceneManager>().switch_to_scene("main");
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, 10)); // Gap
|
||||
|
||||
if (ImGui::Button("Quit",button_size)){
|
||||
v::ServiceLocator::get<v::SceneManager>().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();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "engine/scene/scene.hpp"
|
||||
|
||||
namespace v = varicle;
|
||||
|
||||
class MenuScene : public v::Scene{
|
||||
public:
|
||||
void init() override;
|
||||
void update(float dt) override;
|
||||
void render() override;
|
||||
void ui() override ;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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();
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
#include<entt/entt.hpp>
|
||||
|
||||
void update_movement_system(entt::registry& registry, float dt);
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
void update_render_system(entt::registry ®istry);
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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];
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
#include <render.hpp>
|
||||
#include <components.hpp>
|
||||
|
||||
#include<raylib.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
void update_render_system(entt::registry ®istry){
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user