/** Sets the current ball possessor */ void AMagicBattleSoccerBall::SetPossessor(AMagicBattleSoccerCharacter* Player) { if (Role < ROLE_Authority) { // Safety check. Only authority entities should drive the ball. } else { // We only allow a possession change if the ball is being unpossessed or the player is not one we're ignoring if (nullptr == Player || (CanPossessBall(Player) && (PossessorToIgnore != Player))) { AMagicBattleSoccerCharacter *OldPossessor = Possessor; // Assign the new possessor Possessor = Player; // Handle cases when the ball had a possessor in the previous frame if (nullptr != OldPossessor) { // Assign the last possessor LastPossessor = OldPossessor; // Assign the possessor to ignore PossessorToIgnore = OldPossessor; } // Toggle physics UPrimitiveComponent *Root = Cast<UPrimitiveComponent>(GetRootComponent()); if (nullptr != Possessor) { Possessor->StopWeaponFire(Possessor->PrimaryWeapon); Possessor->StopWeaponFire(Possessor->SecondaryWeapon); Root->PutRigidBodyToSleep(); Root->SetSimulatePhysics(false); Root->SetEnableGravity(false); SetActorEnableCollision(false); MoveWithPossessor(); } else { Root->SetSimulatePhysics(true); Root->SetEnableGravity(true); SetActorEnableCollision(true); Root->PutRigidBodyToSleep(); } } // Force the orientation to be replicated at the same time the possessor is replicated UPrimitiveComponent *Root = Cast<UPrimitiveComponent>(GetRootComponent()); ServerPhysicsState.pos = GetActorLocation(); ServerPhysicsState.rot = GetActorRotation(); ServerPhysicsState.vel = Root->GetComponentVelocity(); ServerPhysicsState.timestamp = AMagicBattleSoccerPlayerController::GetLocalTime(); } }
void AMagicBattleSoccerBall::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); if (nullptr != Possessor) { // If the ball is possessed by a player, then the ball should move as a function // of the possessor MoveWithPossessor(); } else { // No possessor. The ball is freely moving. if (Role < ROLE_Authority) { // Clients should update its local position based on where it is on the server ClientSimulateFreeMovingBall(); } else { // Update the charging value if (GetVelocity().SizeSquared() > 1.f) { IsCharging = false; } // Servers should simulate the ball physics freely and replicate the orientation UPrimitiveComponent *Root = Cast<UPrimitiveComponent>(GetRootComponent()); ServerPhysicsState.pos = GetActorLocation(); ServerPhysicsState.rot = GetActorRotation(); ServerPhysicsState.vel = Root->GetComponentVelocity(); ServerPhysicsState.timestamp = AMagicBattleSoccerPlayerController::GetLocalTime(); // Servers should also test the distance from the old possessor and reset it if (nullptr != PossessorToIgnore) { if (!PossessorToIgnore->IsAlive()) { PossessorToIgnore = nullptr; } else { FVector2D PossessorLoc(PossessorToIgnore->GetActorLocation()); FVector2D BallLoc(GetActorLocation()); float d = FVector2D::DistSquared(PossessorLoc, BallLoc); if (d > 14000) { PossessorToIgnore = nullptr; } } } } } }