Hi! Im working on a network multiplayer top down game where each player’ character looks at the right stick direction or left stick direction if right isnt pressed (classic Twinstick shooter orientation mechanic). I’ve set a replicated FRotator for this that updates all other player’s character orientation on tick (works perfectly).
Im using AddMovementInput to move the characters in space, which works as expected on self and other players, I’ve also managed to untoggle the ■■■■■ “MakeMeLookWhereImMovingToo” ‘feature’ so that it doesnt override my carefully set character orientation.
The Problem: This works on the owning player, but not on the replicated ones of the other players. In other words, when im on PlayerX’s screen and controlling him, the rotations and Movement work as expected, but on all the other players’ screens my carefully set orientation gets overriden by the AddMovementInput.
I’ve toyed around with these settings and they always only seem to work on the owning player. On all the others its like bOrientRotToMove is always true…
Note: Controller and main Actor orientation is always Zero and never changed by me, I only change the GetMesh() orientation to face right or left stick direction.
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = false; // Character moves in the direction of input...
GetCharacterMovement()->bIgnoreBaseRotation = true;
GetCharacterMovement()->bUseControllerDesiredRotation = false;
GetCharacterMovement()->RotationRate = FRotator(0.0f, 0.0f, 0.0f); // ...at this rotation rate
GetCharacterMovement()->JumpZVelocity = 600.f;
GetCharacterMovement()->AirControl = 0.2f;
GetCharacterMovement()->SetIsReplicated(true);
//Heres my FRotator replication
void AMPBattlersCharacter::SrvUpdateLookingDirection_Implementation(FRotator lookingDirection)
{
MRPCUpdateLookingDirection(lookingDirection);
}
bool AMPBattlersCharacter::SrvUpdateLookingDirection_Validate(FRotator lookingDirection)
{
return true;
}
void AMPBattlersCharacter::MRPCUpdateLookingDirection_Implementation(FRotator lookingDirection)
{
GetMesh()->SetWorldRotation(lookingDirection);
}
//Heres the Move call (much like Epic's default)
if ((Controller != NULL) && (Value != 0.0f))
{
const FRotator YawRotation(0, 0, 0);
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
For now I’ll make my own movement method to stop using AddMovementInput, but I hope someone has a solution for this, or if someone else stumbles on this and has the same problem, doesnt waste 4hrs trying to figure it out.
Edit1;
SetActorLocation() seems to be auto orientating the characters as well.
//Tick segment
void AMPBattlersCharacter::Tick(float deltaSeconds ){
Super::Tick(deltaSeconds );
if (IsLocallyControlled()) {
if (GetCharacterMovement()->IsMovingOnGround()) {
FVector nextLoc = GetActorLocation() + (deltaSeconds * GetCharacterMovement()->MaxWalkSpeed * MoveDirection);
SrvUpdateLocation(nextLoc);
}
}
}
//Server
void AMPBattlersCharacter::SrvUpdateLocation_Implementation(FVector worldLocation)
{
//MRPCUpdateLocation(worldLocation); //with or without the Multicast, its the same
SetActorLocation(worldLocation);
}
Edit2: and temporal solution
I still have’nt found out why AddMovementInput and SetActorLocation override/reset the orientation I set to my GetMesh() on the other player screens. Its like everytime I run one of these two functions, the rotation of the child mesh gets reset to (0,0,0), ONLY on the other player screens, and this from any player controller. On the owning player, the rotation I set is kept as it should.
Anyhow, I’ve managed to have my networking multiplayer prototype orientation controls work as expected by having a Replicated FRotator updated by server everytime the owning player presses a stick. And then use GetMesh()->SetWorldRotation(OrientedDirection); locally for each player on every tick. I’ve tried multi casting it right after setting it on the server, but it wouldnt work as it probably gets overriden by AddMoveInput right after ^^
void AMPBattlersCharacter::Tick(float deltaSeconds)
{
Super::Tick(deltaSeconds);
GetMesh()->SetWorldRotation(OrientedDirection); //UGLY; but only way for now: https://answers.unrealengine.com/questions/594926/why-does-addmovementinput-send-wrong-orientation-t.html
if (IsLocallyControlled()) {
// I prioritize right stick orientation over left stick
if (KeyInputLookDirection.X > LookInputDeadZone || KeyInputLookDirection.X < -LookInputDeadZone || KeyInputLookDirection.Y > LookInputDeadZone || KeyInputLookDirection.Y < -LookInputDeadZone) {
SrvUpdateLookingDirection(LookDirection.ToOrientationRotator());
}
else if (KeyInputMoveDirection.X > LookInputDeadZone || KeyInputMoveDirection.X < -LookInputDeadZone || KeyInputMoveDirection.Y > LookInputDeadZone || KeyInputMoveDirection.Y < -LookInputDeadZone) {
SrvUpdateLookingDirection(MoveDirection.ToOrientationRotator());
}
}
}
void AMPBattlersCharacter::SrvUpdateLookingDirection_Implementation(FRotator lookingDirection)
{
OrientedDirection = lookingDirection;
//OrientedDirection is set as Replicated
}
Its ugly and I dont like this, but it’ll have to do until I have more information on this.