Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fd24f03a1 | ||
|
|
223eaf2f32 | ||
|
|
6e508ccde2 | ||
|
|
e35adc23b2 | ||
|
|
b5fe9f7c8d | ||
|
|
64421d8ff7 | ||
|
|
b6315f3076 | ||
|
|
306db05bfc | ||
|
|
a9fd36efa6 |
@@ -1,8 +1,60 @@
|
||||
/*
|
||||
* ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
* ©2026 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 "i_damageable.h"
|
||||
|
||||
#include "orng_macros.h"
|
||||
|
||||
#include "godot_cpp/classes/scene_tree.hpp"
|
||||
#include "godot_cpp/classes/scene_tree_timer.hpp"
|
||||
|
||||
|
||||
void IDamageable::_slice_meshes(Ref<MeshEditSliceInput> data)
|
||||
{
|
||||
this->_is_slicing = true;
|
||||
this->_input_queue.emplace_back(data);
|
||||
if (this->_slice_state_queue.empty())
|
||||
this->_new_slice_loop();
|
||||
}
|
||||
|
||||
void IDamageable::_new_slice_loop()
|
||||
{
|
||||
this->_slice_state_queue.emplace_back(MeshEditingLibrary::slice_mesh(this->_input_queue.front()));
|
||||
this->_slice_loop();
|
||||
}
|
||||
|
||||
void IDamageable::_slice_loop()
|
||||
{
|
||||
Ref<MeshSliceState> current_state = this->_slice_state_queue.front();
|
||||
switch(current_state->current_stage)
|
||||
{
|
||||
case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_INIT:
|
||||
MeshEditingLibrary::slice_mesh_init(current_state);
|
||||
break;
|
||||
case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_PLANE_SPLIT:
|
||||
MeshEditingLibrary::slice_mesh_plane_split(current_state);
|
||||
break;
|
||||
case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_EDGE_SPLIT:
|
||||
MeshEditingLibrary::slice_mesh_edge_split(current_state);
|
||||
break;
|
||||
case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_APPLY_CAP:
|
||||
MeshEditingLibrary::slice_mesh_apply_cap(current_state);
|
||||
break;
|
||||
case MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_COMPLETE:
|
||||
this->_slice_complete(current_state->output);
|
||||
this->_input_queue.erase(this->_input_queue.begin());
|
||||
this->_slice_state_queue.erase(this->_slice_state_queue.begin());
|
||||
if (!this->_input_queue.empty())
|
||||
return this->_new_slice_loop();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!this->_input_queue.empty())
|
||||
CALL_NEXT_FRAME(callable_mp(this, &IDamageable::_slice_loop));
|
||||
else
|
||||
this->_is_slicing = false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
* ©2026 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.
|
||||
@@ -7,9 +7,32 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nodes/mesh_editing_library.h"
|
||||
|
||||
class IDamageable
|
||||
#include "godot_cpp/classes/node.hpp"
|
||||
using namespace godot;
|
||||
|
||||
|
||||
class IDamageable : public Node3D
|
||||
{
|
||||
public:
|
||||
virtual void take_damage(const struct HurtboxDamage &hit_data) = 0;
|
||||
|
||||
protected:
|
||||
void _slice_meshes(Ref<MeshEditSliceInput> data);
|
||||
|
||||
virtual void _slice_complete(Ref<MeshEditSliceOutput> data) = 0;
|
||||
|
||||
private:
|
||||
void _new_slice_loop();
|
||||
void _slice_loop();
|
||||
|
||||
bool _is_slicing = false;
|
||||
|
||||
std::vector<Ref<MeshSliceState>> _slice_state_queue;
|
||||
std::vector<Ref<MeshEditSliceInput>> _input_queue;
|
||||
|
||||
// Godot boilerplate below
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
};
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <godot_cpp/classes/physical_bone3d.hpp>
|
||||
#include <godot_cpp/classes/physical_bone_simulator3d.hpp>
|
||||
#include <godot_cpp/classes/random_number_generator.hpp>
|
||||
#include <godot_cpp/classes/scene_tree.hpp>
|
||||
#include <godot_cpp/classes/scene_tree_timer.hpp>
|
||||
#include <godot_cpp/classes/skin.hpp>
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
using namespace godot;
|
||||
@@ -25,7 +27,6 @@ using namespace godot;
|
||||
|
||||
void Character3D::_ready()
|
||||
{
|
||||
this->skeleton_list.clear();
|
||||
if (this->character_skeleton)
|
||||
{
|
||||
this->_rebuild_mesh_instances();
|
||||
@@ -35,74 +36,119 @@ void Character3D::_ready()
|
||||
void Character3D::set_meshes(TypedArray<ArrayMesh> m)
|
||||
{
|
||||
this->meshes = m;
|
||||
this->full_aabb = AABB();
|
||||
this->_full_aabb = AABB();
|
||||
this->_rebuild_mesh_instances();
|
||||
}
|
||||
|
||||
void Character3D::set_character_skeleton(CharacterSkeleton3D *cs)
|
||||
{
|
||||
this->character_skeleton = cs;
|
||||
this->_rebuild_mesh_instances();
|
||||
if (cs)
|
||||
{
|
||||
if (this->character_skeleton)
|
||||
{
|
||||
this->skeleton_set.erase(this->character_skeleton);
|
||||
this->character_skeleton->queue_free();
|
||||
}
|
||||
this->character_skeleton = cs;
|
||||
this->skeleton_set.emplace(this->character_skeleton);
|
||||
this->_rebuild_mesh_instances();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Character3D::take_damage(const HurtboxDamage &hit_data)
|
||||
{
|
||||
for (const auto &[character_skeleton, bones] : hit_data.bones)
|
||||
if (this->_hurtbox_queue.empty())
|
||||
CALL_NEXT_FRAME(callable_mp(this, &Character3D::_next_hurtbox_in_queue));
|
||||
this->_hurtbox_queue.emplace_back(hit_data);
|
||||
}
|
||||
|
||||
void Character3D::_next_hurtbox_in_queue()
|
||||
{
|
||||
HurtboxDamage &hit_data = this->_hurtbox_queue.front();
|
||||
if (!hit_data.bones.empty())
|
||||
{
|
||||
Skeleton3D *skeleton = character_skeleton->get_skeleton();
|
||||
CharacterSkeleton3D *character_skeleton = hit_data.bones.begin()->first;
|
||||
const std::vector<int32_t> &bone_hits = hit_data.bones.begin()->second;
|
||||
hit_data.bones.erase(this->_hurtbox_queue.begin()->bones.begin());
|
||||
|
||||
Skeleton3D *skeleton = character_skeleton->get_skeleton();
|
||||
const Plane &local_slice_plane = skeleton->get_global_transform().inverse().xform(Plane(hit_data.global_hit_transform.get_basis().get_column(1), hit_data.global_hit_transform.origin));
|
||||
|
||||
std::vector<MeshInstance3D*> sliced_mesh_instances = character_skeleton->get_mesh_instances();
|
||||
TypedArray<MeshInstance3D> sliced_mesh_instances = character_skeleton->get_mesh_instances();
|
||||
const uint32_t num_mesh_instances = sliced_mesh_instances.size();
|
||||
TypedArray<ArrayMesh> first_half_meshes_to_add;
|
||||
TypedArray<ArrayMesh> other_half_meshes_to_add;
|
||||
for (uint32_t i = 0; i < num_mesh_instances; i++)
|
||||
{
|
||||
MeshInstance3D *original_mesh_instance = sliced_mesh_instances[i];
|
||||
Ref<ArrayMesh> first_half; first_half.instantiate();
|
||||
Ref<ArrayMesh> other_half; other_half.instantiate();
|
||||
PackedVector3Array &impact_points = MeshEditingLibrary::slice_mesh(original_mesh_instance, skeleton, this->full_aabb, local_slice_plane, first_half, other_half, MeshEditingLibrary::CAP_UV_FILL_MESH_BOUNDS, this->inner_materials);
|
||||
|
||||
if (first_half->get_surface_count() <= 0 && other_half->get_surface_count() > 0)
|
||||
{
|
||||
Ref<ArrayMesh> temp = first_half;
|
||||
first_half = other_half;
|
||||
other_half = temp;
|
||||
}
|
||||
|
||||
if (first_half->get_surface_count() > 0)
|
||||
{
|
||||
first_half_meshes_to_add.append(first_half);
|
||||
}
|
||||
|
||||
if (other_half->get_surface_count() > 0)
|
||||
{
|
||||
other_half_meshes_to_add.append(other_half);
|
||||
}
|
||||
}
|
||||
|
||||
character_skeleton->set_meshes(first_half_meshes_to_add);
|
||||
if (other_half_meshes_to_add.size() > 0)
|
||||
Ref<MeshEditSliceInput> input; input.instantiate();
|
||||
input->mesh_instance = cast_to<MeshInstance3D>(sliced_mesh_instances[0]);
|
||||
input->skeleton = skeleton;
|
||||
input->full_aabb = this->_full_aabb;
|
||||
input->local_plane = local_slice_plane;
|
||||
input->cap_option = MeshEditingLibrary::CAP_UV_FILL_MESH_BOUNDS;
|
||||
input->cap_materials = this->inner_materials;
|
||||
this->_slice_meshes(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_hurtbox_queue.erase(this->_hurtbox_queue.begin());
|
||||
}
|
||||
|
||||
if (!this->_hurtbox_queue.empty())
|
||||
CALL_NEXT_FRAME(callable_mp(this, &Character3D::_next_hurtbox_in_queue));
|
||||
}
|
||||
|
||||
void Character3D::_slice_complete(Ref<MeshEditSliceOutput> data)
|
||||
{
|
||||
if (data->main_half->get_surface_count() <= 0 && data->secondary_half->get_surface_count() > 0)
|
||||
{
|
||||
Ref<ArrayMesh> temp = data->main_half;
|
||||
data->main_half = data->secondary_half;
|
||||
data->secondary_half = temp;
|
||||
}
|
||||
|
||||
TypedArray<ArrayMesh> first_half_meshes_to_add;
|
||||
TypedArray<ArrayMesh> other_half_meshes_to_add;
|
||||
|
||||
if (data->main_half->get_surface_count() > 0)
|
||||
{
|
||||
first_half_meshes_to_add.append(data->main_half);
|
||||
}
|
||||
|
||||
if (data->secondary_half->get_surface_count() > 0)
|
||||
{
|
||||
other_half_meshes_to_add.append(data->secondary_half);
|
||||
}
|
||||
|
||||
for (CharacterSkeleton3D *skeleton : this->skeleton_set)
|
||||
{
|
||||
if (skeleton->get_skeleton() == data->original_skeleton)
|
||||
{
|
||||
RandomNumberGenerator *rng = memnew(RandomNumberGenerator);
|
||||
const float random_x = rng->randf_range(-0.05f, 0.05f);
|
||||
const float random_z = rng->randf_range(-0.05f, 0.05f);
|
||||
|
||||
CharacterSkeleton3D *new_character_skeleton = cast_to<CharacterSkeleton3D>(this->character_skeleton->duplicate());
|
||||
this->character_skeleton->add_sibling(new_character_skeleton);
|
||||
new_character_skeleton->set_position(Vector3(random_x, 0.0f, random_z));
|
||||
|
||||
PRINT_LOG(CHARACTER3D_TAG, "Adding new meshes:");
|
||||
for (uint16_t i = 0; i < other_half_meshes_to_add.size(); i++)
|
||||
{
|
||||
const Ref<ArrayMesh> &new_array_mesh = other_half_meshes_to_add[i];
|
||||
PRINT_LOG(CHARACTER3D_TAG, " Mesh ", i+1, " size: ", new_array_mesh->get_surface_count());
|
||||
}
|
||||
new_character_skeleton->set_meshes(other_half_meshes_to_add);
|
||||
skeleton->set_meshes(first_half_meshes_to_add);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (other_half_meshes_to_add.size() > 0)
|
||||
{
|
||||
RandomNumberGenerator *rng = memnew(RandomNumberGenerator);
|
||||
const float random_x = rng->randf_range(-0.05f, 0.05f);
|
||||
const float random_z = rng->randf_range(-0.05f, 0.05f);
|
||||
|
||||
CharacterSkeleton3D *new_character_skeleton = cast_to<CharacterSkeleton3D>(this->character_skeleton->duplicate());
|
||||
this->character_skeleton->add_sibling(new_character_skeleton);
|
||||
new_character_skeleton->set_position(Vector3(random_x, 0.0f, random_z));
|
||||
|
||||
PRINT_LOG(CHARACTER3D_TAG, "Adding new meshes:");
|
||||
for (uint16_t i = 0; i < other_half_meshes_to_add.size(); i++)
|
||||
{
|
||||
const Ref<ArrayMesh> &new_array_mesh = other_half_meshes_to_add[i];
|
||||
PRINT_LOG(CHARACTER3D_TAG, " Mesh ", i+1, " size: ", new_array_mesh->get_surface_count());
|
||||
}
|
||||
new_character_skeleton->set_meshes(other_half_meshes_to_add);
|
||||
|
||||
this->skeleton_set.emplace(new_character_skeleton);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,34 +160,30 @@ void Character3D::_on_fell_out_of_world()
|
||||
|
||||
void Character3D::_rebuild_mesh_instances()
|
||||
{
|
||||
if (!this->is_node_ready()) return;
|
||||
if (!this->character_skeleton || !this->is_node_ready())
|
||||
return;
|
||||
|
||||
uint16_t num_mesh_instances = this->_mesh_instances.size();
|
||||
for (uint16_t i = 0; i < num_mesh_instances; i++)
|
||||
TypedArray<MeshInstance3D> mesh_instances = this->character_skeleton->set_meshes(this->meshes);
|
||||
const uint32_t num_meshes = mesh_instances.size();
|
||||
this->_full_aabb = AABB();
|
||||
for (uint32_t i = 0; i < num_meshes; i++)
|
||||
{
|
||||
this->_mesh_instances[i]->queue_free();
|
||||
}
|
||||
|
||||
if (!this->character_skeleton) return;
|
||||
|
||||
this->_mesh_instances = this->character_skeleton->set_meshes(this->meshes);
|
||||
const uint32_t num_meshes = this->_mesh_instances.size();
|
||||
for (const MeshInstance3D *mesh_instance : this->_mesh_instances)
|
||||
{
|
||||
const Vector3 &full_aabb_position = this->full_aabb.get_position();
|
||||
const Vector3 &full_aabb_size = this->full_aabb.get_size();
|
||||
const MeshInstance3D *mesh_instance = cast_to<MeshInstance3D>(mesh_instances[i]);
|
||||
|
||||
const Vector3 &full_aabb_position = this->_full_aabb.get_position();
|
||||
const Vector3 &full_aabb_size = this->_full_aabb.get_size();
|
||||
|
||||
const AABB &aabb = mesh_instance->get_aabb();
|
||||
const Vector3 &aabb_position = aabb.get_position();
|
||||
const Vector3 &aabb_size = aabb.get_size();
|
||||
|
||||
this->full_aabb.set_position(Vector3(
|
||||
this->_full_aabb.set_position(Vector3(
|
||||
UtilityFunctions::minf(full_aabb_position.x, aabb_position.x),
|
||||
UtilityFunctions::minf(full_aabb_position.y, aabb_position.y),
|
||||
UtilityFunctions::minf(full_aabb_position.z, aabb_position.z)
|
||||
));
|
||||
|
||||
this->full_aabb.set_size(Vector3(
|
||||
this->_full_aabb.set_size(Vector3(
|
||||
UtilityFunctions::maxf(full_aabb_position.x, aabb_size.x),
|
||||
UtilityFunctions::maxf(full_aabb_position.y, aabb_size.y),
|
||||
UtilityFunctions::maxf(full_aabb_position.z, aabb_size.z)
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "nodes/character_nodes/character_skeleton3d.h"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <godot_cpp/classes/character_body3d.hpp>
|
||||
#include <godot_cpp/classes/material.hpp>
|
||||
#include <godot_cpp/classes/mesh_instance3d.hpp>
|
||||
@@ -23,9 +25,9 @@ using namespace godot;
|
||||
#define CHARACTER3D_TAG "Character3D"
|
||||
|
||||
|
||||
class Character3D : public CharacterBody3D, public IDamageable
|
||||
class Character3D : public IDamageable
|
||||
{
|
||||
GDCLASS(Character3D, CharacterBody3D);
|
||||
GDCLASS(Character3D, IDamageable);
|
||||
|
||||
public:
|
||||
virtual void _ready() override;
|
||||
@@ -47,15 +49,19 @@ protected:
|
||||
|
||||
private:
|
||||
void _rebuild_mesh_instances();
|
||||
void _next_hurtbox_in_queue();
|
||||
|
||||
virtual void _slice_complete(Ref<MeshEditSliceOutput> data) override;
|
||||
|
||||
TypedArray<ArrayMesh> meshes;
|
||||
CharacterSkeleton3D *character_skeleton = nullptr;
|
||||
|
||||
AABB full_aabb;
|
||||
std::unordered_set<CharacterSkeleton3D*> skeleton_set;
|
||||
|
||||
AABB _full_aabb;
|
||||
TypedArray<Material> inner_materials;
|
||||
|
||||
std::vector<MeshInstance3D*> _mesh_instances;
|
||||
std::vector<CharacterSkeleton3D*> skeleton_list;
|
||||
std::vector<HurtboxDamage> _hurtbox_queue;
|
||||
|
||||
// Godot boilerplate below
|
||||
protected:
|
||||
|
||||
@@ -9,36 +9,42 @@
|
||||
|
||||
#include "orng_macros.h"
|
||||
|
||||
#include <godot_cpp/classes/scene_tree.hpp>
|
||||
#include <godot_cpp/classes/scene_tree_timer.hpp>
|
||||
#include <godot_cpp/classes/physical_bone3d.hpp>
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
using namespace godot;
|
||||
|
||||
|
||||
std::vector<MeshInstance3D*> CharacterSkeleton3D::set_meshes(TypedArray<ArrayMesh> meshes)
|
||||
TypedArray<MeshInstance3D> CharacterSkeleton3D::set_meshes(TypedArray<ArrayMesh> meshes)
|
||||
{
|
||||
if (this->skeleton)
|
||||
{
|
||||
uint16_t num_mesh_instances = this->_mesh_instances.size();
|
||||
for (uint16_t i = 0; i < num_mesh_instances; i++)
|
||||
{
|
||||
this->_mesh_instances[i]->queue_free();
|
||||
}
|
||||
this->_old_mesh_instances = this->_mesh_instances.duplicate(true);
|
||||
this->_mesh_instances.clear();
|
||||
|
||||
uint16_t num_new_meshes = meshes.size();
|
||||
this->_mesh_instances.resize(num_new_meshes);
|
||||
for (uint16_t i = 0; i < num_new_meshes; i++)
|
||||
{
|
||||
MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
|
||||
this->skeleton->add_child(mesh_instance, false, Node::INTERNAL_MODE_BACK);
|
||||
mesh_instance->set_owner(this->get_owner());
|
||||
mesh_instance->set_mesh(meshes[i]);
|
||||
mesh_instance->set_skeleton_path(this->skeleton->get_path());
|
||||
this->_mesh_instances.emplace_back(mesh_instance);
|
||||
this->skeleton->add_child(mesh_instance, false, Node::INTERNAL_MODE_BACK);
|
||||
this->_mesh_instances[i] = mesh_instance;
|
||||
}
|
||||
|
||||
CALL_NEXT_FRAME(callable_mp(this, &CharacterSkeleton3D::_delete_old_meshes));
|
||||
}
|
||||
|
||||
return this->_mesh_instances;
|
||||
}
|
||||
void CharacterSkeleton3D::_delete_old_meshes()
|
||||
{
|
||||
for (uint16_t i = 0; i < this->_old_mesh_instances.size(); i++)
|
||||
cast_to<MeshInstance3D>(this->_old_mesh_instances[i])->queue_free();
|
||||
this->_old_mesh_instances.clear();
|
||||
}
|
||||
|
||||
|
||||
void CharacterSkeleton3D::_activate_ragdoll()
|
||||
|
||||
@@ -26,15 +26,15 @@ class CharacterSkeleton3D : public Node3D
|
||||
GDCLASS(CharacterSkeleton3D, Node3D);
|
||||
|
||||
public:
|
||||
std::vector<MeshInstance3D*> set_meshes(TypedArray<ArrayMesh> meshes);
|
||||
TypedArray<MeshInstance3D> set_meshes(TypedArray<ArrayMesh> meshes);
|
||||
|
||||
Skeleton3D *get_skeleton() const { return this->skeleton; }
|
||||
PhysicalBoneSimulator3D *get_physical_bone_simulator() const { return this->physical_bone_simulator; }
|
||||
AnimationPlayer *get_animation_player() const { return this->animation_player; }
|
||||
AnimationTree *get_animation_tree() const { return this->animation_tree; }
|
||||
|
||||
void replace_mesh_instance(const uint16_t index, Ref<ArrayMesh> new_mesh) { this->_mesh_instances[index]->set_mesh(new_mesh); }
|
||||
std::vector<MeshInstance3D*> get_mesh_instances() const { return this->_mesh_instances; }
|
||||
void replace_mesh_instance(const uint16_t index, Ref<ArrayMesh> new_mesh) { cast_to<MeshInstance3D>(this->_mesh_instances[index])->set_mesh(new_mesh); }
|
||||
TypedArray<MeshInstance3D> get_mesh_instances() const { return this->_mesh_instances; }
|
||||
|
||||
protected:
|
||||
void set_skeleton(Skeleton3D *s) { this->skeleton = s; }
|
||||
@@ -43,7 +43,8 @@ protected:
|
||||
void set_animation_tree(AnimationTree *at) { this->animation_tree = at; }
|
||||
|
||||
private:
|
||||
void _refresh_skins_and_meshes();
|
||||
// void _refresh_skins_and_meshes();
|
||||
void _delete_old_meshes();
|
||||
|
||||
void _activate_ragdoll();
|
||||
|
||||
@@ -52,7 +53,8 @@ private:
|
||||
AnimationPlayer *animation_player = nullptr;
|
||||
AnimationTree *animation_tree = nullptr;
|
||||
|
||||
std::vector<MeshInstance3D*> _mesh_instances;
|
||||
TypedArray<MeshInstance3D> _mesh_instances;
|
||||
TypedArray<MeshInstance3D> _old_mesh_instances;
|
||||
|
||||
// Godot boilerplate below
|
||||
protected:
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
using namespace godot;
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
|
||||
void HurtboxBase::_enter_tree()
|
||||
{
|
||||
@@ -50,7 +52,7 @@ void HurtboxBase::_ready()
|
||||
this->set_process(false);
|
||||
this->remaining_life = this->lifetime;
|
||||
|
||||
CALL_NEXT_FRAME(callable_mp(this, &HurtboxBase::_send_next_in_queue));
|
||||
this->_send_next_in_queue();
|
||||
}
|
||||
|
||||
void HurtboxBase::_physics_process(double delta)
|
||||
@@ -58,7 +60,7 @@ void HurtboxBase::_physics_process(double delta)
|
||||
const TypedArray<Node3D> &bodies = this->get_overlapping_bodies();
|
||||
const uint32_t num_bodies = bodies.size();
|
||||
|
||||
std::vector<IDamageable*> new_hit_bodies;
|
||||
std::unordered_set<IDamageable*> new_hit_bodies;
|
||||
std::vector<CharacterSkeleton3D*> new_hit_skeletons;
|
||||
|
||||
for (uint32_t i = 0; i < num_bodies; i++)
|
||||
@@ -71,7 +73,7 @@ void HurtboxBase::_physics_process(double delta)
|
||||
{
|
||||
if (std::find(this->hit_bodies.begin(), this->hit_bodies.end(), body) == this->hit_bodies.end())
|
||||
{
|
||||
new_hit_bodies.emplace_back(body);
|
||||
new_hit_bodies.emplace(body);
|
||||
|
||||
if (std::find(new_hit_skeletons.begin(), new_hit_skeletons.end(), character_skeleton) == new_hit_skeletons.end())
|
||||
{
|
||||
@@ -110,12 +112,32 @@ void HurtboxBase::_send_next_in_queue()
|
||||
{
|
||||
if (!this->hit_data_queue.empty())
|
||||
{
|
||||
const std::map<IDamageable*, std::vector<HurtboxDamage>>::iterator &first_in_queue = this->hit_data_queue.begin();
|
||||
for (const HurtboxDamage &damage : first_in_queue->second)
|
||||
IDamageable *closest_damageable = nullptr;
|
||||
float shortest_distance_from_hurtbox = FLT_MAX;
|
||||
bool found_character_3d = false;
|
||||
for (const auto &[damageable, hit_data_list] : this->hit_data_queue)
|
||||
{
|
||||
first_in_queue->first->take_damage(damage);
|
||||
if (const Character3D *node = (Character3D*)(damageable))
|
||||
{
|
||||
const float distance_to_hurtbox = node->get_global_position().distance_squared_to(this->get_global_position());
|
||||
if (distance_to_hurtbox < shortest_distance_from_hurtbox)
|
||||
{
|
||||
closest_damageable = damageable;
|
||||
shortest_distance_from_hurtbox = distance_to_hurtbox;
|
||||
found_character_3d = true;
|
||||
}
|
||||
// if (!found_character_3d && const SliceablePhysicsObject3D *node = (SliceablePhysicsObject3D*)(damageable) )
|
||||
// {
|
||||
// // This is where we handle regular physics objects.
|
||||
// }
|
||||
}
|
||||
}
|
||||
if (closest_damageable)
|
||||
{
|
||||
for (const HurtboxDamage &damage : this->hit_data_queue[closest_damageable])
|
||||
closest_damageable->take_damage(damage);
|
||||
this->hit_data_queue.erase(closest_damageable);
|
||||
}
|
||||
this->hit_data_queue.erase(this->hit_data_queue.begin());
|
||||
}
|
||||
|
||||
if (this->hit_data_queue.empty() && this->remaining_life <= 0.0f)
|
||||
@@ -124,6 +146,6 @@ void HurtboxBase::_send_next_in_queue()
|
||||
}
|
||||
else
|
||||
{
|
||||
CALL_NEXT_FRAME(callable_mp(this, &HurtboxBase::_send_next_in_queue));
|
||||
CALL_ON_TIMEOUT(1.0f / 8.0f, callable_mp(this, &HurtboxBase::_send_next_in_queue));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,11 +15,12 @@
|
||||
#include <godot_cpp/variant/vector3.hpp>
|
||||
using namespace godot;
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#define MESH_EDITING_LIBRARY_TAG "MeshEditingLibrary"
|
||||
|
||||
typedef std::vector<Vector3> SkinnedVertices;
|
||||
typedef PackedVector3Array SkinnedVertices;
|
||||
typedef std::vector<SkinnedVertices> SkinnedSurfaces;
|
||||
|
||||
|
||||
@@ -55,6 +56,11 @@ struct MeshEditPolygon2D
|
||||
};
|
||||
|
||||
|
||||
class MeshEditSliceInput;
|
||||
class MeshEditSliceOutput;
|
||||
class MeshSliceState;
|
||||
|
||||
|
||||
class MeshEditingLibrary : public Node
|
||||
{
|
||||
GDCLASS(MeshEditingLibrary, Node);
|
||||
@@ -63,6 +69,15 @@ public:
|
||||
MeshEditingLibrary(){}
|
||||
~MeshEditingLibrary(){}
|
||||
|
||||
enum MeshEditSliceStage
|
||||
{
|
||||
SLICE_STAGE_INIT,
|
||||
SLICE_STAGE_PLANE_SPLIT,
|
||||
SLICE_STAGE_EDGE_SPLIT,
|
||||
SLICE_STAGE_APPLY_CAP,
|
||||
SLICE_STAGE_COMPLETE
|
||||
};
|
||||
|
||||
enum MeshEditCapUV
|
||||
{
|
||||
CAP_UV_FILL_MESH_BOUNDS,
|
||||
@@ -70,7 +85,12 @@ public:
|
||||
CAP_UV_TILED
|
||||
};
|
||||
|
||||
static PackedVector3Array slice_mesh(MeshInstance3D *original_mesh_instance, const Skeleton3D *original_skeleton, const AABB &original_aabb, const Plane &local_plane, Ref<ArrayMesh> out_first_half, Ref<ArrayMesh> out_other_half, const MeshEditCapUV cap_option, const TypedArray<Material> &cap_materials);
|
||||
static Ref<class MeshSliceState> slice_mesh(const Ref<class MeshEditSliceInput> input);
|
||||
|
||||
static void slice_mesh_init(Ref<class MeshSliceState> state);
|
||||
static void slice_mesh_plane_split(Ref<class MeshSliceState> state);
|
||||
static void slice_mesh_edge_split(Ref<class MeshSliceState> state);
|
||||
static void slice_mesh_apply_cap(Ref<class MeshSliceState> state);
|
||||
|
||||
protected:
|
||||
enum MeshSlicePlaneOrientation
|
||||
@@ -83,7 +103,9 @@ protected:
|
||||
private:
|
||||
static const Vector2 calculate_planar_uv(const Vector3 &vertex, const Vector3 &mesh_bounds, const MeshSlicePlaneOrientation &axis);
|
||||
|
||||
static SkinnedSurfaces get_skinned_vertex_positions(const Mesh *mesh, const Skeleton3D *skeleton = nullptr, std::vector<std::vector<Transform3D>> &bone_transforms = std::vector<std::vector<Transform3D>>());
|
||||
static SkinnedVertices get_skinned_vertex_positions(const uint8_t surface, const Ref<ArrayMesh> mesh, const Skeleton3D *skeleton = nullptr, std::vector<Transform3D> &bone_transforms = std::vector<Transform3D>());
|
||||
|
||||
static constexpr const uint8_t uv_to_body_part_shift(const float x, const float y) { return (uint8_t(y * 5.0f) * 5) + uint8_t(x * 5.0f); }
|
||||
|
||||
static const Transform3D project_edges(std::vector<MeshEditEdge2D> &out_2d_edges, const std::vector<MeshEditEdge3D> &in_3d_edges, const Plane &plane);
|
||||
static void build_2d_polygons_from_edges(std::vector<MeshEditPolygon2D> &out_polygons, const std::vector<MeshEditEdge2D> &in_edges, std::vector<MeshEditPolygon2D> &error_polygons);
|
||||
@@ -96,7 +118,13 @@ private:
|
||||
protected:
|
||||
static void _bind_methods()
|
||||
{
|
||||
ClassDB::bind_static_method("MeshEditingLibrary", D_METHOD("slice_mesh", "original_mesh_instance", "original_skeleton", "local_plane", "out_first_half", "out_other_half", "cap_option", "cap_material"), &MeshEditingLibrary::slice_mesh);
|
||||
ClassDB::bind_static_method("MeshEditingLibrary", D_METHOD("slice_mesh", "input"), &MeshEditingLibrary::slice_mesh);
|
||||
|
||||
BIND_ENUM_CONSTANT(SLICE_STAGE_INIT);
|
||||
BIND_ENUM_CONSTANT(SLICE_STAGE_PLANE_SPLIT);
|
||||
BIND_ENUM_CONSTANT(SLICE_STAGE_EDGE_SPLIT);
|
||||
BIND_ENUM_CONSTANT(SLICE_STAGE_APPLY_CAP);
|
||||
BIND_ENUM_CONSTANT(SLICE_STAGE_COMPLETE);
|
||||
|
||||
BIND_ENUM_CONSTANT(CAP_UV_FILL_MESH_BOUNDS);
|
||||
BIND_ENUM_CONSTANT(CAP_UV_FILL_CAP_BOUNDS);
|
||||
@@ -104,4 +132,116 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(MeshEditingLibrary::MeshEditSliceStage);
|
||||
VARIANT_ENUM_CAST(MeshEditingLibrary::MeshEditCapUV);
|
||||
|
||||
|
||||
class MeshEditSliceInput : public RefCounted
|
||||
{
|
||||
GDCLASS(MeshEditSliceInput, RefCounted);
|
||||
|
||||
public:
|
||||
MeshInstance3D *mesh_instance = nullptr;
|
||||
const Skeleton3D *skeleton = nullptr;
|
||||
AABB full_aabb;
|
||||
Plane local_plane;
|
||||
|
||||
uint32_t hit_mask = 0b1111111111111111111111111;
|
||||
|
||||
MeshEditingLibrary::MeshEditCapUV cap_option;
|
||||
TypedArray<Material> cap_materials;
|
||||
|
||||
protected:
|
||||
static void _bind_methods(){}
|
||||
};
|
||||
|
||||
class MeshEditSliceOutput : public RefCounted
|
||||
{
|
||||
GDCLASS(MeshEditSliceOutput, RefCounted);
|
||||
|
||||
public:
|
||||
const Skeleton3D *original_skeleton = nullptr;
|
||||
Ref<ArrayMesh> main_half;
|
||||
Ref<ArrayMesh> secondary_half;
|
||||
|
||||
PackedVector3Array impact_points;
|
||||
uint32_t hit_map = 0b0000000000000000000000000;
|
||||
|
||||
protected:
|
||||
static void _bind_methods(){}
|
||||
};
|
||||
|
||||
|
||||
class MeshSliceState : public RefCounted
|
||||
{
|
||||
GDCLASS(MeshSliceState, RefCounted);
|
||||
|
||||
public:
|
||||
MeshEditingLibrary::MeshEditSliceStage current_stage = MeshEditingLibrary::MeshEditSliceStage::SLICE_STAGE_INIT;
|
||||
MeshInstance3D *current_mesh = nullptr;
|
||||
|
||||
Ref<MeshEditSliceInput> input;
|
||||
|
||||
uint8_t surface = 0;
|
||||
uint32_t element = 0;
|
||||
|
||||
Ref<ArrayMesh> first_half;
|
||||
Ref<ArrayMesh> other_half;
|
||||
|
||||
Ref<ArrayMesh> original_mesh;
|
||||
uint8_t num_surfaces;
|
||||
|
||||
std::vector<Array> surface_arrays_list;
|
||||
std::vector<SkinnedVertices> skinned_vertex_positions;
|
||||
std::vector<std::vector<Transform3D>> skinned_vertex_transforms;
|
||||
|
||||
std::vector<bool> has_normal;
|
||||
std::vector<bool> has_tangent;
|
||||
std::vector<bool> has_uv;
|
||||
std::vector<bool> has_uv2;
|
||||
std::vector<bool> has_colour;
|
||||
std::vector<bool> has_bone;
|
||||
std::vector<bool> has_weight;
|
||||
std::vector<bool> has_custom0;
|
||||
|
||||
std::vector<uint8_t> num_bones_per_vertex;
|
||||
std::vector<uint8_t> num_custom0_per_vertex;
|
||||
|
||||
std::vector<PackedVector3Array> first_half_vertices;
|
||||
std::vector<PackedVector3Array> first_half_normals;
|
||||
std::vector<PackedFloat32Array> first_half_tangents;
|
||||
std::vector<PackedVector2Array> first_half_uvs;
|
||||
std::vector<PackedVector2Array> first_half_uv2s;
|
||||
std::vector<PackedColorArray> first_half_colours;
|
||||
std::vector<PackedInt32Array> first_half_bones;
|
||||
std::vector<PackedFloat32Array> first_half_weights;
|
||||
std::vector<PackedFloat32Array> first_half_custom0;
|
||||
|
||||
std::vector<PackedVector3Array> other_half_vertices;
|
||||
std::vector<PackedVector3Array> other_half_normals;
|
||||
std::vector<PackedFloat32Array> other_half_tangents;
|
||||
std::vector<PackedVector2Array> other_half_uvs;
|
||||
std::vector<PackedVector2Array> other_half_uv2s;
|
||||
std::vector<PackedColorArray> other_half_colours;
|
||||
std::vector<PackedInt32Array> other_half_bones;
|
||||
std::vector<PackedFloat32Array> other_half_weights;
|
||||
std::vector<PackedFloat32Array> other_half_custom0;
|
||||
|
||||
std::vector<PackedInt32Array> first_half_indices;
|
||||
std::vector<PackedInt32Array> other_half_indices;
|
||||
|
||||
std::vector<std::vector<float>> vertex_distances;
|
||||
|
||||
std::vector<std::map<uint32_t, uint32_t>> base_to_first_sliced_vert_indices;
|
||||
std::vector<std::map<uint32_t, uint32_t>> base_to_other_sliced_vert_indices;
|
||||
|
||||
uint32_t first_half_split_map = 0x00000000;
|
||||
uint32_t other_half_split_map = 0x00000000;
|
||||
|
||||
std::vector<MeshEditEdge3D> clip_edges;
|
||||
|
||||
Ref<MeshEditSliceOutput> output;
|
||||
|
||||
protected:
|
||||
static void _bind_methods(){}
|
||||
};
|
||||
|
||||
@@ -34,8 +34,10 @@
|
||||
/**
|
||||
* Deferred function helpers
|
||||
*/
|
||||
#define CALL_ON_TIMEOUT(T,C) \
|
||||
this->get_tree()->create_timer(T)->connect("timeout", C)
|
||||
#define CALL_NEXT_FRAME(C) \
|
||||
this->get_tree()->create_timer(SMALL_NUMBER)->connect("timeout", C)
|
||||
CALL_ON_TIMEOUT(SMALL_NUMBER,C)
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -78,6 +78,9 @@ void initialize_orng_module(ModuleInitializationLevel p_level) {
|
||||
ClassDB::register_class<SaveFileData>();
|
||||
|
||||
ClassDB::register_class<MeshEditingLibrary>();
|
||||
ClassDB::register_class<MeshEditSliceInput>();
|
||||
ClassDB::register_class<MeshEditSliceOutput>();
|
||||
ClassDB::register_class<MeshSliceState>();
|
||||
|
||||
GDSINGLETON_REGISTER_CLASS(InputHandler, _input_handler_singleton);
|
||||
GDSINGLETON_REGISTER_CLASS(SaveManager, _save_manager_singleton);
|
||||
|
||||
Reference in New Issue
Block a user