diff --git a/.gitignore b/.gitignore index 6297a84..b2b3eca 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ api.json # Visual Studio Code Project file -source.code-workspace +*.code-workspace # Visual Studio Cache .vs/ diff --git a/Makefile b/Makefile index d3c418b..e651b4f 100644 --- a/Makefile +++ b/Makefile @@ -24,10 +24,10 @@ godot-cpp-windows: game: game-linux game-windows game-linux: - scons use_llvm=$(USE_LLVM) target=$(RELEASE_TYPE) target_path=godot/gdnative/ target_name=libjuego platform=linux bits=64 -j $(PROCS) + scons use_llvm=$(USE_LLVM) target=$(RELEASE_TYPE) target_path=godot/gdnative/ target_name=libalai platform=linux bits=64 -j $(PROCS) game-windows: - scons target=$(RELEASE_TYPE) target_name=libjuego target_path=godot/gdnative/ platform=windows bits=64 -j $(PROCS) + scons target=$(RELEASE_TYPE) target_name=libalai target_path=godot/gdnative/ platform=windows bits=64 -j $(PROCS) docs: # if doxygen and bear are installed create the code documentation diff --git a/README.md b/README.md index d87c67f..d7339e6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# Juego +# Alai ## License -[3-Clause BSD License](LICENSE) \ No newline at end of file +[3-Clause BSD License](LICENSE) diff --git a/SConstruct b/SConstruct index d6aa482..a17df99 100644 --- a/SConstruct +++ b/SConstruct @@ -63,6 +63,7 @@ if env['platform'] == 'linux': env.Append(CCFLAGS=['-g3', '-Og']) else: env.Append(CCFLAGS=['-g', '-O3']) + env.Append(CPPDEFINES=['NDEBUG']) env.Append(CCFLAGS=['-m64']) env.Append(LINKFLAGS=['-m64']) @@ -109,7 +110,7 @@ else: cpp_library += '.' + str(env['bits']) # make sure our binding library is properly includes -env.Append(CPPPATH=['.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/', 'src/include/', 'lib/include']) +env.Append(CPPPATH=['.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/']) env.Append(LIBPATH=[cpp_bindings_path + 'bin/']) env.Append(LIBS=[cpp_library]) diff --git a/doxygen.conf b/doxygen.conf index bb27cef..244e1f1 100644 --- a/doxygen.conf +++ b/doxygen.conf @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "juego" +PROJECT_NAME = "Alai" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version diff --git a/godot/Level 1.tscn b/godot/Level1.tscn similarity index 95% rename from godot/Level 1.tscn rename to godot/Level1.tscn index aaa0575..4c3cddc 100644 --- a/godot/Level 1.tscn +++ b/godot/Level1.tscn @@ -4,10 +4,9 @@ [ext_resource path="res://levels/level01.tmx" type="PackedScene" id=3] [ext_resource path="res://characters/player/Player.tscn" type="PackedScene" id=4] -[node name="Level 1" type="Node2D"] +[node name="Level1" type="Node2D"] [node name="Player" parent="." instance=ExtResource( 4 )] -position = Vector2( 8, 5 ) [node name="Camera2D" type="Camera2D" parent="Player"] current = true diff --git a/godot/Main.gdns b/godot/Main.gdns index 1a43cfc..524516e 100644 --- a/godot/Main.gdns +++ b/godot/Main.gdns @@ -1,6 +1,6 @@ [gd_resource type="NativeScript" load_steps=2 format=2] -[ext_resource path="res://gdnative/libjuego.tres" type="GDNativeLibrary" id=1] +[ext_resource path="res://gdnative/alai.tres" type="GDNativeLibrary" id=1] [resource] resource_name = "Main" diff --git a/godot/Main.tscn b/godot/Main.tscn index 83963c6..d264a5c 100644 --- a/godot/Main.tscn +++ b/godot/Main.tscn @@ -1,10 +1,9 @@ [gd_scene load_steps=3 format=2] [ext_resource path="res://Main.gdns" type="Script" id=1] -[ext_resource path="res://Level 1.tscn" type="PackedScene" id=2] +[ext_resource path="res://Level1.tscn" type="PackedScene" id=2] [node name="Main" type="Node"] script = ExtResource( 1 ) -launch_screen = 0 -[node name="Level 1" parent="." instance=ExtResource( 2 )] +[node name="Level1" parent="." instance=ExtResource( 2 )] diff --git a/godot/characters/player/Player.gdns b/godot/characters/player/Player.gdns index 047be51..4553176 100644 --- a/godot/characters/player/Player.gdns +++ b/godot/characters/player/Player.gdns @@ -1,8 +1,13 @@ [gd_resource type="NativeScript" load_steps=2 format=2] -[ext_resource path="res://gdnative/libjuego.tres" type="GDNativeLibrary" id=1] +[sub_resource type="GDNativeLibrary" id=1] +symbol_prefix = "godot_player" +entry/Windows.64 = "res://gdnative/windows.64/libalai.dll" +entry/X11.64 = "res://gdnative/linux.64/libalai.so" +dependency/Windows.64 = [ ] +dependency/X11.64 = [ ] [resource] resource_name = "Player" class_name = "Player" -library = ExtResource( 1 ) +library = SubResource( 1 ) diff --git a/godot/characters/player/Player.tscn b/godot/characters/player/Player.tscn index 896dbe3..fd71fe2 100644 --- a/godot/characters/player/Player.tscn +++ b/godot/characters/player/Player.tscn @@ -1,14 +1,18 @@ -[gd_scene load_steps=4 format=2] +[gd_scene load_steps=9 format=2] [ext_resource path="res://characters/player/sprites/green.tres" type="SpriteFrames" id=1] -[ext_resource path="res://characters/player/Player.gdns" type="Script" id=2] +[ext_resource path="res://characters/player/states/Idle.gdns" type="Script" id=2] +[ext_resource path="res://state_machine/StateMachine.gdns" type="Script" id=3] +[ext_resource path="res://characters/player/states/Move.gdns" type="Script" id=4] +[ext_resource path="res://characters/player/Player.gdns" type="Script" id=5] +[ext_resource path="res://characters/player/states/Jump.gdns" type="Script" id=6] +[ext_resource path="res://characters/player/states/Fall.gdns" type="Script" id=7] -[sub_resource type="CapsuleShape2D" id=1] -radius = 6.0 -height = 12.0 +[sub_resource type="RectangleShape2D" id=1] +extents = Vector2( 7, 12 ) [node name="Player" type="KinematicBody2D"] -script = ExtResource( 2 ) +script = ExtResource( 5 ) [node name="AnimatedSprite" type="AnimatedSprite" parent="."] frames = ExtResource( 1 ) @@ -19,4 +23,18 @@ centered = false position = Vector2( 12, 12 ) shape = SubResource( 1 ) -[connection signal="player_moved" from="." to="." method="_on_Player_player_moved"] +[node name="StateMachine" type="Node" parent="."] +script = ExtResource( 3 ) +default_state = "Idle" + +[node name="Idle" type="Node" parent="StateMachine"] +script = ExtResource( 2 ) + +[node name="Move" type="Node" parent="StateMachine"] +script = ExtResource( 4 ) + +[node name="Jump" type="Node" parent="StateMachine"] +script = ExtResource( 6 ) + +[node name="Fall" type="Node" parent="StateMachine"] +script = ExtResource( 7 ) diff --git a/godot/characters/player/states/Fall.gdns b/godot/characters/player/states/Fall.gdns new file mode 100644 index 0000000..520e3af --- /dev/null +++ b/godot/characters/player/states/Fall.gdns @@ -0,0 +1,8 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/alai.tres" type="GDNativeLibrary" id=1] + +[resource] +resource_name = "PlayerFall" +class_name = "PlayerFall" +library = ExtResource( 1 ) diff --git a/godot/characters/player/states/Idle.gdns b/godot/characters/player/states/Idle.gdns new file mode 100644 index 0000000..4e5fb7d --- /dev/null +++ b/godot/characters/player/states/Idle.gdns @@ -0,0 +1,8 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/alai.tres" type="GDNativeLibrary" id=1] + +[resource] +resource_name = "PlayerIdle" +class_name = "PlayerIdle" +library = ExtResource( 1 ) diff --git a/godot/characters/player/states/Jump.gdns b/godot/characters/player/states/Jump.gdns new file mode 100644 index 0000000..915bbca --- /dev/null +++ b/godot/characters/player/states/Jump.gdns @@ -0,0 +1,8 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/alai.tres" type="GDNativeLibrary" id=1] + +[resource] +resource_name = "PlayerJump" +class_name = "PlayerJump" +library = ExtResource( 1 ) diff --git a/godot/characters/player/states/Move.gdns b/godot/characters/player/states/Move.gdns new file mode 100644 index 0000000..5b43556 --- /dev/null +++ b/godot/characters/player/states/Move.gdns @@ -0,0 +1,8 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/alai.tres" type="GDNativeLibrary" id=1] + +[resource] +resource_name = "PlayerMove" +class_name = "PlayerMove" +library = ExtResource( 1 ) diff --git a/godot/default_env.tres b/godot/default_env.tres deleted file mode 100644 index 20207a4..0000000 --- a/godot/default_env.tres +++ /dev/null @@ -1,7 +0,0 @@ -[gd_resource type="Environment" load_steps=2 format=2] - -[sub_resource type="ProceduralSky" id=1] - -[resource] -background_mode = 2 -background_sky = SubResource( 1 ) diff --git a/godot/gdnative/alai.tres b/godot/gdnative/alai.tres new file mode 100644 index 0000000..e54b81b --- /dev/null +++ b/godot/gdnative/alai.tres @@ -0,0 +1,7 @@ +[gd_resource type="GDNativeLibrary" format=2] + +[resource] +entry/Windows.64 = "res://gdnative/windows.64/libalai.dll" +entry/X11.64 = "res://gdnative/linux.64/libalai.so" +dependency/Windows.64 = [ ] +dependency/X11.64 = [ ] diff --git a/godot/gdnative/libjuego.tres b/godot/gdnative/libjuego.tres deleted file mode 100644 index 3cc3c56..0000000 --- a/godot/gdnative/libjuego.tres +++ /dev/null @@ -1,7 +0,0 @@ -[gd_resource type="GDNativeLibrary" format=2] - -[resource] -entry/Windows.64 = "res://gdnative/windows.64/libjuego.dll" -entry/X11.64 = "res://gdnative/linux.64/libjuego.so" -dependency/Windows.64 = [ ] -dependency/X11.64 = [ ] diff --git a/godot/icon.png.import b/godot/icon.png.import index a4c02e6..eb3cdb6 100644 --- a/godot/icon.png.import +++ b/godot/icon.png.import @@ -20,7 +20,7 @@ compress/hdr_mode=0 compress/bptc_ldr=0 compress/normal_map=0 flags/repeat=0 -flags/filter=true +flags/filter=false flags/mipmaps=false flags/anisotropic=false flags/srgb=2 @@ -31,5 +31,5 @@ process/invert_color=false process/normal_map_invert_y=false stream=false size_limit=0 -detect_3d=true +detect_3d=false svg/scale=1.0 diff --git a/godot/project.godot b/godot/project.godot index a7f684a..e1b9eb4 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -10,7 +10,8 @@ config_version=4 [application] -config/name="Juego" +config/name="Alai" +config/description="This game is for testing an Artificial Intelligence." run/main_scene="res://Main.tscn" config/icon="res://icon.png" @@ -21,6 +22,10 @@ window/size/height=288 window/stretch/mode="viewport" window/stretch/aspect="keep" +[editor] + +scene/scene_naming=1 + [editor_plugins] enabled=PoolStringArray( "res://addons/vnen.tiled_importer/plugin.cfg" ) @@ -74,14 +79,25 @@ right={ ] } +[layer_names] + +2d_physics/layer_1="Tiles" +2d_physics/layer_2="Player" + [physics] common/enable_pause_aware_picking=true +2d/cell_size=18 [rendering] -environment/default_environment="res://default_env.tres" +2d/snapping/use_gpu_pixel_snap=true +misc/lossless_compression/force_png=true [tiled_importer] enable_json_format=false + +[world] + +2d/cell_size=18 diff --git a/godot/state_machine/State.gdns b/godot/state_machine/State.gdns new file mode 100644 index 0000000..757946d --- /dev/null +++ b/godot/state_machine/State.gdns @@ -0,0 +1,8 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/alai.tres" type="GDNativeLibrary" id=1] + +[resource] +resource_name = "State" +class_name = "State" +library = ExtResource( 1 ) diff --git a/godot/state_machine/StateMachine.gdns b/godot/state_machine/StateMachine.gdns new file mode 100644 index 0000000..77bc502 --- /dev/null +++ b/godot/state_machine/StateMachine.gdns @@ -0,0 +1,8 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/alai.tres" type="GDNativeLibrary" id=1] + +[resource] +resource_name = "StateMachine" +class_name = "StateMachine" +library = ExtResource( 1 ) diff --git a/src/Main.cpp b/src/Main.cpp index 6202fcf..387ff6e 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -3,14 +3,15 @@ #include using namespace godot; +using namespace main; void Main::_register_methods() { register_method("_ready", &Main::_ready); register_method("_physics_process", &Main::_physics_process); - register_property("full_screen", &Main::set_full_screen, &Main::get_full_screen, JUEGO_MAIN_FULL_SCREEN); - register_property("window_size", &Main::set_window_size, &Main::get_window_size, JUEGO_MAIN_WINDOW_SIZE); - register_property("launch_screen", &Main::set_launch_screen, &Main::get_launch_screen, JUEGO_MAIN_LAUNCH_SCREEN); + register_property("full_screen", &Main::set_full_screen, &Main::get_full_screen, main::full_screen); + register_property("window_size", &Main::set_window_size, &Main::get_window_size, main::window_size); + register_property("launch_screen", &Main::set_launch_screen, &Main::get_launch_screen, main::launch_screen); } Main::Main() @@ -26,9 +27,9 @@ void Main::_init() _os = OS::get_singleton(); _input = Input::get_singleton(); - full_screen = JUEGO_MAIN_FULL_SCREEN; - window_size = JUEGO_MAIN_WINDOW_SIZE; - launch_screen = JUEGO_MAIN_LAUNCH_SCREEN; + full_screen = main::full_screen; + window_size = main::window_size; + launch_screen = main::launch_screen; } void Main::_ready() @@ -39,17 +40,10 @@ void Main::_ready() } else { - String resolution = String("Resolution before: " + String().num(_os->get_window_size().x) + "x" + String().num(_os->get_window_size().y)); - Godot::print(resolution); - _os->set_window_size(window_size); _os->set_window_position( _os->get_screen_position(get_launch_screen()) + _os->get_screen_size() * 0.5 - _os->get_window_size() * 0.5 ); - - resolution = String("Resolution after: " + String().num(_os->get_window_size().x) + "x" + String().num(_os->get_window_size().y)); - - Godot::print(resolution); } } @@ -61,39 +55,39 @@ void Main::_physics_process(float delta) } } -void Main::set_full_screen(bool new_full_screen) +void Main::set_full_screen(bool full_screen) { - full_screen = new_full_screen; + this->full_screen = full_screen; } bool Main::get_full_screen() { - return full_screen; + return this->full_screen; } -void Main::set_window_size(Vector2 new_window_size) +void Main::set_window_size(Vector2 window_size) { - window_size = new_window_size; + this-> window_size = window_size; } Vector2 Main::get_window_size() { - return window_size; + return this->window_size; } -void Main::set_launch_screen(int8_t new_launch_screen) +void Main::set_launch_screen(int8_t launch_screen) { - launch_screen = new_launch_screen; + this->launch_screen = launch_screen; } int8_t Main::get_launch_screen() { - if (launch_screen == -1) + if (this->launch_screen == -1) { return _os->get_current_screen(); } else { - return launch_screen; + return this->launch_screen; } } diff --git a/src/Main.h b/src/Main.h new file mode 100644 index 0000000..4d86783 --- /dev/null +++ b/src/Main.h @@ -0,0 +1,165 @@ +#ifndef ALAI_MAIN_H +#define ALAI_MAIN_H + +#include +#include +#include +#include + +/** + * @brief This is the godot namespace for all the code included in the library. + * + * @details This namespace is used a prefix when the Godot engine looks for classes, methods, and properties. + */ +namespace godot +{ + /** + * @brief This namespace houses some global variables and the main class. + * + */ + namespace main + { + /** + * @brief The default value for if the game should start in full screen. + * + */ + const bool full_screen = false; + /** + * @brief The default resolution for the game window. + * + */ + const Vector2 window_size = Vector2(1280, 720); + /** + * @brief The default screen the the game should open on. + * + * @details -1 opens it on the currently active screen. And 0 and above are the screens to use. + */ + const int8_t launch_screen = -1; + + /** + * @brief This class controls the Main node. + * + * @details The main node is responsible for controling the window and the game iteself is a child of it. + */ + class Main : public Node + { + GODOT_CLASS(Main, Node) + + private: + /** + * @brief OS singleton. + * + */ + OS *_os; + /** + * @brief Input singleton. + * + */ + Input *_input; + + /** + * @brief If the window is full screen or not. + * + */ + bool full_screen; + /** + * @brief The size of the window. + * + */ + Vector2 window_size; + /** + * @brief The screen to launch the game on. + * + */ + int8_t launch_screen; + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new Main object. + * + */ + Main(); + + /** + * @brief Destroy the Main object. + * + */ + ~Main(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + void _init(); + + /** + * @brief Code to be run when ready. + * + * @details This method is run when all the children of this node are ready. + */ + void _ready(); + + /** + * @brief This class handles the physics processing. + * + * @details Every delta time, this function is called to check for input and update positioning. + * + * @param[in] delta The difference in time that passed since the last call to this method. + */ + void _physics_process(float delta); + + /** + * @brief Set the full screen object. + * + * @param[in] full_screen The new full screen state. + */ + void set_full_screen(bool full_screen); + + /** + * @brief Get the full screen object. + * + * @return true If full screen. + * @return false If not full screen. + */ + bool get_full_screen(); + + /** + * @brief Set the window size object. + * + * @param[in] window_size The new window size. + */ + void set_window_size(Vector2 window_size); + + /** + * @brief Get the window size object. + * + * @return Vector2 The window size. + */ + Vector2 get_window_size(); + + /** + * @brief Set the launch screen object. + * + * @param[in] launch_screen The launch screen to use. + */ + void set_launch_screen(int8_t launch_screen); + + /** + * @brief Get the launch screen object. + * + * @return int8_t The launch screen. + */ + int8_t get_launch_screen(); + }; + } +} + +#endif diff --git a/src/godot.cpp b/src/godot.cpp index 4389706..76e07ec 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -1,15 +1,29 @@ #include +#include "state_machine/StateMachine.h" +#include "state_machine/State.h" #include "Main.h" -#include "Player.h" +#include "player/Player.h" +#include "player/states/PlayerIdle.h" +#include "player/states/PlayerMove.h" +#include "player/states/PlayerJump.h" +#include "player/states/PlayerFall.h" using namespace godot; +/** + * @brief This function connects the gdnative init function. + * + */ extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) { Godot::gdnative_init(o); } +/** + * @brief This function connects the gdnative terminate function. + * + */ extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) { // This next line is a workaround to fix bug: @@ -18,9 +32,19 @@ extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_opt Godot::gdnative_terminate(o); } +/** + * @brief This function connects the init methods in the classes to godot's gdnative. + * + */ extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) { Godot::nativescript_init(handle); - register_class
(); - register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); } diff --git a/src/include/Main.h b/src/include/Main.h deleted file mode 100644 index 98c5611..0000000 --- a/src/include/Main.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef JUEGO_MAIN_H -#define JUEGO_MAIN_H - -#include -#include -#include -#include - -/** - * @brief If the game should be full screen or not by default. - */ -#define JUEGO_MAIN_FULL_SCREEN false -/** - * @brief The default size of the window. - * @details This is ignored if full screen is true. - */ -#define JUEGO_MAIN_WINDOW_SIZE Vector2(1280, 720) -/** - * @brief Which screen to launch the game on. - * @details If -1 it will launch the game on the "active" screen. Anything between 0 and N represents the screen number to show the game on when opened. - */ -#define JUEGO_MAIN_LAUNCH_SCREEN -1 - -/** - * @brief This is the godot namespace for all the code included in the library. - * @details This namespace is used a prefix when the Godot engine looks for classes, methods, and properties. - */ -namespace godot -{ - /** - * @brief This class controls the Main node. - * @details The main node is responsible for controling the window and the game iteself is a child of it. - */ - class Main : public Node - { - GODOT_CLASS(Main, Node) - - private: - /** - * @brief OS singleton. - */ - OS *_os; - /** - * @brief Input singleton. - */ - Input *_input; - - /** - * @brief If the window is full screen or not. - */ - bool full_screen; - /** - * @brief The size of the window. - */ - Vector2 window_size; - /** - * @brief The screen to launch the game on. - */ - int8_t launch_screen; - - public: - /** - * @brief This method registers classes with Godot. - * @details This method registers methods, properties, and signals with the Godot engine. - */ - static void _register_methods(); - - /** - * @brief Construct a new Main object. - */ - Main(); - - /** - * @brief Destroy the Main object. - */ - ~Main(); - - /** - * @brief Initialize the class from Godot. - * @details This method is called just once when the Godot engine connects to the instance of the class. - */ - void _init(); - - /** - * @brief Code to be run when ready. - * @details This method is run when all the children of this node are ready. - */ - void _ready(); - - /** - * @brief This class handles the physics processing. - * @details Every delta time, this function is called to check for input and update positioning. - * - * @param[in] delta The difference in time that passed since the last call to this method. - */ - void _physics_process(float delta); - - /** - * @brief Set the full screen object. - * - * @param[in] new_full_screen The new full screen state. - */ - void set_full_screen(bool new_full_screen); - - /** - * @brief Get the full screen object. - * - * @return true If full screen. - * @return false If not full screen. - */ - bool get_full_screen(); - - /** - * @brief Set the window size object. - * - * @param[in] new_window_size The new window size. - */ - void set_window_size(Vector2 new_window_size); - - /** - * @brief Get the window size object. - * - * @return Vector2 The window size. - */ - Vector2 get_window_size(); - - /** - * @brief Set the launch screen object. - * - * @param[in] new_launch_screen The launch screen to use. - */ - void set_launch_screen(int8_t new_launch_screen); - - /** - * @brief Get the launch screen object. - * - * @return int8_t The launch screen. - */ - int8_t get_launch_screen(); - }; -} - -#endif diff --git a/src/include/Player.h b/src/include/Player.h deleted file mode 100644 index ab30e97..0000000 --- a/src/include/Player.h +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef JUEGO_PLAYER_H -#define JUEGO_PLAYER_H - -/** - * @brief This resource is loaded by default for the AnimatedSprite node. - */ -#define JUEGO_PLAYER_SPRITE_FRAMES "res://characters/player/sprites/green.tres" -/** - * @brief The speed the player should move it. - */ -#define JUEGO_PLAYER_SPEED 100.0 -/** - * @brief The force applied to the player when jumping. - */ -#define JUEGO_PLAYER_JUMP_FORCE 300.0 -/** - * @brief The gravity applied to the player. - */ -#define JUEGO_PLAYER_GRAVITY 9.81 -/** - * @brief The multiplier used to change the speed of the player when running. - */ -#define JUEGO_PLAYER_RUN_SPEED 2.0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * @brief This is the godot namespace for all the code included in the library. - * @details This namespace is used a prefix when the Godot engine looks for classes, methods, and properties. - */ -namespace godot -{ - /** - * @brief This class is used to control the player. - * @details This class allows the player to move, run, and jump as well as controls the sprite displayed for those actions. - */ - class Player : public KinematicBody2D - { - GODOT_CLASS(Player, KinematicBody2D) - - private: - /** - * @brief OS singleton. - */ - OS *_os; - /** - * @brief Input singleton. - */ - Input *_input; - /** - * @brief ResourceLoader singleton. - */ - ResourceLoader *_resource_loader; - - /** - * @brief The animated sprite connected to the KinematicBody2D. - */ - AnimatedSprite *animated_sprite; - /** - * @brief The sprite frames used in the animated sprite. - */ - Ref sprite_frames; - /** - * @brief The coins the player has collected. - */ - uint8_t coins; - /** - * @brief The velocity at which moves the player moves. - */ - Vector2 velocity; - /** - * @brief The speed that the player moves in. - */ - float speed; - /** - * @brief The force applied to the player when jumping. - */ - float jump_force; - /** - * @brief The gravity applied to the player. - */ - float gravity; - /** - * @brief The speed multiplier used to make the player move faster. - */ - float run_speed; - - /** - * @brief State of jumping of the player. To be replaced with a state machine in the future. - */ - uint8_t jumping; - - public: - /** - * @brief This method registers classes with Godot. - * @details This method registers methods, properties, and signals with the Godot engine. - */ - static void _register_methods(); - - /** - * @brief Construct a new Player object. - */ - Player(); - - /** - * @brief Destroy the Player object. - */ - ~Player(); - - /** - * @brief Initialize the class from Godot. - * @details This method is called just once when the Godot engine connects to the instance of the class. - */ - void _init(); - - /** - * @brief Code to be run when ready. - * @details This method is run when all the children of this node are ready. - */ - void _ready(); - - /** - * @brief This class handles the physics processing. - * @details Every delta time, this function is called to check for input and update positioning. - * - * @param[in] delta The difference in time that passed since the last call to this method. - */ - void _physics_process(float delta); - - /** - * @brief Set the sprite frames object. - * - * @param[in] new_sprite_frames The new sprite frame. - */ - void set_sprite_frames(Ref new_sprite_frames); - - /** - * @brief Get the sprite frames object. - * - * @return Ref A reference to the sprite frames object. - */ - Ref get_sprite_frames(); - - /** - * @brief Set the speed object. - * - * @param[in] new_speed The new speed. - */ - void set_speed(float new_speed); - - /** - * @brief Get the speed object. - * - * @return float The current speed of the player. - */ - float get_speed(); - - /** - * @brief Set the jump force object. - * - * @param[in] new_jump_force The new force applied to the player to make him jump. - */ - void set_jump_force(float new_jump_force); - - /** - * @brief Get the jump force object. - * - * @return float The current force being applied to the player. - */ - float get_jump_force(); - - /** - * @brief Set the gravity object. - * - * @param[in] new_gravity The new gravity to apply to the player. - */ - void set_gravity(float new_gravity); - - /** - * @brief Get the gravity object. - * - * @return float The current gravity applied to the player. - */ - float get_gravity(); - - /** - * @brief Set the run speed object. - * - * @param[in] new_run_speed The new speed for running. - */ - void set_run_speed(float new_run_speed); - - /** - * @brief Get the run speed object. - * - * @return float The current run speed of the player. - */ - float get_run_speed(); - - /** - * @brief This signal is called when the player moves. - * @details The jump action is not included in this signal, just moving left or right. - * - * @param[in] position The new position of the player. - */ - void _on_Player_player_moved(Vector2 position); - }; -} - -#endif diff --git a/src/Player.cpp b/src/player/Player.cpp similarity index 56% rename from src/Player.cpp rename to src/player/Player.cpp index efb7fda..843043b 100644 --- a/src/Player.cpp +++ b/src/player/Player.cpp @@ -1,4 +1,4 @@ -#include "Player.h" +#include "player/Player.h" #include #include @@ -7,18 +7,20 @@ #include using namespace godot; +using namespace player; void Player::_register_methods() { register_method("_ready", &Player::_ready); register_method("_physics_process", &Player::_physics_process); - register_method("_on_Player_player_moved", &Player::_on_Player_player_moved); + register_method("set_velocity", &Player::set_velocity); + register_method("get_velocity", &Player::get_velocity); //register_property>("sprite_frames", &Player::set_sprite_frames, &Player::get_sprite_frames, Ref(), GODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_RESOURCE_TYPE, String("SpriteFrames")); - register_property("speed", &Player::set_speed, &Player::get_speed, JUEGO_PLAYER_SPEED); - register_property("jump_force", &Player::set_jump_force, &Player::get_jump_force, JUEGO_PLAYER_JUMP_FORCE); - register_property("gravity", &Player::set_gravity, &Player::get_gravity, JUEGO_PLAYER_GRAVITY); - register_property("run_speed", &Player::set_run_speed, &Player::get_run_speed, JUEGO_PLAYER_RUN_SPEED); - register_signal("player_moved", "position", GODOT_VARIANT_TYPE_VECTOR2); + register_property("speed", &Player::set_speed, &Player::get_speed, player::speed); + register_property("jump_force", &Player::set_jump_force, &Player::get_jump_force, player::jump_force); + register_property("gravity", &Player::set_gravity, &Player::get_gravity, player::gravity); + register_property("run_speed", &Player::set_run_speed, &Player::get_run_speed, player::run_speed); + register_property("double_jump", &Player::set_double_jump, &Player::get_double_jump, player::double_jump); } Player::Player() @@ -31,21 +33,18 @@ Player::~Player() void Player::_init() { - _os = OS::get_singleton(); - _input = Input::get_singleton(); _resource_loader = ResourceLoader::get_singleton(); - //sprite_frames = _resource_loader->load(JUEGO_PLAYER_SPRITE_FRAMES); - set_speed(JUEGO_PLAYER_SPEED); - set_jump_force(JUEGO_PLAYER_JUMP_FORCE); - set_gravity(JUEGO_PLAYER_GRAVITY); - set_run_speed(JUEGO_PLAYER_RUN_SPEED); + //sprite_frames = _resource_loader->load(player::sprite_frames); + set_speed(player::speed); + set_jump_force(player::jump_force); + set_gravity(player::gravity); + set_run_speed(player::run_speed); + set_double_jump(player::double_jump); coins = 0; velocity = Vector2(); - - jumping = 0; } void Player::_ready() @@ -53,7 +52,7 @@ void Player::_ready() animated_sprite = get_node("AnimatedSprite"); if (!animated_sprite) { - WARN_PRINT("AnimateSprite not found!"); + ERR_PRINT("AnimateSprite not found!"); animated_sprite = AnimatedSprite()._new(); } //animated_sprite->set_sprite_frames(sprite_frames); @@ -74,74 +73,7 @@ void Player::_ready() void Player::_physics_process(float delta) { - auto current_speed = get_speed(); - velocity.x = 0; - if (_input->is_action_pressed("run")) - { - current_speed *= get_run_speed(); - } - - if (_input->is_action_pressed("right")) - { - velocity.x += current_speed; - } - - if (_input->is_action_pressed("left")) - { - velocity.x += -current_speed; - } - - if (velocity.x > 0) - { - animated_sprite->play("move"); - animated_sprite->set_flip_h(true); - } - else if (velocity.x < 0) - { - animated_sprite->play("move"); - animated_sprite->set_flip_h(false); - } - else - { - animated_sprite->stop(); - animated_sprite->set_animation("idle"); - } - - if (jumping > 0 && is_on_floor()) - { - animated_sprite->set_frame(1); - jumping = 0; - } - - if (!is_on_floor()) - { - animated_sprite->stop(); - animated_sprite->set_animation("air"); - if (jumping == 0) - { - jumping = 2; - } - } - velocity.y += get_gravity(); - if (_input->is_action_just_pressed("jump") && jumping < 2) - { - velocity.y = -get_jump_force(); - jumping++; - } - - if (_input->is_action_just_released("jump")) - { - if (velocity.y < -100) - { - velocity.y = -100; - } - } - - if (velocity.x < 0 || velocity.x > 0) - { - //emit_signal("player_moved", get_position()); - } velocity = move_and_slide(velocity, Vector2::UP, true); velocity.x = Math::lerp((float) velocity.x, (float) 0, (float) 0.2); @@ -170,7 +102,6 @@ void Player::_physics_process(float delta) { if (get_parent()->get_class() == "TileMap") { - Godot::print("Off screen"); auto error = get_tree()->change_scene("res://Main.tscn"); if (error != Error::OK) { @@ -181,57 +112,72 @@ void Player::_physics_process(float delta) } } -void Player::set_sprite_frames(Ref new_sprite_frames) +void Player::set_sprite_frames(Ref sprite_frames) { - sprite_frames = new_sprite_frames; + this->sprite_frames = sprite_frames; } Ref Player::get_sprite_frames() { - return sprite_frames; + return this->sprite_frames; } -void Player::set_speed(float new_speed) +void Player::set_speed(float speed) { - speed = new_speed; + this->speed = speed; } float Player::get_speed() { - return speed; + return this->speed; } -void Player::set_jump_force(float new_jump_force) +void Player::set_jump_force(float jump_force) { - jump_force = new_jump_force; + this->jump_force = jump_force; } float Player::get_jump_force() { - return jump_force; + return this->jump_force; } -void Player::set_gravity(float new_gravity) +void Player::set_gravity(float gravity) { - gravity = new_gravity; + this->gravity = gravity; } float Player::get_gravity() { - return gravity; + return this->gravity; } -void Player::set_run_speed(float new_run_speed) +void Player::set_run_speed(float run_speed) { - run_speed = new_run_speed; + this->run_speed = run_speed; } float Player::get_run_speed() { - return run_speed; + return this->run_speed; } -void Player::_on_Player_player_moved(Vector2 position) +void Player::set_double_jump(bool double_jump) { - Godot::print(position); + this->double_jump = double_jump; +} + +bool Player::get_double_jump() +{ + return this->double_jump; +} + +void Player::set_velocity(Vector2 velocity) +{ + this->velocity = velocity; +} + +Vector2 Player::get_velocity() +{ + return this->velocity; } diff --git a/src/player/Player.h b/src/player/Player.h new file mode 100644 index 0000000..fd2474a --- /dev/null +++ b/src/player/Player.h @@ -0,0 +1,262 @@ +#ifndef ALAI_PLAYER_H +#define ALAI_PLAYER_H + +#include +#include +#include +#include +#include +#include + +/** + * @brief This is the godot namespace for all the code included in the library. + * + * @details This namespace is used a prefix when the Godot engine looks for classes, methods, and properties. + */ +namespace godot +{ + /** + * @brief This namespace contains the global variables related to the player and its states. + * + */ + namespace player + { + /** + * @brief The default sprite resource of the player. + * + */ + const char player_sprite_frames[] = "res://characters/player/sprites/green.tres"; + /** + * @brief The default speed of the player. + * + */ + const float speed = 60.0; + /** + * @brief The default jump force applied when jumping. + * + */ + const float jump_force = 300.0; + /** + * @brief The default gravity applied to the player. + * + */ + const float gravity = 9.81; + /** + * @brief The default run speed multiplier. + * + */ + const float run_speed = 2.0; + /** + * @brief The default double jump activation state. + * + */ + const bool double_jump = true; + + /** + * @brief This class is used to control the player. + * + * @details This class allows the player to move, run, and jump as well as controls the sprite displayed for those actions. + */ + class Player : public KinematicBody2D + { + GODOT_CLASS(Player, KinematicBody2D) + + private: + /** + * @brief ResourceLoader singleton. + * + */ + ResourceLoader *_resource_loader; + + /** + * @brief The animated sprite connected to the KinematicBody2D. + * + */ + AnimatedSprite *animated_sprite; + /** + * @brief The sprite frames used in the animated sprite. + * + */ + Ref sprite_frames; + /** + * @brief The coins the player has collected. + * + */ + uint8_t coins; + /** + * @brief The velocity at which moves the player moves. + * + */ + Vector2 velocity; + /** + * @brief The speed that the player moves in. + * + */ + float speed; + /** + * @brief The force applied to the player when jumping. + * + */ + float jump_force; + /** + * @brief The gravity applied to the player. + * + */ + float gravity; + /** + * @brief The speed multiplier used to make the player move faster. + * + */ + float run_speed; + /** + * @brief If double jump is enabled or not. + * + */ + bool double_jump; + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new Player object. + * + */ + Player(); + + /** + * @brief Destroy the Player object. + * + */ + ~Player(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + void _init(); + + /** + * @brief Code to be run when ready. + * + * @details This method is run when all the children of this node are ready. + */ + void _ready(); + + /** + * @brief This class handles the physics processing. + * + * @details Every delta time, this function is called to check for input and update positioning. + * + * @param[in] delta The difference in time that passed since the last call to this method. + */ + void _physics_process(float delta); + + /** + * @brief Set the sprite frames object. + * + * @param[in] sprite_frames The new sprite frame. + */ + void set_sprite_frames(Ref sprite_frames); + + /** + * @brief Get the sprite frames object. + * + * @return Ref A reference to the sprite frames object. + */ + Ref get_sprite_frames(); + + /** + * @brief Set the speed object. + * + * @param[in] speed The new speed. + */ + void set_speed(float speed); + + /** + * @brief Get the speed object. + * + * @return float The current speed of the player. + */ + float get_speed(); + + /** + * @brief Set the jump force object. + * + * @param[in] jump_force The new force applied to the player to make him jump. + */ + void set_jump_force(float jump_force); + + /** + * @brief Get the jump force object. + * + * @return float The current force being applied to the player. + */ + float get_jump_force(); + + /** + * @brief Set the gravity object. + * + * @param[in] gravity The new gravity to apply to the player. + */ + void set_gravity(float gravity); + + /** + * @brief Get the gravity object. + * + * @return float The current gravity applied to the player. + */ + float get_gravity(); + + /** + * @brief Set the run speed object. + * + * @param[in] run_speed The new speed for running. + */ + void set_run_speed(float run_speed); + + /** + * @brief Get the run speed object. + * + * @return float The current run speed of the player. + */ + float get_run_speed(); + + /** + * @brief Set the double jump object. + * + * @param[in] double_jump The new double dump value. + */ + void set_double_jump(bool double_jump); + + /** + * @brief Get the double jump object. + * + * @return true If double jump is enabled. + * @return false If double jump is disabled. + */ + bool get_double_jump(); + + /** + * @brief Set the velocity object. + * + * @param[in] velocity The new velocity of the player. + */ + void set_velocity(Vector2 velocity); + + /** + * @brief Get the velocity object. + * + * @return Vector2 Returns the velocity of the player. + */ + Vector2 get_velocity(); + }; + } +} + +#endif diff --git a/src/player/states/PlayerFall.cpp b/src/player/states/PlayerFall.cpp new file mode 100644 index 0000000..c3e6ff4 --- /dev/null +++ b/src/player/states/PlayerFall.cpp @@ -0,0 +1,78 @@ +#include "player/states/PlayerFall.h" +#include "player/Player.h" + +using namespace godot; +using namespace player; + +void PlayerFall::_register_methods() +{ + register_method("_state_enter", &PlayerFall::_state_enter); + register_method("_state_exit", &PlayerFall::_state_exit); + register_method("_physics_process", &PlayerFall::_physics_process); +} + +PlayerFall::PlayerFall() +{ +} + +PlayerFall::~PlayerFall() +{ +} + +void PlayerFall::_init() +{ + _input = Input::get_singleton(); +} + +void PlayerFall::_state_enter() +{ + animated_sprite = get_parent()->get_node("AnimatedSprite"); + animated_sprite->stop(); + animated_sprite->set_animation("air"); +} + +void PlayerFall::_state_exit() +{ + animated_sprite->set_animation("move"); + animated_sprite->set_frame(1); +} + +void PlayerFall::_physics_process(float delta) +{ + auto parent = Object::cast_to(get_parent()); + + if (parent->is_on_floor()) + { + get_state_machine()->change("Move"); + return; + } + + auto current_speed = parent->get_speed(); + auto velocity = parent->get_velocity(); + velocity.x = 0; + if (_input->is_action_pressed("run")) + { + current_speed *= parent->get_run_speed(); + } + + if (_input->is_action_pressed("right")) + { + velocity.x += current_speed; + } + + if (_input->is_action_pressed("left")) + { + velocity.x += -current_speed; + } + + if (velocity.x > 0) + { + animated_sprite->set_flip_h(true); + } + else if (velocity.x < 0) + { + animated_sprite->set_flip_h(false); + } + + parent->set_velocity(velocity); +} diff --git a/src/player/states/PlayerFall.h b/src/player/states/PlayerFall.h new file mode 100644 index 0000000..d53fd4f --- /dev/null +++ b/src/player/states/PlayerFall.h @@ -0,0 +1,89 @@ +#ifndef JUEGO_PLAYER_FALL_H +#define JUEGO_PLAYER_FALL_H + +#include "state_machine/State.h" + +#include +#include +#include + +/** + * @brief This is the godot namespace for all the code included in the library. + * + * @details This namespace is used a prefix when the Godot engine looks for classes, methods, and properties. + */ +namespace godot +{ + namespace player + { + /** + * @brief This class controls what happens when the player is in a falling state. + * + */ + class PlayerFall : public State + { + GODOT_CLASS(PlayerFall, State) + + private: + /** + * @brief Input singleton. + * + */ + Input *_input; + + /** + * @brief The animated sprite connected to the player. + * + */ + AnimatedSprite *animated_sprite; + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new Player Fall object. + * + */ + PlayerFall(); + + /** + * @brief Destroy the Player Fall object. + * + */ + ~PlayerFall(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + void _init(); + + /** + * @brief Called when the fall state is entered. + * + */ + void _state_enter(); + + /** + * @brief Called when the fall state is exited. + * + */ + void _state_exit(); + + /** + * @brief The physics processed every delta time. + * + * @param[in] delta The time since the method was last run. + */ + void _physics_process(float delta); + }; + } +} + +#endif diff --git a/src/player/states/PlayerIdle.cpp b/src/player/states/PlayerIdle.cpp new file mode 100644 index 0000000..026b5cf --- /dev/null +++ b/src/player/states/PlayerIdle.cpp @@ -0,0 +1,65 @@ +#include "player/states/PlayerIdle.h" +#include "player/Player.h" + +using namespace godot; +using namespace player; + +void PlayerIdle::_register_methods() +{ + register_method("_state_enter", &PlayerIdle::_state_enter); + register_method("_state_exit", &PlayerIdle::_state_exit); + register_method("_physics_process", &PlayerIdle::_physics_process); +} + +PlayerIdle::PlayerIdle() +{ +} + +PlayerIdle::~PlayerIdle() +{ +} + +void PlayerIdle::_init() +{ + _input = Input::get_singleton(); +} + +void PlayerIdle::_state_enter() +{ + animated_sprite = get_parent()->get_node("AnimatedSprite"); + animated_sprite->stop(); + animated_sprite->set_animation("idle"); +} + +void PlayerIdle::_state_exit() +{ +} + +void PlayerIdle::_physics_process(float delta) +{ + auto parent = Object::cast_to(get_parent()); + + if (_input->is_action_pressed("right")) + { + get_state_machine()->change("Move"); + return; + } + + if (_input->is_action_pressed("left")) + { + get_state_machine()->change("Move"); + return; + } + + if (_input->is_action_just_pressed("jump")) + { + get_state_machine()->change("Jump"); + return; + } + + if (!parent->is_on_floor()) + { + get_state_machine()->change("Fall"); + return; + } +} diff --git a/src/player/states/PlayerIdle.h b/src/player/states/PlayerIdle.h new file mode 100644 index 0000000..76e4685 --- /dev/null +++ b/src/player/states/PlayerIdle.h @@ -0,0 +1,84 @@ +#ifndef JUEGO_PLAYER_IDLE_H +#define JUEGO_PLAYER_IDLE_H + +#include "state_machine/State.h" + +#include +#include +#include +#include + +namespace godot +{ + namespace player + { + /** + * @brief This class controls what happens when the player is in the idle state. + * + */ + class PlayerIdle : public State + { + GODOT_CLASS(PlayerIdle, State) + + private: + /** + * @brief Input singleton. + * + */ + Input *_input; + /** + * @brief The animated sprite of the player. + * + */ + AnimatedSprite *animated_sprite; + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new Player Idle object. + * + */ + PlayerIdle(); + + /** + * @brief Destroy the Player Idle object. + * + */ + ~PlayerIdle(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + void _init(); + + /** + * @brief Called when the idle state is entered. + * + */ + void _state_enter(); + + /** + * @brief Called when the idle state is exited. + * + */ + void _state_exit(); + + /** + * @brief The physics processed every delta time. + * + * @param[in] delta The time since the method was last run. + */ + void _physics_process(float delta); + }; + } +} + +#endif diff --git a/src/player/states/PlayerJump.cpp b/src/player/states/PlayerJump.cpp new file mode 100644 index 0000000..8255e1b --- /dev/null +++ b/src/player/states/PlayerJump.cpp @@ -0,0 +1,105 @@ +#include "player/states/PlayerJump.h" +#include "player/Player.h" + +using namespace godot; +using namespace player; + +void PlayerJump::_register_methods() +{ + register_method("_state_enter", &PlayerJump::_state_enter); + register_method("_state_exit", &PlayerJump::_state_exit); + register_method("_physics_process", &PlayerJump::_physics_process); +} + +PlayerJump::PlayerJump() +{ +} + +PlayerJump::~PlayerJump() +{ +} + +void PlayerJump::_init() +{ + _input = Input::get_singleton(); +} + +void PlayerJump::_state_enter(const String state) +{ + animated_sprite = get_parent()->get_node("AnimatedSprite"); + animated_sprite->stop(); + animated_sprite->set_animation("air"); + + if (state == "Jump") + { + double_jumped = true; + } + else + { + double_jumped = false; + } + + auto parent = Object::cast_to(get_parent()); + auto velocity = parent->get_velocity(); + velocity.y = -parent->get_jump_force(); + parent->set_velocity(velocity); +} + +void PlayerJump::_state_exit() +{ + animated_sprite->set_animation("move"); + animated_sprite->set_frame(1); +} + +void PlayerJump::_physics_process(float delta) +{ + auto parent = Object::cast_to(get_parent()); + if (parent->is_on_floor()) + { + get_state_machine()->change("Move"); + return; + } + + auto current_speed = parent->get_speed(); + auto velocity = parent->get_velocity(); + velocity.x = 0; + if (_input->is_action_pressed("run")) + { + current_speed *= parent->get_run_speed(); + } + + if (_input->is_action_pressed("right")) + { + velocity.x += current_speed; + } + + if (_input->is_action_pressed("left")) + { + velocity.x += -current_speed; + } + + if (_input->is_action_just_released("jump")) + { + if (velocity.y < -100) + { + velocity.y = -100; + } + } + + if (parent->get_double_jump() && !double_jumped && _input->is_action_just_pressed("jump")) + { + get_state_machine()->change("Jump"); + return; + } + + if (velocity.x > 0) + { + animated_sprite->set_flip_h(true); + } + else if (velocity.x < 0) + { + animated_sprite->set_flip_h(false); + } + + parent->set_velocity(velocity); +} diff --git a/src/player/states/PlayerJump.h b/src/player/states/PlayerJump.h new file mode 100644 index 0000000..aee1059 --- /dev/null +++ b/src/player/states/PlayerJump.h @@ -0,0 +1,91 @@ +#ifndef JUEGO_PLAYER_JUMP_H +#define JUEGO_PLAYER_JUMP_H + +#include "state_machine/State.h" + +#include +#include +#include + +namespace godot +{ + namespace player + { + /** + * @brief This class control what happens when the player is in the jump state. + * + */ + class PlayerJump : public State + { + GODOT_CLASS(PlayerJump, State) + + private: + /** + * @brief Input singleton. + * + */ + Input *_input; + /** + * @brief The animated sprite connected to the player. + * + */ + AnimatedSprite *animated_sprite; + /** + * @brief If the player has already performed a double jump or not. + * + */ + bool double_jumped; + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new Player Jump object. + * + */ + PlayerJump(); + + /** + * @brief Destroy the Player Jump object. + * + */ + ~PlayerJump(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + void _init(); + + /** + * @brief Called when the player enters the jump state. + * + * @details If the previous state was the jump state, a double jump was performed. + * + * @param[in] state The previous state before this one was entered. + */ + void _state_enter(const String state); + + /** + * @brief Called when the player exits the jump state. + * + */ + void _state_exit(); + + /** + * @brief The physics processed every delta time. + * + * @param[in] delta The time since the method was last run. + */ + void _physics_process(float delta); + }; + } +} + +#endif diff --git a/src/player/states/PlayerMove.cpp b/src/player/states/PlayerMove.cpp new file mode 100644 index 0000000..77df13e --- /dev/null +++ b/src/player/states/PlayerMove.cpp @@ -0,0 +1,94 @@ +#include "player/states/PlayerMove.h" +#include "player/Player.h" + +using namespace godot; +using namespace player; + +void PlayerMove::_register_methods() +{ + register_method("_state_enter", &PlayerMove::_state_enter); + register_method("_state_exit", &PlayerMove::_state_exit); + register_method("_physics_process", &PlayerMove::_physics_process); +} + +PlayerMove::PlayerMove() +{ +} + +PlayerMove::~PlayerMove() +{ +} + +void PlayerMove::_init() +{ + _input = Input::get_singleton(); +} + +void PlayerMove::_state_enter() +{ + animated_sprite = get_parent()->get_node("AnimatedSprite"); + animated_sprite->set_animation("move"); + animated_sprite->play(); +} + +void PlayerMove::_state_exit() +{ +} + +void PlayerMove::_physics_process(float delta) +{ + auto parent = Object::cast_to(get_parent()); + + auto direction_pressed = false; + + auto current_speed = parent->get_speed(); + auto velocity = parent->get_velocity(); + velocity.x = 0; + if (_input->is_action_pressed("run")) + { + current_speed *= parent->get_run_speed(); + } + + if (_input->is_action_pressed("right")) + { + direction_pressed = true; + velocity.x += current_speed; + } + + if (_input->is_action_pressed("left")) + { + direction_pressed = true; + velocity.x += -current_speed; + } + + if (_input->is_action_just_pressed("jump")) + { + get_state_machine()->change("Jump"); + return; + } + + if (velocity.x > 0) + { + animated_sprite->set_flip_h(true); + } + else if (velocity.x < 0) + { + animated_sprite->set_flip_h(false); + } + else + { + if (!direction_pressed) + { + get_state_machine()->change("Idle"); + } + return; + } + + parent->set_velocity(velocity); + + if (!parent->is_on_floor()) + { + get_state_machine()->change("Fall"); + return; + } +} diff --git a/src/player/states/PlayerMove.h b/src/player/states/PlayerMove.h new file mode 100644 index 0000000..0df3078 --- /dev/null +++ b/src/player/states/PlayerMove.h @@ -0,0 +1,83 @@ +#ifndef JUEGO_PLAYER_MOVE_H +#define JUEGO_PLAYER_MOVE_H + +#include "state_machine/State.h" + +#include +#include +#include + +namespace godot +{ + namespace player + { + /** + * @brief This class controls what happens when the player is in the move state. + * + */ + class PlayerMove : public State + { + GODOT_CLASS(PlayerMove, State) + + private: + /** + * @brief Input singleton. + * + */ + Input *_input; + /** + * @brief The animated sprite of the player. + * + */ + AnimatedSprite *animated_sprite; + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new Player Move object. + * + */ + PlayerMove(); + + /** + * @brief Destroy the Player Move object. + * + */ + ~PlayerMove(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + void _init(); + + /** + * @brief Called when the player enters the move state. + * + */ + void _state_enter(); + + /** + * @brief Called when the player exists the move state. + * + */ + void _state_exit(); + + /** + * @brief The physics processed every delta time. + * + * @param[in] delta The time since the method was last run. + */ + void _physics_process(float delta); + }; + } +} + +#endif diff --git a/src/state_machine/State.cpp b/src/state_machine/State.cpp new file mode 100644 index 0000000..29efa48 --- /dev/null +++ b/src/state_machine/State.cpp @@ -0,0 +1,54 @@ +#include "state_machine/State.h" + +using namespace godot; + +void State::_register_methods() +{ + register_method("set_parent", &State::set_parent); + register_method("get_parent", &State::get_parent); + register_method("set_state_machine", &State::set_state_machine); + register_method("_state_enter", &State::_state_enter); + register_method("_state_exit", &State::_state_exit); +} + +State::State() +{ +} + +State::~State() +{ +} + +void State::_init() +{ +} + +void State::_state_enter(const String state, const Array args) +{ + WARN_PRINT("State " + state + " is missing its _state_enter method!"); +} + +void State::_state_exit(const String state, const Array args) +{ + WARN_PRINT("State " + state + " is missing its _state_exit method!"); +} + +void State::set_parent(Node *parent) +{ + this->parent = parent; +} + +Node *State::get_parent() +{ + return parent; +} + +void State::set_state_machine(StateMachine *state_machine) +{ + this->state_machine = state_machine; +} + +StateMachine *State::get_state_machine() +{ + return this->state_machine; +} diff --git a/src/state_machine/State.h b/src/state_machine/State.h new file mode 100644 index 0000000..46ebe38 --- /dev/null +++ b/src/state_machine/State.h @@ -0,0 +1,104 @@ +#ifndef JUEGO_STATE_H +#define JUEGO_STATE_H + +#include "StateMachine.h" + +#include +#include + +namespace godot +{ + /** + * @brief This class provides a virtual template state that real states should extend from and override. + * + */ + class State : public StateMachine + { + GODOT_CLASS(State, Node) + + private: + /** + * @brief The state's parent, this is the node 1 level above the state machine. + * + */ + Node *parent; + /** + * @brief The state machine itself, used to handle all state related work. + * + */ + StateMachine *state_machine; + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new State object. + * + */ + State(); + + /** + * @brief Destroy the State object. + * + */ + ~State(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + virtual void _init(); + + /** + * @brief This is called when a state is entered. + * + * @param[in] state This will contain the previous state. + * @param[in] args The arguments passed to the state. + */ + virtual void _state_enter(const String state, const Array args = Array()); + + /** + * @brief This is called when a state is exited. + * + * @param[in] state The state we are going to. + * @param[in] args The arguments passed to the state. + */ + virtual void _state_exit(const String state, const Array args = Array()); + + /** + * @brief Set the parent object. + * + * @param[in] parent The parent of the state. + */ + virtual void set_parent(Node *parent) final; + + /** + * @brief Get the parent object. + * + * @return Node* The parent of the state. + */ + virtual Node *get_parent() final; + + /** + * @brief Set the state machine object. + * + * @param[in] state_machine The state machine. + */ + virtual void set_state_machine(StateMachine *state_machine) final; + + /** + * @brief Get the state machine object. + * + * @return StateMachine* The state machine. + */ + virtual StateMachine *get_state_machine() final; + }; +} + +#endif diff --git a/src/state_machine/StateMachine.cpp b/src/state_machine/StateMachine.cpp new file mode 100644 index 0000000..4370842 --- /dev/null +++ b/src/state_machine/StateMachine.cpp @@ -0,0 +1,208 @@ +#include "state_machine/StateMachine.h" +#include "state_machine/State.h" + +using namespace godot; + +void StateMachine::_register_methods() +{ + register_method("_ready", &StateMachine::_ready); + register_method("_on_StateMachine_tree_entered", &StateMachine::_on_StateMachine_tree_entered); + register_method("_on_StateMachine_tree_exiting", &StateMachine::_on_StateMachine_tree_exiting); + register_property("default_state", &StateMachine::set_default_state, &StateMachine::get_default_state, String()); + register_property("debug", &StateMachine::set_debug, &StateMachine::get_debug, false); + register_signal("state_entered", "state", GODOT_VARIANT_TYPE_STRING); + register_signal("state_exited", "state", GODOT_VARIANT_TYPE_STRING); + register_signal("state_restarted", "state", GODOT_VARIANT_TYPE_STRING); +} + +StateMachine::StateMachine() +{ +} + +StateMachine::~StateMachine() +{ +} + +void StateMachine::_init() +{ + set_default_state(String()); + set_debug(false); +} + +void StateMachine::_ready() +{ + connect("tree_entered", this, "_on_StateMachine_tree_entered"); + connect("tree_exiting", this, "_on_StateMachine_tree_exiting"); + parent = get_parent(); + set_current_state(get_default_state()); + setup(); +} + +void StateMachine::setup() +{ + auto children = get_children(); + + if (get_current_state() == "") + { + if (children.size() > 0) + { + WARN_PRINT("State machine doesn't have a default state set, using first child!"); + auto child = Object::cast_to(children[0].operator Object*()); + set_current_state(child->get_name()); + } + else + { + ERR_PRINT("State machine doesn't have a default state set and has no child states!"); + return; + } + } + + for (uint8_t i = 0; i < children.size(); i++) + { + auto child = Object::cast_to(children[i].operator Object*()); + add_state(child->get_name(), child); + + child->call("set_state_machine", this); + + child->call("set_parent", parent); + + if (child->get_name() != get_current_state()) + { + this->remove_child(child); + } + } + + this->call("_state_enter", get_current_state()); +} + +void StateMachine::add_state(const String state, Node *child) +{ + states[state] = child; +} + +bool StateMachine::is_current(const String state) +{ + if (get_current_state() == "") + { + return false; + } + else + { + return get_current_state() == state; + } +} + +bool StateMachine::has(const String state) +{ + return states.has(state); +} + +void StateMachine::restart(const String state, const Array& args) +{ + this->call("_state_exit", state, args); + this->call("_state_enter", state, args); + this->emit_signal("state_restarted", get_current_state()); +} + +void StateMachine::change(const String state, const Array &args) +{ + if (is_current(state)) + { + return this->restart(state, args); + } + + auto previous_state = get_current_state(); + auto exiting = this->call("_state_exit", state, args); + + if (get_current_state() != "") + { + auto child = Object::cast_to(states[get_current_state()].operator Object*()); + if (child != nullptr) + { + this->remove_child(child); + } + this->emit_signal("state_exited", get_current_state()); + if (debug) + { + Godot::print(get_current_state() + " exited!"); + } + } + + set_current_state(state); + auto child = Object::cast_to(states[get_current_state()].operator Object*()); + this->add_child(child); + + this->call("_state_enter", previous_state, args); + this->emit_signal("state_entered", get_current_state()); + if (debug) + { + Godot::print(get_current_state() + " entered!"); + } +} + +Variant StateMachine::call(const String method, const Array &args) +{ + auto node = Object::cast_to(states[get_current_state()].operator Object*()); + if (node != nullptr) + { + return node->call(method, args); + } + return Variant(); +} + +Variant StateMachine::_call(const String method, const Array &args) +{ + return this->call(method, args); +} + +void StateMachine::set_default_state(const String default_state) +{ + this->default_state = default_state; +} + +String StateMachine::get_default_state() +{ + return this->default_state; +} + +void StateMachine::set_current_state(const String current_sate) +{ + this->current_state = current_sate; +} + +String StateMachine::get_current_state() +{ + return this->current_state; +} + +void StateMachine::set_debug(bool debug) +{ + this->debug = debug; +} + +bool StateMachine::get_debug() +{ + return this->debug; +} + +void StateMachine::_on_StateMachine_tree_entered() +{ + setup(); +} + +void StateMachine::_on_StateMachine_tree_exiting() +{ + auto keys = states.keys(); + for (uint8_t i = 0; i < keys.size(); i++) + { + auto child = Object::cast_to(states[keys[i]].operator Object*()); + if (child != nullptr) + { + auto children = get_children(); + if (!children.has(child)) + { + this->add_child(child); + } + } + } +} diff --git a/src/state_machine/StateMachine.h b/src/state_machine/StateMachine.h new file mode 100644 index 0000000..02789ba --- /dev/null +++ b/src/state_machine/StateMachine.h @@ -0,0 +1,256 @@ +#ifndef JUEGO_STATE_MACHINE_H +#define JUEGO_STATE_MACHINE_H + +#include +#include + +namespace godot +{ + /** + * @brief This class provides a finite state machine that can be used with any scene and node. + * + */ + class StateMachine : public Node + { + GODOT_CLASS(StateMachine, Node) + + private: + /** + * @brief The parent node which is one level above the state machine. + * + */ + Node *parent; + /** + * @brief The default state for the state machine to run. + * + * @details If this is not set, the state machine will try to run the first state node. + * If no state nodes are present, an error will be printed and the state machine will not work. + */ + String default_state; + /** + * @brief If set to true the state machine will print a message showing when it enters or exits a state. + * + */ + bool debug; + /** + * @brief The current state the machine is in. + * + */ + String current_state; + /** + * @brief A list of the states in the state machine. + * + */ + Dictionary states; + + /** + * @brief This adds a state to the list of states in the state machine. + * + * @param[in] state The new state. + * @param[in] child The godot node which represents the state. + */ + void add_state(const String state, Node *child); + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new State Machine object. + */ + StateMachine(); + + /** + * @brief Destroy the State Machine object. + */ + ~StateMachine(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + void _init(); + + /** + * @brief Code to be run when ready. + * + * @details This method is run when all the children of this node are ready. + */ + void _ready(); + + /** + * @brief This method will remove all no default states from the scene tree and start the default state. + * + */ + void setup(); + + /** + * @brief Check if the given state is the current running state. + * + * @param[in] state The state to compare with the running state. + * @return true If the running state and given state are the same. + * @return false If the running state and given state are not the same. + */ + bool is_current(const String state); + + /** + * @brief Check if the state machine has a given state. + * + * @param[in] state The state to check for. + * @return true If the state exists. + * @return false If the state doesn't exist. + */ + bool has(const String state); + + /** + * @brief Restar the running state by calling its enter and exit methods. + * + * @param[in] state The state that is being restarted. + * @param[in] args The arguments to pass to the state on exit and enter. + */ + void restart(const String state, const Array& args = Array()); + + /** + * @brief Change to a different state. + * + * @details If the running state is the same as the state it will restart it. + * + * @param[in] state The state to change to. + * @param[in] args The arguments to pass to the exiting state and the entering state. + */ + void change(const String state, const Array &args = Array()); + + /** + * @brief Call a registered godot method in the class. + * + * @param[in] method The method name to call. + * @param[in] args The arguments to pass to the method. + * @return Variant Returns a Variant based off what the method returns. + */ + Variant call(const String method, const Array &args = Array()); + + /** + * @brief This method is to link up a signal call back. + * + * @param[in] method The method to call for the signal. + * @param[in] args The arguments to pass to the method. + * @return Variant Returns a Variant based off what the method returns. + */ + Variant _call(const String method, const Array &args = Array()); + + /** + * @brief Set the default state object. + * + * @param[in] default_state The new default state. + */ + void set_default_state(const String default_state); + + /** + * @brief Get the default state object. + * + * @return String The default state. + */ + String get_default_state(); + + /** + * @brief Set the debug object. + * + * @param[in] debug Whether or not to debug. + */ + void set_debug(bool debug); + + /** + * @brief Get the debug object. + * + * @return true If debugging is enabled. + * @return false If debugging is disabled. + */ + bool get_debug(); + + /** + * @brief Set the current state object. + * + * @param[in] current_state The current state that is running. + */ + void set_current_state(const String current_state); + + /** + * @brief Get the current state object. + * + * @return String The current running state. + */ + String get_current_state(); + + /** + * @brief This method is called when the signal tree_entered is emitted. + * + * @details This will run the setup method to prepare the state machine for use. + */ + void _on_StateMachine_tree_entered(); + + /** + * @brief This method is called when the signal tree_exiting is emitted. + * + * @details If the tree is in the exiting state readd all the removed state nodes to the scene tree. + * This is important because the memory won't be freed if they are no longer in the scene tree. + */ + void _on_StateMachine_tree_exiting(); + + /** + * @brief Restarts the running state. + * + * @tparam Args Variable number of arguments to pass to restart. + * @param[in] state The state being restarted. + * @param[in] args The arguments to pass when restarting. + */ + template void restart(const String state, Args ...args) + { + return restart(state, Array::make(args...)); + } + + /** + * @brief Changes to a new state. + * + * @tparam Args Variable number of arguments to pass when chaning states. + * @param[in] state The state to change to. + * @param[in] args The arguments to pass to the new state. + */ + template void change(const String state, Args ...args) + { + return change(state, Array::make(args...)); + } + + /** + * @brief Call a registered godot method in the class. + * + * @tparam Args The variable arguments to pass to the method. + * @param[in] method The method to call. + * @param[in] args The arguments to pass to it. + * @return Variant The Variant object returned by the method called. + */ + template Variant call(const String method, Args ...args) + { + return call(method, Array::make(args...)); + } + + /** + * @brief This is used to connect a callback from a signal. + * + * @tparam Args The arguments to pass to the callback method. + * @param[in] method The method to call. + * @param[in] args The arguments to pass. + * @return Variant The Variant object returned by the method called. + */ + template Variant _call(const String method, Args ...args) + { + return _call(method, Array::make(args...)); + } + }; +} + +#endif