Compare commits
3 Commits
3b277a3862
...
e1ac85e556
Author | SHA1 | Date |
---|---|---|
Sara | e1ac85e556 | |
Sara | edf779ebc6 | |
Sara | 68bb445f43 |
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
[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
|
||||||
|
|
|
@ -6,5 +6,3 @@
|
||||||
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
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=5 format=3 uid="uid://dw8q1vqnc657"]
|
[gd_scene load_steps=6 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,9 +203,37 @@ _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"]
|
||||||
selected = "Torso"
|
active_customization = {
|
||||||
index = 15
|
"ArmLowerLeft": 8,
|
||||||
|
"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")]
|
||||||
|
@ -217,3 +245,7 @@ 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")
|
||||||
|
|
101
src/player.cpp
101
src/player.cpp
|
@ -10,8 +10,7 @@ namespace godot {
|
||||||
void Player::_bind_methods() {
|
void Player::_bind_methods() {
|
||||||
#define CLASSNAME Player
|
#define CLASSNAME Player
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
GDPROPERTY(selected, Variant::STRING);
|
GDPROPERTY(active_customization, Variant::DICTIONARY);
|
||||||
GDPROPERTY(index, Variant::INT);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void Player::_enter_tree() {
|
void Player::_enter_tree() {
|
||||||
|
@ -21,8 +20,8 @@ void Player::_enter_tree() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::_exit_tree() {
|
void Player::_exit_tree() {
|
||||||
for(std::pair<const String, std::pair<size_t, std::vector<Node3D*>>>& pair: this->customization) {
|
for(std::pair<const String, CustomizationState>& pair: this->customization) {
|
||||||
for(Node3D *option: pair.second.second) {
|
for(Node3D *option: pair.second.options) {
|
||||||
if(!option->is_inside_tree()) {
|
if(!option->is_inside_tree()) {
|
||||||
option->queue_free();
|
option->queue_free();
|
||||||
}
|
}
|
||||||
|
@ -34,43 +33,85 @@ 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() {
|
||||||
customizationParent = this->get_node<Skeleton3D>("Model/RootNode/Skeleton3D");
|
this->customizationParent = this->get_node<Skeleton3D>("Model/RootNode/Skeleton3D");
|
||||||
if(!customizationParent)
|
if(!this->customizationParent)
|
||||||
return;
|
return;
|
||||||
for(int i = 0; i < customizationParent->get_child_count(); ++i) {
|
for(int i = 0; i < customizationParent->get_child_count(); ++i) {
|
||||||
Node3D *child = Object::cast_to<Node3D>(customizationParent->get_child(i));
|
// get the next valid child
|
||||||
if(!child)
|
Node3D *child = Object::cast_to<Node3D>(this->customizationParent->get_child(i));
|
||||||
continue;
|
if(!child) continue;
|
||||||
String name = child->get_name();
|
// split it's name into parts based on _
|
||||||
PackedStringArray slices = name.split("_", false);
|
// the format for the names will be Chr_<CATEGORY NAME>_<NUMBER>
|
||||||
if(customization.find(slices[1]) != customization.end()) {
|
// number IS NOT guaranteed to start at 0 or 1
|
||||||
auto &array = customization.at(slices[1]);
|
// the category name will serve as the key to the customization map
|
||||||
array.second.push_back(child);
|
PackedStringArray slices = child->get_name().split("_", false);
|
||||||
customizationParent->remove_child(child);
|
// create a new customization state if one does not exist for this category
|
||||||
|
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}}});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UtilityFunctions::print("customization categories:");
|
std::vector<String> empty{};
|
||||||
for(std::pair<const String, std::pair<size_t, std::vector<Node3D *>>>& pair: this->customization) {
|
UtilityFunctions::print("categories:");
|
||||||
UtilityFunctions::print("- ", pair.first);
|
for(std::pair<String, CustomizationState> const& pair: this->customization) {
|
||||||
|
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) {
|
||||||
std::pair<size_t, std::vector<Node3D *>> &pair = this->customization.at(key);
|
if(this->customization.find(key) == this->customization.end())
|
||||||
if(index > pair.second.size())
|
|
||||||
return;
|
return;
|
||||||
if(index == pair.first)
|
CustomizationState &pair = this->customization.at(key);
|
||||||
|
// 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;
|
||||||
customizationParent->remove_child(pair.second[pair.first]);
|
// disable previous chosen option, if any
|
||||||
customizationParent->add_child(pair.second[index]);
|
if(pair.currentSelected < pair.options.size())
|
||||||
pair.first = index;
|
customizationParent->remove_child(pair.options[pair.currentSelected]);
|
||||||
|
// enable chosen option, if any
|
||||||
|
if(index < pair.options.size())
|
||||||
|
customizationParent->add_child(pair.options[index]);
|
||||||
|
pair.currentSelected = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
Dictionary Player::get_active_customization() const {
|
||||||
void Player::set_selected(String value) { this->selected = value; }
|
Dictionary result{};
|
||||||
String Player::get_selected() const { return this->selected; }
|
// translate the map to a dictionary of keys and indexes
|
||||||
#endif
|
for(std::pair<String, CustomizationState> const &pair: this->customization)
|
||||||
|
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
|
||||||
|
|
|
@ -10,15 +10,16 @@ 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;
|
||||||
|
@ -31,12 +32,8 @@ public:
|
||||||
|
|
||||||
void select_customization(String key, int value);
|
void select_customization(String key, int value);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
Dictionary get_active_customization() const;
|
||||||
void set_selected(String value);
|
void set_active_customization(Dictionary 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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue