From b84ed691980194f77768484526508041f46d2de8 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Sun, 26 Feb 2023 21:45:25 -0300 Subject: [PATCH] integrate obelisk into alai --- SConstruct | 9 +- godot/Main.tscn | 2 +- godot/alai.kb | Bin 0 -> 81920 bytes godot/characters/enemies/WalkingEnemy.gd | 41 ++-- godot/characters/player/AI.gdns | 8 + godot/characters/player/Player.tscn | 6 +- godot/collectables/coin/Coin.gd | 5 + godot/collectables/coin/Coin.tscn | 5 +- godot/goal/Goal.gd | 5 + godot/goal/Goal.tscn | 7 +- godot/levels/TestLevel.tscn | 10 +- obelisk/include/knowledge_base.h | 292 +++++++++++++++++++++++ obelisk/include/models/action.h | 128 ++++++++++ obelisk/include/models/entity.h | 128 ++++++++++ obelisk/include/models/fact.h | 247 +++++++++++++++++++ obelisk/include/models/rule.h | 163 +++++++++++++ obelisk/include/models/suggest_action.h | 185 ++++++++++++++ obelisk/include/models/verb.h | 126 ++++++++++ obelisk/include/obelisk.h | 82 +++++++ src/Event.cpp | 1 + src/Main.cpp | 5 + src/godot.cpp | 8 +- src/player/AI.cpp | 104 ++++++++ src/player/AI.h | 88 +++++++ 24 files changed, 1619 insertions(+), 36 deletions(-) mode change 100644 => 100755 SConstruct create mode 100644 godot/alai.kb create mode 100644 godot/characters/player/AI.gdns create mode 100644 godot/collectables/coin/Coin.gd create mode 100644 godot/goal/Goal.gd create mode 100644 obelisk/include/knowledge_base.h create mode 100644 obelisk/include/models/action.h create mode 100644 obelisk/include/models/entity.h create mode 100644 obelisk/include/models/fact.h create mode 100644 obelisk/include/models/rule.h create mode 100644 obelisk/include/models/suggest_action.h create mode 100644 obelisk/include/models/verb.h create mode 100644 obelisk/include/obelisk.h create mode 100644 src/player/AI.cpp create mode 100644 src/player/AI.h diff --git a/SConstruct b/SConstruct old mode 100644 new mode 100755 index 27e219b..57e9f0b --- a/SConstruct +++ b/SConstruct @@ -37,6 +37,9 @@ godot_headers_path = "godot-cpp/godot-headers/" cpp_bindings_path = "godot-cpp/" cpp_library = "libgodot-cpp" +obelisk_bindings_path = "obelisk/" +obelisk_library = "libobelisk" + # Updates the environment with the option variables. opts.Update(env) @@ -112,9 +115,9 @@ 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/']) -env.Append(LIBPATH=[cpp_bindings_path + 'bin/']) -env.Append(LIBS=[cpp_library]) +env.Append(CPPPATH=['.', obelisk_bindings_path + 'include/', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/']) +env.Append(LIBPATH=[cpp_bindings_path + 'bin/', obelisk_bindings_path + 'bin/']) +env.Append(LIBS=[cpp_library, obelisk_library]) # tweak this if you want to use different folders, or more folders, to store your source code in. env.Append(CPPPATH=['src/']) diff --git a/godot/Main.tscn b/godot/Main.tscn index b7e3351..2cc9a1b 100644 --- a/godot/Main.tscn +++ b/godot/Main.tscn @@ -8,7 +8,7 @@ [node name="Main" type="Node"] pause_mode = 2 script = ExtResource( 1 ) -game_version = "1.1.0" +game_version = "1.0.0" level = ExtResource( 2 ) [node name="Level" type="Node" parent="."] diff --git a/godot/alai.kb b/godot/alai.kb new file mode 100644 index 0000000000000000000000000000000000000000..c9d78ac69f21d5a08983b7a15cd4fbc21eb8c68b GIT binary patch literal 81920 zcmeI*+ix6K9l-IKIdffKP8`>=tbj6XknEKsgpI^Ygus|hvFg~Zy_WFPYGZGlrJG&q zT?hKWLnt7HM|el@50q!%jUrO1h)bnP1tbJ&L=lJ*s#4O@2YzQ}z4mNlI~O}Qz9a4U z%*>gYGoSf+*6VZGl?5WPBh>5-@aFandnsbzPlQ@ z{)FMn;@p!9>3Nd<3-MC%Y;mc$Fk4(U`-(=c(+@!!LY#Fc=*fvA?~T#QEk{y=q=M8`Eaho{`)eHT%bK zZ|>~<%5PRHt!5+tp}37_zgV1oYNEUSW1r~+LQnAAQ;>E}-gC%I3>{`XZl5j_H2X*Q zPRNWO^GDB&>=iQRhLxwyd}v%Bm~qNvJoYWsmxRLAS`rGTAm-Jd4TYq9hw)IWS1+{7 z)keG4e*WO+)aB~t`P+U1Zq_y~?i~7nfUC92=DE;0cyDHTx}2R^nJ>kk%*N?mh1u>a zmScaTIe&K4O zuRLw$gX8@NW}Gq^2d?aC05yX*2H|j}FW@WisZjEPKJ|*qHr- zod~57kk0+A()RD`E&r%FT&MBzdvux%{L#;j?e&CAucSPk{tPGm+sHhXW)7Zq{n5!u zdo|JOyj{1d&uvv3Yt^1bFXPvrr zKh*R}%G2pjchb3y%u{J*C7&Zg^I2j*UY`DirQgwi(ZAQfkt7oW2q1s}0tg_000Iag zfB*srJd^^Vr>xO-b8GEl=t`<`xmjD!DP^5lYu4*k`4_aKtdn2fy7ZN}DgUp^*|H^F zYUJd4Jbm5LALw`W4gEJsG9iEf0tg_000IagfB*srAb`LlDBvmE_B=CpT{Bn8%pFIm zC`v#7U$gXY^&j-V^_!aZ_mAKmrpO2&fB*srAbowU34|4vSwh&uKE1N!fluU|Cn|9_?btY6nZlLaOO5I_I{1Q0*~0R#|0 z009ILcz^=OeO0it0}!d4r^f8GSHBlJYQ#1pQaFLDMj|sRO{ip*8O9@!az{}zT!k%r zq$4rpO#lC!zG~_J=(qHrr2qdl{bT*2{(=6ktYks}0R#|0009ILKmY**5I_Kd!xac} z${P7WPce2;N(WLz8wydbFk;r2_WwCE{$IEMzy71N z0(e#bl92!p_Xcw`1Q0*~0R#|0009ILKmY**?p46_=g&z)0NaitGY@4zK-&)FzXG=H z`)0mh|Nor+j-|h+Z^{?|Kh!Vle@Z`qAL*aSN+tvlKmY**5I_I{1Q0*~0R#{@WPwoH z>6`lhoaw9It^beAQn&s;%t_1rwEjOZ8@l!XzS-N<|9e`U+V1sl>i=Dnty}-E(rop0 zCy?#|rvBfw|9AAiEd8F$m=Hh!0R#|0009ILKmY**5J2GZ5b&i7!0=k7;YkmGp<2td z|9AAeN&ElD;{v$~1Q0*~0R#|0009ILKmY**5J&|~kAR);|8w-)mVR5mj}8I|Ab=ypHzz~@0R#|0009ILKmY**5I_KdqZaUNS9%I0?f-54 zfwccW>JxH&1Q0*~0R#|0009ILKmY**5O@#*N=1?B|8L9C|BU|sAnpL?L;wK<5I_I{ z1Q0*~0R#|0;HU*Wcf0++(r void: - if direction == 1: - $AnimatedSprite.flip_h = true - $FloorChecker.position.x = $CollisionShape2D.shape.get_extents().x * direction - $FloorChecker.enabled = detect_edges - Event.connect("level_loaded", self, "_on_level_loaded") + if direction == 1: + $AnimatedSprite.flip_h = true + $FloorChecker.position.x = $CollisionShape2D.shape.get_extents().x * direction + $FloorChecker.enabled = detect_edges + Event.connect("level_loaded", self, "_on_level_loaded") func _physics_process(_delta: float) -> void: - if is_on_wall() or not $FloorChecker.is_colliding() and is_on_floor() and $FloorChecker.enabled: - direction *= -1 - $AnimatedSprite.flip_h = not $AnimatedSprite.flip_h - $FloorChecker.position.x = $CollisionShape2D.shape.get_extents().x * direction + if is_on_wall() or not $FloorChecker.is_colliding() and is_on_floor() and $FloorChecker.enabled: + direction *= -1 + $AnimatedSprite.flip_h = not $AnimatedSprite.flip_h + $FloorChecker.position.x = $CollisionShape2D.shape.get_extents().x * direction - velocity.y += gravity - velocity.x = speed * direction - velocity = move_and_slide(velocity, Vector2.UP) + velocity.y += gravity + velocity.x = speed * direction + velocity = move_and_slide(velocity, Vector2.UP) - for i in get_slide_count(): - var collision = get_slide_collision(i) - if collision.collider.name == "Player": - Event.emit_signal("player_touched", 3) + for i in get_slide_count(): + var collision = get_slide_collision(i) + if collision.collider.name == "Player": + Event.emit_signal("player_touched", 3) - Event.emit_signal("object_updated", self.get_name(), "Walking", global_position, velocity) + Event.emit_signal("object_updated", self.get_name(), "Walking", global_position, velocity) + Event.emit_signal("report_object", self.get_name(), "Walking", global_position, velocity) func squash() -> void: - Event.emit_signal("object_removed", self.get_name()) - queue_free() + Event.emit_signal("object_removed", self.get_name()) + queue_free() func _on_level_loaded() -> void: - Event.emit_signal("object_created", self.get_name(), "Walking", global_position, Vector2(0, 0)) + Event.emit_signal("object_created", self.get_name(), "Walking", global_position, Vector2(0, 0)) diff --git a/godot/characters/player/AI.gdns b/godot/characters/player/AI.gdns new file mode 100644 index 0000000..9ac28b0 --- /dev/null +++ b/godot/characters/player/AI.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 = "AI" +class_name = "AI" +library = ExtResource( 1 ) diff --git a/godot/characters/player/Player.tscn b/godot/characters/player/Player.tscn index 5ac8d15..471d986 100644 --- a/godot/characters/player/Player.tscn +++ b/godot/characters/player/Player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=10 format=2] +[gd_scene load_steps=11 format=2] [ext_resource path="res://characters/player/sprites/green.tres" type="SpriteFrames" id=1] [ext_resource path="res://characters/player/states/Idle.gdns" type="Script" id=2] @@ -8,6 +8,7 @@ [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] [ext_resource path="res://assets/sounds/jump.wav" type="AudioStream" id=8] +[ext_resource path="res://characters/player/AI.gdns" type="Script" id=9] [sub_resource type="RectangleShape2D" id=1] extents = Vector2( 7, 12 ) @@ -16,6 +17,9 @@ extents = Vector2( 7, 12 ) collision_mask = 10 script = ExtResource( 5 ) +[node name="AI" type="Node" parent="."] +script = ExtResource( 9 ) + [node name="AnimatedSprite" type="AnimatedSprite" parent="."] frames = ExtResource( 1 ) animation = "idle" diff --git a/godot/collectables/coin/Coin.gd b/godot/collectables/coin/Coin.gd new file mode 100644 index 0000000..7ab13fe --- /dev/null +++ b/godot/collectables/coin/Coin.gd @@ -0,0 +1,5 @@ +extends Area2D + + +func _process(_delta: float) -> void: + Event.emit_signal("report_object", self.get_name(), "not collected", global_position, Vector2()) diff --git a/godot/collectables/coin/Coin.tscn b/godot/collectables/coin/Coin.tscn index 1c40bc1..7dd7f88 100644 --- a/godot/collectables/coin/Coin.tscn +++ b/godot/collectables/coin/Coin.tscn @@ -1,10 +1,11 @@ -[gd_scene load_steps=11 format=2] +[gd_scene load_steps=12 format=2] [ext_resource path="res://assets/coin.png" type="Texture" id=1] [ext_resource path="res://state_machine/StateMachine.gdns" type="Script" id=2] [ext_resource path="res://collectables/coin/states/CoinNotCollected.gdns" type="Script" id=3] [ext_resource path="res://collectables/coin/states/CoinCollected.gdns" type="Script" id=4] [ext_resource path="res://assets/sounds/coin.wav" type="AudioStream" id=5] +[ext_resource path="res://collectables/coin/Coin.gd" type="Script" id=6] [sub_resource type="CircleShape2D" id=1] radius = 6.0 @@ -43,6 +44,7 @@ tracks/0/keys = { [node name="Coin" type="Area2D"] collision_layer = 4 +script = ExtResource( 6 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="."] position = Vector2( 9, 9 ) @@ -51,7 +53,6 @@ shape = SubResource( 1 ) [node name="AnimatedSprite" type="AnimatedSprite" parent="."] frames = SubResource( 4 ) animation = "spin" -frame = 1 playing = true centered = false diff --git a/godot/goal/Goal.gd b/godot/goal/Goal.gd new file mode 100644 index 0000000..f9aa6db --- /dev/null +++ b/godot/goal/Goal.gd @@ -0,0 +1,5 @@ +extends Area2D + + +func _process(_delta: float) -> void: + Event.emit_signal("report_object", self.get_name(), "not touched", global_position, Vector2()) diff --git a/godot/goal/Goal.tscn b/godot/goal/Goal.tscn index ee70903..e2b005a 100644 --- a/godot/goal/Goal.tscn +++ b/godot/goal/Goal.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=9 format=2] +[gd_scene load_steps=10 format=2] [ext_resource path="res://assets/flag.png" type="Texture" id=1] [ext_resource path="res://goal/GoalNotReached.gdns" type="Script" id=2] [ext_resource path="res://goal/GoalReached.gdns" type="Script" id=3] [ext_resource path="res://state_machine/StateMachine.gdns" type="Script" id=4] +[ext_resource path="res://goal/Goal.gd" type="Script" id=5] [sub_resource type="RectangleShape2D" id=5] extents = Vector2( 10, 18 ) @@ -25,15 +26,13 @@ animations = [ { } ] [node name="Goal" type="Area2D"] -position = Vector2( 324, 378 ) collision_layer = 32 +script = ExtResource( 5 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="."] -position = Vector2( 18, 18 ) shape = SubResource( 5 ) [node name="AnimatedSprite" type="AnimatedSprite" parent="."] -position = Vector2( 18, 18 ) frames = SubResource( 8 ) animation = "flagmove" playing = true diff --git a/godot/levels/TestLevel.tscn b/godot/levels/TestLevel.tscn index d261917..3503d69 100644 --- a/godot/levels/TestLevel.tscn +++ b/godot/levels/TestLevel.tscn @@ -13,7 +13,7 @@ [node name="TestLevel" type="Node2D"] [node name="Player" parent="." instance=ExtResource( 5 )] -position = Vector2( 36, 444 ) +position = Vector2( 36, 498 ) collision_layer = 5 [node name="Camera2D" type="Camera2D" parent="Player"] @@ -63,15 +63,21 @@ position = Vector2( 216, 504 ) [node name="Coin8" parent="Coins" instance=ExtResource( 2 )] position = Vector2( 459, 468 ) +[node name="Coin9" parent="Coins" instance=ExtResource( 2 )] +position = Vector2( 560, 468 ) + [node name="BGM" type="AudioStreamPlayer" parent="."] stream = ExtResource( 6 ) volume_db = -25.0 autoplay = true [node name="Goal" parent="." instance=ExtResource( 3 )] -position = Vector2( 621, 486 ) +position = Vector2( 656, 504 ) [node name="Enemies" type="Node" parent="."] [node name="Shelly" parent="Enemies" instance=ExtResource( 1 )] position = Vector2( 379, 510 ) + +[node name="Shelly2" parent="Enemies" instance=ExtResource( 1 )] +position = Vector2( 628, 510 ) diff --git a/obelisk/include/knowledge_base.h b/obelisk/include/knowledge_base.h new file mode 100644 index 0000000..4930033 --- /dev/null +++ b/obelisk/include/knowledge_base.h @@ -0,0 +1,292 @@ +#ifndef OBELISK_KNOWLEDGE_BASE_H +#define OBELISK_KNOWLEDGE_BASE_H + +#include "models/action.h" +#include "models/entity.h" +#include "models/fact.h" +#include "models/rule.h" +#include "models/suggest_action.h" +#include "models/verb.h" + +#include + +#include +#include +#include +#include + +namespace obelisk +{ + /** + * @brief The KnowledgeBase class represents a collection of facts, rules, + * actions, and related language connectors. + * + */ + class KnowledgeBase + { + private: + /** + * @brief The filename of the opened KnowledgeBase. + * + */ + const char* filename_; + + /** + * @brief The SQLite connection handle. + * + */ + sqlite3* dbConnection_ = nullptr; + + /** + * @brief The user passed flags to use when opening the database. + * + */ + int flags_; + + /** + * @brief Enable foreign key functionality in the open database. + * + * This must always be done when the connection is opened or it will + * not enforce the foreign key constraints. + */ + void enableForeignKeys(); + + /** + * @brief Create the tables in the database. + * + * @param[in] function This function is called to create the table. + */ + void createTable(std::function function); + + public: + /** + * @brief Construct a new KnowledgeBase object. + * + * @param[in] filename The name of the file to save the knowledge + * base as. + * @param[in] flags The flags to open the KnowledgeBase with. + */ + KnowledgeBase(const char* filename, int flags); + + /** + * @brief Construct a new KnowledgeBase object. + * + * @param[in] filename The name of the file to save the knowledge + * base as. + */ + KnowledgeBase(const char* filename) : + KnowledgeBase(filename, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) + { + } + + /** + * @brief Destroy the KnowledgeBase object. + * + * This will close the opened KnowledgeBase before destroying it. + */ + ~KnowledgeBase(); + + /** + * @brief Add entities to the KnowledgeBase. + * + * @param[in,out] entities The entities to add. If the insert is + * successful it will have a row ID, if not the ID will be 0. + */ + void addEntities(std::vector& entities); + + /** + * @brief Add verbs to the KnowledgeBase. + * + * @param[in,out] verbs The verbs to add. If the insert is + * successful it will have a row ID, if not the ID will be 0. + */ + void addVerbs(std::vector& verbs); + + /** + * @brief Add actions to the KnowledgeBase. + * + * @param[in,out] actions The actions to add. If the insert is + * successful it will have a row ID, if nto the ID will be 0. + */ + void addActions(std::vector& actions); + + /** + * @brief Add facts to the KnowledgeBase. + * + * @param[in,out] facts The facts to add. If the insert is + * successful it will have a row ID, if not the ID will be 0. + */ + void addFacts(std::vector& facts); + + /** + * @brief Add suggested actions to the KnowledgeBase. + * + * @param[in,out] suggestActions The suggested actions to add. If + * the insert is successful it will have a row ID, if not the ID + * will be 0. + */ + void addSuggestActions( + std::vector& suggestActions); + + /** + * @brief Add rules to the KnowledgeBase. + * + * @param[in,out] rules The rules to add. If the insert is + * successful it will have a row ID, if not the ID will be 0. + */ + void addRules(std::vector& rules); + + /** + * @brief Get an Entity object based on the ID it contains. + * + * @param[in,out] entity The Entity object should contain just the + * ID and the rest will be filled in. + */ + void getEntity(obelisk::Entity& entity); + + /** + * @brief Get a Verb object based on the ID it contains. + * + * @param[in,out] verb The Verb object should contain just the ID + * and the rest will be filled in. + */ + void getVerb(obelisk::Verb& verb); + + /** + * @brief Get an Action based on the ID it contains. + * + * @param[in] action The Action object should contain just the ID + * and the rest will be filled in. + */ + void getAction(obelisk::Action& action); + + /** + * @brief Get a Fact object based on the ID it contains. + * + * @param[in,out] fact The Fact object should contain just the ID + * and the rest will be filled in. + */ + void getFact(obelisk::Fact& fact); + + /** + * @brief Get a SuggestAction based on the ID it contains. + * + * @param[in,out] suggestAction The SuggestAction object should + * contain just the ID and the rest will be filled in. + */ + void getSuggestAction(obelisk::SuggestAction& suggestAction); + + /** + * @brief Get a Rule based on the ID it contains. + * + * @param[in,out] rule The Rule object should contain just the ID + * and the rest will be filled in. + */ + void getRule(obelisk::Rule& rule); + + /** + * @brief Check if a rule looks for this Fact, if so update its + * truth. + * + * @param[in,out] fact The Fact to check for existing rules. + */ + void checkRule(obelisk::Fact& fact); + + /** + * @brief Update the is true field in the KnowledgeBase. + * + * @param[in,out] fact The fact to update. + */ + void updateIsTrue(obelisk::Fact& fact); + + /** + * @brief Query the KnowledgeBase to see if a Fact is true or false. + * + * @param[in] fact The Fact to check. + */ + void queryFact(obelisk::Fact& fact); + + /** + * @brief Query the KnowledgeBase to get a suggested action based + * on a Fact. + * If a SuggestAction doesn't exist, it will return an empty Action. + * + * @param[in] fact The Fact to search for. + * @param[out] action The Action that is suggested to take. + */ + void querySuggestAction(obelisk::Fact& fact, + obelisk::Action& action); + + /** + * @brief Take a float and divide it into 2 floats. + * + * This is useful to store doubles in SQLite since SQLite doesn't + * have a double type. Instead just store the 2 floats in the + * database. Then after selecting them combine them. + * + * @param[out] result1 The first float generated from the double. + * @param[out] result2 The second float generated from the double. + * @param[in] var The double to split into the 2 floats. + */ + void getFloat(float& result1, float& result2, double var); + + /** + * @brief Combines 2 separated floats back into a double. + * + * This will recombine the separated floats from the getFloat + * method. + * + * @param[out] result The double generated from the combined floats. + * @param[in] var1 The first float to combine. + * @param[in] var2 The second float to combine. + */ + void getDouble(double& result, float var1, float var2); + }; + + /** + * @brief Exception thrown by the KnowledgeBase. + * + */ + class KnowledgeBaseException : public std::exception + { + private: + /** + * @brief The error message given. + * + */ + const std::string errorMessage_; + + public: + /** + * @brief Construct a new KnowledgeBaseException object. + * + */ + KnowledgeBaseException() : + errorMessage_("an unknown error ocurred") + { + } + + /** + * @brief Construct a new KnowledgeBaseException object. + * + * @param[in] errorMessage The error message given when thrown. + */ + KnowledgeBaseException(const std::string& errorMessage) : + errorMessage_(errorMessage) + { + } + + /** + * @brief Get the error message that occurred. + * + * @return const char* Returns the error message. + */ + const char* what() const noexcept + { + return errorMessage_.c_str(); + } + }; +} // namespace obelisk + +#endif diff --git a/obelisk/include/models/action.h b/obelisk/include/models/action.h new file mode 100644 index 0000000..2d06c03 --- /dev/null +++ b/obelisk/include/models/action.h @@ -0,0 +1,128 @@ +#ifndef OBELISK_MODELS_ACTION_H +#define OBELISK_MODELS_ACTION_H + +#include + +#include + +namespace obelisk +{ + /** + * @brief The Action model represents an action to take when a fact is true + * or false. + * + */ + class Action + { + private: + /** + * @brief The ID of the Action in the KnowledgeBase. + * + */ + int id_; + + /** + * @brief The name of the Action. + * + */ + std::string name_; + + public: + /** + * @brief Construct a new Action object. + * + */ + Action() : + id_(0), + name_("") + { + } + + /** + * @brief Construct a new Action object. + * + * @param[in] id The ID of the Action. + */ + Action(int id) : + id_(id), + name_("") + { + } + + /** + * @brief Construct a new Action object. + * + * @param[in] name The name of the Action. + */ + Action(std::string name) : + id_(0), + name_(name) + { + } + + /** + * @brief Construct a new Action object. + * + * @param[in] id The ID of the Action. + * @param[in] name The name of the Action. + */ + Action(int id, std::string name) : + id_(id), + name_(name) + { + } + + /** + * @brief Create the Action table in the KnowledgeBase. + * + * @return const char* Returns the query used to create the table. + */ + static const char* createTable(); + + /** + * @brief Get the ID of the Action. + * + * @return int& Returns the ID. + */ + int& getId(); + + /** + * @brief Set the ID of the Action. + * + * @param[in] id Set the ID of the Action. + */ + void setId(int id); + + /** + * @brief Get the name of the Action. + * + * @return std::string& The Action name. + */ + std::string& getName(); + + /** + * @brief Set the name of the Action. + * + * @param[in] name The name of the Action. + */ + void setName(std::string name); + + /** + * @brief Select an Action from the datbase based on the object + * name. + * + * @param[in] dbConnection The database connection to use. + */ + void selectByName(sqlite3* dbConnection); + + /** + * @brief Insert an Action into the KnowledgeBase based on the + * object's fields. + * + * @param[in] dbConnection The database connection to use. + */ + void insert(sqlite3* dbConnection); + }; +} // namespace obelisk + +#endif diff --git a/obelisk/include/models/entity.h b/obelisk/include/models/entity.h new file mode 100644 index 0000000..0241575 --- /dev/null +++ b/obelisk/include/models/entity.h @@ -0,0 +1,128 @@ +#ifndef OBELISK_MODELS_ENTITY_H +#define OBELISK_MODELS_ENTITY_H + +#include + +#include + +namespace obelisk +{ + /** + * @brief The Entity model represents either a left or right side entity, + * typically used in facts and rules. + * + */ + class Entity + { + private: + /** + * @brief The ID of the Entity in the KnowledgeBase. + * + */ + int id_; + + /** + * @brief The name of the Entity. + * + */ + std::string name_; + + public: + /** + * @brief Construct a new Entity object. + * + */ + Entity() : + id_(0), + name_("") + { + } + + /** + * @brief Construct a new Entity object. + * + * @param[in] id The ID of the Entity. + */ + Entity(int id) : + id_(id), + name_("") + { + } + + /** + * @brief Construct a new Entity object. + * + * @param[in] name The name of the Entity. + */ + Entity(std::string name) : + id_(0), + name_(name) + { + } + + /** + * @brief Construct a new Entity object. + * + * @param[in] id The ID of the Entity. + * @param[in] name The name of the Entity. + */ + Entity(int id, std::string name) : + id_(id), + name_(name) + { + } + + /** + * @brief Create the table in the KnowledgeBase. + * + * @return const char* Returns the query used to create the table. + */ + static const char* createTable(); + + /** + * @brief Get the ID of the Entity. + * + * @return int& Returns the ID. + */ + int& getId(); + + /** + * @brief Set the ID of the Entity. + * + * @param[in] id The ID of the Entity. + */ + void setId(int id); + + /** + * @brief Get the name of the Entity. + * + * @return std::string& The name of the Entity. + */ + std::string& getName(); + + /** + * @brief Set the name of the Entity. + * + * @param[in] name The name of the Entity. + */ + void setName(std::string name); + + /** + * @brief Select an Entity from the KnowledgeBase based on the + * object's name. + * + * @param[in] dbConnection The database connection to use. + */ + void selectByName(sqlite3* dbConnection); + + /** + * @brief Insert an Entity into the KnowledgeBase based on the + * object's fields. + * + * @param[in] dbConnection The database connection to use. + */ + void insert(sqlite3* dbConnection); + }; +} // namespace obelisk + +#endif diff --git a/obelisk/include/models/fact.h b/obelisk/include/models/fact.h new file mode 100644 index 0000000..21810b2 --- /dev/null +++ b/obelisk/include/models/fact.h @@ -0,0 +1,247 @@ +#ifndef OBELISK_MODELS_FACT_H +#define OBELISK_MODELS_FACT_H + +#include "models/action.h" +#include "models/entity.h" +#include "models/fact.h" +#include "models/verb.h" + +#include + +namespace obelisk +{ + /** + * @brief The Fact model represents truth in the releationship between two + * entities separated by a verb. + * + */ + class Fact + { + private: + /** + * @brief The ID of the Fact in the KnowledgeBase. + * + */ + int id_; + + /** + * @brief The Entity from the left side of the expression. + * + */ + obelisk::Entity leftEntity_; + + /** + * @brief The Entity from the right side of the expression. + * + */ + obelisk::Entity rightEntity_; + + /** + * @brief The Verb that represents the relationship in the + * expression. + * + */ + obelisk::Verb verb_; + + /** + * @brief Whether or not the fact is considered true or not. + * + */ + double isTrue_; + + public: + /** + * @brief Construct a new Fact object. + * + */ + Fact() : + id_(0), + leftEntity_(), + rightEntity_(), + verb_(), + isTrue_(0) + { + } + + /** + * @brief Construct a new Fact object. + * + * @param[in] id The ID of the Fact in the KnowledgeBase. + */ + Fact(int id) : + id_(id), + leftEntity_(), + rightEntity_(), + verb_(), + isTrue_(0) + { + } + + /** + * @brief Construct a new Fact object. + * + * @param[in] leftEntity The Entity on the left side of the + * expression. + * @param[in] rightEntity The Entity on the right side of the + * expression. + * @param[in] verb The Verb separating the entities. + * @param[in] isTrue Whether or not the fact is true. + */ + Fact(obelisk::Entity leftEntity, + obelisk::Entity rightEntity, + obelisk::Verb verb, + double isTrue = 0) : + id_(0), + leftEntity_(leftEntity), + rightEntity_(rightEntity), + verb_(verb), + isTrue_(isTrue) + { + } + + /** + * @brief Construct a new Fact object. + * + * @param[in] id The ID of the Fact in the KnowledgeBase. + * @param[in] leftEntity The Entity on the left side of the + * expression. + * @param[in] rightEntity The Entity on the right side of the + * expression. + * @param[in] verb The Verb separating the entities. + * @param[in] isTrue Whether or not the fact is true. + */ + Fact(int id, + obelisk::Entity leftEntity, + obelisk::Entity rightEntity, + obelisk::Verb verb, + double isTrue = 0) : + id_(id), + leftEntity_(leftEntity), + rightEntity_(rightEntity), + verb_(verb), + isTrue_(isTrue) + { + } + + /** + * @brief Create the Fact table in the KnowledgeBase. + * + * @return const char* Returns the query used to create the table. + */ + static const char* createTable(); + + /** + * @brief Get the ID of the Fact + * + * @return int& Returns the ID. + */ + int& getId(); + + /** + * @brief Set the ID of the Fact. + * + * @param[in] id Set the ID of the Fact. + */ + void setId(int id); + + /** + * @brief Get the left Entity object. + * + * @return Entity& The left Entity. + */ + Entity& getLeftEntity(); + + /** + * @brief Set the left Entity object. + * + * @param[in] leftEntity The left Entity to set. + */ + void setLeftEntity(obelisk::Entity leftEntity); + + /** + * @brief Get the right Entity object. + * + * @return Entity& The right Entity. + */ + Entity& getRightEntity(); + + /** + * @brief Set the right Entity object. + * + * @param[in] rightEntity The right Entity to set. + */ + void setRightEntity(obelisk::Entity rightEntity); + + /** + * @brief Get the Verb object. + * + * @return Verb& The Verb. + */ + Verb& getVerb(); + + /** + * @brief Set the Verb object. + * + * @param[in] verb The Verb. + */ + void setVerb(obelisk::Verb verb); + + /** + * @brief Gets the isTrue value. + * + * @return true If the Fact is considered true. + * @return false If the Fact is considered false. + */ + double& getIsTrue(); + + /** + * @brief Set the Fact as true or false. + * + * @param[in] isTrue Whether or not the Fact is true. + */ + void setIsTrue(double isTrue); + + /** + * @brief Select the Fact from the KnowledgeBase by IDs of the + * sub-objects. + * + * @param[in] dbConnection The database connection to use. + */ + void selectById(sqlite3* dbConnection); + + /** + * @brief Select the Fact from the KnowledgeBase by the name's of + * the entities and verb. + * + * @param[in] dbConnection The database connection to use. + */ + void selectByName(sqlite3* dbConnection); + + /** + * @brief Select an Action from the KnowledgeBase using the provided + * Fact. + * + * @param[in] dbConnection The database connection to use. + * @param[out] action The Action to take based on the provided fact. + */ + void selectActionByFact(sqlite3* dbConnection, + obelisk::Action& action); + + /** + * @brief Insert the Fact into the KnowledgeBase. + * + * @param[in] dbConnection The database connection to use. + */ + void insert(sqlite3* dbConnection); + + /** + * @brief Update whether or not the fact is true in the + * KnowledgeBase. + * + * @param[in] dbConnection The database connection. + */ + void updateIsTrue(sqlite3* dbConnection); + }; +} // namespace obelisk + +#endif diff --git a/obelisk/include/models/rule.h b/obelisk/include/models/rule.h new file mode 100644 index 0000000..efbdced --- /dev/null +++ b/obelisk/include/models/rule.h @@ -0,0 +1,163 @@ +#ifndef OBELISK_MODELS_RULE_H +#define OBELISK_MODELS_RULE_H + +#include "models/fact.h" + +#include +#include + +namespace obelisk +{ + /** + * @brief The Rule model represents a truth relation between 2 Facts. + * + */ + class Rule + { + private: + /** + * @brief The ID of the Rule in the KnowledgeBase. + * + */ + int id_; + + /** + * @brief The Fact that depends on the Fact reason being true. + * + */ + obelisk::Fact fact_; + + /** + * @brief The Fact that makes the other Fact true or false. + * + */ + obelisk::Fact reason_; + + public: + /** + * @brief Construct a new Rule object. + * + */ + Rule() : + id_(0), + fact_(), + reason_() + { + } + + /** + * @brief Construct a new Rule object. + * + * @param[in] id The ID of the Rule in the KnowledgeBase. + */ + Rule(int id) : + id_(id), + fact_(), + reason_() + { + } + + /** + * @brief Construct a new Rule object. + * + * @param[in] fact The Fact. + * @param[in] reason The reason Fact. + */ + Rule(obelisk::Fact fact, obelisk::Fact reason) : + id_(0), + fact_(fact), + reason_(reason) + { + } + + /** + * @brief Construct a new Rule object. + * + * @param[in] id The ID of the Rule. + * @param[in] fact The Fact. + * @param[in] reason The reason Fact. + */ + Rule(int id, obelisk::Fact fact, obelisk::Fact reason) : + id_(id), + fact_(fact), + reason_(reason) + { + } + + /** + * @brief Create the Rule table in the KnowledgeBase. + * + * @return const char* Returns the query used to create the table. + */ + static const char* createTable(); + + /** + * @brief Get the ID of the Rule. + * + * @return int& The ID. + */ + int& getId(); + + /** + * @brief Set the ID of the Rule. + * + * @param[in] id The ID. + */ + void setId(int id); + + /** + * @brief Get the Fact object. + * + * @return obelisk::Fact& The Fact. + */ + obelisk::Fact& getFact(); + + /** + * @brief Set the Fact object. + * + * @param[in] fact The Fact. + */ + void setFact(obelisk::Fact fact); + + /** + * @brief Get the reason Fact object. + * + * @return obelisk::Fact& The reason Fact. + */ + obelisk::Fact& getReason(); + + /** + * @brief Set the reason Fact object. + * + * @param[in] reason The reason Fact. + */ + void setReason(obelisk::Fact reason); + + /** + * @brief Select the Rule from the KnowledgeBase by IDs of the + * sub-objects. + * + * @param[in] dbConnection The database connection to use. + */ + void selectById(sqlite3* dbConnection); + + /** + * @brief Get the rules that match the reason. + * + * @param[in] dbConnection The database connection to use. + * @param[out] rules The rules to fill in from the database. + */ + static void selectByReason(sqlite3* dbConnection, + int reasonId, + std::vector& rules); + + /** + * @brief Insert the Rule into the KnowledgeBase. + * + * @param[in] dbConnection The database connection to use. + */ + void insert(sqlite3* dbConnection); + }; +} // namespace obelisk + +#endif diff --git a/obelisk/include/models/suggest_action.h b/obelisk/include/models/suggest_action.h new file mode 100644 index 0000000..16d123e --- /dev/null +++ b/obelisk/include/models/suggest_action.h @@ -0,0 +1,185 @@ +#ifndef OBELISK_MODELS_SUGGEST_ACTION_H +#define OBELISK_MODELS_SUGGEST_ACTION_H + +#include "models/action.h" +#include "models/fact.h" + +#include + +namespace obelisk +{ + /** + * @brief The SuggestAction model representas the actions to take depending + * on if the Fact is true or false. + * + */ + class SuggestAction + { + private: + /** + * @brief The ID of the SuggestAction. + * + */ + int id_; + + /** + * @brief The Fact to check the truth of. + * + */ + obelisk::Fact fact_; + + /** + * @brief The Action to take if the Fact is true. + * + */ + obelisk::Action trueAction_; + + /** + * @brief The Action to take if the Fact is false. + * + */ + obelisk::Action falseAction_; + + public: + /** + * @brief Construct a new SuggestAction object. + * + */ + SuggestAction() : + id_(0), + fact_(), + trueAction_(), + falseAction_() + { + } + + /** + * @brief Construct a new SuggestAction object. + * + * @param[in] id The ID of the SuggestAction in the KnowledgeBase. + */ + SuggestAction(int id) : + id_(id), + fact_(), + trueAction_(), + falseAction_() + { + } + + /** + * @brief Construct a new SuggestAction object. + * + * @param[in] fact The Fact. + * @param[in] trueAction The true Action. + * @param[in] falseAction The false Action. + */ + SuggestAction(obelisk::Fact fact, + obelisk::Action trueAction, + obelisk::Action falseAction) : + id_(0), + fact_(fact), + trueAction_(trueAction), + falseAction_(falseAction) + { + } + + /** + * @brief Construct a new SuggestAction object. + * + * @param[in] id The ID of the SuggestAction in the KnowledgeBase. + * @param[in] fact The Fact. + * @param[in] trueAction The true Action. + * @param[in] falseAction The false Action. + */ + SuggestAction(int id, + obelisk::Fact fact, + obelisk::Action trueAction, + obelisk::Action falseAction) : + id_(id), + fact_(fact), + trueAction_(trueAction), + falseAction_(falseAction) + { + } + + /** + * @brief Create the SuggestAction table in the database. + * + * @return const char* Returns the query used to create the table. + */ + static const char* createTable(); + + /** + * @brief Get the ID of the SuggestAction. + * + * @return int& Returns the ID. + */ + int& getId(); + + /** + * @brief Set the ID of the SuggestAction. + * + * @param[in] id The new ID. + */ + void setId(int id); + + /** + * @brief Get the Fact object. + * + * @return obelisk::Fact& Returns the Fact. + */ + obelisk::Fact& getFact(); + + /** + * @brief Set the Fact object. + * + * @param[in] fact The new Fact. + */ + void setFact(obelisk::Fact fact); + + /** + * @brief Get the true Action object. + * + * @return obelisk::Action& Returns the true Action. + */ + obelisk::Action& getTrueAction(); + + /** + * @brief Set the true Action object. + * + * @param[in] trueAction The new true Action. + */ + void setTrueAction(obelisk::Action trueAction); + + /** + * @brief Get the false Action object. + * + * @return obelisk::Action& Returns the false Action. + */ + obelisk::Action& getFalseAction(); + + /** + * @brief Set the false Action object. + * + * @param[in] falseAction The new false Action. + */ + void setFalseAction(obelisk::Action falseAction); + + /** + * @brief Select the SuggestAction from the KnowledgeBase by IDs of + * the sub-objects. + * + * @param[in] dbConnection The database connection to use. + */ + void selectById(sqlite3* dbConnection); + + /** + * @brief Insert the SuggestAction into the KnowledgeBase. + * + * @param[in] dbConnection The database connection to use. + */ + void insert(sqlite3* dbConnection); + }; +} // namespace obelisk + +#endif diff --git a/obelisk/include/models/verb.h b/obelisk/include/models/verb.h new file mode 100644 index 0000000..150e86f --- /dev/null +++ b/obelisk/include/models/verb.h @@ -0,0 +1,126 @@ +#ifndef OBELISK_MODELS_VERB_H +#define OBELISK_MODELS_VERB_H + +#include + +#include + +namespace obelisk +{ + /** + * @brief The Verb model represents a verb which is used to connnect + * entities. + * + */ + class Verb + { + private: + /** + * @brief The ID of the Verb in the KnowledgeBase. + * + */ + int id_; + + /** + * @brief The name of the Verb. + * + */ + std::string name_; + + public: + /** + * @brief Construct a new Verb object. + * + */ + Verb() : + id_(0), + name_("") + { + } + + /** + * @brief Construct a new Verb object. + * + * @param[in] id The ID of the Verb. + */ + Verb(int id) : + id_(id), + name_("") + { + } + + /** + * @brief Construct a new Verb object. + * + * @param[in] name The name of the Verb. + */ + Verb(std::string name) : + id_(0), + name_(name) + { + } + + /** + * @brief Construct a new Verb object. + * + * @param[in] id The ID of the Verb. + * @param[in] name The name of the Verb. + */ + Verb(int id, std::string name) : + id_(id), + name_(name) + { + } + + /** + * @brief Create the Verb table in the KnowledgeBase. + * + * @return const char* Returns the query used to create the table. + */ + static const char* createTable(); + + /** + * @brief Get the ID of the Verb. + * + * @return int& Returns the ID. + */ + int& getId(); + + /** + * @brief Set the ID of the Verb. + * + * @param[in] id Set the ID of the Verb. + */ + void setId(int id); + + /** + * @brief Get the name of the Verb. + * + * @return std::string& The Verb name. + */ + std::string& getName(); + + /** + * @brief Set the name of the Verb. + * + * @param[in] name The Verb name. + */ + void setName(std::string name); + + /** + * @brief Select a verb by name from the KnowledgeBase. + * + * @param[in] dbConnection The database connection to use. + */ + void selectByName(sqlite3* dbConnection); + + /** + * @brief Insert a new verb into the KnowledgeBase. + * + * @param[in] dbConnection The database connection to use. + */ + void insert(sqlite3* dbConnection); + }; +} // namespace obelisk + +#endif diff --git a/obelisk/include/obelisk.h b/obelisk/include/obelisk.h new file mode 100644 index 0000000..1e434bc --- /dev/null +++ b/obelisk/include/obelisk.h @@ -0,0 +1,82 @@ +#ifndef OBELISK_INCLUDE_OBELISK_H +#define OBELISK_INCLUDE_OBELISK_H + +#include "knowledge_base.h" + +#include +#include + +/** + * @brief The obelisk namespace contains everything needed to compile obelisk + * code. + * + */ +namespace obelisk +{ + /** + * @brief The obelisk library provides everything needed to consult the + * KnowledgeBase. + * + */ + class Obelisk + { + private: + std::unique_ptr kb_; + + public: + /** + * @brief Construct a new Obelisk object. + * + */ + Obelisk(std::string filename); + + /** + * @brief Destroy the Obelisk object. + * + */ + ~Obelisk() = default; + + /** + * @brief Get the obelisk version. + * + * @return std::string The version. + */ + std::string getVersion(); + + /** + * @brief Get the obelisk library so version. + * + * @return int The version. + */ + int getLibVersion(); + + /** + * @brief Query the obelisk KnowledgeBase to see if a Fact is true + * or not. + * + * @param[in] p_obelisk The obelisk object pointer. + * @param[in] left_entity The left entity. + * @param[in] verb The verb. + * @param[in] right_entity The right entity. + * @return double Returns whether or not the Fact is true. + */ + double query(const std::string& leftEntity, + const std::string& verb, + const std::string& rightEntity); + + /** + * @brief Query the Obelisk KnowledgeBase and return the suggested + * action to take. + * + * @param[in] leftEntity The left entity. + * @param[in] verb The verb. + * @param[in] rightEntity The right entity. + * @return std::string Returns the suggested action. + */ + std::string queryAction(const std::string& leftEntity, + const std::string& verb, + const std::string& rightEntity); + }; +} // namespace obelisk + +#endif diff --git a/src/Event.cpp b/src/Event.cpp index cd762b0..26b0efc 100644 --- a/src/Event.cpp +++ b/src/Event.cpp @@ -12,6 +12,7 @@ void alai::Event::_register_methods() godot::register_signal("player_died"); godot::register_signal("player_won"); godot::register_signal("player_touched", "damage", GODOT_VARIANT_TYPE_INT); + godot::register_signal("report_object", "name", GODOT_VARIANT_TYPE_STRING, "state", GODOT_VARIANT_TYPE_STRING, "position", GODOT_VARIANT_TYPE_VECTOR2, "velocity", GODOT_VARIANT_TYPE_VECTOR2); } alai::Event::Event() diff --git a/src/Main.cpp b/src/Main.cpp index f6f1341..0059a96 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,5 +1,6 @@ #include "Event.h" #include "Main.h" +#include "obelisk.h" #include @@ -39,6 +40,10 @@ void alai::Main::_init() void alai::Main::_ready() { + auto obelisk = std::unique_ptr {new obelisk::Obelisk("alai.kb")}; + godot::Godot::print("Obelisk version: " + godot::String(obelisk->getVersion().c_str())); + godot::Godot::print("Obelisk library version: " + godot::String(std::to_string(obelisk->getLibVersion()).c_str())); + auto success = _project_settings->load_resource_pack("monitor.pck"); if (success) { diff --git a/src/godot.cpp b/src/godot.cpp index d0835f3..8e07724 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -8,6 +8,7 @@ #include "goal/GoalReached.h" #include "gui/game_over/GameOverScreen.h" #include "gui/game_won/GameWonScreen.h" +#include "player/AI.h" #include "player/Player.h" #include "player/states/PlayerFall.h" #include "player/states/PlayerIdle.h" @@ -20,7 +21,7 @@ /** * @brief This function connects the gdnative init function. - * + * */ extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) { @@ -29,7 +30,7 @@ extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) /** * @brief This function connects the gdnative terminate function. - * + * */ extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) { @@ -41,7 +42,7 @@ extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_opt /** * @brief This function connects the init methods in the classes to godot's gdnative. - * + * */ extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) { @@ -53,6 +54,7 @@ extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) godot::register_class(); godot::register_class(); godot::register_class(); + godot::register_class(); godot::register_class(); godot::register_class(); godot::register_class(); diff --git a/src/player/AI.cpp b/src/player/AI.cpp new file mode 100644 index 0000000..d667bf0 --- /dev/null +++ b/src/player/AI.cpp @@ -0,0 +1,104 @@ +#include "player/AI.h" + +void alai::player::AI::_register_methods() +{ + godot::register_method("_ready", &AI::_ready); + godot::register_method("_physics_process", &AI::_physics_process); + godot::register_method("_on_object_report", &AI::_on_object_report); +} + +alai::player::AI::AI() +{ +} + +alai::player::AI::~AI() +{ +} + +void alai::player::AI::_init() +{ + _input = godot::Input::get_singleton(); + obelisk = std::unique_ptr {new obelisk::Obelisk("alai.kb")}; +} + +void alai::player::AI::_ready() +{ + parent = Object::cast_to(get_parent()); + + event = get_node("/root/Event"); + event->connect("report_object", this, "_on_object_report"); +} + +void alai::player::AI::_physics_process(float delta) +{ + while (!entities.empty()) + { + const auto& entity = entities.front(); + + if (obelisk->query(entity.name.utf8().get_data(), "is", "touchable") > 0) + { + auto player_position = parent->get_global_position(); + if (entity.position.x > player_position.x) + { + _input->action_press("right"); + } + else + { + _input->action_press("left"); + } + } + + if (obelisk->query(entity.name.utf8().get_data(), "is", "bouncable") > 0) + { + auto player_position = parent->get_global_position(); + auto distance = sqrt(pow(player_position.x - entity.position.x, 2) + pow(player_position.y - entity.position.y, 2)); + int jump_distance = 0; + + auto player_direction = parent->get_velocity(); + + auto action = obelisk->queryAction(entity.name.utf8().get_data(), "is", "bouncable"); + if (action == "jump on") + { + jump_distance = 100; + } + else if (action == "jump over") + { + jump_distance = 50; + } + + if (distance < jump_distance) + { + if (_input->is_action_pressed("right") && player_position.x < entity.position.x) + { + _input->action_press("jump"); + } + else if (_input->is_action_pressed("left") && player_position.x > entity.position.x) + { + _input->action_press("jump"); + } + } + } + + if (obelisk->query(entity.name.utf8().get_data(), "is", "gold") > 0 && obelisk->query(std::string("gold ") + entity.name.utf8().get_data(), "is", "collectable") > 0) + { + auto player_position = parent->get_global_position(); + float distance = player_position.x - entity.position.x; + if (distance > -10 && distance < 10 && player_position.y - entity.position.y > 20) + { + _input->action_press("jump"); + } + } + + entities.pop(); + } +} + +void alai::player::AI::_on_object_report(godot::String name, godot::String state, godot::Vector2 position, godot::Vector2 velocity) +{ + auto entity = Entity(); + entity.name = name.to_lower().rstrip("0123456789"); + entity.state = state; + entity.position = position; + entity.velocity = velocity; + entities.push(entity); +} diff --git a/src/player/AI.h b/src/player/AI.h new file mode 100644 index 0000000..e3ae57d --- /dev/null +++ b/src/player/AI.h @@ -0,0 +1,88 @@ +#ifndef ALAI_PLAYER_AI_H +#define ALAI_PLAYER_AI_H + +#include "Event.h" +#include "obelisk.h" +#include "player/Player.h" + +#include +#include +#include +#include +#include + +namespace alai +{ + namespace player + { + class Entity + { + public: + godot::String name; + godot::String state; + godot::Vector2 position; + godot::Vector2 velocity; + }; + + class AI : public godot::Node + { + GODOT_CLASS(AI, godot::Node) + + private: + /** + * @brief Input singleton. + * + */ + godot::Input* _input; + + /** + * @brief The obelisk object. + * + */ + std::unique_ptr obelisk; + + alai::Event* event; + + std::queue entities; + + alai::player::Player* parent; + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void + _register_methods(); + + AI(); + ~AI(); + + /** + * @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 The physics processed every delta time. + * + * @param[in] delta The time since the method was last run. + */ + void _physics_process(float delta); + + void _on_object_report(godot::String name, godot::String state, godot::Vector2 position, godot::Vector2 velocity); + }; + } // namespace player +} // namespace alai + +#endif