- LevelScene now executes a signal when a Character3D falls out of the world. - slice_mesh() now transforms the slice cap normals to match the vertices.
110 lines
3.5 KiB
C++
110 lines
3.5 KiB
C++
/*
|
|
* ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
|
*
|
|
* If this source code makes it to the public internet, this software can be
|
|
* considered to be protected by the MIT licence. Have fun with it.
|
|
*/
|
|
|
|
#include "level_scene.h"
|
|
|
|
#include "character_3d.h"
|
|
#include "nodes/player_spawn.h"
|
|
#include "singletons/save_manager.h"
|
|
|
|
#include <godot_cpp/classes/engine.hpp>
|
|
#include <godot_cpp/classes/scene_tree.hpp>
|
|
#include <godot_cpp/classes/window.hpp>
|
|
#include <godot_cpp/variant/utility_functions.hpp>
|
|
|
|
using namespace godot;
|
|
|
|
|
|
void LevelScene::_ready()
|
|
{
|
|
#ifdef DEBUG_ENABLED
|
|
if(Engine::get_singleton()->is_editor_hint()) { return; }
|
|
#endif // DEBUG_ENABLED
|
|
|
|
// We defer this call until the end of the setup frame, since we'll need
|
|
// SaveManager to have been registered as a global singleton before we can
|
|
// find the correct player spawn. This should not be necessary any time
|
|
// after the first scene has loaded and the singleton has been registered,
|
|
// but for safety purposes this still makes sense right now.
|
|
this->call_deferred("_scene_ready");
|
|
}
|
|
void LevelScene::_scene_ready()
|
|
{
|
|
// We should probably assert that there is a valid GameClasses file first
|
|
// thing, since that's vital for initialising LevelScenes.
|
|
#ifdef DEBUG_ENABLED
|
|
if (!this->game_classes.is_valid())
|
|
{
|
|
UtilityFunctions::push_error("No GameClasses resource attached to level.");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
this->level_death_plane_node = cast_to<Area3D>(this->get_node_or_null(this->level_death_plane));
|
|
if (this->level_death_plane_node)
|
|
{
|
|
this->level_death_plane_node->set_monitoring(true);
|
|
|
|
this->level_death_plane_node->set_gravity_space_override_mode(Area3D::SpaceOverride::SPACE_OVERRIDE_DISABLED);
|
|
this->level_death_plane_node->set_linear_damp_space_override_mode(Area3D::SpaceOverride::SPACE_OVERRIDE_DISABLED);
|
|
this->level_death_plane_node->set_angular_damp_space_override_mode(Area3D::SpaceOverride::SPACE_OVERRIDE_DISABLED);
|
|
|
|
this->level_death_plane_node->connect("body_entered", callable_mp(this, &LevelScene::_body_fell_out_of_world));
|
|
}
|
|
|
|
SpawnPointMap spawn_points = this->_find_player_spawns();
|
|
const StringName ¤t_checkpoint = SaveManager::get_singleton()->get_current_checkpoint();
|
|
|
|
const PlayerOrigin *spawn_point = spawn_points[current_checkpoint];
|
|
#ifdef DEBUG_ENABLED
|
|
if (!spawn_point)
|
|
{
|
|
UtilityFunctions::push_error("Could not find a spawn point named ", current_checkpoint, "; defaulting to origin...");
|
|
spawn_point = spawn_points[PLAYER_ORIGIN_TAG];
|
|
DEV_ASSERT(spawn_point);
|
|
}
|
|
#endif
|
|
|
|
// Attempt to spawn the player scene at this spawn point.
|
|
spawn_point->spawn_player(this, this->game_classes->get_player_scene());
|
|
}
|
|
|
|
|
|
SpawnPointMap LevelScene::_find_player_spawns() const
|
|
{
|
|
SpawnPointMap spawn_points;
|
|
this->_find_player_spawns_recursive(this, spawn_points);
|
|
return spawn_points;
|
|
}
|
|
|
|
void LevelScene::_find_player_spawns_recursive(const Node *node, SpawnPointMap &spawn_points) const
|
|
{
|
|
if (const PlayerOrigin *potential_spawn = cast_to<PlayerOrigin>(node))
|
|
{
|
|
spawn_points.emplace(potential_spawn->get_tag(), potential_spawn);
|
|
}
|
|
|
|
const TypedArray<Node> &children = node->get_children();
|
|
for (int i = 0; i < children.size(); i++)
|
|
{
|
|
this->_find_player_spawns_recursive(cast_to<Node>(children[i]), spawn_points);
|
|
}
|
|
}
|
|
|
|
|
|
void LevelScene::_body_fell_out_of_world(Node3D *body)
|
|
{
|
|
if (Character3D *character3d = cast_to<Character3D>(body))
|
|
{
|
|
character3d->emit_signal(FELL_OUT_OF_WORLD_SIGNAL);
|
|
}
|
|
else if (body->has_method(FELL_OUT_OF_WORLD_METHOD))
|
|
{
|
|
body->call(FELL_OUT_OF_WORLD_METHOD);
|
|
}
|
|
}
|