Smoothed yaw rotation for objects (#6825)

This commit is contained in:
SmallJoker 2018-08-03 00:25:37 +02:00 committed by Paramat
parent 741e3efaf5
commit f3997025fd
4 changed files with 89 additions and 52 deletions

@ -53,51 +53,65 @@ struct ToolCapabilities;
std::unordered_map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types; std::unordered_map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
void SmoothTranslator::init(v3f vect) template<typename T>
void SmoothTranslator<T>::init(T current)
{ {
vect_old = vect; val_old = current;
vect_show = vect; val_current = current;
vect_aim = vect; val_target = current;
anim_counter = 0;
anim_time = 0; anim_time = 0;
anim_time_counter = 0; anim_time_counter = 0;
aim_is_end = true; aim_is_end = true;
} }
void SmoothTranslator::update(v3f vect_new, bool is_end_position, float update_interval) template<typename T>
void SmoothTranslator<T>::update(T new_target, bool is_end_position, float update_interval)
{ {
aim_is_end = is_end_position; aim_is_end = is_end_position;
vect_old = vect_show; val_old = val_current;
vect_aim = vect_new; val_target = new_target;
if(update_interval > 0) if (update_interval > 0) {
{
anim_time = update_interval; anim_time = update_interval;
} else { } else {
if(anim_time < 0.001 || anim_time > 1.0) if (anim_time < 0.001 || anim_time > 1.0)
anim_time = anim_time_counter; anim_time = anim_time_counter;
else else
anim_time = anim_time * 0.9 + anim_time_counter * 0.1; anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
} }
anim_time_counter = 0; anim_time_counter = 0;
anim_counter = 0;
} }
void SmoothTranslator::translate(f32 dtime) template<typename T>
void SmoothTranslator<T>::translate(f32 dtime)
{ {
anim_time_counter = anim_time_counter + dtime; anim_time_counter = anim_time_counter + dtime;
anim_counter = anim_counter + dtime; T val_diff = val_target - val_old;
v3f vect_move = vect_aim - vect_old;
f32 moveratio = 1.0; f32 moveratio = 1.0;
if(anim_time > 0.001) if (anim_time > 0.001)
moveratio = anim_time_counter / anim_time; moveratio = anim_time_counter / anim_time;
f32 move_end = aim_is_end ? 1.0 : 1.5;
// Move a bit less than should, to avoid oscillation // Move a bit less than should, to avoid oscillation
moveratio = moveratio * 0.8; moveratio = std::min(moveratio * 0.8f, move_end);
float move_end = 1.5; val_current = val_old + val_diff * moveratio;
if(aim_is_end) }
move_end = 1.0;
if(moveratio > move_end) void SmoothTranslatorWrapped::translate(f32 dtime)
moveratio = move_end; {
vect_show = vect_old + vect_move * moveratio; anim_time_counter = anim_time_counter + dtime;
f32 val_diff = std::abs(val_target - val_old);
if (val_diff > 180.f)
val_diff = 360.f - val_diff;
f32 moveratio = 1.0;
if (anim_time > 0.001)
moveratio = anim_time_counter / anim_time;
f32 move_end = aim_is_end ? 1.0 : 1.5;
// Move a bit less than should, to avoid oscillation
moveratio = std::min(moveratio * 0.8f, move_end);
wrappedApproachShortest(val_current, val_target,
val_diff * moveratio, 360.f);
} }
/* /*
@ -331,7 +345,9 @@ void GenericCAO::processInitData(const std::string &data)
processMessage(message); processMessage(message);
} }
m_yaw = wrapDegrees_0_360(m_yaw);
pos_translator.init(m_position); pos_translator.init(m_position);
yaw_translator.init(m_yaw);
updateNodePos(); updateNodePos();
} }
@ -359,7 +375,7 @@ v3f GenericCAO::getPosition()
return m_position; return m_position;
} }
return pos_translator.vect_show; return pos_translator.val_current;
} }
const bool GenericCAO::isImmortal() const bool GenericCAO::isImmortal()
@ -717,10 +733,10 @@ void GenericCAO::updateNodePos()
if (node) { if (node) {
v3s16 camera_offset = m_env->getCameraOffset(); v3s16 camera_offset = m_env->getCameraOffset();
node->setPosition(pos_translator.vect_show - intToFloat(camera_offset, BS)); node->setPosition(pos_translator.val_current - intToFloat(camera_offset, BS));
if (node != m_spritenode) { // rotate if not a sprite if (node != m_spritenode) { // rotate if not a sprite
v3f rot = node->getRotation(); v3f rot = node->getRotation();
rot.Y = -m_yaw; rot.Y = m_is_local_player ? -m_yaw : -yaw_translator.val_current;
node->setRotation(rot); node->setRotation(rot);
} }
} }
@ -735,10 +751,11 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
int old_anim = player->last_animation; int old_anim = player->last_animation;
float old_anim_speed = player->last_animation_speed; float old_anim_speed = player->last_animation_speed;
m_position = player->getPosition(); m_position = player->getPosition();
m_yaw = wrapDegrees_0_360(player->getYaw());
m_velocity = v3f(0,0,0); m_velocity = v3f(0,0,0);
m_acceleration = v3f(0,0,0); m_acceleration = v3f(0,0,0);
pos_translator.vect_show = m_position; pos_translator.val_current = m_position;
m_yaw = player->getYaw(); yaw_translator.val_current = m_yaw;
const PlayerControl &controls = player->getPlayerControl(); const PlayerControl &controls = player->getPlayerControl();
bool walking = false; bool walking = false;
@ -841,7 +858,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
m_position = getPosition(); m_position = getPosition();
m_velocity = v3f(0,0,0); m_velocity = v3f(0,0,0);
m_acceleration = v3f(0,0,0); m_acceleration = v3f(0,0,0);
pos_translator.vect_show = m_position; pos_translator.val_current = m_position;
if(m_is_local_player) // Update local player attachment position if(m_is_local_player) // Update local player attachment position
{ {
@ -850,7 +867,8 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
m_env->getLocalPlayer()->parent = getParent(); m_env->getLocalPlayer()->parent = getParent();
} }
} else { } else {
v3f lastpos = pos_translator.vect_show; yaw_translator.translate(dtime);
v3f lastpos = pos_translator.val_current;
if(m_prop.physical) if(m_prop.physical)
{ {
@ -882,7 +900,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
updateNodePos(); updateNodePos();
} }
float moved = lastpos.getDistanceFrom(pos_translator.vect_show); float moved = lastpos.getDistanceFrom(pos_translator.val_current);
m_step_distance_counter += moved; m_step_distance_counter += moved;
if (m_step_distance_counter > 1.5f * BS) { if (m_step_distance_counter > 1.5f * BS) {
m_step_distance_counter = 0.0f; m_step_distance_counter = 0.0f;
@ -921,6 +939,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
} }
if (!getParent() && std::fabs(m_prop.automatic_rotate) > 0.001) { if (!getParent() && std::fabs(m_prop.automatic_rotate) > 0.001) {
m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI; m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI;
yaw_translator.val_current = m_yaw;
updateNodePos(); updateNodePos();
} }
@ -931,14 +950,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
+ m_prop.automatic_face_movement_dir_offset; + m_prop.automatic_face_movement_dir_offset;
float max_rotation_delta = float max_rotation_delta =
dtime * m_prop.automatic_face_movement_max_rotation_per_sec; dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
float delta = wrapDegrees_0_360(target_yaw - m_yaw);
if (delta > max_rotation_delta && 360 - delta > max_rotation_delta) { wrappedApproachShortest(m_yaw, target_yaw, max_rotation_delta, 360.f);
m_yaw += (delta < 180) ? max_rotation_delta : -max_rotation_delta; yaw_translator.val_current = m_yaw;
m_yaw = wrapDegrees_0_360(m_yaw);
} else {
m_yaw = target_yaw;
}
updateNodePos(); updateNodePos();
} }
} }
@ -1304,6 +1318,7 @@ void GenericCAO::processMessage(const std::string &data)
m_yaw = readF1000(is); m_yaw = readF1000(is);
else else
readF1000(is); readF1000(is);
m_yaw = wrapDegrees_0_360(m_yaw);
bool do_interpolate = readU8(is); bool do_interpolate = readU8(is);
bool is_end_position = readU8(is); bool is_end_position = readU8(is);
float update_interval = readF1000(is); float update_interval = readF1000(is);
@ -1323,6 +1338,7 @@ void GenericCAO::processMessage(const std::string &data)
} else { } else {
pos_translator.init(m_position); pos_translator.init(m_position);
} }
yaw_translator.update(m_yaw, false, update_interval);
updateNodePos(); updateNodePos();
} else if (cmd == GENERIC_CMD_SET_TEXTURE_MOD) { } else if (cmd == GENERIC_CMD_SET_TEXTURE_MOD) {
std::string mod = deSerializeString(is); std::string mod = deSerializeString(is);

@ -34,25 +34,31 @@ struct Nametag;
SmoothTranslator SmoothTranslator
*/ */
template<typename T>
struct SmoothTranslator struct SmoothTranslator
{ {
v3f vect_old; T val_old;
v3f vect_show; T val_current;
v3f vect_aim; T val_target;
f32 anim_counter = 0;
f32 anim_time = 0; f32 anim_time = 0;
f32 anim_time_counter = 0; f32 anim_time_counter = 0;
bool aim_is_end = true; bool aim_is_end = true;
SmoothTranslator() = default; SmoothTranslator() = default;
void init(v3f vect); void init(T current);
void update(v3f vect_new, bool is_end_position=false, float update_interval=-1); void update(T new_target, bool is_end_position = false,
float update_interval = -1);
void translate(f32 dtime); void translate(f32 dtime);
}; };
struct SmoothTranslatorWrapped : SmoothTranslator<f32>
{
void translate(f32 dtime);
};
class GenericCAO : public ClientActiveObject class GenericCAO : public ClientActiveObject
{ {
private: private:
@ -76,7 +82,8 @@ private:
v3f m_acceleration; v3f m_acceleration;
float m_yaw = 0.0f; float m_yaw = 0.0f;
s16 m_hp = 1; s16 m_hp = 1;
SmoothTranslator pos_translator; SmoothTranslator<v3f> pos_translator;
SmoothTranslatorWrapped yaw_translator;
// Spritesheet/animation stuff // Spritesheet/animation stuff
v2f m_tx_size = v2f(1,1); v2f m_tx_size = v2f(1,1);
v2s16 m_tx_basepos; v2s16 m_tx_basepos;

@ -443,14 +443,9 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
+ m_prop.automatic_face_movement_dir_offset; + m_prop.automatic_face_movement_dir_offset;
float max_rotation_delta = float max_rotation_delta =
dtime * m_prop.automatic_face_movement_max_rotation_per_sec; dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
float delta = wrapDegrees_0_360(target_yaw - m_yaw);
if (delta > max_rotation_delta && 360 - delta > max_rotation_delta) {
m_yaw += (delta < 180) ? max_rotation_delta : -max_rotation_delta;
m_yaw = wrapDegrees_0_360(m_yaw); m_yaw = wrapDegrees_0_360(m_yaw);
} else { wrappedApproachShortest(m_yaw, target_yaw, max_rotation_delta, 360.f);
m_yaw = target_yaw;
}
} }
} }

@ -376,3 +376,22 @@ inline u32 npot2(u32 orig) {
orig |= orig >> 16; orig |= orig >> 16;
return orig + 1; return orig + 1;
} }
// Gradual steps towards the target value in a wrapped (circular) system
// using the shorter of both ways
template<typename T>
inline void wrappedApproachShortest(T &current, const T target, const T stepsize,
const T maximum)
{
T delta = target - current;
if (delta < 0)
delta += maximum;
if (delta > stepsize && maximum - delta > stepsize) {
current += (delta < maximum / 2) ? stepsize : -stepsize;
if (current >= maximum)
current -= maximum;
} else {
current = target;
}
}