Compare commits

..

No commits in common. "e1ac85e55694a9ae7b66ac2a5983fce6e3722845" and "3b277a38620380c4fe883e2c069012db2253c56e" have entirely different histories.

5 changed files with 45 additions and 117 deletions

View File

@ -4,10 +4,6 @@
[resource] [resource]
resource_name = "lambert2" resource_name = "lambert2"
diffuse_mode = 2
specular_mode = 2
albedo_texture = ExtResource("1_ysskd") albedo_texture = ExtResource("1_ysskd")
rim_tint = 1.0 rim_tint = 1.0
grow_amount = -0.264 grow_amount = -0.264
distance_fade_min_distance = 2.4
distance_fade_max_distance = 3.25

View File

@ -6,3 +6,5 @@
resource_name = "lambert3" resource_name = "lambert3"
albedo_color = Color(0.905882, 0.905882, 0.905882, 1) albedo_color = Color(0.905882, 0.905882, 0.905882, 1)
albedo_texture = ExtResource("1_s0844") albedo_texture = ExtResource("1_s0844")
metallic = 0.2
roughness = 0.8

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=6 format=3 uid="uid://dw8q1vqnc657"] [gd_scene load_steps=5 format=3 uid="uid://dw8q1vqnc657"]
[ext_resource type="PackedScene" uid="uid://c8h5f82tunglj" path="res://Models/Characters/ModularCharacters.fbx" id="1_b4mv3"] [ext_resource type="PackedScene" uid="uid://c8h5f82tunglj" path="res://Models/Characters/ModularCharacters.fbx" id="1_b4mv3"]
@ -203,37 +203,9 @@ _data = {
[sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_7e1iu"] [sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_7e1iu"]
graph_offset = Vector2(-457, 44) graph_offset = Vector2(-457, 44)
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_hqeid"]
radius = 0.548248
height = 1.85415
[node name="Player" type="Player"] [node name="Player" type="Player"]
active_customization = { selected = "Torso"
"ArmLowerLeft": 8, index = 15
"ArmLowerRight": 0,
"ArmUpperLeft": 0,
"ArmUpperRight": 0,
"BackAttachment": 1,
"Ear": -1,
"ElbowAttachLeft": -1,
"ElbowAttachRight": -1,
"Eyebrow": 0,
"Hair": 13,
"HandLeft": 0,
"HandRight": 4,
"Head": 15,
"HeadCoverings": -1,
"HelmetAttachment": -1,
"Hips": 3,
"HipsAttachment": 3,
"KneeAttachLeft": -1,
"KneeAttachRight": -1,
"LegLeft": 12,
"LegRight": 12,
"ShoulderAttachLeft": 16,
"ShoulderAttachRight": -1,
"Torso": 11
}
slide_on_ceiling = false slide_on_ceiling = false
[node name="Model" parent="." instance=ExtResource("1_b4mv3")] [node name="Model" parent="." instance=ExtResource("1_b4mv3")]
@ -245,7 +217,3 @@ libraries = {
} }
tree_root = SubResource("AnimationNodeStateMachine_7e1iu") tree_root = SubResource("AnimationNodeStateMachine_7e1iu")
anim_player = NodePath("../Model/AnimationPlayer") anim_player = NodePath("../Model/AnimationPlayer")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.925894, 0)
shape = SubResource("CapsuleShape3D_hqeid")

View File

