From 3e8c8a08f24e6e93d19f74f3188f1da30fe5a5d8 Mon Sep 17 00:00:00 2001 From: Sara Date: Wed, 22 May 2024 10:22:12 +0200 Subject: [PATCH] feat: implemented enemy spawning --- src/enemy_spawnpoint.cpp | 47 +++++++++++++++ src/enemy_spawnpoint.hpp | 26 +++++++++ src/spawner.cpp | 123 +++++++++++++++++++++++++++++++++++++++ src/spawner.hpp | 49 ++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 src/enemy_spawnpoint.cpp create mode 100644 src/enemy_spawnpoint.hpp create mode 100644 src/spawner.cpp create mode 100644 src/spawner.hpp diff --git a/src/enemy_spawnpoint.cpp b/src/enemy_spawnpoint.cpp new file mode 100644 index 0000000..dea4a8d --- /dev/null +++ b/src/enemy_spawnpoint.cpp @@ -0,0 +1,47 @@ +#include "enemy_spawnpoint.hpp" +#include "spawner.hpp" +#include "utils/godot_macros.h" +#include +#include +#include +#include +#include + +namespace godot { +void EnemySpawnpoint::_bind_methods() { +#define CLASSNAME EnemySpawnpoint + GDPROPERTY(keys, Variant::BOOL); + GDPROPERTY(cars, Variant::BOOL); + GDPROPERTY(drones, Variant::BOOL); +} + +bool EnemySpawnpoint::player_can_see() const { + Dictionary result = this->get_world_3d()->get_direct_space_state() + ->intersect_ray(PhysicsRayQueryParameters3D::create(this->get_global_position(), this->get_viewport()->get_camera_3d()->get_global_position())); + return result.is_empty(); +} + +void EnemySpawnpoint::set_keys(bool val) { + this->keys = val; +} + +bool EnemySpawnpoint::get_keys() const { + return this->keys; +} + +void EnemySpawnpoint::set_cars(bool val) { + this->cars = val; +} + +bool EnemySpawnpoint::get_cars() const { + return this->cars; +} + +void EnemySpawnpoint::set_drones(bool val) { + this->drones = val; +} + +bool EnemySpawnpoint::get_drones() const { + return this->drones; +} +} diff --git a/src/enemy_spawnpoint.hpp b/src/enemy_spawnpoint.hpp new file mode 100644 index 0000000..449c444 --- /dev/null +++ b/src/enemy_spawnpoint.hpp @@ -0,0 +1,26 @@ +#ifndef ENEMY_SPAWNPOINT_HPP +#define ENEMY_SPAWNPOINT_HPP + +#include + +namespace godot { +class EnemySpawnpoint : public Node3D { + GDCLASS(EnemySpawnpoint, Node3D); + static void _bind_methods(); +public: + bool player_can_see() const; +public: + void set_keys(bool val); + bool get_keys() const; + void set_cars(bool val); + bool get_cars() const; + void set_drones(bool val); + bool get_drones() const; +private: + bool keys{false}; + bool cars{true}; + bool drones{true}; +}; +} + +#endif // !ENEMY_SPAWNPOINT_HPP diff --git a/src/spawner.cpp b/src/spawner.cpp new file mode 100644 index 0000000..5e4225f --- /dev/null +++ b/src/spawner.cpp @@ -0,0 +1,123 @@ +#include "spawner.hpp" +#include "enemy_spawnpoint.hpp" +#include "godot_cpp/classes/time.hpp" +#include "rally_rush_game_mode.hpp" +#include "utils/game_root.hpp" +#include "utils/godot_macros.h" + +namespace godot { +void Spawner::_bind_methods() { +#define CLASSNAME Spawner + GDPROPERTY_HINTED(drone_scene, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"); + GDPROPERTY_HINTED(car_scene, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"); + GDPROPERTY_HINTED(key_scene, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"); +} + +void Spawner::_ready() { + this->game_mode = Object::cast_to(GameRoot3D::get_singleton()->get_game_mode().ptr()); + this->spawn_key(); + this->spawn_key(); + this->spawn_key(); +} + +void Spawner::_process(double delta_time) { + if(Time::get_singleton()->get_ticks_msec() * 0.001f > next) { + if(num_cars < this->max_enemy_cars() && tick % 2 == 0) this->spawn_enemy_car(); + else if(num_drones < this->max_enemy_drones()) this->spawn_enemy_drone(); + } +} + +int Spawner::max_enemy_cars() { + return this->game_mode->get_num_found_keys() * 3; +} + +int Spawner::max_enemy_drones() { + return this->game_mode->get_num_found_keys() * 3; +} + +void Spawner::spawn_enemy_car() { + int const child_count{this->get_child_count()}; + int iter_count{0}; + int child_index{int(this->rng.get_state()) % child_count}; + while(iter_count++ < child_count) { + EnemySpawnpoint *spawnpoint = Object::cast_to(this->get_child(child_index)); + child_index++; + if(!spawnpoint) continue; + if(!spawnpoint->get_cars()) continue; + if(spawnpoint->player_can_see()) continue; + Node3D *node = Object::cast_to(this->car_scene->instantiate()); + this->get_parent()->add_child(node); + node->set_global_transform(spawnpoint->get_global_transform()); + this->num_cars++; + node->connect("tree_exited", callable_mp(this, &Spawner::decrement_cars)); + return; + } +} + +void Spawner::spawn_enemy_drone() { + int const child_count{this->get_child_count()}; + int iter_count{0}; + int child_index{int(this->rng.get_state()) % child_count}; + while(iter_count++ < child_count) { + EnemySpawnpoint *spawnpoint = Object::cast_to(this->get_child(child_index)); + child_index++; + if(!spawnpoint) continue; + if(!spawnpoint->get_drones()) continue; + if(spawnpoint->player_can_see()) continue; + Node3D *node = Object::cast_to(this->drone_scene->instantiate()); + this->get_parent()->add_child(node); + node->set_global_transform(spawnpoint->get_global_transform()); + this->num_drones++; + node->connect("tree_exited", callable_mp(this, &Spawner::decrement_drones)); + return; + } +} + +void Spawner::spawn_key() { + int const child_count{this->get_child_count()}; + int iter_count{0}; + int child_index{int(this->rng.get_state()) % child_count}; + while(iter_count++ < child_count) { + EnemySpawnpoint *spawnpoint = Object::cast_to(this->get_child(child_index)); + child_index++; + if(!spawnpoint) continue; + if(!spawnpoint->get_keys()) continue; + Node3D *node = Object::cast_to(this->key_scene->instantiate()); + this->get_parent()->add_child(node); + node->set_global_transform(spawnpoint->get_global_transform()); + return; + } +} + +void Spawner::decrement_cars() { + this->num_cars--; +} + +void Spawner::decrement_drones() { + this->num_drones--; +} + +void Spawner::set_drone_scene(Ref scene) { + this->drone_scene = scene; +} + +Ref Spawner::get_drone_scene() const { + return this->drone_scene; +} + +void Spawner::set_car_scene(Ref scene) { + this->car_scene = scene; +} + +Ref Spawner::get_car_scene() const { + return this->car_scene; +} + +void Spawner::set_key_scene(Ref scene) { + this->key_scene = scene; +} + +Ref Spawner::get_key_scene() const { + return this->key_scene; +} +} diff --git a/src/spawner.hpp b/src/spawner.hpp new file mode 100644 index 0000000..e04959e --- /dev/null +++ b/src/spawner.hpp @@ -0,0 +1,49 @@ +#ifndef SPAWNER_HPP +#define SPAWNER_HPP + +#include "enemy_spawnpoint.hpp" +#include "godot_cpp/classes/packed_scene.hpp" +#include "godot_cpp/classes/random_number_generator.hpp" +#include "godot_cpp/templates/vector.hpp" +#include "rally_rush_game_mode.hpp" +#include + +namespace godot { +class EnemySpawnpoint; +class Spawner : public Node { + GDCLASS(Spawner, Node); + static void _bind_methods(); +public: + virtual void _ready() override; + virtual void _process(double delta_time) override; + + int max_enemy_cars(); + int max_enemy_drones(); + +protected: + void spawn_enemy_car(); + void spawn_enemy_drone(); + void spawn_key(); + void decrement_cars(); + void decrement_drones(); + void set_drone_scene(Ref scene); + Ref get_drone_scene() const; + void set_car_scene(Ref scene); + Ref get_car_scene() const; + void set_key_scene(Ref scene); + Ref get_key_scene() const; +private: + double next{0}; + unsigned tick{0}; + RallyRushGameMode *game_mode; + Vector spawnpoints{}; + Ref drone_scene{}; + Ref car_scene{}; + Ref key_scene{}; + RandomNumberGenerator rng{}; + unsigned num_cars{0}; + unsigned num_drones{0}; +}; +} + +#endif // !SPAWNER_HPP