Merge pull request 'feature/finishing_touches' (#62) from feature/finishing_touches into develop

Reviewed-on: #62
This commit is contained in:
Chris Cromer 2023-03-01 22:24:46 -03:00
commit 77d844c911
10 changed files with 226 additions and 84 deletions

View File

@ -2,7 +2,7 @@
# See https://pre-commit.com/hooks.html for more hooks # See https://pre-commit.com/hooks.html for more hooks
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0 rev: v4.4.0
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
- id: end-of-file-fixer - id: end-of-file-fixer
@ -15,16 +15,11 @@ repos:
- id: no-commit-to-branch - id: no-commit-to-branch
args: [--branch, master, --branch, develop] args: [--branch, master, --branch, develop]
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: v14.0.6 rev: v15.0.7
hooks: hooks:
- id: clang-format - id: clang-format
types_or: [c++, c] types_or: [c++, c]
args: ["-style=file"] 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 #- repo: https://github.com/pocc/pre-commit-hooks
# rev: v1.3.5 # rev: v1.3.5
# hooks: # hooks:

View File

@ -8,7 +8,7 @@
[node name="Main" type="Node"] [node name="Main" type="Node"]
pause_mode = 2 pause_mode = 2
script = ExtResource( 1 ) script = ExtResource( 1 )
game_version = "1.0.0" game_version = "1.1.0"
level = ExtResource( 2 ) level = ExtResource( 2 )
[node name="Level" type="Node" parent="."] [node name="Level" type="Node" parent="."]

Binary file not shown.

View File

@ -6,6 +6,7 @@ export var direction = -1
export var detect_edges = true export var detect_edges = true
export var speed = 25 export var speed = 25
export var gravity = 9.8 export var gravity = 9.8
var timer := Timer.new()
func _ready() -> void: func _ready() -> void:
@ -15,6 +16,12 @@ func _ready() -> void:
$FloorChecker.enabled = detect_edges $FloorChecker.enabled = detect_edges
Event.connect("level_loaded", self, "_on_level_loaded") 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: func _physics_process(_delta: float) -> void:
if is_on_wall() or not $FloorChecker.is_colliding() and is_on_floor() and $FloorChecker.enabled: if is_on_wall() or not $FloorChecker.is_colliding() and is_on_floor() and $FloorChecker.enabled:
@ -32,7 +39,6 @@ func _physics_process(_delta: float) -> void:
Event.emit_signal("player_touched", 3) 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: func squash() -> void:
@ -42,3 +48,8 @@ func squash() -> void:
func _on_level_loaded() -> void: 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()

View File

@ -1,5 +1,17 @@
extends Area2D extends Area2D
func _process(_delta: float) -> void: 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()) Event.emit_signal("report_object", self.get_name(), "not collected", global_position, Vector2())
timer.start()

View File

@ -1,5 +1,17 @@
extends Area2D extends Area2D
func _process(_delta: float) -> void: 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()) Event.emit_signal("report_object", self.get_name(), "not touched", global_position, Vector2())
timer.start()

View File

