Running into an issue with movement animations stuttering client side. In the server side viewport, animations are smooth. But client side they stutter pretty bad. I tried replicating the movement function and calling the server implementation during move but that didn’t help. It also seems very expensive to do that. One caveat, if I sprint or exceed a certain speed the animations are smooth.
I increased the walk speed to be close to the sprint speed and it got rid of the stuttering. There seems to be some discrepancy with movement syncing between client and server but replication should have fixed that.
Using typical movement implementations.
void ABaseCharacter::Turn(float Value)
{
this->AddControllerYawInput(Value);
}
void ABaseCharacter::Look(float Value)
{
this->AddControllerPitchInput(Value);
}
void ABaseCharacter::MoveForward(float Value)
{
this->AddMovementInput(this->GetActorForwardVector() * Value);
}
void ABaseCharacter::Strafe(float Value)
{
this->AddMovementInput(this->GetActorRightVector() * Value);
}
Video below you can see an example. One client viewing another also appears smooth. It’s only locally that animations are stuttering
Server and client discrepancy in CMC walk speed. How are you setting movement speeds? Looks like the servers movement speed is defaulted to sprint. So when you start sprinting you’re matching the servers speed, thus location. It doesn’t send a correction.
Your max walk speed should be set based on the default movement mode and corresponding movement state. So on Spawn the value should be what your normal run/walk speed is.
Anyway here’s a multiplayer setup for handling sprint. Works in Net mode: Play as Client.
1 Like
All of it is via C++. Movement component has a max speed and default speed. Input values for W and S is 1 and -1. On sprint pressed, the action modifies the movement component’s max walk speed with a multiplier, caching the default value. On sprint release / interrupt, the default value is re-applied.
The movement component should be replicated. Most of my flags for actions are replicated as well.
Currently have the speed set to 400 on the component.
// BaseCharacter.h
UPROPERTY(BlueprintReadOnly, meta=(AllowPrivateAccess="true"), Replicated)
float BaseSpeed = 400.f;
// Sets default values
ABaseCharacter::ABaseCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
this->SpringArmComponent = this->CreateDefaultSubobject<USpringArmComponent>(DefaultSpringComponentName);
this->SpringArmComponent->SetupAttachment(this->GetRootComponent());
this->SpringArmComponent->bEnableCameraLag = true;
this->SpringArmComponent->CameraLagSpeed = 10.f;
this->PlayerCamera = this->CreateDefaultSubobject<UCameraComponent>(DefaultCameraComponentName);
this->PlayerCamera->SetupAttachment(this->SpringArmComponent);
this->HealthComponent = this->CreateDefaultSubobject<UBaseHealthComponent>(DefaultHealthComponentName);
this->HealthComponent->OnHealthChanged.AddDynamic(this, &ABaseCharacter::OnHealthChange);
if (this->GetMovementComponent())
{
this->GetMovementComponent()->NavAgentProps.bCanCrouch = true;
}
if (this->GetCharacterMovement())
{
this->GetCharacterMovement()->MaxWalkSpeed = this->BaseSpeed;
this->DefaultWalkingSpeed = this->GetCharacterMovement()->MaxWalkSpeed;
}
}
void ABaseCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ABaseCharacter, EquippedWeapon);
DOREPLIFETIME(ABaseCharacter, BaseSpeed);
DOREPLIFETIME(ABaseCharacter, SprintSpeedMultiplier);
DOREPLIFETIME(ABaseCharacter, bIsDead);
DOREPLIFETIME(ABaseCharacter, bIsReloading);
DOREPLIFETIME(ABaseCharacter, bIsSprinting);
DOREPLIFETIME(ABaseCharacter, bIsZooming);
}
I figured it out. I created server implementations of the sprint methods as well as the method that initializes default behavior on begin play