From e23880e37c2f9d17281d82107b4665b7fc75bf0c Mon Sep 17 00:00:00 2001 From: sal Date: Fri, 6 Oct 2023 15:07:27 -0400 Subject: [PATCH] inheritance implemented for character and controller, cmake overhaul, project restructure (#7) --- .gitignore | 1 + .vs/launch.vs.json | 6 +- .vscode/launch.json | 24 +- .vscode/settings.json | 1 + CMakeLists.txt | 344 +++++------------- CMakePresets.json | 2 +- LICENSE | 2 +- README.md | 1 + cmake/ccache.cmake | 22 ++ cmake/clang-format.cmake | 31 ++ .../utils.cmake => cmake/cmake-utils.cmake | 6 +- cmake/godot-dev-configuration.cmake | 176 +++++++++ cmake/iwyu.cmake | 1 + cmake/vcpkg-init.cmake | 21 ++ cmake/vcpkg-setup.cmake | 38 ++ project/bin/roguelite.gdextension | 12 +- project/icons/.gdignore | 0 project/icons/donut.svg | 39 ++ project/icons/ghost.svg | 46 +++ project/icons/graph.svg | 62 ++++ project/icons/pentagon.svg | 38 ++ project/icons/triangle.svg | 38 ++ project/icons/tristar.svg | 39 ++ project/scenes/characters/enemy.tscn | 2 +- scripts/shell/install-deps.sh | 16 - src/api/extension_interface.cpp | 60 +-- src/{util => core}/assert.hpp | 0 src/{util => core}/attributes.hpp | 0 src/core/concepts.hpp | 40 ++ src/{util => core}/constants.hpp | 10 +- src/{util => core}/function_traits.hpp | 0 src/{nodes => entity}/camera.cpp | 2 +- src/{nodes => entity}/camera.hpp | 0 src/{nodes => entity/character}/character.cpp | 63 ++-- src/entity/character/character.hpp | 111 ++++++ src/entity/character/enemy.cpp | 18 + src/entity/character/enemy.hpp | 21 ++ src/{nodes => entity/character}/player.cpp | 10 +- src/{nodes => entity/character}/player.hpp | 10 +- .../controller/character_controller.cpp | 53 +++ .../controller/character_controller.hpp | 93 +++++ src/entity/controller/enemy_controller.cpp | 21 ++ src/entity/controller/enemy_controller.hpp | 37 ++ .../controller}/player_controller.cpp | 43 +-- src/entity/controller/player_controller.hpp | 26 ++ src/{nodes => entity}/level.cpp | 17 +- src/{nodes => entity}/level.hpp | 9 +- .../projectile}/projectile.cpp | 2 +- .../projectile}/projectile.hpp | 3 +- .../projectile}/projectile_spawner.cpp | 2 +- .../projectile}/projectile_spawner.hpp | 4 +- src/main.cpp | 2 +- src/main.hpp | 3 +- src/nodes/character.hpp | 63 ---- src/nodes/player_controller.hpp | 41 --- src/ui/main_dialog.cpp | 4 +- src/ui/main_dialog.hpp | 2 +- src/util/bind.hpp | 24 +- src/util/concepts.hpp | 35 -- src/util/conversions.hpp | 2 +- src/util/input.cpp | 2 + src/util/io.hpp | 7 +- src/util/scene.hpp | 22 +- src/util/variant.hpp | 13 +- vcpkg.json | 2 +- 65 files changed, 1237 insertions(+), 608 deletions(-) create mode 100644 cmake/ccache.cmake create mode 100644 cmake/clang-format.cmake rename scripts/cmake/utils.cmake => cmake/cmake-utils.cmake (95%) create mode 100644 cmake/godot-dev-configuration.cmake create mode 100644 cmake/iwyu.cmake create mode 100644 cmake/vcpkg-init.cmake create mode 100644 cmake/vcpkg-setup.cmake create mode 100644 project/icons/.gdignore create mode 100644 project/icons/donut.svg create mode 100644 project/icons/ghost.svg create mode 100644 project/icons/graph.svg create mode 100644 project/icons/pentagon.svg create mode 100644 project/icons/triangle.svg create mode 100644 project/icons/tristar.svg delete mode 100755 scripts/shell/install-deps.sh rename src/{util => core}/assert.hpp (100%) rename src/{util => core}/attributes.hpp (100%) create mode 100644 src/core/concepts.hpp rename src/{util => core}/constants.hpp (86%) rename src/{util => core}/function_traits.hpp (100%) rename src/{nodes => entity}/camera.cpp (90%) rename src/{nodes => entity}/camera.hpp (100%) rename src/{nodes => entity/character}/character.cpp (63%) create mode 100644 src/entity/character/character.hpp create mode 100644 src/entity/character/enemy.cpp create mode 100644 src/entity/character/enemy.hpp rename src/{nodes => entity/character}/player.cpp (51%) rename src/{nodes => entity/character}/player.hpp (59%) create mode 100644 src/entity/controller/character_controller.cpp create mode 100644 src/entity/controller/character_controller.hpp create mode 100644 src/entity/controller/enemy_controller.cpp create mode 100644 src/entity/controller/enemy_controller.hpp rename src/{nodes => entity/controller}/player_controller.cpp (64%) create mode 100644 src/entity/controller/player_controller.hpp rename src/{nodes => entity}/level.cpp (86%) rename src/{nodes => entity}/level.hpp (84%) rename src/{nodes => entity/projectile}/projectile.cpp (97%) rename src/{nodes => entity/projectile}/projectile.hpp (98%) rename src/{nodes => entity/projectile}/projectile_spawner.cpp (96%) rename src/{nodes => entity/projectile}/projectile_spawner.hpp (95%) delete mode 100644 src/nodes/character.hpp delete mode 100644 src/nodes/player_controller.hpp delete mode 100644 src/util/concepts.hpp diff --git a/.gitignore b/.gitignore index 9245e74..072c76f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .godot/ .import/ .out/ +out/ cmake-build-*/ export.cfg diff --git a/.vs/launch.vs.json b/.vs/launch.vs.json index 4d78394..d84d40d 100644 --- a/.vs/launch.vs.json +++ b/.vs/launch.vs.json @@ -15,7 +15,8 @@ "${workspaceRoot}/project" ], "project": "CMakeLists.txt", - "name": "gdextension (editor)" + "name": "gdextension (editor)", + "visualizerFile": "${workspaceRoot}/extern/godot-engine/platform/windows/godot.natvis" }, { "type": "dll", @@ -28,7 +29,8 @@ "${workspaceRoot}/project" ], "project": "CMakeLists.txt", - "name": "gdextension (console)" + "name": "gdextension (project)", + "visualizerFile": "${workspaceRoot}/extern/godot-engine/platform/windows/godot.natvis" } ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index a3feecd..3651dc0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,6 @@ "type": "cppdbg", "request": "launch", "MIMode": "gdb", - "program": "unsupported platform, add executable path to launch.json", "linux": { "program": "${workspaceFolder}/extern/godot-engine/bin/godot.linuxbsd.editor.dev.x86_64", "miDebuggerPath": "/usr/bin/gdb" @@ -23,14 +22,11 @@ "--verbose", "--path", "${workspaceFolder}/project", - "res://main.tscn" ], - "cwd": "${workspaceFolder}/project", + "cwd": "${workspaceFolder}", "visualizerFile": "${workspaceFolder}/extern/godot-engine/platform/windows/godot.natvis", "internalConsoleOptions": "openOnSessionStart", "launchCompleteCommand": "exec-run", - "targetArchitecture": "x64", - "externalConsole": false, "symbolLoadInfo": { "loadAll": true, "exceptionList": "", @@ -48,11 +44,14 @@ "type": "cppdbg", "request": "launch", "MIMode": "gdb", - "program": "unsupported platform, add executable path to launch.json", "linux": { "program": "${workspaceFolder}/extern/godot-engine/bin/godot.linuxbsd.editor.dev.x86_64", "miDebuggerPath": "/usr/bin/gdb" }, + "windows": { + "program": "${workspaceFolder}/extern/godot-engine/bin/godot.windows.editor.dev.x86_64.exe", + "miDebuggerPath": "C:\\tools\\mingw64\\bin\\gdb.exe" + }, "args": [ "--editor", "--debug", @@ -60,12 +59,10 @@ "--path", "${workspaceFolder}/project" ], - "cwd": "${workspaceFolder}/project", + "cwd": "${workspaceFolder}", "visualizerFile": "${workspaceFolder}/extern/godot-engine/platform/windows/godot.natvis", "internalConsoleOptions": "openOnSessionStart", "launchCompleteCommand": "exec-run", - "targetArchitecture": "x64", - "externalConsole": false, "symbolLoadInfo": { "loadAll": true, "exceptionList": "" @@ -95,14 +92,12 @@ "--debug", "--verbose", "--path", - "${workspaceFolder}/project", - "res://main.tscn" + "${workspaceFolder}/project" ], - "cwd": "${workspaceFolder}/project", + "cwd": "${workspaceFolder}", "visualizerFile": "${workspaceFolder}/extern/godot-engine/platform/windows/godot.natvis", "internalConsoleOptions": "openOnSessionStart", "console": "internalConsole", - "externalConsole": false, }, { "name": "editor (vsdbg)", @@ -124,11 +119,10 @@ "--path", "${workspaceFolder}/project" ], - "cwd": "${workspaceFolder}/project", + "cwd": "${workspaceFolder}", "visualizerFile": "${workspaceFolder}/extern/godot-engine/platform/windows/godot.natvis", "internalConsoleOptions": "openOnSessionStart", "console": "internalConsole", - "externalConsole": false, } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index dbe2fad..7365b85 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -101,4 +101,5 @@ "workbench.list.smoothScrolling": true, "workbench.tree.renderIndentGuides": "always", "dotnet.defaultSolution": "disable", + "svg.preview.background": "editor", } diff --git a/CMakeLists.txt b/CMakeLists.txt index 55c25d8..540ceb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,296 +1,106 @@ cmake_minimum_required(VERSION 3.20) -## Uncomment to output a dump of every CMake variable -# set(CMAKE_MESSAGE_LOG_LEVEL DEBUG) +set(GDEXTENSION_LIB_NAME roguelite) +set(GDEXTENSION_LIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/project/bin") -# ======================================================================= -# VCPKG submodule init/update. Needs to happen before anything else -# because this submodule contains a toolchain file needed for the -# main project configuration, which must set before project() is called -# ======================================================================= - -# confirm we found the vcpkg submodule ports dir. -# if the ports dir isn't found, the submodule probably -# hasn't been initialized or updated yet. -if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/ports") - message(NOTICE "VCPKG package manager sources not found") - message(NOTICE "initializing/updating the vcpkg submodule...") - - # update the vcpkg submodule to populate it with the code necessary - # to grab all dependencies needed for the gdextension library build - execute_process( - COMMAND git submodule update --init extern/vcpkg - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND_ERROR_IS_FATAL ANY - ) -endif() - -# define toolchain file early for vcpkg. -# this will be pulled in by the vcpkg submodule initialized above -if(NOT CMAKE_TOOLCHAIN_FILE) - set(toolchain_file_path "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/scripts/buildsystems/vcpkg.cmake") - if (EXISTS "${toolchain_file_path}") - set(CMAKE_TOOLCHAIN_FILE "${toolchain_file_path}") - else() - message(WARNING "VCPKG toolchain file not found: ${toolchain_file_path}") - endif() -endif() - -project(roguelite LANGUAGES C CXX) -set(gdextension_lib_name ${PROJECT_NAME}) +option( + AUTOFORMAT_SRC_ON_CONFIGURE + "If enabled, clang-format will be used to format all sources in src/ during configuration" + ON +) -string(TOLOWER "${CMAKE_SYSTEM_NAME}" host_os) -set(VCPKG_TARGET_TRIPLET "x64-${host_os}-static") +option( + USE_CCACHE_FOR_GDEXT_BUILD + "If enabled, ccache will be used to when building the project lib" + ON +) -# needs to be >= C++17 set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS ON) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_COLOR_DIAGNOSTICS ON) +set(CMAKE_MESSAGE_LOG_LEVEL STATUS) -# define output paths for gdextension shared lib and debug symbols -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/project/bin") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/project/bin") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/project/bin") -set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/project/bin") -set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/project/bin") - -# postfix debug binaries with "d" -set(CMAKE_DEBUG_POSTFIX "d") - -# confirm we found the godot engine source files. -# if the sources list is empty, the submodule probably -# hasn't been initialized or updated yet. -if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/core") - message(NOTICE "Godot engine sources not found") - message(NOTICE "initializing/updating the engine submodule...") - - # update the engine submodule to populate it with the - # code necessary to build a debug version of the editor that - # can be easily debugged along with the gdextension library - execute_process( - COMMAND git submodule update --init extern/godot-engine - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMAND_ERROR_IS_FATAL ANY - ) -endif() - -# ======================================================================= -# VCPKG bootstrap / initialization. -# Only happens once, when vcpkg executable is missing. -# ======================================================================= - -set(vcpkg_executable "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/vcpkg${CMAKE_EXECUTABLE_SUFFIX}") - -if(EXISTS "${vcpkg_executable}") - message(NOTICE "Found VCPKG Executable: ${vcpkg_executable}") -else() - message(NOTICE "Could not find VCPKG Executable: ${vcpkg_executable}") - message(NOTICE "Calling VCPKG bootstrap scripts.") - # bootstrap vcpkg to configured and install - - if(WIN32) - execute_process( - COMMAND ps -c "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/bootstrap-vcpkg.bat" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMAND_ERROR_IS_FATAL ANY - ) - elseif(UNIX) - execute_process( - COMMAND bash "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/bootstrap-vcpkg.sh" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMAND_ERROR_IS_FATAL ANY - ) - endif() - - # fail out if vcpkg isn't found after setup - if(NOT EXISTS "${vcpkg_executable}") - message(FATAL_ERROR "ERROR: '${vcpkg_executable}' not found!") - endif() -endif() - -# ======================================================================= -# Godot Engine and C++ bindings submodule management -# ======================================================================= - -# confirm we found the godot engine source files. -# if the sources list is empty, the submodule probably -# hasn't been initialized or updated yet. -if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-cpp/src") - message(NOTICE "godot-cpp bingings source not found") - message(NOTICE "initializing/updating the godot-cpp submodule...") - - # update the c++ bingings submodule to populate it with - # the necessary source for the gdextension library - execute_process( - COMMAND git submodule update --init extern/godot-cpp - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND_ERROR_IS_FATAL ANY - ) -endif() - -# ======================================================================= -# Godot editor/engine debug build -# ======================================================================= - -# define variable to be used in the engine build when specifying platform. -set(host_os_engine "${host_os}") -if(UNIX) - # the scons build expects linuxbsd to be passed in as the platform - # when building on linux, so just append bsd to CMAKE_SYSTEM_NAME - set(host_os_engine "${host_os}bsd") -endif() - -set(godot_debug_editor_executable - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/bin/godot.${host_os_engine}.editor.dev.x86_64${CMAKE_EXECUTABLE_SUFFIX}" +list(APPEND CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-cpp/cmake/" ) -message(NOTICE "godot_debug_editor_executable = ${godot_debug_editor_executable}") - -# if the engine/editor executable isn't found in the -# engine's submodule bin folder, invoke the scons build. -if(NOT EXISTS "${godot_debug_editor_executable}") - message("Godot engine debug binaries not found, invoking debug build of engine...") - - execute_process( - COMMAND scons platform=${host_os} arch=x64 target=editor use_static_cpp=yes dev_build=yes debug_symbols=yes optimize=none use_lto=no --clean - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine" - COMMAND_ERROR_IS_FATAL ANY - ) +include(vcpkg-init) - # this build should only ever need to be run once (unless the enging debug binaries - # are deleted or you want to change the build configuration/command invoked below). - execute_process( - COMMAND scons platform=${host_os} arch=x64 target=editor use_static_cpp=yes dev_build=yes debug_symbols=yes optimize=none use_lto=no use_lto=no - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine" - COMMAND_ERROR_IS_FATAL ANY - ) +project("${GDEXTENSION_LIB_NAME}" + LANGUAGES + C CXX + VERSION + 0.1.0 +) - # not necessary, the temp file in here just confuses Visual Studio - file(REMOVE_RECURSE "${CMAKE_CURRENT_SOURCE_DIR}}/extern/godot-engine/.sconf_temp") +include(vcpkg-setup) - if(NOT EXISTS "${godot_debug_editor_executable}") - message(FATAL_ERROR "Couldn't find godot debug executable after scons build: ${godot_debug_editor_executable}") - endif() -endif() +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${GDEXTENSION_LIB_PATH}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${GDEXTENSION_LIB_PATH}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${GDEXTENSION_LIB_PATH}") +set(CMAKE_PDB_OUTPUT_DIRECTORY "${GDEXTENSION_LIB_PATH}") +set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY "${GDEXTENSION_LIB_PATH}") +set(CMAKE_DEBUG_POSTFIX ".debug.${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}") # ======================================================================= # Compiler identification # ======================================================================= -# used below to conditionally set certain compile options depending on the toolset used. -# taken from godot-cpp's cmakelists.txt for consistency (along with some of the compiler -# options defined in target_compile_options() below). set(compiler_is_clang "$,$>") set(compiler_is_gnu "$") set(compiler_is_msvc "$") # ======================================================================= -# 3rd party library setup/configuration (leverages vcpkg) -# ======================================================================= - -find_package(fmt CONFIG REQUIRED) -find_package(spdlog CONFIG REQUIRED) - -# ======================================================================= -# Godot C++ bindings library setup/configuration +# Configure godot-engine and godot-cpp submodules and define libraries. +# godot-cpp: +# configured as a library that will statically +# link this project's gdextension library. +# godot-engine: +# the engine submodule will be (re)built using scons if a +# debug build of the editor doesn't already exist. +# the engine sources and headers will then be used to declare +# a library in cmake (but will not built). the cmake library +# will improve code browsing, syntax highlighting, searching, +# debbuging, and autocomplete/intellisense for any IDEs that +# gather data from cmake (i.e. VSCode and Visual Studio 2022) # ======================================================================= -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-cpp) +include(godot-dev-configuration) # ======================================================================= -# Godot engine library setup/configuration. -# Not necessary, just provides better support in multiple IDEs -# for engine source code browsing, intellisense, and debugging +# 3rd party library setup/configuration (leverages vcpkg) # ======================================================================= -# populate source file list for the godot engine submodule -file(GLOB_RECURSE godot_engine_sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/*.[hc]" - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/*.[hc]pp" -) - -# add the engine sources as a library so intellisense works in VS and VSCode -# (and any other IDEs that support CMake in a way where the information from -# the CMake build is fed into the IDE for additional context about the code -# when browsing/debugging). even though the engine is being added as a library here, -# the EXCLUDE_FROM_ALL option will prevent it from compiling. This is done -# purely for IDE integration so it's able to properly navigate the engine -# source code using features like "go do definition", or typical tooltips. -add_library(godot_engine EXCLUDE_FROM_ALL ${godot_engine_sources}) - -# this is just a handful of additional include directories used by the engine. -# this isn't a complete list, I just add them as needed whenever I venture into -# code where the IDE can't find certain header files during engine source browsing. -target_include_directories(godot_engine PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine" - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/platform/windows" - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/zlib" - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/vulkan" - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/vulkan/include" - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/vulkan/include/vulkan" - "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/drivers/vulkan" - SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/glad" - SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/volk" - SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/zstd" - SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/mbedtls/include" -) - -# define a bunch of the same symbol definitions -# used when by the scons engine build. These build -# flags can differen based on the engine's build for -# you system. Update as needed for your setup. -target_compile_definitions(godot_engine PUBLIC - $<$: - DEBUG_ENABLED - DEBUG_METHODS_ENABLED - DEV_ENABLED - > - NOMINMAX - TOOLS_ENABLED - NO_EDITOR_SPLASH - WINDOWS_ENABLED - WASAPI_ENABLED - WINMIDI_ENABLED - TYPED_METHOD_BIND - VULKAN_ENABLED - GLES3_ENABLED - MINIZIP_ENABLED - BROTLI_ENABLED - ZSTD_STATIC_LINKING_ONLY - USE_VOLK - VK_USE_PLATFORM_WIN32_KHR - GLAD_ENABLED - GLES_OVER_GL - _SCRT_STARTUP_WINMAIN=1 - $<${compiler_is_msvc}: - MSVC - > -) +find_package(fmt CONFIG REQUIRED) +find_package(spdlog CONFIG REQUIRED) # ======================================================================= # GDExtension dynamic library setup/configuration # ======================================================================= -# create gdextension dynamic lib from the project sources. -# CONFIGURE_DEPENDS here will forcefully invoke a reconfiguration -# of the project any time the GLOB call results in a different -# files listing of all sources present within the src/ directory. -file(GLOB_RECURSE roguelite_sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/*.[hc]" - "${CMAKE_CURRENT_SOURCE_DIR}/src/*.[hc]pp" +# add library sources +file(GLOB_RECURSE gdext_sources + CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.[hc]" + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.[hc]pp" ) # add the gdextension dynamic library -add_library(${gdextension_lib_name} SHARED ${roguelite_sources}) +add_library(${PROJECT_NAME} + SHARED + ${gdext_sources} +) -# import the same compiler warning settings that the bindings library uses -include("${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-cpp/cmake/GodotCompilerWarnings.cmake") +# import compiler warningS from godot-cpp +include(GodotCompilerWarnings) # set compiler options for the gdextension library based on the compiler being used -target_compile_options(${gdextension_lib_name} PUBLIC +target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_msvc}: /EHsc /utf-8 @@ -324,14 +134,15 @@ target_compile_options(${gdextension_lib_name} PUBLIC > ) -# define include directories for the gdextension library -target_include_directories(${gdextension_lib_name} PUBLIC +##### <<<<<<<<< + +# include directories gdextension library +target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src" ) -# linker options for the gdextension library, also taken -# from godot-cpp's cmakelists.txt for consistency -target_link_options(${gdextension_lib_name} PRIVATE +# linker options for the gdextension library +target_link_options(${PROJECT_NAME} PRIVATE $<$: -static-libgcc -static-libstdc++ @@ -339,13 +150,24 @@ target_link_options(${gdextension_lib_name} PRIVATE > ) +# ======================================================================= +# Optional configuration / build features +# ======================================================================= + +if (USE_CCACHE_FOR_GDEXT_BUILD MATCHES ON) + include(ccache) +endif() + +if (AUTOFORMAT_SRC_ON_CONFIGURE MATCHES ON) + include(clang-format) +endif() + # ======================================================================= # Dependency linkage # ======================================================================= -# link gdextension to the cpp bindings library -# and all 3rd pary libs brought in by vcpkg -target_link_libraries(${gdextension_lib_name} +# gdextension library dependency linkage +target_link_libraries(${PROJECT_NAME} PUBLIC godot::cpp PRIVATE fmt::fmt PRIVATE fmt::fmt-header-only @@ -356,7 +178,7 @@ target_link_libraries(${gdextension_lib_name} # Print configuration report # ======================================================================= -# include utility script that prints a handful of +# include utility script that prints a handful of # useful build/configuration cmake variables -include(${CMAKE_SOURCE_DIR}/scripts/cmake/utils.cmake) +include(cmake-utils) print_project_variables() diff --git a/CMakePresets.json b/CMakePresets.json index 340cc9b..c640c99 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -12,7 +12,7 @@ "strategy": "external" }, "environment": { - "NINJA_STATUS": "%p [%f/%t] - " + "NINJA_STATUS": "%p [%es] (%f/%t) -" } }, { diff --git a/LICENSE b/LICENSE index 4ad7499..ca6017f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 vorlac +Copyright (c) 2023 sal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 209f878..264c0d2 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ This repo and/or the [gdextension developer documentation](https://github.com/vo The projects below are also worth checking out for some additional GDExtension examples to use as references * https://github.com/paddy-exe/GDExtensionSummator * https://github.com/asmaloney/GDExtensionTemplate +* https://github.com/godotengine/godot-cpp/tree/master/test/src # Licensing #### Code diff --git a/cmake/ccache.cmake b/cmake/ccache.cmake new file mode 100644 index 0000000..4bb5661 --- /dev/null +++ b/cmake/ccache.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Unlicense + +# See: https://crascit.com/2016/04/09/using-ccache-with-cmake/ +find_program( CCACHE_PROGRAM ccache ) + +if ( CCACHE_PROGRAM ) + # get version information + execute_process( + COMMAND "${CCACHE_PROGRAM}" --version + OUTPUT_VARIABLE CCACHE_VERSION + ) + + string( REGEX MATCH "[^\r\n]*" CCACHE_VERSION ${CCACHE_VERSION} ) + + message( STATUS "Using ccache: ${CCACHE_PROGRAM} (${CCACHE_VERSION})" ) + + # Turn on ccache for all targets + set( CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" ) + set( CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" ) + + unset( CCACHE_VERSION ) +endif() diff --git a/cmake/clang-format.cmake b/cmake/clang-format.cmake new file mode 100644 index 0000000..3fee73f --- /dev/null +++ b/cmake/clang-format.cmake @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: Unlicense + +find_program(CLANG_FORMAT_PROGRAM NAMES clang-format) + +if (CLANG_FORMAT_PROGRAM) + execute_process( + COMMAND "${CLANG_FORMAT_PROGRAM}" --version + OUTPUT_VARIABLE CLANG_FORMAT_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + message("Using clang-format: ${CLANG_FORMAT_PROGRAM} (${CLANG_FORMAT_VERSION})") + + file(GLOB_RECURSE + format_src_list + RELATIVE + "${CMAKE_CURRENT_SOURCE_DIR}" + "src/*.[hc]" + "src/*.[hc]pp" + ) + + foreach(_src_file ${format_src_list}) + message(" formatting => ${_src_file}") + execute_process( + COMMAND "${CLANG_FORMAT_PROGRAM}" --style=file -i "${_src_file}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + endforeach() + + unset(CLANG_FORMAT_VERSION) +endif() diff --git a/scripts/cmake/utils.cmake b/cmake/cmake-utils.cmake similarity index 95% rename from scripts/cmake/utils.cmake rename to cmake/cmake-utils.cmake index de00e17..235c537 100644 --- a/scripts/cmake/utils.cmake +++ b/cmake/cmake-utils.cmake @@ -29,9 +29,9 @@ endfunction(run_active_cmake_diagnostics) # values using a case insentive regex match # # examples: -# 1. print all cmake variables: +# 1. print all cmake variables: # > dump_cmake_variables(".*") -# 2. print all boolt cmake variables: +# 2. print all boolt cmake variables: # > dump_cmake_variables("^boost.*") function(dump_cmake_variables) get_cmake_property(_vars VARIABLES) @@ -97,6 +97,8 @@ function(print_project_variables) message(NOTICE " CMAKE_TOOLCHAIN_FILE:....................: " ${CMAKE_TOOLCHAIN_FILE}) message(NOTICE " CMAKE_SOURCE_DIR:........................: " ${CMAKE_SOURCE_DIR}) message(NOTICE " CMAKE_COMMAND:...........................: " ${CMAKE_COMMAND}) + message(NOTICE " CLANG_FORMAT_PROGRAM:....................: " ${CLANG_FORMAT_PROGRAM}) + message(NOTICE " SCONS_PROGRAM:...........................: " ${SCONS_PROGRAM}) message(NOTICE " CMAKE_CXX_COMPILER:......................: " ${CMAKE_CXX_COMPILER}) message(NOTICE " CMAKE_LINKER:............................: " ${CMAKE_LINKER}) message(NOTICE " CMAKE_BUILD_TOOL:........................: " ${CMAKE_BUILD_TOOL}) diff --git a/cmake/godot-dev-configuration.cmake b/cmake/godot-dev-configuration.cmake new file mode 100644 index 0000000..2bb66df --- /dev/null +++ b/cmake/godot-dev-configuration.cmake @@ -0,0 +1,176 @@ +# ======================================================================= +# Godot Engine submodule update/init +# ======================================================================= + +# confirm we found the godot engine source files. +# if the sources list is empty, the submodule probably +# hasn't been initialized or updated yet. +if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/core") + message(NOTICE "Godot engine sources not found") + message(NOTICE "initializing/updating the engine submodule...") + + # update the engine submodule to populate it with the + # code necessary to build a debug version of the editor that + # can be easily debugged along with the gdextension library + execute_process( + COMMAND git submodule update --init extern/godot-engine + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND_ERROR_IS_FATAL ANY + ) +endif() + +# ======================================================================= +# Godot-cpp bindings submodule update/init +# ======================================================================= + +# confirm we found the godot engine source files. +# if the sources list is empty, the submodule probably +# hasn't been initialized or updated yet. +if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-cpp/src") + message(NOTICE "godot-cpp bingings source not found") + message(NOTICE "initializing/updating the godot-cpp submodule...") + + # update the c++ bingings submodule to populate it with + # the necessary source for the gdextension library + execute_process( + COMMAND git submodule update --init extern/godot-cpp + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND_ERROR_IS_FATAL ANY + ) +endif() + +# ======================================================================= +# Godot editor/engine debug build +# ======================================================================= + +# define variable to be used in the engine build when specifying platform. +set(host_os_engine "${host_os}") +if(UNIX) + # the scons build expects linuxbsd to be passed in as the platform + # when building on linux, so just append bsd to CMAKE_SYSTEM_NAME + set(host_os_engine "${host_os}bsd") +endif() + +set(godot_debug_editor_executable + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/bin/godot.${host_os_engine}.editor.dev.x86_64${CMAKE_EXECUTABLE_SUFFIX}" +) + +find_program(SCONS_PROGRAM NAMES scons) +if (NOT EXISTS "${SCONS_PROGRAM}") + message(FATAL_ERROR + "scons not found, it is required for the godot engine build. " + "Please install scons and confirm it is in your system PATH." + ) +endif() + +message(NOTICE "godot_debug_editor_executable = ${godot_debug_editor_executable}") + +# if the engine/editor executable isn't found in the +# engine's submodule bin folder, invoke the scons build. +if(NOT EXISTS "${godot_debug_editor_executable}") + message("Godot engine debug binaries not found, invoking debug build of engine...") + + execute_process( + COMMAND scons platform=${host_os} arch=x64 target=editor use_static_cpp=yes dev_build=yes debug_symbols=yes optimize=none use_lto=no --clean + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine" + COMMAND_ERROR_IS_FATAL ANY + ) + + # this build should only ever need to be run once (unless the enging debug binaries + # are deleted or you want to change the build configuration/command invoked below). + execute_process( + COMMAND scons platform=${host_os} arch=x64 target=editor use_static_cpp=yes dev_build=yes debug_symbols=yes optimize=none use_lto=no + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine" + COMMAND_ERROR_IS_FATAL ANY + ) + + # not necessary, the temp file in here just confuses Visual Studio + file(REMOVE_RECURSE "${CMAKE_CURRENT_SOURCE_DIR}}/extern/godot-engine/.sconf_temp") + + if(NOT EXISTS "${godot_debug_editor_executable}") + message(FATAL_ERROR "Couldn't find godot debug executable after scons build: ${godot_debug_editor_executable}") + endif() +endif() + +# ======================================================================= +# Godot C++ bindings library setup/configuration +# ======================================================================= + +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-cpp) + +# ======================================================================= +# Godot engine library setup/configuration. +# Not necessary, just provides better support in multiple IDEs +# for engine source code browsing, intellisense, and debugging +# ======================================================================= + +# populate source file list for the godot engine submodule +file(GLOB_RECURSE godot_engine_sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/*.[hc]" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/*.[hc]pp" +) + +# add the engine sources as a library so intellisense works in VS and VSCode +# (and any other IDEs that support CMake in a way where the information from +# the CMake build is fed into the IDE for additional context about the code +# when browsing/debugging). even though the engine is being added as a library here, +# the EXCLUDE_FROM_ALL option will prevent it from compiling. This is done +# purely for IDE integration so it's able to properly navigate the engine +# source code using features like "go do definition", or typical tooltips. +add_library(godot_engine EXCLUDE_FROM_ALL ${godot_engine_sources}) + +# this is just a handful of additional include directories used by the engine. +# this isn't a complete list, I just add them as needed whenever I venture into +# code where the IDE can't find certain header files during engine source browsing. +target_include_directories(godot_engine PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/platform/windows" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/zlib" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/vulkan" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/vulkan/include" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/vulkan/include/vulkan" + "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/drivers/vulkan" + SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/glad" + SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/volk" + SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/zstd" + SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/extern/godot-engine/thirdparty/mbedtls/include" +) + +# define a bunch of the same symbol definitions +# used when by the scons engine build. These build +# flags can differen based on the engine's build for +# you system. Update as needed for your setup. +target_compile_definitions(godot_engine PUBLIC + $<$: + DEBUG_ENABLED + DEBUG_METHODS_ENABLED + DEV_ENABLED + > + $<$: + UNIX_ENABLED + VK_USE_PLATFORM_XLIB_KHR + > + $<$: + WINDOWS_ENABLED + WASAPI_ENABLED + WINMIDI_ENABLED + TYPED_METHOD_BIND + NOMINMAX + WIN32 + VK_USE_PLATFORM_WIN32_KHR + _SCRT_STARTUP_WINMAIN=1 + $<$: + MSVC + > + > + TOOLS_ENABLED + NO_EDITOR_SPLASH + GLAD_ENABLED + GLES3_ENABLED + GLES_OVER_GL + VULKAN_ENABLED + USE_VOLK + MINIZIP_ENABLED + BROTLI_ENABLED + ZSTD_STATIC_LINKING_ONLY +) diff --git a/cmake/iwyu.cmake b/cmake/iwyu.cmake new file mode 100644 index 0000000..b5fbbda --- /dev/null +++ b/cmake/iwyu.cmake @@ -0,0 +1 @@ +# TODO: implement include-what-you-use auto analysis target \ No newline at end of file diff --git a/cmake/vcpkg-init.cmake b/cmake/vcpkg-init.cmake new file mode 100644 index 0000000..bd7311c --- /dev/null +++ b/cmake/vcpkg-init.cmake @@ -0,0 +1,21 @@ + +# VCPKG submodule init/update +if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/ports") + message(NOTICE "VCPKG package manager sources not found") + message(NOTICE "initializing/updating the vcpkg submodule...") + execute_process( + COMMAND git submodule update --init extern/vcpkg + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND_ERROR_IS_FATAL ANY + ) +endif() + +# VCPKG toolchain file +if(NOT CMAKE_TOOLCHAIN_FILE) + set(toolchain_file_path "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/scripts/buildsystems/vcpkg.cmake") + if (EXISTS "${toolchain_file_path}") + set(CMAKE_TOOLCHAIN_FILE "${toolchain_file_path}") + else() + message(WARNING "VCPKG toolchain file not found: ${toolchain_file_path}") + endif() +endif() diff --git a/cmake/vcpkg-setup.cmake b/cmake/vcpkg-setup.cmake new file mode 100644 index 0000000..d4ff756 --- /dev/null +++ b/cmake/vcpkg-setup.cmake @@ -0,0 +1,38 @@ +# ======================================================================= +# VCPKG bootstrap / initialization. +# ======================================================================= + +set(vcpkg_executable "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/vcpkg${CMAKE_EXECUTABLE_SUFFIX}") + +if(EXISTS "${vcpkg_executable}") + message(NOTICE "Found VCPKG Executable: ${vcpkg_executable}") +else() + message(NOTICE "Could not find VCPKG Executable: ${vcpkg_executable}") + message(NOTICE "Calling VCPKG bootstrap scripts.") + + if(WIN32) + execute_process( + COMMAND powershell -c "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/bootstrap-vcpkg.bat" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND_ERROR_IS_FATAL ANY + ) + elseif(UNIX) + execute_process( + COMMAND bash "${CMAKE_CURRENT_SOURCE_DIR}/extern/vcpkg/bootstrap-vcpkg.sh" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND_ERROR_IS_FATAL ANY + ) + endif() + + # fail out if vcpkg isn't found after setup + if(NOT EXISTS "${vcpkg_executable}") + message(FATAL_ERROR "ERROR: '${vcpkg_executable}' not found!") + endif() +endif() + +# ======================================================================= +# VCPKG triplet definition (should enforce static linkage for all deps) +# ======================================================================= + +string(TOLOWER "${CMAKE_SYSTEM_NAME}" host_os) +set(VCPKG_TARGET_TRIPLET "x64-${host_os}-static") diff --git a/project/bin/roguelite.gdextension b/project/bin/roguelite.gdextension index 0fed447..bd97f9d 100644 --- a/project/bin/roguelite.gdextension +++ b/project/bin/roguelite.gdextension @@ -5,11 +5,7 @@ compatibility_minimum = 4.1 [libraries] -windows.debug.x86_32 = "res://bin/roguelited.dll" -windows.debug.x86_64 = "res://bin/roguelited.dll" -windows.release.x86_64 = "res://bin/roguelite.dll" -windows.release.x86_32 = "res://bin/roguelite.dll" -linux.debug.x86_32 = "res://bin/libroguelited.so" -linux.debug.x86_64 = "res://bin/libroguelited.so" -linux.release.x86_64 = "res://bin/libroguelite.so" -linux.release.x86_32 = "res://bin/libroguelite.so" +windows.debug.x86_64 = "res://bin/roguelite.debug.x64.dll" +windows.release.x86_64 = "res://bin/roguelite.release.x64.dll" +linux.debug.x86_64 = "res://bin/libroguelite.debug.x64.so" +linux.release.x86_64 = "res://bin/libroguelite.release.x64.so" diff --git a/project/icons/.gdignore b/project/icons/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/project/icons/donut.svg b/project/icons/donut.svg new file mode 100644 index 0000000..7619e84 --- /dev/null +++ b/project/icons/donut.svg @@ -0,0 +1,39 @@ + + + + diff --git a/project/icons/ghost.svg b/project/icons/ghost.svg new file mode 100644 index 0000000..4a1466f --- /dev/null +++ b/project/icons/ghost.svg @@ -0,0 +1,46 @@ + + + + diff --git a/project/icons/graph.svg b/project/icons/graph.svg new file mode 100644 index 0000000..04b6d43 --- /dev/null +++ b/project/icons/graph.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + diff --git a/project/icons/pentagon.svg b/project/icons/pentagon.svg new file mode 100644 index 0000000..5d1e551 --- /dev/null +++ b/project/icons/pentagon.svg @@ -0,0 +1,38 @@ + + + + diff --git a/project/icons/triangle.svg b/project/icons/triangle.svg new file mode 100644 index 0000000..799c39d --- /dev/null +++ b/project/icons/triangle.svg @@ -0,0 +1,38 @@ + + + + diff --git a/project/icons/tristar.svg b/project/icons/tristar.svg new file mode 100644 index 0000000..8103b54 --- /dev/null +++ b/project/icons/tristar.svg @@ -0,0 +1,39 @@ + + + + + diff --git a/project/scenes/characters/enemy.tscn b/project/scenes/characters/enemy.tscn index 475b6a6..82318c1 100644 --- a/project/scenes/characters/enemy.tscn +++ b/project/scenes/characters/enemy.tscn @@ -2,7 +2,7 @@ [ext_resource type="Texture2D" uid="uid://cjlu0wl3qj8dh" path="res://assets/art/topdown/shooter/robot_1/robot1_gun.png" id="1_oue85"] -[node name="Enemy" type="Character"] +[node name="Enemy" type="Enemy"] scale = Vector2(2, 2) collision_mask = 8 platform_on_leave = 2 diff --git a/scripts/shell/install-deps.sh b/scripts/shell/install-deps.sh deleted file mode 100755 index e753224..0000000 --- a/scripts/shell/install-deps.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/bash - -sudo pacman -Syy git \ - python \ - gcc \ - llvm \ - cmake \ - scons \ - ninja \ - dotnet-sdk - -# needed for clang-format v16 so the binary path defined in .vscode works. -# arch core clang/llvm packages are still v15.0. -# install path should be something like this: -# /opt/clang-format-static/clang-format-16 -paru -Syy clang-format-static-bin diff --git a/src/api/extension_interface.cpp b/src/api/extension_interface.cpp index dff5be2..3e6745f 100644 --- a/src/api/extension_interface.cpp +++ b/src/api/extension_interface.cpp @@ -1,12 +1,15 @@ #include "api/extension_interface.hpp" +#include "entity/camera.hpp" +#include "entity/character/character.hpp" +#include "entity/character/enemy.hpp" +#include "entity/character/player.hpp" +#include "entity/controller/character_controller.hpp" +#include "entity/controller/enemy_controller.hpp" +#include "entity/controller/player_controller.hpp" +#include "entity/level.hpp" +#include "entity/projectile/projectile_spawner.hpp" #include "main.hpp" -#include "nodes/camera.hpp" -#include "nodes/character.hpp" -#include "nodes/level.hpp" -#include "nodes/player.hpp" -#include "nodes/player_controller.hpp" -#include "nodes/projectile_spawner.hpp" #include "singletons/console.hpp" #include "ui/main_dialog.hpp" #include "util/engine.hpp" @@ -18,14 +21,14 @@ #include #include -namespace godot +namespace rl { - static inline rl::Console* console_singleton{ nullptr }; + static inline console* console_singleton{ nullptr }; void initialize_static_objects() { - console_singleton = memnew(rl::Console); - rl::engine::get()->register_singleton("Console", rl::Console::get()); + console_singleton = memnew(console); + rl::engine::get()->register_singleton("Console", console::get()); } void teardown_static_objects() @@ -34,28 +37,35 @@ namespace godot memdelete(console_singleton); } - void initialize_extension_module(ModuleInitializationLevel init_level) + void initialize_extension_module(godot::ModuleInitializationLevel init_level) { - if (init_level != MODULE_INITIALIZATION_LEVEL_SCENE) + if (init_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) return; - ClassDB::register_class>(); - ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); + godot::ClassDB::register_class(); + godot::ClassDB::register_class(); + + godot::ClassDB::register_abstract_class(); + godot::ClassDB::register_class(); + godot::ClassDB::register_class(); + + godot::ClassDB::register_class(); + godot::ClassDB::register_class(); + godot::ClassDB::register_class(); + godot::ClassDB::register_class(); + + godot::ClassDB::register_class(); + godot::ClassDB::register_class(); + godot::ClassDB::register_class(); + + godot::ClassDB::register_class(); initialize_static_objects(); } - void uninitialize_extension_module(ModuleInitializationLevel init_level) + void uninitialize_extension_module(godot::ModuleInitializationLevel init_level) { - if (init_level != MODULE_INITIALIZATION_LEVEL_SCENE) + if (init_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) return; teardown_static_objects(); @@ -67,7 +77,7 @@ namespace godot GDExtensionClassLibraryPtr lib, GDExtensionInitialization* init) { - const auto init_level = MODULE_INITIALIZATION_LEVEL_SCENE; + const auto init_level = godot::MODULE_INITIALIZATION_LEVEL_SCENE; godot::GDExtensionBinding::InitObject init_obj(addr, lib, init); init_obj.register_initializer(initialize_extension_module); diff --git a/src/util/assert.hpp b/src/core/assert.hpp similarity index 100% rename from src/util/assert.hpp rename to src/core/assert.hpp diff --git a/src/util/attributes.hpp b/src/core/attributes.hpp similarity index 100% rename from src/util/attributes.hpp rename to src/core/attributes.hpp diff --git a/src/core/concepts.hpp b/src/core/concepts.hpp new file mode 100644 index 0000000..d9fbf2f --- /dev/null +++ b/src/core/concepts.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include + +namespace godot +{ + template + struct GetTypeInfo; + class Variant; + class Object; +} + +namespace rl::inline utils +{ + template + concept CompileTimeStr = std::same_as + || std::same_as + || std::same_as; + + template + concept GDObjectDerived + = std::derived_from>, godot::Object> + || std::same_as>, godot::Object>; + + template + concept VariantConstructable = requires(const T& t) { static_cast(t); }; + + template + concept VariantConvertable = requires(T t) { static_cast(t); }; + + template + concept VariantCompatible + = VariantConstructable> && VariantConvertable> + && requires { + godot::GetTypeInfo>, void>::VARIANT_TYPE; + }; +} diff --git a/src/util/constants.hpp b/src/core/constants.hpp similarity index 86% rename from src/util/constants.hpp rename to src/core/constants.hpp index 7e18b1b..f2fd1d4 100644 --- a/src/util/constants.hpp +++ b/src/core/constants.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include namespace rl::inline constants @@ -22,6 +23,7 @@ namespace rl::inline constants namespace character { constexpr inline auto player{ "Player" }; + constexpr inline auto enemy{ "Enemy" }; constexpr inline auto firing_pt{ "FiringPoint" }; } @@ -33,14 +35,14 @@ namespace rl::inline constants constexpr inline auto entered_area{ "entered_area" }; constexpr inline auto exited_area{ "exited_area" }; constexpr inline auto spawn_projectile{ "spawn_projectile" }; - constexpr inline auto player_move{ "player_move" }; - constexpr inline auto player_rotate{ "player_rotate" }; - constexpr inline auto player_shoot{ "player_shoot" }; + constexpr inline auto character_move{ "character_move" }; + constexpr inline auto character_rotate{ "character_rotate" }; + constexpr inline auto character_shoot{ "character_shoot" }; constexpr inline auto body_entered{ "body_entered" }; constexpr inline auto body_exited{ "body_exited" }; } - enum class layer : uint32_t + enum class LayerID : uint32_t { Player = 0x00000001, NPCs = 0x00000002, diff --git a/src/util/function_traits.hpp b/src/core/function_traits.hpp similarity index 100% rename from src/util/function_traits.hpp rename to src/core/function_traits.hpp diff --git a/src/nodes/camera.cpp b/src/entity/camera.cpp similarity index 90% rename from src/nodes/camera.cpp rename to src/entity/camera.cpp index 7cafcb2..82c8067 100644 --- a/src/nodes/camera.cpp +++ b/src/entity/camera.cpp @@ -1,4 +1,4 @@ -#include "nodes/camera.hpp" +#include "entity/camera.hpp" #include diff --git a/src/nodes/camera.hpp b/src/entity/camera.hpp similarity index 100% rename from src/nodes/camera.hpp rename to src/entity/camera.hpp diff --git a/src/nodes/character.cpp b/src/entity/character/character.cpp similarity index 63% rename from src/nodes/character.cpp rename to src/entity/character/character.cpp index ad690c0..3db5ceb 100644 --- a/src/nodes/character.cpp +++ b/src/entity/character/character.cpp @@ -1,10 +1,11 @@ -#include "nodes/character.hpp" +#include "entity/character/character.hpp" -#include "nodes/camera.hpp" -#include "nodes/player_controller.hpp" -#include "util/assert.hpp" +#include "core/assert.hpp" +#include "core/concepts.hpp" +#include "core/constants.hpp" +#include "entity/camera.hpp" +#include "entity/controller/character_controller.hpp" #include "util/bind.hpp" -#include "util/constants.hpp" #include "util/engine.hpp" #include "util/input.hpp" #include "util/io.hpp" @@ -12,6 +13,7 @@ #include #include +#include #include #include @@ -28,7 +30,8 @@ namespace rl { - Character::Character() + Character::Character(CharacterController* controller) + : m_character_controller(controller) { this->set_motion_mode(MotionMode::MOTION_MODE_FLOATING); } @@ -36,29 +39,40 @@ namespace rl void Character::_ready() { this->add_child(m_camera); - this->add_child(m_player_controller); + this->add_child(m_character_controller); m_firing_point = gdcast( this->find_child(name::character::firing_pt, true, false)); + runtime_assert(m_firing_point != nullptr); + runtime_assert(m_character_controller != nullptr); - signal::connect(m_player_controller) - <=> slot(this, on_player_movement); + if (m_character_controller != nullptr) + { + signal::connect(m_character_controller) + <=> slot(this, on_character_movement); - signal::connect(m_player_controller) - <=> slot(this, on_player_rotate); + signal::connect(m_character_controller) + <=> slot(this, on_character_rotate); - signal::connect(m_player_controller) - <=> slot(this, on_player_shoot); + signal::connect(m_character_controller) + <=> slot(this, on_character_shoot); + } } - PlayerController* Character::get_controller() const + void Character::set_controller(CharacterController* controller) { - return m_player_controller; + m_character_controller = controller; + runtime_assert(m_character_controller != nullptr); + } + + CharacterController* Character::get_controller() const + { + return m_character_controller; } [[signal_slot]] - void Character::on_player_movement(godot::Vector2 movement_velocity, double delta_time) + void Character::on_character_movement(godot::Vector2 movement_velocity, double delta_time) { double increment = m_movement_friction * delta_time; godot::Vector2 velocity{ this->get_velocity().lerp(movement_velocity, increment) }; @@ -69,7 +83,7 @@ namespace rl } [[signal_slot]] - void Character::on_player_rotate(double rotation_angle, double delta_time) + void Character::on_character_rotate(double rotation_angle, double delta_time) { double smoothed_angle = godot::Math::lerp_angle(this->get_rotation(), rotation_angle, m_rotation_speed * delta_time); @@ -77,7 +91,7 @@ namespace rl } [[signal_slot]] - void Character::on_player_shoot() + void Character::on_character_shoot() { // TODO: fix this this->emit_signal(event::spawn_projectile, m_firing_point); @@ -118,17 +132,4 @@ namespace rl { m_rotation_speed = rotation_speed; } - - void Character::_bind_methods() - { - bind_member_function(Character, on_player_movement); - bind_member_function(Character, on_player_rotate); - bind_member_function(Character, on_player_shoot); - - bind_property(Character, movement_speed, double); - bind_property(Character, movement_friction, double); - bind_property(Character, rotation_speed, double); - - signal_binding::add(); - } } diff --git a/src/entity/character/character.hpp b/src/entity/character/character.hpp new file mode 100644 index 0000000..771ebed --- /dev/null +++ b/src/entity/character/character.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include "core/attributes.hpp" +#include "core/constants.hpp" +#include "entity/camera.hpp" +#include "singletons/console.hpp" +#include "util/bind.hpp" +#include "util/io.hpp" + +#include + +#include + +namespace godot +{ + class Marker2D; + class Object; + struct Vector2; +} + +namespace rl +{ + class CharacterController; +} + +namespace rl +{ + class Character : public godot::CharacterBody2D + { + GDCLASS(Character, godot::CharacterBody2D); + + public: + Character(CharacterController* controller = nullptr); + virtual ~Character() = default; + + void _ready() override; + + CharacterController* get_controller() const; + void set_controller(CharacterController* controller); + + protected: + [[property]] double get_movement_speed() const; + [[property]] double get_movement_friction() const; + [[property]] double get_rotation_speed() const; + [[property]] void set_movement_speed(const double move_speed); + [[property]] void set_movement_friction(const double move_friction); + [[property]] void set_rotation_speed(const double rotation_speed); + + [[signal_slot]] void on_character_shoot(); + [[signal_slot]] void on_character_rotate(double rotation_angle, double delta_time); + [[signal_slot]] void on_character_movement(godot::Vector2 movement_velocity, + double delta_time); + + protected: + template + requires std::derived_from + static void bind_members() + { + log::print("Character::bind_members<{}>() called", + to(T::get_class_static())); + log::print(" - method: {} binded", "on_character_movement"); + log::print(" - method: {} binded", "on_character_rotate"); + log::print(" - method: {} binded", "on_character_shoot"); + log::print(" - property: {} added", "movement_speed"); + log::print(" - property: {} added", "movement_friction"); + log::print(" - property: {} added", "rotation_speed"); + log::print(" - signal: {} added", event::character_shoot); + log::print(" - signal: {} added", event::spawn_projectile); + + bind_member_function(T, on_character_movement); + bind_member_function(T, on_character_rotate); + bind_member_function(T, on_character_shoot); + + bind_property(T, movement_speed, double); + bind_property(T, movement_friction, double); + bind_property(T, rotation_speed, double); + + using pos_changed_signal_t = signal_binding; + using add_pos_changed_signal_binding_t + = pos_changed_signal_t::template add; + add_pos_changed_signal_binding_t(); + + using spawn_projectile_signal_t = signal_binding; + using add_spawn_projectile_signal_binding_t + = spawn_projectile_signal_t::template add; + add_spawn_projectile_signal_binding_t(); + } + + static void _bind_methods() + { + Character::bind_members(); + } + + protected: + // Rate of acceleration/deceleration (unit/s/s) + double m_movement_friction{ 5.0 }; + // Rate of rotational acceleration/deceleration (unit/s/s) + double m_rotation_speed{ 10.0 }; + // target movement speed (units/s) + double m_movement_speed{ 500.0 }; + // target facing angle (radians) + double m_rotation_angle{ 0.0 }; + + // the player character camera + Camera* m_camera{ memnew(Camera) }; + // handles all input related player controls + CharacterController* m_character_controller{ nullptr }; + // marker identifying location where to spwwn projectiles + godot::Marker2D* m_firing_point{ nullptr }; + }; +} diff --git a/src/entity/character/enemy.cpp b/src/entity/character/enemy.cpp new file mode 100644 index 0000000..1576471 --- /dev/null +++ b/src/entity/character/enemy.cpp @@ -0,0 +1,18 @@ +#include "entity/character/enemy.hpp" + +#include "core/constants.hpp" +#include "entity/character/character.hpp" +#include "util/scene.hpp" + +namespace rl +{ + Enemy::Enemy() + : Character() + { + scene::node::set_unique_name(this, name::character::enemy); + } + + void Enemy::_bind_methods() + { + } +} diff --git a/src/entity/character/enemy.hpp b/src/entity/character/enemy.hpp new file mode 100644 index 0000000..ef701d6 --- /dev/null +++ b/src/entity/character/enemy.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "core/constants.hpp" +#include "entity/character/character.hpp" +#include "util/bind.hpp" + +namespace rl +{ + class Enemy : public Character + { + GDCLASS(Enemy, Character); + + public: + Enemy(); + + using Character::_ready; + + protected: + static void _bind_methods(); + }; +} diff --git a/src/nodes/player.cpp b/src/entity/character/player.cpp similarity index 51% rename from src/nodes/player.cpp rename to src/entity/character/player.cpp index 6e95969..a1de800 100644 --- a/src/nodes/player.cpp +++ b/src/entity/character/player.cpp @@ -1,7 +1,7 @@ -#include "nodes/player.hpp" +#include "entity/character/player.hpp" -#include "nodes/character.hpp" -#include "util/constants.hpp" +#include "core/constants.hpp" +#include "entity/character/character.hpp" #include "util/scene.hpp" namespace rl @@ -11,4 +11,8 @@ namespace rl { scene::node::set_unique_name(this, name::character::player); } + + void Player::_bind_methods() + { + } } diff --git a/src/nodes/player.hpp b/src/entity/character/player.hpp similarity index 59% rename from src/nodes/player.hpp rename to src/entity/character/player.hpp index 35374cd..e8d1add 100644 --- a/src/nodes/player.hpp +++ b/src/entity/character/player.hpp @@ -1,8 +1,8 @@ #pragma once -#include "nodes/character.hpp" +#include "core/constants.hpp" +#include "entity/character/character.hpp" #include "util/bind.hpp" -#include "util/constants.hpp" namespace rl { @@ -12,6 +12,7 @@ namespace rl public: Player(); + ~Player() = default; void _ready() override { @@ -19,9 +20,6 @@ namespace rl } protected: - static void _bind_methods() - { - signal_binding::add<>(); - } + static void _bind_methods(); }; } diff --git a/src/entity/controller/character_controller.cpp b/src/entity/controller/character_controller.cpp new file mode 100644 index 0000000..599f95f --- /dev/null +++ b/src/entity/controller/character_controller.cpp @@ -0,0 +1,53 @@ +#include "entity/controller/character_controller.hpp" + +#include "core/constants.hpp" +#include "util/bind.hpp" +#include "util/engine.hpp" +#include "util/input.hpp" +#include "util/io.hpp" + +#include +#include +#include + +namespace rl +{ + void CharacterController::_process(double delta_time) + { + if (engine::editor_active()) + return; + + godot::Input* input_handler{ input::get() }; + if (input_handler != nullptr) + { + this->process_movement_input(input_handler, delta_time); + this->process_rotation_input(input_handler, delta_time); + this->process_action_input(input_handler, delta_time); + + m_elapsed_time += delta_time; + if (m_elapsed_time > 1.0) + { + m_elapsed_time = 0.0; + this->emit_signal(event::position_changed, this->get_parent(), + this->get_global_position()); + } + } + } + + // void CharacterController::process_action_input(godot::Input* const input, double delta_time) + //{ + // } + + // void CharacterController::process_movement_input(godot::Input* const input, double delta_time) + //{ + // } + + // void CharacterController::process_rotation_input(godot::Input* const input, double delta_time) + //{ + // } + + // void CharacterController::_bind_methods() + //{ + // CharacterController::bind_members(); + // } +} diff --git a/src/entity/controller/character_controller.hpp b/src/entity/controller/character_controller.hpp new file mode 100644 index 0000000..2e2e86b --- /dev/null +++ b/src/entity/controller/character_controller.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include "core/concepts.hpp" +#include "core/constants.hpp" +#include "util/bind.hpp" +#include "util/io.hpp" + +#include + +#include +#include +#include +#include + +namespace rl +{ + class CharacterController : public godot::Node2D + { + GDCLASS(CharacterController, godot::Node2D); + + public: + enum class InputMode + { + MouseAndKeyboard, + Controller, + AI + }; + + public: + CharacterController() = default; + virtual ~CharacterController() = default; + + void _process(double delta_time) override; + + virtual void process_action_input(godot::Input* const input, double delta_time) + { + } + + virtual void process_movement_input(godot::Input* const input, double delta_time) + { + } + + virtual void process_rotation_input(godot::Input* const input, double delta_time) + { + } + + protected: + template + requires std::derived_from + static void bind_members() + { + log::print("CharacterController::bind_members<{}>() called", + to(T::get_class_static())); + log::print(" - signal: {} added", event::character_move); + log::print(" - signal: {} added", event::character_rotate); + log::print(" - signal: {} added", event::character_shoot); + log::print(" - signal: {} added", event::position_changed); + + using character_move_signal_t = signal_binding; + using add_character_move_signal_binding_t + = character_move_signal_t::template add; + add_character_move_signal_binding_t(); + + using character_rotate_signal_t = signal_binding; + using add_character_rotate_signal_binding_t + = character_rotate_signal_t::template add; + add_character_rotate_signal_binding_t(); + + using character_shoot_signal_t = signal_binding; + using add_character_shoot_signal_binding_t + = character_shoot_signal_t::template add; + add_character_shoot_signal_binding_t(); + + using position_changed_signal_t = signal_binding; + using add_position_changed_signal_binding_t + = position_changed_signal_t::template add; + add_position_changed_signal_binding_t(); + } + + static void _bind_methods() + { + CharacterController::bind_members(); + } + + protected: + // the active input mode for character controls + InputMode m_input_mode{ InputMode::MouseAndKeyboard }; + // target rotation + double m_rotation_angle{ 0.0 }; + // elapsed runtime (seconds) + double m_elapsed_time{ 0.0 }; + }; +} diff --git a/src/entity/controller/enemy_controller.cpp b/src/entity/controller/enemy_controller.cpp new file mode 100644 index 0000000..c5999f8 --- /dev/null +++ b/src/entity/controller/enemy_controller.cpp @@ -0,0 +1,21 @@ +// #include "entity/character/enemy_controller.hpp" + +// namespace rl +// { +// void EnemyController::process_action_input(godot::Input* const input, double delta_time) +// { +// } + +// void EnemyController::process_movement_input(godot::Input* const input, double delta_time) +// { +// } + +// void EnemyController::process_rotation_input(godot::Input* const input, double delta_time) +// { +// } + +// void EnemyController::_bind_methods() +// { +// CharacterController::bind_member_functions(); +// } +// } diff --git a/src/entity/controller/enemy_controller.hpp b/src/entity/controller/enemy_controller.hpp new file mode 100644 index 0000000..1ff8aed --- /dev/null +++ b/src/entity/controller/enemy_controller.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "entity/controller/character_controller.hpp" + +namespace godot +{ + class Input; +} + +namespace rl +{ + class EnemyController : public CharacterController + { + GDCLASS(EnemyController, CharacterController); + + public: + EnemyController() = default; + ~EnemyController() = default; + + void process_action_input(godot::Input* const input, double delta_time) override + { + } + + void process_movement_input(godot::Input* const input, double delta_time) override + { + } + + void process_rotation_input(godot::Input* const input, double delta_time) override + { + } + + protected: + static void _bind_methods() + { + } + }; +} diff --git a/src/nodes/player_controller.cpp b/src/entity/controller/player_controller.cpp similarity index 64% rename from src/nodes/player_controller.cpp rename to src/entity/controller/player_controller.cpp index e50ed13..7b91d0b 100644 --- a/src/nodes/player_controller.cpp +++ b/src/entity/controller/player_controller.cpp @@ -1,7 +1,6 @@ -#include "nodes/player_controller.hpp" +#include "entity/controller/player_controller.hpp" -#include "util/bind.hpp" -#include "util/constants.hpp" +#include "core/constants.hpp" #include "util/engine.hpp" #include "util/input.hpp" #include "util/io.hpp" @@ -12,39 +11,17 @@ namespace rl { - void PlayerController::_process(double delta_time) - { - if (engine::editor_active()) - return; - - godot::Input* input_handler{ input::get() }; - if (input_handler != nullptr) - { - this->process_movement_input(input_handler, delta_time); - this->process_rotation_input(input_handler, delta_time); - this->process_state_input(input_handler, delta_time); - - m_elapsed_time += delta_time; - if (m_elapsed_time > 1.0) - { - m_elapsed_time = 0.0; - this->emit_signal(event::position_changed, this->get_parent(), - this->get_global_position()); - } - } - } - - void PlayerController::process_state_input(godot::Input* const input, double delta_time) + void PlayerController::process_action_input(godot::Input* const input, double delta_time) { if (input->is_action_pressed("shoot")) - this->emit_signal(event::player_shoot); + this->emit_signal(event::character_shoot); } void PlayerController::process_movement_input(godot::Input* const input, double delta_time) { auto velocity{ input->get_vector(input::action::move_left, input::action::move_right, input::action::move_up, input::action::move_down) }; - this->emit_signal(event::player_move, velocity, delta_time); + this->emit_signal(event::character_move, velocity, delta_time); } PlayerController::InputMode PlayerController::get_input_mode(godot::Input* const input) @@ -103,14 +80,6 @@ namespace rl } } - this->emit_signal(event::player_rotate, m_rotation_angle, delta_time); - } - - void PlayerController::_bind_methods() - { - signal_binding::add(); - signal_binding::add(); - signal_binding::add(); - signal_binding::add(); + this->emit_signal(event::character_rotate, m_rotation_angle, delta_time); } } diff --git a/src/entity/controller/player_controller.hpp b/src/entity/controller/player_controller.hpp new file mode 100644 index 0000000..0280e6d --- /dev/null +++ b/src/entity/controller/player_controller.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "entity/controller/character_controller.hpp" + +namespace rl +{ + class PlayerController : public CharacterController + { + GDCLASS(PlayerController, CharacterController); + + public: + public: + PlayerController() = default; + ~PlayerController() = default; + + void process_action_input(godot::Input* const input, double delta_time) override; + void process_movement_input(godot::Input* const input, double delta_time) override; + void process_rotation_input(godot::Input* const input, double delta_time) override; + InputMode get_input_mode(godot::Input* const input); + + protected: + static void _bind_methods() + { + } + }; +} diff --git a/src/nodes/level.cpp b/src/entity/level.cpp similarity index 86% rename from src/nodes/level.cpp rename to src/entity/level.cpp index fccbabe..b6d51d0 100644 --- a/src/nodes/level.cpp +++ b/src/entity/level.cpp @@ -1,6 +1,7 @@ -#include "nodes/level.hpp" +#include "entity/level.hpp" -#include "nodes/character.hpp" +#include "entity/character/character.hpp" +#include "entity/controller/player_controller.hpp" #include "singletons/console.hpp" #include "util/bind.hpp" #include "util/conversions.hpp" @@ -31,11 +32,15 @@ namespace rl this->add_child(m_player); this->add_child(m_projectile_spawner); - signal::connect(m_player->get_controller()) - <=> slot(this, on_character_position_changed); + PlayerController* controller{ gdcast(m_player->get_controller()) }; + if (controller != nullptr) + { + signal::connect(controller) + <=> slot(this, on_character_position_changed); - signal::connect(m_player) - <=> slot(this, on_player_spawn_projectile); + signal::connect(m_player) + <=> slot(this, on_player_spawn_projectile); + } } void Level::_process(double delta_time) diff --git a/src/nodes/level.hpp b/src/entity/level.hpp similarity index 84% rename from src/nodes/level.hpp rename to src/entity/level.hpp index 24208d2..d5b42a8 100644 --- a/src/nodes/level.hpp +++ b/src/entity/level.hpp @@ -1,9 +1,10 @@ #pragma once -#include "nodes/player.hpp" -#include "nodes/projectile_spawner.hpp" +#include "core/constants.hpp" +#include "entity/character/player.hpp" +#include "entity/controller/player_controller.hpp" +#include "entity/projectile/projectile_spawner.hpp" #include "util/bind.hpp" -#include "util/constants.hpp" #include "util/scene.hpp" #include @@ -50,7 +51,7 @@ namespace rl godot::Node* m_background{ nullptr }; ProjectileSpawner* m_projectile_spawner{ memnew(rl::ProjectileSpawner) }; resource::preload::scene player_scene{ path::scene::Player }; - Player* m_player{ player_scene.instantiate() }; + Player* m_player{ player_scene.instantiate(memnew(PlayerController)) }; godot::RigidBody2D* m_physics_box{ nullptr }; }; } diff --git a/src/nodes/projectile.cpp b/src/entity/projectile/projectile.cpp similarity index 97% rename from src/nodes/projectile.cpp rename to src/entity/projectile/projectile.cpp index 3b4367e..4a3d61a 100644 --- a/src/nodes/projectile.cpp +++ b/src/entity/projectile/projectile.cpp @@ -1,4 +1,4 @@ -#include "nodes/projectile.hpp" +#include "entity/projectile/projectile.hpp" #include "util/engine.hpp" diff --git a/src/nodes/projectile.hpp b/src/entity/projectile/projectile.hpp similarity index 98% rename from src/nodes/projectile.hpp rename to src/entity/projectile/projectile.hpp index f06571c..454e278 100644 --- a/src/nodes/projectile.hpp +++ b/src/entity/projectile/projectile.hpp @@ -1,7 +1,7 @@ #pragma once +#include "core/attributes.hpp" #include "singletons/console.hpp" -#include "util/attributes.hpp" #include "util/bind.hpp" #include "util/conversions.hpp" #include "util/io.hpp" @@ -27,6 +27,7 @@ namespace rl [[property]] double get_max_travel_dist() const; [[property]] double get_acceleration() const; [[property]] double get_velocity() const; + [[property]] void set_movement_speed(double speed); [[property]] void set_time_to_live(double ttl); [[property]] void set_max_travel_dist(double dist); diff --git a/src/nodes/projectile_spawner.cpp b/src/entity/projectile/projectile_spawner.cpp similarity index 96% rename from src/nodes/projectile_spawner.cpp rename to src/entity/projectile/projectile_spawner.cpp index 6885b75..ab9051e 100644 --- a/src/nodes/projectile_spawner.cpp +++ b/src/entity/projectile/projectile_spawner.cpp @@ -1,4 +1,4 @@ -#include "nodes/projectile_spawner.hpp" +#include "entity/projectile/projectile_spawner.hpp" #include "util/bind.hpp" diff --git a/src/nodes/projectile_spawner.hpp b/src/entity/projectile/projectile_spawner.hpp similarity index 95% rename from src/nodes/projectile_spawner.hpp rename to src/entity/projectile/projectile_spawner.hpp index a20f9f6..b1ff129 100644 --- a/src/nodes/projectile_spawner.hpp +++ b/src/entity/projectile/projectile_spawner.hpp @@ -1,8 +1,8 @@ #pragma once -#include "nodes/projectile.hpp" +#include "core/constants.hpp" +#include "entity/projectile/projectile.hpp" #include "util/bind.hpp" -#include "util/constants.hpp" #include "util/scene.hpp" #include diff --git a/src/main.cpp b/src/main.cpp index b2c787d..48318c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ #include "main.hpp" -#include "util/assert.hpp" +#include "core/assert.hpp" #include "util/conversions.hpp" #include "util/engine.hpp" #include "util/input.hpp" diff --git a/src/main.hpp b/src/main.hpp index d4da42c..13d754e 100644 --- a/src/main.hpp +++ b/src/main.hpp @@ -1,6 +1,6 @@ #pragma once -#include "nodes/level.hpp" +#include "entity/level.hpp" #include "ui/main_dialog.hpp" #include @@ -18,7 +18,6 @@ namespace rl void _ready() override; void initialize(); - //void notification(int notification_type); protected: void apply_default_settings(); diff --git a/src/nodes/character.hpp b/src/nodes/character.hpp deleted file mode 100644 index 5727ac0..0000000 --- a/src/nodes/character.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include "nodes/camera.hpp" -#include "nodes/player_controller.hpp" -#include "util/attributes.hpp" -#include "util/scene.hpp" - -#include -#include -#include - -namespace godot -{ - class Marker2D; -} - -namespace rl -{ - class Character : public godot::CharacterBody2D - { - GDCLASS(Character, godot::CharacterBody2D); - - public: - Character(); - virtual ~Character() = default; - - void _ready() override; - - PlayerController* get_controller() const; - - protected: - [[property]] double get_movement_speed() const; - [[property]] double get_movement_friction() const; - [[property]] double get_rotation_speed() const; - [[property]] void set_movement_speed(const double move_speed); - [[property]] void set_movement_friction(const double move_friction); - [[property]] void set_rotation_speed(const double rotation_speed); - - [[signal_slot]] void on_player_shoot(); - [[signal_slot]] void on_player_rotate(double rotation_angle, double delta_time); - [[signal_slot]] void on_player_movement(godot::Vector2 movement_velocity, double delta_time); - - protected: - static void _bind_methods(); - - protected: - // Rate of acceleration/deceleration (unit/s/s) - double m_movement_friction{ 5.0 }; - // Rate of rotational acceleration/deceleration (unit/s/s) - double m_rotation_speed{ 10.0 }; - // target movement speed (units/s) - double m_movement_speed{ 500.0 }; - // target facing angle (radians) - double m_rotation_angle{ 0.0 }; - - // the player character camera - Camera* m_camera{ memnew(Camera) }; - // handles all input related player controls - PlayerController* m_player_controller{ memnew(PlayerController) }; - // marker identifying location where to spwwn projectiles - godot::Marker2D* m_firing_point{ nullptr }; - }; -} diff --git a/src/nodes/player_controller.hpp b/src/nodes/player_controller.hpp deleted file mode 100644 index ad845ce..0000000 --- a/src/nodes/player_controller.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include - -namespace rl -{ - class PlayerController : public godot::Node2D - { - GDCLASS(PlayerController, godot::Node2D); - - public: - PlayerController() = default; - ~PlayerController() = default; - - void _process(double delta_time) override; - - void process_state_input(godot::Input* const input, double delta_time); - void process_movement_input(godot::Input* const input, double delta_time); - void process_rotation_input(godot::Input* const input, double delta_time); - - protected: - enum class InputMode - { - MouseAndKeyboard, - Controller - }; - - InputMode get_input_mode(godot::Input* const input); - - static void _bind_methods(); - - protected: - // the active input mode for character controls - InputMode m_input_mode{ InputMode::MouseAndKeyboard }; - // target rotation - double m_rotation_angle{ 0.0 }; - // elapsed runtime (seconds) - double m_elapsed_time{ 0.0 }; - }; -} diff --git a/src/ui/main_dialog.cpp b/src/ui/main_dialog.cpp index 539bcde..775a111 100644 --- a/src/ui/main_dialog.cpp +++ b/src/ui/main_dialog.cpp @@ -1,8 +1,8 @@ #include "ui/main_dialog.hpp" +#include "core/assert.hpp" +#include "core/constants.hpp" #include "singletons/console.hpp" -#include "util/assert.hpp" -#include "util/constants.hpp" #include "util/conversions.hpp" #include "util/engine.hpp" diff --git a/src/ui/main_dialog.hpp b/src/ui/main_dialog.hpp index ecfa0c7..fbef6a9 100644 --- a/src/ui/main_dialog.hpp +++ b/src/ui/main_dialog.hpp @@ -1,6 +1,6 @@ #pragma once -#include "nodes/level.hpp" +#include "entity/level.hpp" #include #include diff --git a/src/util/bind.hpp b/src/util/bind.hpp index 55bc01d..a2bdb69 100644 --- a/src/util/bind.hpp +++ b/src/util/bind.hpp @@ -1,9 +1,9 @@ #pragma once -#include "util/assert.hpp" -#include "util/concepts.hpp" +#include "core/assert.hpp" +#include "core/concepts.hpp" +#include "core/function_traits.hpp" #include "util/conversions.hpp" -#include "util/function_traits.hpp" #include "util/variant.hpp" #include @@ -14,11 +14,11 @@ #include #include -#include #include #include #include #include +#include #define bind_member_function(class_name, func_name) method<&class_name::func_name>::bind(#func_name) @@ -107,23 +107,12 @@ namespace rl::inline utils } }; - struct signal_registry - { - using signal_name_t = std::string; - using signal_args_t = std::vector; - using signal_properties_t = std::pair; - using signal_info_vec_t = std::vector; - using class_signal_map_t = std::unordered_map; - - static inline class_signal_map_t class_bindings = {}; - }; - template class signal_binding { public: using object_t = std::type_identity_t; - using signal_t = signal_binding; + using signal_t = std::type_identity_t>; static inline constexpr std::string_view signal_name{ SignalName }; static inline std::vector signal_params{}; @@ -138,7 +127,7 @@ namespace rl::inline utils template struct add { - using arg_types = std::tuple; + using arg_types = std::tuple...>; static constexpr inline size_t arg_count{ std::tuple_size_v }; add() @@ -171,7 +160,6 @@ namespace rl::inline utils std::forward(signal_params))); } - signal_registry::class_bindings[class_name].emplace_back(signal_name, signal_params); runtime_assert(signal_params.size() == arg_count); } }; diff --git a/src/util/concepts.hpp b/src/util/concepts.hpp deleted file mode 100644 index 82e4e27..0000000 --- a/src/util/concepts.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -namespace rl::inline utils -{ - template - concept CompileTimeStr = std::same_as || - std::same_as || - std::same_as; - - template - concept GDObjectDerived = - std::derived_from>, godot::Object> || - std::same_as>, godot::Object>; - - template - concept VariantConstructable = requires(const T& t) { godot::Variant(t); }; - - template - concept VariantConvertable = requires(T t) { godot::Variant(t).operator T(); }; - - template - concept VariantCompatible = VariantConstructable> && - VariantConvertable> && requires { - godot::GetTypeInfo>::VARIANT_TYPE; - }; -} diff --git a/src/util/conversions.hpp b/src/util/conversions.hpp index dc0b9cf..b6a0c2d 100644 --- a/src/util/conversions.hpp +++ b/src/util/conversions.hpp @@ -1,6 +1,6 @@ #pragma once -#include "util/assert.hpp" +#include "core/assert.hpp" #include #include diff --git a/src/util/input.cpp b/src/util/input.cpp index 7e2be56..d8410c8 100644 --- a/src/util/input.cpp +++ b/src/util/input.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include namespace rl::inline utils { diff --git a/src/util/io.hpp b/src/util/io.hpp index 7b6a1e3..919b4b3 100644 --- a/src/util/io.hpp +++ b/src/util/io.hpp @@ -1,6 +1,6 @@ #pragma once -#include "util/concepts.hpp" +#include "core/concepts.hpp" #include #include @@ -15,6 +15,8 @@ #include #include +#include + namespace rl::inline utils { namespace io @@ -125,7 +127,8 @@ namespace rl::inline utils template static inline void print(spdlog::format_string_t fmt, Args&&... args) { - spdlog::debug(fmt, std::forward(args)...); + std::string msg{ fmt::format(fmt, std::forward(args)...) }; + ERR_PRINT_ED(msg.data()); } }; } diff --git a/src/util/scene.hpp b/src/util/scene.hpp index 13d2027..f510f3c 100644 --- a/src/util/scene.hpp +++ b/src/util/scene.hpp @@ -1,6 +1,6 @@ #pragma once -#include "util/assert.hpp" +#include "core/assert.hpp" #include "util/conversions.hpp" #include @@ -13,6 +13,11 @@ #include #include +namespace rl +{ + class Character; +} + namespace rl::inline utils { namespace scene::node @@ -69,8 +74,8 @@ namespace rl::inline utils namespace preload { template - requires std::derived_from && - std::convertible_to + requires std::derived_from + && std::convertible_to class scene { public: @@ -92,8 +97,8 @@ namespace rl::inline utils } } - [[nodiscard]] - auto instantiate() -> TObj* + template + [[nodiscard]] auto instantiate(TArgs... args) -> TObj* { assertion(initialized, "instantiation invoked from uninitialized scene loader"); if (!initialized) [[unlikely]] @@ -101,6 +106,13 @@ namespace rl::inline utils TObj* obj{ gdcast(m_packed_resource->instantiate()) }; runtime_assert(obj != nullptr); + + if constexpr (std::is_base_of_v) + { + if (obj != nullptr) + obj->set_controller(args...); + } + return obj; } diff --git a/src/util/variant.hpp b/src/util/variant.hpp index 543f9e9..208b7c9 100644 --- a/src/util/variant.hpp +++ b/src/util/variant.hpp @@ -1,21 +1,20 @@ #pragma once -#include "util/concepts.hpp" +#include "core/concepts.hpp" #include #include -#include -#include +#include namespace rl::inline utils { template struct variant_traits { - using raw_type = std::type_identity_t; - using type_info = std::type_identity_t>>; - static constexpr inline godot::Variant::Type variant_type = - static_cast(type_info::VARIANT_TYPE); + using raw_type = T; + using type_info = godot::GetTypeInfo>; + static constexpr inline godot::Variant::Type variant_type + = static_cast(type_info::VARIANT_TYPE); }; } diff --git a/vcpkg.json b/vcpkg.json index 8e37023..a69a900 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", "documentation": "https://github.com/microsoft/vcpkg/blob/master/docs/users/manifests.md", "name": "roguelite", - "version": "0.0.1", + "version": "0.1.0", "dependencies": [ "fmt", "spdlog"