@ -10,7 +10,8 @@ namespace godot {
void Player::_bind_methods() { void Player::_bind_methods() {
#define CLASSNAME Player #define CLASSNAME Player
#ifndef NDEBUG #ifndef NDEBUG
GDPROPERTY(active_customization, Variant::DICTIONARY); GDPROPERTY(selected, Variant::STRING);
GDPROPERTY(index, Variant::INT);
#endif #endif
} }
void Player::_enter_tree() { void Player::_enter_tree() {
@ -20,8 +21,8 @@ void Player::_enter_tree() {
} }
void Player::_exit_tree() { void Player::_exit_tree() {
for(std::pair<const String, CustomizationState>& pair: this->customization) { for(std::pair<const String, std::pair<size_t, std::vector<Node3D*>>>& pair: this->customization) {
for(Node3D *option: pair.second.options) { for(Node3D *option: pair.second.second) {
if(!option->is_inside_tree()) { if(!option->is_inside_tree()) {
option->queue_free(); option->queue_free();
} }
@ -33,85 +34,43 @@ void Player::_process(double deltaTime) {}
void Player::_physics_process(double deltaTime) {} void Player::_physics_process(double deltaTime) {}
void Player::customization_init() { void Player::customization_init() {
this->customizationParent = this->get_node<Skeleton3D>("Model/RootNode/Skeleton3D"); customizationParent = this->get_node<Skeleton3D>("Model/RootNode/Skeleton3D");
if(!this->customizationParent) if(!customizationParent)
return; return;
for(int i = 0; i < customizationParent->get_child_count(); ++i) { for(int i = 0; i < customizationParent->get_child_count(); ++i) {
// get the next valid child Node3D *child = Object::cast_to<Node3D>(customizationParent->get_child(i));
Node3D *child = Object::cast_to<Node3D>(this->customizationParent->get_child(i)); if(!child)
if(!child) continue; continue;
// split it's name into parts based on _ String name = child->get_name();
// the format for the names will be Chr_<CATEGORY NAME>_<NUMBER> PackedStringArray slices = name.split("_", false);
// number IS NOT guaranteed to start at 0 or 1 if(customization.find(slices[1]) != customization.end()) {
// the category name will serve as the key to the customization map auto &array = customization.at(slices[1]);
PackedStringArray slices = child->get_name().split("_", false); array.second.push_back(child);
// create a new customization state if one does not exist for this category customizationParent->remove_child(child);
if(this->customization.find(slices[1]) == this->customization.end())
this->customization.insert({slices[1], {0, {}}});
// add the new child to the customization options for this category
CustomizationState &state = this->customization.at(slices[1]);
state.options.push_back(child);
// only allow this child to exist in the scene tree if it was saved as the current selection
if(state.currentSelected != state.options.size()-1) {
this->customizationParent->remove_child(child);
--i; --i;
} else {
customization.insert({slices[1], {0, {child}}});
} }
} }
std::vector<String> empty{}; UtilityFunctions::print("customization categories:");
UtilityFunctions::print("categories:"); for(std::pair<const String, std::pair<size_t, std::vector<Node3D *>>>& pair: this->customization) {
for(std::pair<String, CustomizationState> const& pair: this->customization) { UtilityFunctions::print("- ", pair.first);
UtilityFunctions::print("- ", pair.first, " selected ", pair.second.currentSelected);
if(pair.second.options.size() == 0)
empty.push_back(pair.first);
}
for(String const& key: empty) {
this->customization.erase(key);
UtilityFunctions::print("removing invalid category: ", key);
} }
} }
void Player::select_customization(String key, int index) { void Player::select_customization(String key, int index) {
if(this->customization.find(key) == this->customization.end()) std::pair<size_t, std::vector<Node3D *>> &pair = this->customization.at(key);
if(index > pair.second.size())
return; return;
CustomizationState &pair = this->customization.at(key); if(index == pair.first)
// invalid keys are stored as the size of the array
if(index < 0 || index > pair.options.size())
index = pair.options.size();
// nothing changes
if(index == pair.currentSelected)
return; return;
// disable previous chosen option, if any customizationParent->remove_child(pair.second[pair.first]);
if(pair.currentSelected < pair.options.size()) customizationParent->add_child(pair.second[index]);
customizationParent->remove_child(pair.options[pair.currentSelected]); pair.first = index;
// enable chosen option, if any
if(index < pair.options.size())
customizationParent->add_child(pair.options[index]);
pair.currentSelected = index;
} }
Dictionary Player::get_active_customization() const { #ifndef NDEBUG
Dictionary result{}; void Player::set_selected(String value) { this->selected = value; }
// translate the map to a dictionary of keys and indexes String Player::get_selected() const { return this->selected; }
for(std::pair<String, CustomizationState> const &pair: this->customization) #endif
result[pair.first] = pair.second.currentSelected >= pair.second.options.size()
? -1 // an invalid key will always be -1
: pair.second.currentSelected;
return result;
}
void Player::set_active_customization(Dictionary value) {
for(int64_t i = 0; i < value.size(); ++i) {
String key = value.keys()[i];
size_t selection = value[key];
bool exists = this->customization.find(key) != this->customization.end(); // wether or not the a given key exists in the customization map
// if not, it can be added, as long as the customization map has not yet been initialized by _enter_tree
if(!exists && !this->is_inside_tree())
this->customization.insert({key, {selection, {}}});
// if the key does not exist in customization and _enter_tree is already called, the key is not valid and discarted
else if(!exists)
return;
else
this->select_customization(key, selection);
}
}
} // namespace godot } // namespace godot

View File

@ -10,16 +10,15 @@ namespace godot {
class Player : public CharacterBody3D { class Player : public CharacterBody3D {
GDCLASS(Player, CharacterBody3D) GDCLASS(Player, CharacterBody3D)
static void _bind_methods(); static void _bind_methods();
struct CustomizationState {
size_t currentSelected;
std::vector<Node3D *> options;
};
protected: protected:
std::map<String, CustomizationState> customization{};
Node3D* model{nullptr}; Node3D* model{nullptr};
AnimationTree* animTree{nullptr}; AnimationTree* animTree{nullptr};
std::map<String, std::pair<size_t, std::vector<Node3D *>>> customization{};
Skeleton3D *customizationParent{nullptr}; Skeleton3D *customizationParent{nullptr};
#ifndef NDEBUG
String selected;
#endif
public: public:
virtual void _enter_tree() override; virtual void _enter_tree() override;
@ -32,8 +31,12 @@ public:
void select_customization(String key, int value); void select_customization(String key, int value);
Dictionary get_active_customization() const; #ifndef NDEBUG
void set_active_customization(Dictionary value); void set_selected(String value);
String get_selected() const;
void set_index(int value) { this->select_customization(this->selected, value); }
int get_index() { return this->customization.find(this->selected) == this->customization.end() ? 0 : this->customization.at(this->selected).first; }
#endif
}; };
} // namespace godot } // namespace godot