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
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:

View File

@ -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="."]

Binary file not shown.

View File

@ -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()

View File

@ -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()

View File

@ -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()

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://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 )

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 <InputEventAction.hpp>
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<alai::Event>("/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);
}

View File

@ -8,6 +8,7 @@
#include <Godot.hpp>
#include <Input.hpp>
#include <Node.hpp>
#include <Timer.hpp>
#include <Vector2.hpp>
#include <queue>
@ -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<alai::player::Entity> entities;
std::deque<alai::player::Entity> 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