@ -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://characters/enemies/shelly/Shelly.tscn" type="PackedScene" id=1]
[ext_resource path="res://collectables/coin/Coin.tscn" type="PackedScene" id=2] [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://assets/backgrounds/hills.png" type="Texture" id=7]
[ext_resource path="res://levels/TestLevel.tmx" type="PackedScene" id=8] [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://CameraLimit.gdns" type="Script" id=9]
[ext_resource path="res://characters/enemies/dreadtooth/Dreadtooth.tscn" type="PackedScene" id=10]
[node name="TestLevel" type="Node2D"] [node name="TestLevel" type="Node2D"]
@ -79,5 +80,5 @@ position = Vector2( 656, 504 )
[node name="Shelly" parent="Enemies" instance=ExtResource( 1 )] [node name="Shelly" parent="Enemies" instance=ExtResource( 1 )]
position = Vector2( 379, 510 ) position = Vector2( 379, 510 )
[node name="Shelly2" parent="Enemies" instance=ExtResource( 1 )] [node name="Dreadtooth" parent="Enemies" instance=ExtResource( 10 )]
position = Vector2( 628, 510 ) position = Vector2( 640, 510 )

17
obelisk/alai.obk Normal file
View File

@ -0,0 +1,17 @@
fact("coin" is "gold");
rule("gold coin" is "collectable" if "coin" is "gold");
fact("goal" is "touchable");
fact("shelly" is "dangerous");
fact("shelly" is "bouncable");
fact("shelly" can "walk");
fact("dreadtooth" is "dangerous");
fact("dreadtooth" can "walk");
action(if "shelly" is "bouncable" then "jump on" else "jump over");
action(if "dreadtooth" is "bouncable" then "jump on" else "jump over");
action(if "coin" is "collectable" then "collect" else "avoid");
action(if "goal" is "touchable" then "touch" else "avoid");

View File

@ -1,10 +1,13 @@
#include "player/AI.h" #include "player/AI.h"
#include <InputEventAction.hpp>
void alai::player::AI::_register_methods() void alai::player::AI::_register_methods()
{ {
godot::register_method("_ready", &AI::_ready); godot::register_method("_ready", &AI::_ready);
godot::register_method("_physics_process", &AI::_physics_process); godot::register_method("_physics_process", &AI::_physics_process);
godot::register_method("_on_object_report", &AI::_on_object_report); godot::register_method("_on_object_report", &AI::_on_object_report);
godot::register_method("_on_timer_timeout", &AI::_on_timer_timeout);
} }
alai::player::AI::AI() alai::player::AI::AI()
@ -27,36 +30,37 @@ void alai::player::AI::_ready()
event = get_node<alai::Event>("/root/Event"); event = get_node<alai::Event>("/root/Event");
event->connect("report_object", this, "_on_object_report"); 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) 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()) 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();
{
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) double distance = std::abs(player_position.x - entity.position.x);
{
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(); int jump_distance = -1;
auto action = obelisk->queryAction(entityName, "is", "bouncable");
auto action = obelisk->queryAction(entity.name.utf8().get_data(), "is", "bouncable");
if (action == "jump on") if (action == "jump on")
{ {
jump_distance = 100; jump_distance = 100;
@ -66,39 +70,102 @@ void alai::player::AI::_physics_process(float delta)
jump_distance = 50; jump_distance = 50;
} }
if (distance < jump_distance) if (lastEntity == "")
{ {
if (_input->is_action_pressed("right") && player_position.x < entity.position.x) if (jump_distance != -1 && distance < jump_distance)
{ {
_input->action_press("jump"); 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 (_input->is_action_pressed("left") && player_position.x > entity.position.x) else if (player_position.x > entity.position.x)
{ {
_input->action_press("jump"); auto ev = godot::InputEventAction()._new();
ev->set_action("jump");
ev->set_pressed(true);
_input->parse_input_event(ev);
} }
} }
} }
if (obelisk->query(entity.name.utf8().get_data(), "is", "gold") > 0 && obelisk->query(std::string("gold ") + entity.name.utf8().get_data(), "is", "collectable") > 0) 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)
float distance = player_position.x - entity.position.x; {
if (!walking && !_input->is_action_pressed("left") && !_input->is_action_pressed("right"))
{
walking = true;
_input->action_press("right");
}
}
else
{
if (!walking && !_input->is_action_pressed("left") && !_input->is_action_pressed("right"))
{
walking = true;
_input->action_press("left");
}
}
if (distance > -10 && distance < 10 && player_position.y - entity.position.y > 20) if (distance > -10 && distance < 10 && player_position.y - entity.position.y > 20)
{
timer->stop();
lastEntity = "";
if (!_input->is_action_pressed("jump"))
{ {
_input->action_press("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) void alai::player::AI::_on_object_report(godot::String name, godot::String state, godot::Vector2 position, godot::Vector2 velocity)
{ {
auto entity = Entity(); auto entity = Entity();
entity.originalName = name;
entity.name = name.to_lower().rstrip("0123456789"); entity.name = name.to_lower().rstrip("0123456789");
entity.state = state; entity.state = state;
entity.position = position; entity.position = position;
entity.velocity = velocity; entity.velocity = velocity;
entities.push(entity); entities.emplace_front(entity);
} }

View File

@ -8,6 +8,7 @@
#include <Godot.hpp> #include <Godot.hpp>
#include <Input.hpp> #include <Input.hpp>
#include <Node.hpp> #include <Node.hpp>
#include <Timer.hpp>
#include <Vector2.hpp> #include <Vector2.hpp>
#include <queue> #include <queue>
@ -18,6 +19,7 @@ namespace alai
class Entity class Entity
{ {
public: public:
godot::String originalName;
godot::String name; godot::String name;
godot::String state; godot::String state;
godot::Vector2 position; godot::Vector2 position;
@ -43,10 +45,14 @@ namespace alai
alai::Event* event; alai::Event* event;
std::queue<alai::player::Entity> entities; std::deque<alai::player::Entity> entities;
alai::player::Player* parent; alai::player::Player* parent;
godot::String lastEntity;
godot::Timer* timer = godot::Timer()._new();
public: public:
/** /**
* @brief This method registers classes with Godot. * @brief This method registers classes with Godot.
@ -56,7 +62,16 @@ namespace alai
static void static void
_register_methods(); _register_methods();
/**
* @brief Construct a new AI object.
*
*/
AI(); AI();
/**
* @brief Destroy the AI object.
*
*/
~AI(); ~AI();
/** /**
@ -80,6 +95,18 @@ namespace alai
*/ */
void _physics_process(float delta); 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); void _on_object_report(godot::String name, godot::String state, godot::Vector2 position, godot::Vector2 velocity);
}; };
} // namespace player } // namespace player