diff --git a/godot/Enemies/enemy.tscn b/godot/Enemies/enemy.tscn deleted file mode 100644 index 7b218d8..0000000 --- a/godot/Enemies/enemy.tscn +++ /dev/null @@ -1,46 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://deb8qiasxsobt"] - -[sub_resource type="SphereShape3D" id="SphereShape3D_tnc8b"] -radius = 7.23 - -[sub_resource type="SphereShape3D" id="SphereShape3D_1inhn"] - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_y3cyo"] -albedo_color = Color(0.0666667, 0.223529, 0.254902, 1) - -[sub_resource type="BoxMesh" id="BoxMesh_y311e"] -material = SubResource("StandardMaterial3D_y3cyo") -size = Vector3(0.77, 0.59, 0.805) - -[sub_resource type="BoxMesh" id="BoxMesh_bc6co"] -material = SubResource("StandardMaterial3D_y3cyo") -size = Vector3(0.475, 0.495, 0.47) - -[node name="Enemy" type="Enemy"] -collision_layer = 7 - -[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."] -path_desired_distance = 2.25 - -[node name="VisionArea" type="Area3D" parent="."] -collision_layer = 0 -collision_mask = 2 - -[node name="CollisionShape3D" type="CollisionShape3D" parent="VisionArea"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.32109, 0) -shape = SubResource("SphereShape3D_tnc8b") - -[node name="CollisionShape3D" type="CollisionShape3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.495191, 0) -shape = SubResource("SphereShape3D_1inhn") - -[node name="Health" type="Health" parent="."] -max_health = 10 - -[node name="MeshInstance3D" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.445159, -0.0811542) -mesh = SubResource("BoxMesh_y311e") - -[node name="MeshInstance3D2" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.430494, 0.458904) -mesh = SubResource("BoxMesh_bc6co") diff --git a/godot/Enemies/flower.tscn b/godot/Enemies/flower.tscn new file mode 100644 index 0000000..4642b61 --- /dev/null +++ b/godot/Enemies/flower.tscn @@ -0,0 +1,26 @@ +[gd_scene load_steps=3 format=3 uid="uid://dopygosr0hxb5"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_ag2i6"] +radius = 2.63833 + +[sub_resource type="CylinderMesh" id="CylinderMesh_vcf5j"] +height = 0.2 +radial_segments = 16 +rings = 1 +cap_bottom = false + +[node name="CharacterActor" type="CharacterActor"] + +[node name="Health" type="Health" parent="."] + +[node name="Planner" type="Planner" parent="."] + +[node name="CharacterAwareness" type="CharacterAwareness" parent="."] +collision_mask = 2 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="CharacterAwareness"] +shape = SubResource("SphereShape3D_ag2i6") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.364549, 0) +mesh = SubResource("CylinderMesh_vcf5j") diff --git a/godot/Projectiles/default_pellet.tscn b/godot/Projectiles/default_pellet.tscn index 1a182e5..c815880 100644 --- a/godot/Projectiles/default_pellet.tscn +++ b/godot/Projectiles/default_pellet.tscn @@ -2,14 +2,19 @@ [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_l2qcn"] albedo_color = Color(1, 0.345098, 0, 1) +emission_enabled = true +emission = Color(1, 0.683333, 0, 1) [sub_resource type="CapsuleMesh" id="CapsuleMesh_0fa8x"] material = SubResource("StandardMaterial3D_l2qcn") radius = 0.02 -height = 0.3 +height = 0.12 +radial_segments = 8 +rings = 2 [node name="PelletProjectile" type="PelletProjectile"] [node name="MeshInstance3D" type="MeshInstance3D" parent="."] transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0) +cast_shadow = 0 mesh = SubResource("CapsuleMesh_0fa8x") diff --git a/godot/Weapons/pistol.tres b/godot/Weapons/pistol.tres index 35b087a..f1b6c29 100644 --- a/godot/Weapons/pistol.tres +++ b/godot/Weapons/pistol.tres @@ -3,7 +3,8 @@ [ext_resource type="PackedScene" uid="uid://c3fyth1hvgy2m" path="res://Projectiles/default_pellet.tscn" id="1_h12ld"] [sub_resource type="Curve" id="Curve_tdh3d"] -_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0] +max_value = 2.0 +_data = [Vector2(0, 2), 0.0, 0.0, 0, 0, Vector2(1, 2), 0.0, 0.0, 0, 0] point_count = 2 [resource] diff --git a/godot/player_character.tscn b/godot/player_character.tscn index 846e5e5..0c3b846 100644 --- a/godot/player_character.tscn +++ b/godot/player_character.tscn @@ -36,7 +36,7 @@ prerequisites = { [sub_resource type="CapsuleMesh" id="CapsuleMesh_rwcvu"] radial_segments = 12 -rings = 1 +rings = 2 [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_scmx3"] albedo_color = Color(0.94902, 0.909804, 0, 1) @@ -52,6 +52,9 @@ collision_layer = 7 actions = [SubResource("Action_gtisq"), SubResource("Action_cwmvs")] goals = [SubResource("Goal_sqtwb")] +[node name="CharacterAwareness" type="CharacterAwareness" parent="."] +collision_mask = 2 + [node name="Health" type="Health" parent="."] max_health = 5 diff --git a/src/character_actor.cpp b/src/character_actor.cpp index 273d0fb..dd0585f 100644 --- a/src/character_actor.cpp +++ b/src/character_actor.cpp @@ -6,7 +6,6 @@ #include "tunnels_game_mode.hpp" #include "utils/game_root.hpp" #include "utils/godot_macros.h" -#include #include #include #include @@ -16,11 +15,12 @@ namespace godot { void CharacterActor::_bind_methods() { #define CLASSNAME CharacterActor GDPROPERTY_HINTED(rotation_speed_curve, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Curve"); - GDPROPERTY_HINTED(target, Variant::OBJECT, PROPERTY_HINT_NODE_TYPE, "Node"); + GDPROPERTY_HINTED(character_type, Variant::INT, PROPERTY_HINT_ENUM, "Neutral,Player,Enemy"); GDPROPERTY(acceleration, Variant::FLOAT); GDPROPERTY(walk_speed, Variant::FLOAT); GDPROPERTY(sprint_speed, Variant::FLOAT); GDPROPERTY(rotation_speed, Variant::FLOAT); + GDFUNCTION(get_target); GDFUNCTION(get_is_near_player); } @@ -31,8 +31,7 @@ void CharacterActor::_enter_tree() { GDGAMEONLY(); this->health = this->get_node("Health"); this->primary_weapon_pool = this->get_node("ProjectilePool"); this->planner = this->get_node("Planner"); - Ref game_mode = GameRoot::get_singleton()->get_game_mode(); - game_mode->register_player_character(this); + Ref(GameRoot3D::get_singleton()->get_game_mode())->register_player_character(this); } void CharacterActor::_process(double delta_time) { GDGAMEONLY(); @@ -63,9 +62,13 @@ void CharacterActor::move(Vector3 world_vector) { } void CharacterActor::aim(Vector3 at) { - // calculate the forward vector by normalized difference between player character and the target on the XZ plane - Vector3 const position{this->weapon_muzzle->get_global_position()}; - Vector3 const forward{Vector3{at.x, 0.f, at.z} - Vector3{position.x, 0.f, position.z}}; + // the forward vector by normalized difference between player character and the target on the XZ plane + Vector3 const pos_flat{this->get_global_position().x, 0.f, this->get_global_position().z}; + Vector3 const target_flat{at.x, 0.f, at.z}; + Vector3 const muzzle_flat{this->weapon_muzzle->get_global_position().x, 0.f, this->weapon_muzzle->get_global_position().z}; + if(pos_flat.distance_squared_to(target_flat) < pos_flat.distance_squared_to(muzzle_flat)) + return; + Vector3 const forward{target_flat - muzzle_flat}; this->aim_direction(forward.normalized()); } @@ -101,7 +104,6 @@ void CharacterActor::set_firing(bool firing) { void CharacterActor::set_manual_mode(bool value) { this->mode_manual = value; ProcessMode const mode = value ? ProcessMode::PROCESS_MODE_DISABLED : ProcessMode::PROCESS_MODE_PAUSABLE; - //this->nav_agent->set_process_mode(mode); this->nav_agent->set_avoidance_priority(value ? 1.f : 0.9f); this->set_state(goap::State::new_invalid()); } @@ -141,7 +143,7 @@ Vector3 CharacterActor::get_velocity_target() const { } bool CharacterActor::get_is_near_player() const { - return Ref(GameRoot::get_singleton()->get_game_mode()) + return Ref(GameRoot3D::get_singleton()->get_game_mode()) ->get_player_instance() ->get_character() ->get_global_position().distance_to(this->get_global_position()) < 5.f; @@ -152,7 +154,8 @@ bool CharacterActor::get_is_near_target() const { Node3D *target_node3d = Object::cast_to(this->target); return target_marker ? target_marker->is_point_on(this->get_global_position()) - : (target_node3d && target_node3d->get_global_position().distance_to(this->get_global_position()) < 5.f); + : (target_node3d + && target_node3d->get_global_position().distance_to(this->get_global_position()) < 5.f); } Vector3 CharacterActor::get_move_target() const { @@ -195,64 +198,13 @@ void CharacterActor::set_state(goap::State state) { } } -void CharacterActor::process_behaviour(double delta_time) { - if(this->current_state.is_complete(this) || this->planner->is_action_complete()) - this->set_state(this->planner->get_next_state()); - switch(this->current_state.type) { - default: - break; - case goap::State::STATE_MOVE_TO: - if(this->nav_agent->get_target_position().distance_to(this->get_move_target()) > 2.f) - this->nav_agent->set_target_position(this->get_move_target()); - break; - case goap::State::STATE_ACTIVATE: - break; - case goap::State::STATE_ANIMATE: - break; - } +void CharacterActor::set_character_type(int character_type) { + this->character_type = static_cast(character_type); + UtilityFunctions::print("set_character_type ", character_type); } -void CharacterActor::process_navigation(double delta_time) { - float const distance_sqr = this->nav_agent->get_target_position().distance_squared_to(this->get_global_position()); - float const distance_target_sqr = std::pow(this->nav_agent->get_target_desired_distance(), 2.f); - if(!this->nav_agent->is_navigation_finished() && distance_sqr >= distance_target_sqr) { - Vector3 const target_position = this->nav_agent->get_next_path_position(); - Vector3 const direction = (target_position - this->get_global_position()).normalized(); - if(this->nav_agent->get_avoidance_enabled()) - this->nav_agent->set_velocity(direction * CharacterActor::walk_speed); - else - this->move(direction); - } -} - -void CharacterActor::process_rotation(double delta_time) { - // copy the current transform and basis matrix - Transform3D trans{this->get_global_transform()}; - Basis basis = trans.get_basis(); - // construct the current rotation .. - Quaternion const current_quaternion = basis.get_rotation_quaternion(); - // .. and the target rotation from their respective bases - Quaternion const target_quaternion = this->target_rotation.get_rotation_quaternion(); - // calculate the angle that still needs to be traveled - float const angle = current_quaternion.angle_to(target_quaternion); - // calculate the angle amount that can be moved this frame - float const angle_step{float(this->rotation_speed_curve->sample(angle) * CharacterActor::rotation_speed * delta_time)}; - // update this object's global transform with the new rotation - basis.set_quaternion(angle < angle_step ? target_quaternion // to avoid overshooting, check if the max step is smaller than the angle distance - : current_quaternion.slerp(target_quaternion, angle_step / angle)); // convert the angle step to a lerp t value between current and target rotations - trans.set_basis(basis); - this->set_global_transform(trans); -} - -void CharacterActor::try_fire_weapon() { - if(float(Time::get_singleton()->get_ticks_msec()) / 1000.f < this->fire_timer) - return; - if(!this->data->get_weapon()->get_allow_automatic()) - this->set_firing(false); - this->fire_timer = float(Time::get_singleton()->get_ticks_msec()) / 1000.f + this->fire_interval; - Node3D *node = this->primary_weapon_pool->claim_projectile(); - if(node != nullptr) - node->set_global_transform(this->weapon_muzzle->get_global_transform()); +int CharacterActor::get_character_type() const { + return static_cast(this->character_type); } void CharacterActor::set_acceleration(float acceleration) { @@ -286,4 +238,59 @@ void CharacterActor::set_rotation_speed(float rotation_speed) { float CharacterActor::get_rotation_speed() const { return this->rotation_speed; } + +void CharacterActor::process_behaviour(double delta_time) { + if(this->current_state.is_complete(this) || this->planner->is_action_complete()) + this->set_state(this->planner->get_next_state()); + switch(this->current_state.type) { + default: + break; + case goap::State::STATE_MOVE_TO: + if(this->nav_agent->get_target_position().distance_to(this->get_move_target()) > 2.f) + this->nav_agent->set_target_position(this->get_move_target()); + break; + case goap::State::STATE_ACTIVATE: + break; + case goap::State::STATE_ANIMATE: + break; + } +} + +void CharacterActor::process_navigation(double delta_time) { + float const sqr_dist = this->nav_agent->get_target_position().distance_squared_to(this->get_global_position()); + float const sqr_dist_target = Math::pow(this->nav_agent->get_target_desired_distance(), 2.0); + if(this->nav_agent->is_navigation_finished() || sqr_dist < sqr_dist_target) + return; + Vector3 const target_pos = this->nav_agent->get_next_path_position(); + Vector3 const direction = (target_pos - this->get_global_position()).normalized(); + if(this->nav_agent->get_avoidance_enabled()) + this->nav_agent->set_velocity(direction * CharacterActor::walk_speed); + else + this->move(direction); +} + +void CharacterActor::process_rotation(double delta_time) { + Basis basis = this->get_global_basis(); + Quaternion const current_quaternion = basis.get_rotation_quaternion(); + Quaternion const target_quaternion = this->target_rotation.get_rotation_quaternion(); + // the angle that still needs to be traveled + float const angle = current_quaternion.angle_to(target_quaternion); + // calculate the angle amount that can be moved this frame + float const step{float(this->rotation_speed_curve->sample(angle) * CharacterActor::rotation_speed * delta_time)}; + // update this object's global transform with the new rotation + basis.set_quaternion(angle < step ? target_quaternion // to avoid overshooting, check if the max step is smaller than the angle distance + : current_quaternion.slerp(target_quaternion, step / angle)); // convert the angle step to a lerp t value between current and target rotations + this->set_global_basis(basis); +} + +void CharacterActor::try_fire_weapon() { + if(float(Time::get_singleton()->get_ticks_msec()) / 1000.f < this->fire_timer) + return; + if(!this->data->get_weapon()->get_allow_automatic()) + this->set_firing(false); + this->fire_timer = float(Time::get_singleton()->get_ticks_msec()) / 1000.f + this->fire_interval; + Node3D *node = this->primary_weapon_pool->claim_projectile(); + if(node != nullptr) + node->set_global_transform(this->weapon_muzzle->get_global_transform()); +} } diff --git a/src/character_actor.hpp b/src/character_actor.hpp index ca434ae..c106158 100644 --- a/src/character_actor.hpp +++ b/src/character_actor.hpp @@ -1,5 +1,5 @@ -#ifndef PLAYER_CHARACTER_HPP -#define PLAYER_CHARACTER_HPP +#ifndef CHARACTER_ACTOR_HPP +#define CHARACTER_ACTOR_HPP #include "character_data.hpp" #include "health.hpp" @@ -17,10 +17,10 @@ namespace goap { class Planner; }; -enum class Team { - CHARACTER_TEAM_WORLD = 0u, - CHARACTER_TEAM_PLAYER = 1u, - CHARACTER_TEAM_ENEMY = 2u, +enum class CharacterType : unsigned { + NEUTRAL, + PLAYER, + PLANT }; class CharacterActor : public CharacterBody3D, @@ -70,7 +70,9 @@ public: Node *get_target() const; goap::Planner *get_planner() const; void set_state(goap::State state); - + void set_character_type(int character_type); + int get_character_type() const; + // character settings void set_acceleration(float acceleration); float get_acceleration() const; void set_walk_speed(float walk_speed); @@ -113,6 +115,8 @@ private: Ref data; float fire_interval{0.f}; // derived from 1 / the current weapon's rps + CharacterType character_type{CharacterType::NEUTRAL}; + float acceleration{20.f}; float walk_speed{3.f}; float sprint_speed{5.f}; @@ -120,4 +124,4 @@ private: }; } -#endif // !PLAYER_CHARACTER_HPP +#endif // !CHARACTER_ACTOR_HPP diff --git a/src/character_awareness.cpp b/src/character_awareness.cpp new file mode 100644 index 0000000..ab8faac --- /dev/null +++ b/src/character_awareness.cpp @@ -0,0 +1,43 @@ +#include "character_awareness.hpp" +#include "character_actor.hpp" +#include "utils/godot_macros.h" +#include + +namespace godot { +void CharacterAwareness::_bind_methods() { +#define CLASSNAME CharacterAwareness + GDSIGNAL("detect_actor", PropertyInfo(Variant::OBJECT, "character", PROPERTY_HINT_NODE_TYPE, "CharacterActor")); + GDSIGNAL("lose_actor", PropertyInfo(Variant::OBJECT, "character", PROPERTY_HINT_NODE_TYPE, "CharacterActor")); + GDSIGNAL("detect_node", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NODE_TYPE, "Node")); + GDSIGNAL("lose_node", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NODE_TYPE, "Node")); +} + +void CharacterAwareness::_enter_tree() { + this->set_collision_mask(0x2); +} + +void CharacterAwareness::_ready() { + this->connect("body_entered", callable_mp(this, &CharacterAwareness::on_body_entered)); + this->connect("body_exited", callable_mp(this, &CharacterAwareness::on_body_exited)); +} + +void CharacterAwareness::on_body_entered(Node *node) { + this->node_awareness.insert(node); + this->emit_signal("detect_node", node); + CharacterActor *actor = Object::cast_to(node); + if(actor) { + this->actor_awareness.insert(actor); + this->emit_signal("detect_actor", actor); + } +} + +void CharacterAwareness::on_body_exited(Node *node) { + this->node_awareness.erase(node); + this->emit_signal("lose_node", node); + CharacterActor *actor = Object::cast_to(node); + if(actor) { + this->actor_awareness.erase(actor); + this->emit_signal("lose_actor", actor); + } +} +} diff --git a/src/character_awareness.hpp b/src/character_awareness.hpp new file mode 100644 index 0000000..3440fd6 --- /dev/null +++ b/src/character_awareness.hpp @@ -0,0 +1,25 @@ +#ifndef CHARACTER_AWARENESS_HPP +#define CHARACTER_AWARENESS_HPP + +#include "character_actor.hpp" +#include +#include + +namespace godot { +class CharacterAwareness : public Area3D { + GDCLASS(CharacterAwareness, Area3D); + static void _bind_methods(); +public: + virtual void _enter_tree() override; + virtual void _ready() override; + void on_body_entered(Node *node); + void on_body_exited(Node *node); +private: + // awareness of characters specifically + HashSet actor_awareness{}; + // not a character :( cringe + HashSet node_awareness{}; +}; +} + +#endif // !CHARACTER_AWARENESS_HPP diff --git a/src/enemy.cpp b/src/enemy.cpp deleted file mode 100644 index 004e3e1..0000000 --- a/src/enemy.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "enemy.hpp" -#include "godot_cpp/classes/time.hpp" -#include "health.hpp" -#include "character_actor.hpp" -#include "utils/godot_macros.h" -#include - -namespace godot { -void Enemy::_bind_methods() { -#define CLASSNAME Enemy - GDFUNCTION_ARGS(body_entered_vision_area, "body"); - GDFUNCTION_ARGS(on_death, "damage"); - GDFUNCTION_ARGS(on_damage, "damage", "remaining"); -} - -void Enemy::_ready() { GDGAMEONLY(); - this->health = this->get_node("Health"); - this->nav_agent = this->get_node("NavigationAgent3D"); - this->vision_area = this->get_node("VisionArea"); - this->vision_area->connect("body_entered", Callable(this, "body_entered_vision_area")); - this->update_navigation_target(); - this->health->connect("death", Callable(this, "on_death")); - this->health->connect("damage", Callable(this, "on_damage")); -} - -void Enemy::_process(double delta_time) { GDGAMEONLY(); - if(this->renav_time > Time::get_singleton()->get_ticks_msec() / 1000.f) { - this->update_navigation_target(); - } - this->process_navigation(delta_time); - this->move_and_slide(); -} - -void Enemy::process_navigation(double delta_time) { - if(this->nav_agent->is_navigation_finished()) { - return; - } - Vector3 const desired_direction = (this->nav_agent->get_next_path_position() - this->get_global_position()).normalized(); - this->set_velocity(desired_direction); - Transform3D trans = this->get_global_transform(); - Vector3 const forward = desired_direction; - trans.set_basis(Basis{desired_direction.cross(Vector3{0.f, 1.f, 0.f}), Vector3{0.f, 1.f, 0.f}, forward}); - this->set_global_transform(trans); -} - -void Enemy::body_entered_vision_area(Node3D *body) { - CharacterActor *player = Object::cast_to(body); - if(player == nullptr) - return; - // TODO: replace this with some condition deciding wether to attack the new character or the current target - this->target_player = player; - this->update_navigation_target(); -} - -void Enemy::update_navigation_target() { - this->renav_time = float(Time::get_singleton()->get_ticks_msec()) / 1000.f + Enemy::RENAV_INTERVAL; - if(this->target_player == nullptr) - this->nav_agent->set_target_position(this->get_global_position()); - else - this->nav_agent->set_target_position(this->target_player->get_global_position()); -} - -void Enemy::on_damage(int delta, int health_left) { -} - -void Enemy::on_death(int delta) { - this->queue_free(); -} - -Health *Enemy::get_health() { - return this->health; -} - -Health const *Enemy::get_health() const { - return this->health; -} - -float const Enemy::RENAV_INTERVAL{0.25f}; -} diff --git a/src/enemy.hpp b/src/enemy.hpp deleted file mode 100644 index 23aad27..0000000 --- a/src/enemy.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef ENEMY_HPP -#define ENEMY_HPP - -#include "godot_cpp/classes/area3d.hpp" -#include "health.hpp" -#include - -namespace godot { -class CharacterActor; -class NavigationAgent3D; - -class Enemy : public CharacterBody3D, - public IHealthEntity { - GDCLASS(Enemy, CharacterBody3D); - static void _bind_methods(); -public: - virtual void _ready() override; - virtual void _process(double delta_time) override; - void process_navigation(double delta_time); - - void body_entered_vision_area(Node3D *body); - - void update_navigation_target(); - - void on_damage(int delta, int health_left); - void on_death(int damage); - - virtual Health *get_health() override; - virtual Health const *get_health() const override; - -private: - float renav_time{0.f}; - - CharacterActor *target_player{nullptr}; - Health *health{nullptr}; - NavigationAgent3D *nav_agent{nullptr}; - Area3D *vision_area{nullptr}; - - static float const RENAV_INTERVAL; -}; -} - -#endif // !ENEMY_HPP diff --git a/src/global_world_state.cpp b/src/global_world_state.cpp index 4eb6cf6..1f5f8f3 100644 --- a/src/global_world_state.cpp +++ b/src/global_world_state.cpp @@ -38,7 +38,7 @@ Vector3 GlobalWorldState::get_player_position() const { } CharacterActor *GlobalWorldState::get_player_character() const { - return Ref(GameRoot::get_singleton()->get_game_mode())->get_player_instance()->get_character(); + return Ref(GameRoot3D::get_singleton()->get_game_mode())->get_player_instance()->get_character(); } Variant GlobalWorldState::get_world_property(StringName prop_key) { diff --git a/src/planner.hpp b/src/planner.hpp index fee995c..23fe61e 100644 --- a/src/planner.hpp +++ b/src/planner.hpp @@ -88,22 +88,28 @@ struct PlannerNodeHasher { } }; -static _FORCE_INLINE_ bool operator==(PlannerNode const &lhs, PlannerNode const &rhs) { +static _FORCE_INLINE_ +bool operator==(PlannerNode const &lhs, PlannerNode const &rhs) { return PlannerNodeHasher::hash(lhs) == PlannerNodeHasher::hash(rhs); } -static _FORCE_INLINE_ bool operator!=(PlannerNode const &lhs, PlannerNode const &rhs) { +static _FORCE_INLINE_ +bool operator!=(PlannerNode const &lhs, PlannerNode const &rhs) { return !(lhs == rhs); } -static _FORCE_INLINE_ bool operator<(PlannerNode const &lhs, PlannerNode const &rhs) { +static _FORCE_INLINE_ +bool operator<(PlannerNode const &lhs, PlannerNode const &rhs) { return lhs.open_requirements.size() < rhs.open_requirements.size(); } -static _FORCE_INLINE_ bool operator>=(PlannerNode const &lhs, PlannerNode const &rhs) { +static _FORCE_INLINE_ +bool operator>=(PlannerNode const &lhs, PlannerNode const &rhs) { return !(lhs < rhs); } -static _FORCE_INLINE_ bool operator>(PlannerNode const &lhs, PlannerNode const &rhs) { +static _FORCE_INLINE_ +bool operator>(PlannerNode const &lhs, PlannerNode const &rhs) { return lhs.open_requirements.size() > rhs.open_requirements.size(); } -static _FORCE_INLINE_ bool operator<=(PlannerNode const &lhs, PlannerNode const &rhs) { +static _FORCE_INLINE_ +bool operator<=(PlannerNode const &lhs, PlannerNode const &rhs) { return !(lhs > rhs); } } diff --git a/src/register_types.cpp b/src/register_types.cpp index 0beb221..cae7898 100644 --- a/src/register_types.cpp +++ b/src/register_types.cpp @@ -1,8 +1,8 @@ #include "register_types.h" #include "action.hpp" #include "character_actor.hpp" +#include "character_awareness.hpp" #include "character_data.hpp" -#include "enemy.hpp" #include "global_world_state.hpp" #include "goal_marker.hpp" #include "health.hpp" @@ -33,7 +33,6 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level) if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - ClassDB::register_abstract_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); @@ -45,7 +44,6 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level) ClassDB::register_class(); ClassDB::register_class(); - ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); @@ -67,6 +65,7 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level) ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); } extern "C" diff --git a/src/tunnels_game_mode.cpp b/src/tunnels_game_mode.cpp index 0d279c0..a21b5dc 100644 --- a/src/tunnels_game_mode.cpp +++ b/src/tunnels_game_mode.cpp @@ -15,7 +15,7 @@ void TunnelsGameMode::_bind_methods() { } void TunnelsGameMode::_begin() { - GameRoot::get_singleton()->connect("player_spawned", Callable(this, "on_player_spawned")); + GameRoot3D::get_singleton()->connect("player_spawned", Callable(this, "on_player_spawned")); } void TunnelsGameMode::on_player_spawned(Node *player) { diff --git a/src/tunnels_player.cpp b/src/tunnels_player.cpp index a053525..95d4536 100644 --- a/src/tunnels_player.cpp +++ b/src/tunnels_player.cpp @@ -38,7 +38,7 @@ void TunnelsPlayer::_ready() { } void TunnelsPlayer::_exit_tree() { GDGAMEONLY(); - GameRoot::get_singleton()->remove_player(this->get_player_id()); + GameRoot3D::get_singleton()->remove_player(this->get_player_id()); } void TunnelsPlayer::_process(double delta_time) { GDGAMEONLY(); @@ -54,18 +54,13 @@ void TunnelsPlayer::_process(double delta_time) { GDGAMEONLY(); case State::ManualControl: // send the current wasd input to the character this->character->move(this->get_world_move_input().normalized()); + // fall through to shared functionality + case State::Tactics: // send the current world cursor position the character this->character->aim(mouse_world_location); // move the camera along with the character this->set_global_position(this->character->get_global_position()); break; - case State::Tactics: - // move camera along with the input - this->set_global_position(this->get_global_position() + this->get_world_move_input().normalized() * - delta_time * TunnelsPlayer::TACTICS_MOVEMENT_SPEED); - break; - case State::Overview: - break; } } @@ -142,8 +137,6 @@ void TunnelsPlayer::fire_pressed(Ref event, float value) { if(value == 1.f) this->try_select_marker(); break; - case State::Overview: - break; } } @@ -166,8 +159,9 @@ void TunnelsPlayer::try_select_marker() { if(marker == nullptr) return; UtilityFunctions::print("Hit: ", marker->get_path()); + // select a character to send orders to CharacterActor *target_character{nullptr}; - for(CharacterActor *loop_character : Ref(GameRoot::get_singleton()->get_game_mode())->get_player_characters()) { + for(CharacterActor *loop_character : Ref(GameRoot3D::get_singleton()->get_game_mode())->get_player_characters()) { if(loop_character != this->character) { target_character = loop_character; break; @@ -206,12 +200,12 @@ void TunnelsPlayer::initialize_character() { this->character = Object::cast_to(player_scene->instantiate()); this->get_parent()->add_child(this->character); this->character->set_global_transform(this->get_global_transform()); - Ref game_state = GameRoot::get_singleton()->get_game_state(); + Ref game_state = GameRoot3D::get_singleton()->get_game_state(); Ref character = game_state->get_characters()[0]; this->character->set_character_data(game_state->get_characters()[0]); // disable navmesh navigation and start using player input this->character->set_manual_mode(true); - Ref(GameRoot::get_singleton()->get_game_mode())->set_manual_character(this->character); + Ref(GameRoot3D::get_singleton()->get_game_mode())->set_manual_character(this->character); } Vector3 TunnelsPlayer::get_world_move_input() const { @@ -256,5 +250,4 @@ float const TunnelsPlayer::ROTATION_SPEED{0.5f}; float const TunnelsPlayer::ROTATION_Y_MIN_INFLUENCE{7.f}; float const TunnelsPlayer::ROTATION_MARGIN{0.4f}; float const TunnelsPlayer::ROTATION_MARGIN_TACTICS_MUL{0.6f}; -float const TunnelsPlayer::TACTICS_MOVEMENT_SPEED{10.f}; } diff --git a/src/tunnels_player.hpp b/src/tunnels_player.hpp index 86c15f0..656081b 100644 --- a/src/tunnels_player.hpp +++ b/src/tunnels_player.hpp @@ -19,7 +19,6 @@ class TunnelsPlayer : public Node3D, public IPlayer { enum State { ManualControl = 0x0, Tactics = 0x1, - Overview = 0x2, }; public: @@ -66,7 +65,6 @@ private: static float const ROTATION_Y_MIN_INFLUENCE; static float const ROTATION_MARGIN_TACTICS_MUL; static float const ROTATION_MARGIN; - static float const TACTICS_MOVEMENT_SPEED; }; } diff --git a/src/utils b/src/utils index d81ad91..2344f3f 160000 --- a/src/utils +++ b/src/utils @@ -1 +1 @@ -Subproject commit d81ad91a885a74338c02edf1d52a2fa5aa8746b6 +Subproject commit 2344f3f2b653dbf6a6c57c2e18c43a1f2c813024