From 4860855cc897ced73a23f5f879dcb9d3225653d2 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 1 Mar 2023 09:13:53 -0300 Subject: [PATCH 1/4] swap second shelly for a dreadtooth --- godot/levels/TestLevel.tscn | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/godot/levels/TestLevel.tscn b/godot/levels/TestLevel.tscn index 3503d69..4816337 100644 --- a/godot/levels/TestLevel.tscn +++ b/godot/levels/TestLevel.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=10 format=2] +[gd_scene load_steps=11 format=2] [ext_resource path="res://characters/enemies/shelly/Shelly.tscn" type="PackedScene" id=1] [ext_resource path="res://collectables/coin/Coin.tscn" type="PackedScene" id=2] @@ -9,6 +9,7 @@ [ext_resource path="res://assets/backgrounds/hills.png" type="Texture" id=7] [ext_resource path="res://levels/TestLevel.tmx" type="PackedScene" id=8] [ext_resource path="res://CameraLimit.gdns" type="Script" id=9] +[ext_resource path="res://characters/enemies/dreadtooth/Dreadtooth.tscn" type="PackedScene" id=10] [node name="TestLevel" type="Node2D"] @@ -79,5 +80,5 @@ position = Vector2( 656, 504 ) [node name="Shelly" parent="Enemies" instance=ExtResource( 1 )] position = Vector2( 379, 510 ) -[node name="Shelly2" parent="Enemies" instance=ExtResource( 1 )] -position = Vector2( 628, 510 ) +[node name="Dreadtooth" parent="Enemies" instance=ExtResource( 10 )] +position = Vector2( 640, 510 ) From acf6ed6f73aa3c94864f21682f4158f2c5baf709 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 1 Mar 2023 09:14:36 -0300 Subject: [PATCH 2/4] update the knowledge base for the dreadtooth enemy type --- godot/alai.kb | Bin 81920 -> 81920 bytes obelisk/alai.obk | 17 +++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 obelisk/alai.obk diff --git a/godot/alai.kb b/godot/alai.kb index c9d78ac69f21d5a08983b7a15cd4fbc21eb8c68b..8701288987e81108d94649360a570620e8d82027 100644 GIT binary patch delta 480 zcmYL_%_~Gv7{<>z_gwd!d+?0S{!UcLdqZDA5e@;nT?SqWoF@SvB6!~%mO7l z(%oQVlBl74lwzh(NGTsHA7$a48L|8Ip5EVi-pBK7&$H(mc*}faFK^i#jP`Nq@Ab8I zxQsEaCt~A6F1PAM;t<49{;L6+eg?|8!#?s1JvoZ}b=$kNUV7T?;q6vp@miSBBHG=q;%oM9R1AT$;S zs;vnBSDIjED%D==B2x_Vj5}Q61pC;*23Ct)K(Al1f)FPGGcFM4W3QT;-I8 z+9-d2w8Ix7A9?hp+Kd) b;(?xy&|D5cR#_&pS`3moGByV%4!vOy#?4?jD#64*s6)Rzu;WmucUEEBL?N^Q_I8_t)#s^w>K?8TF z1(Bf={9@YnZ__d6Wq~i0nLjhF;*9wYv{r@;*}>`kSlpGUcdCN0SH-X+l^`OiY{&YW zw6rzxWJp;q|0vPwv Date: Wed, 1 Mar 2023 09:19:25 -0300 Subject: [PATCH 3/4] enhance the AI movement process --- .pre-commit-config.yaml | 9 +- godot/characters/enemies/WalkingEnemy.gd | 53 +++++--- godot/collectables/coin/Coin.gd | 16 ++- godot/goal/Goal.gd | 16 ++- src/player/AI.cpp | 161 ++++++++++++++++------- src/player/AI.h | 29 +++- 6 files changed, 204 insertions(+), 80 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4a1c397..5fad248 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -15,16 +15,11 @@ repos: - id: no-commit-to-branch args: [--branch, master, --branch, develop] - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v14.0.6 + rev: v15.0.7 hooks: - id: clang-format types_or: [c++, c] args: ["-style=file"] - - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.3.1 - hooks: - - id: forbid-crlf - - id: forbid-tabs #- repo: https://github.com/pocc/pre-commit-hooks # rev: v1.3.5 # hooks: diff --git a/godot/characters/enemies/WalkingEnemy.gd b/godot/characters/enemies/WalkingEnemy.gd index f3b424f..1542fd8 100644 --- a/godot/characters/enemies/WalkingEnemy.gd +++ b/godot/characters/enemies/WalkingEnemy.gd @@ -6,39 +6,50 @@ export var direction = -1 export var detect_edges = true export var speed = 25 export var gravity = 9.8 +var timer := Timer.new() func _ready() -> 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") + + add_child(timer) + timer.wait_time = 0.1 + var err = timer.connect("timeout", self, "_on_timer_timeout") + if err == OK: + timer.start() 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("report_object", self.get_name(), "Walking", global_position, velocity) + Event.emit_signal("object_updated", 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)) + + +func _on_timer_timeout() -> void: + Event.emit_signal("report_object", self.get_name(), "walking", global_position, velocity) + timer.start() diff --git a/godot/collectables/coin/Coin.gd b/godot/collectables/coin/Coin.gd index 7ab13fe..e31cd98 100644 --- a/godot/collectables/coin/Coin.gd +++ b/godot/collectables/coin/Coin.gd @@ -1,5 +1,17 @@ extends Area2D -func _process(_delta: float) -> void: - Event.emit_signal("report_object", self.get_name(), "not collected", global_position, Vector2()) +var timer := Timer.new() + + +func _ready() -> void: + add_child(timer) + timer.wait_time = 0.1 + var err = timer.connect("timeout", self, "_on_timer_timeout") + if err == OK: + timer.start() + + +func _on_timer_timeout() -> void: + Event.emit_signal("report_object", self.get_name(), "not collected", global_position, Vector2()) + timer.start() diff --git a/godot/goal/Goal.gd b/godot/goal/Goal.gd index f9aa6db..07f76af 100644 --- a/godot/goal/Goal.gd +++ b/godot/goal/Goal.gd @@ -1,5 +1,17 @@ extends Area2D -func _process(_delta: float) -> void: - Event.emit_signal("report_object", self.get_name(), "not touched", global_position, Vector2()) +var timer := Timer.new() + + +func _ready() -> void: + add_child(timer) + timer.wait_time = 0.1 + var err = timer.connect("timeout", self, "_on_timer_timeout") + if err == OK: + timer.start() + + +func _on_timer_timeout() -> void: + Event.emit_signal("report_object", self.get_name(), "not touched", global_position, Vector2()) + timer.start() diff --git a/src/player/AI.cpp b/src/player/AI.cpp index d667bf0..4b80c27 100644 --- a/src/player/AI.cpp +++ b/src/player/AI.cpp @@ -1,10 +1,13 @@ #include "player/AI.h" +#include + 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); + godot::register_method("_on_timer_timeout", &AI::_on_timer_timeout); } alai::player::AI::AI() @@ -27,78 +30,142 @@ void alai::player::AI::_ready() event = get_node("/root/Event"); event->connect("report_object", this, "_on_object_report"); + + add_child(timer); + timer->set_wait_time(1); + auto err = timer->connect("timeout", this, "_on_timer_timeout"); + if (err != godot::Error::OK) + { + godot::Godot::print("Timer could not be connected!"); + } } void alai::player::AI::_physics_process(float delta) { + auto player_position = parent->get_global_position(); + auto player_direction = parent->get_velocity(); + bool walking = false; + + std::sort(entities.begin(), entities.end(), [](const Entity &a, const Entity &b) -> bool + { + return a.position.x < b.position.x; + }); + while (!entities.empty()) { - const auto& entity = entities.front(); + const auto &entity = entities.front(); - if (obelisk->query(entity.name.utf8().get_data(), "is", "touchable") > 0) + auto entityName = entity.name.utf8().get_data(); + + double distance = std::abs(player_position.x - entity.position.x); + + int jump_distance = -1; + auto action = obelisk->queryAction(entityName, "is", "bouncable"); + if (action == "jump on") + { + jump_distance = 100; + } + else if (action == "jump over") + { + jump_distance = 50; + } + + if (lastEntity == "") + { + if (jump_distance != -1 && distance < jump_distance) + { + lastEntity = entity.originalName; + timer->start(); + if (player_position.x < entity.position.x) + { + auto ev = godot::InputEventAction()._new(); + ev->set_action("jump"); + ev->set_pressed(true); + _input->parse_input_event(ev); + } + else if (player_position.x > entity.position.x) + { + auto ev = godot::InputEventAction()._new(); + ev->set_action("jump"); + ev->set_pressed(true); + _input->parse_input_event(ev); + } + } + } + + if (obelisk->query(entityName, "is", "gold") > 0 && obelisk->query(std::string("gold ") + entityName, "is", "collectable") > 0) { - auto player_position = parent->get_global_position(); if (entity.position.x > player_position.x) { - _input->action_press("right"); + if (!walking && !_input->is_action_pressed("left") && !_input->is_action_pressed("right")) + { + walking = true; + _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) + if (!walking && !_input->is_action_pressed("left") && !_input->is_action_pressed("right")) { - _input->action_press("jump"); - } - else if (_input->is_action_pressed("left") && player_position.x > entity.position.x) - { - _input->action_press("jump"); + walking = true; + _input->action_press("left"); } } - } - 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"); + timer->stop(); + lastEntity = ""; + if (!_input->is_action_pressed("jump")) + { + _input->action_press("jump"); + } } } - entities.pop(); + if (obelisk->query(entityName, "is", "touchable") > 0) + { + if (!walking && !_input->is_action_pressed("left") && !_input->is_action_pressed("right")) + { + walking = true; + if (entity.position.x > player_position.x) + { + _input->action_press("right"); + } + else + { + _input->action_press("left"); + } + } + } + + entities.pop_front(); } } +void alai::player::AI::unset_action(godot::String action) +{ + auto ev = godot::InputEventAction()._new(); + ev->set_action(action); + ev->set_pressed(false); + _input->parse_input_event(ev); +} + +void alai::player::AI::_on_timer_timeout() +{ + unset_action("left"); + unset_action("right"); + unset_action("jump"); + lastEntity = ""; +} + 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); + auto entity = Entity(); + entity.originalName = name; + entity.name = name.to_lower().rstrip("0123456789"); + entity.state = state; + entity.position = position; + entity.velocity = velocity; + entities.emplace_front(entity); } diff --git a/src/player/AI.h b/src/player/AI.h index e3ae57d..72d76c8 100644 --- a/src/player/AI.h +++ b/src/player/AI.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,7 @@ namespace alai class Entity { public: + godot::String originalName; godot::String name; godot::String state; godot::Vector2 position; @@ -43,10 +45,14 @@ namespace alai alai::Event* event; - std::queue entities; + std::deque entities; alai::player::Player* parent; + godot::String lastEntity; + + godot::Timer* timer = godot::Timer()._new(); + public: /** * @brief This method registers classes with Godot. @@ -56,7 +62,16 @@ namespace alai static void _register_methods(); + /** + * @brief Construct a new AI object. + * + */ AI(); + + /** + * @brief Destroy the AI object. + * + */ ~AI(); /** @@ -80,6 +95,18 @@ namespace alai */ void _physics_process(float delta); + void _on_timer_timeout(); + + void unset_action(godot::String action); + + /** + * @brief Callback that receives information about the game environment. + * + * @param[in] name The name of the object. + * @param[in] state The state the object is in. + * @param[in] position The position of the object. + * @param[in] velocity The object's velocity. + */ void _on_object_report(godot::String name, godot::String state, godot::Vector2 position, godot::Vector2 velocity); }; } // namespace player From 368ca330060801a52f5ab22fe39d110551ecfcd8 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 1 Mar 2023 22:19:56 -0300 Subject: [PATCH 4/4] prepare 1.1.0 --- godot/Main.tscn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/godot/Main.tscn b/godot/Main.tscn index 2cc9a1b..b7e3351 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.0.0" +game_version = "1.1.0" level = ExtResource( 2 ) [node name="Level" type="Node" parent="."]