155 lines
4.4 KiB
C++
155 lines
4.4 KiB
C++
#include "character.h"
|
|
#include "authority/macros.h"
|
|
#include "core/config/engine.h"
|
|
|
|
void CharacterData::_bind_methods() {
|
|
BIND_PROPERTY(Variant::FLOAT, speed);
|
|
}
|
|
|
|
void Character::_bind_methods() {
|
|
BIND_HPROPERTY(Variant::OBJECT, data, PROPERTY_HINT_RESOURCE_TYPE, "CharacterData");
|
|
}
|
|
|
|
void Character::physics_process(double delta) {
|
|
Vector3 const velocity{ get_velocity() };
|
|
Vector3 new_velocity{ velocity };
|
|
new_velocity.x = this->world_movement_direction.x;
|
|
new_velocity.z = this->world_movement_direction.y;
|
|
set_velocity(new_velocity);
|
|
if (!velocity.is_zero_approx()) {
|
|
move_and_slide();
|
|
}
|
|
}
|
|
|
|
void Character::_notification(int what) {
|
|
if (Engine::get_singleton()->is_editor_hint() || !this->data.is_valid()) {
|
|
return;
|
|
}
|
|
switch (what) {
|
|
default:
|
|
return;
|
|
case NOTIFICATION_READY:
|
|
set_physics_process(true);
|
|
return;
|
|
case NOTIFICATION_PHYSICS_PROCESS:
|
|
physics_process(get_physics_process_delta_time());
|
|
return;
|
|
}
|
|
}
|
|
|
|
PackedStringArray Character::get_configuration_warnings() const {
|
|
PackedStringArray warnings{ super_type::get_configuration_warnings() };
|
|
if (this->data.is_null()) {
|
|
warnings.push_back("Character requires 'data' to be initialised. To avoid crashes consider adding a placeholder if you intend to programmatically initialise it.");
|
|
}
|
|
return warnings;
|
|
}
|
|
|
|
void Character::set_movement(Vector2 movement) {
|
|
this->world_movement_direction = movement;
|
|
}
|
|
|
|
bool Character::is_moving() const {
|
|
return !this->world_movement_direction.is_zero_approx();
|
|
}
|
|
|
|
void CharacterState::_bind_methods() {
|
|
BIND_PROPERTY(Variant::BOOL, start_active);
|
|
}
|
|
|
|
void CharacterState::_notification(int what) {
|
|
if (Engine::get_singleton()->is_editor_hint()) {
|
|
return;
|
|
}
|
|
switch (what) {
|
|
default:
|
|
return;
|
|
case NOTIFICATION_ENTER_TREE:
|
|
this->character = cast_to<Character>(get_parent());
|
|
ERR_FAIL_COND_EDMSG(this->character == nullptr, "CharacterState requires parent to be of type Character");
|
|
return;
|
|
case NOTIFICATION_READY:
|
|
if (start_active) {
|
|
callable_mp(this, &self_type::set_state_active).call_deferred(true);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
PackedStringArray CharacterState::get_configuration_warnings() const {
|
|
PackedStringArray warnings{ super_type::get_configuration_warnings() };
|
|
if (cast_to<Character>(get_parent()) == nullptr) {
|
|
warnings.push_back("CharacterState requires direct Character parent");
|
|
}
|
|
return warnings;
|
|
}
|
|
|
|
void CharacterState::switch_to_state(String value) {
|
|
if (!this->state_active) {
|
|
print_error(vformat("Attempt to switch from inactive state %s to new state %s", get_path(), value));
|
|
return;
|
|
}
|
|
set_state_active(false);
|
|
stack_state_independent(value);
|
|
}
|
|
|
|
void CharacterState::stack_state_dependent(String value) {
|
|
if (!this->state_active) {
|
|
print_error(vformat("Attempt to stack dependent state %s from inactive state %s", value, get_path()));
|
|
return;
|
|
}
|
|
Node *node{ get_parent()->get_node(value) };
|
|
if (CharacterState * state{ cast_to<CharacterState>(node) }) {
|
|
state->depending_state = this;
|
|
this->dependent_states.insert(state);
|
|
state->set_state_active(true);
|
|
}
|
|
}
|
|
|
|
void CharacterState::notify_dependent_inactive(CharacterState *state) {
|
|
if (!this->state_active) {
|
|
print_error(vformat("Received notification that dependent state %s became inactive, while depending state %s was inactive", state->get_path(), get_path()));
|
|
return;
|
|
}
|
|
this->dependent_states.erase(state);
|
|
}
|
|
|
|
void CharacterState::stack_state_independent(String value) {
|
|
if (!this->state_active) {
|
|
print_error(vformat("Attempt to stack state %s from inactive state %s", value, get_path()));
|
|
return;
|
|
}
|
|
Node *node{ get_parent()->get_node(value) };
|
|
if (CharacterState * state{ cast_to<CharacterState>(node) }) {
|
|
state->set_state_active(true);
|
|
} else {
|
|
print_error(vformat("Attempt to stack nonexistent state %s from %s", value, get_path()));
|
|
}
|
|
}
|
|
|
|
void CharacterState::set_state_active(bool active) {
|
|
if (this->state_active != active) {
|
|
this->state_active = active;
|
|
if (active) {
|
|
state_entered();
|
|
} else {
|
|
state_exited();
|
|
if (this->depending_state && this->depending_state->state_active) {
|
|
this->depending_state->notify_dependent_inactive(this);
|
|
}
|
|
this->depending_state = nullptr;
|
|
for (CharacterState *state : this->dependent_states) {
|
|
state->set_state_active(false);
|
|
}
|
|
this->dependent_states.clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CharacterState::get_state_active() const {
|
|
return this->state_active;
|
|
}
|
|
|
|
Character *CharacterState::get_character() const {
|
|
return this->character;
|
|
}
|