/
Metallist64
/
rbfx
Обзор
Документация
Войти
/
Metallist64
/
rbfx
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Source/Samples/110_AdvancedNetworking/AdvancedNetworkingPlayer.cpp
134 строки
5 KB
Eugene Kozlov
Implement generic ReplicatedAnimation.
28 фев 2022, 15:46
28 фев 2022, 15:46
9fc102c
Код
Авторство
О чём код?
// // Copyright (c) 2008-2020 the Urho3D project. // Copyright (c) 2022 the rbfx project. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #include "AdvancedNetworkingPlayer.h" #include <Urho3D/Graphics/Animation.h> #include <Urho3D/Graphics/AnimationController.h> #include <Urho3D/Physics/KinematicCharacterController.h> #include <Urho3D/Replica/PredictedKinematicController.h> #include <Urho3D/Replica/ReplicatedTransform.h> #include <Urho3D/Resource/ResourceCache.h> namespace { /// Return shortest angle between two angles. float ShortestAngle(float lhs, float rhs) { const float delta = Mod(rhs - lhs + 180.0f, 360.0f) - 180.0f; return delta < -180.0f ? delta + 360.0f : delta; } /// Helper function to smoothly transform one quaternion into another. Quaternion TransformRotation(const Quaternion& base, const Quaternion& target, float maxAngularVelocity) { const float baseYaw = base.YawAngle(); const float targetYaw = target.YawAngle(); if (Equals(baseYaw, targetYaw, 0.1f)) return base; const float shortestAngle = ShortestAngle(baseYaw, targetYaw); const float delta = Sign(shortestAngle) * ea::min(Abs(shortestAngle), maxAngularVelocity); return Quaternion{baseYaw + delta, Vector3::UP}; } } AdvancedNetworkingPlayer::AdvancedNetworkingPlayer(Context* context) : NetworkBehavior(context, CallbackMask) { auto cache = GetSubsystem<ResourceCache>(); animations_ = { cache->GetResource<Animation>("Models/Mutant/Mutant_Idle0.ani"), cache->GetResource<Animation>("Models/Mutant/Mutant_Run.ani"), cache->GetResource<Animation>("Models/Mutant/Mutant_Jump1.ani"), }; } void AdvancedNetworkingPlayer::InitializeOnServer() { BaseClassName::InitializeOnServer(); InitializeCommon(); // On server, all players are unimportant because they are moving and need temporal raycasts auto animatedModel = GetComponent<Urho3D::AnimatedModel>(); animatedModel->SetViewMask(UNIMPORTANT_VIEW_MASK); } void AdvancedNetworkingPlayer::InitializeFromSnapshot( Urho3D::NetworkFrame frame, Urho3D::Deserializer& src, bool isOwned) { BaseClassName::InitializeFromSnapshot(frame, src, isOwned); InitializeCommon(); // Mark all players except ourselves as important for raycast. auto animatedModel = GetComponent<AnimatedModel>(); animatedModel->SetViewMask(isOwned ? UNIMPORTANT_VIEW_MASK : IMPORTANT_VIEW_MASK); } void AdvancedNetworkingPlayer::Update(float replicaTimeStep, float inputTimeStep) { if (!GetNetworkObject()->IsReplicatedClient()) UpdateAnimations(inputTimeStep); } void AdvancedNetworkingPlayer::InitializeCommon() { animationController_ = GetComponent<AnimationController>(); replicatedTransform_ = GetNetworkObject()->GetNetworkBehavior<ReplicatedTransform>(); networkController_ = GetNetworkObject()->GetNetworkBehavior<PredictedKinematicController>(); kinematicController_ = networkController_->GetComponent<KinematicCharacterController>(); } void AdvancedNetworkingPlayer::UpdateAnimations(float timeStep) { // Get current state of the controller to deduce animation from const bool isGrounded = kinematicController_->OnGround(); const Vector3 velocity = networkController_->GetVelocity(); const Vector3 walkDirection = Vector3::FromXZ(velocity.ToXZ().NormalizedOrDefault(Vector2::ZERO, 0.1f)); // Start jump if has high vertical velocity and hasn't jumped yet if ((currentAnimation_ != ANIM_JUMP) && velocity.y_ > jumpThreshold_) { animationController_->PlayExclusive(animations_[ANIM_JUMP]->GetName(), 0, false, fadeTime_); animationController_->SetTime(animations_[ANIM_JUMP]->GetName(), 0); currentAnimation_ = ANIM_JUMP; } // Rotate player both on ground and in the air if (walkDirection != Vector3::ZERO) { const Quaternion targetRotation{Vector3::BACK, walkDirection}; const float maxAngularVelocity = MAX_ROTATION_SPEED * timeStep; node_->SetWorldRotation(TransformRotation(node_->GetWorldRotation(), targetRotation, maxAngularVelocity)); } // If on the ground, either walk or stay idle if (isGrounded) { currentAnimation_ = walkDirection != Vector3::ZERO ? ANIM_WALK : ANIM_IDLE; animationController_->PlayExclusive(animations_[currentAnimation_]->GetName(), 0, true, fadeTime_); } }