Джиттер преобразования сети Unity FusionC#

Место общения программистов C#
Ответить
Anonymous
 Джиттер преобразования сети Unity Fusion

Сообщение Anonymous »

Я создаю многопользовательскую игру, используя режим Сервер/Клиент в Photon Fusion 1 в Unity, где игроки сражаются на своих самолетах.
Теперь проблема, с которой я столкнулся, заключается в том, что когда я прикрепляю компонент Network Transform к плоскости игрока, я испытываю сильное дрожание в положении и вращении плоскости независимо от того, является ли игрок сервером или клиентом.
Если я удалю Network Transform, игроки больше не синхронизируются.
RigidBody прикреплен к planePrefab.
вот мой код:
INETWORK CALLBACK

Код: Выделить всё

OnInput()

Код: Выделить всё

public void OnInput(NetworkRunner runner, NetworkInput input)
{
if (!AllowInput)
return;

PlayerInput playerInput = new PlayerInput();

// Roll & Pitch (WASD)
Vector2 rollPitch = Vector2.zero;
// Roll = A/D (left/right)
if (Input.GetKey(KeyCode.A)) rollPitch.x = -1f;
else if (Input.GetKey(KeyCode.D)) rollPitch.x = 1f;
else rollPitch.x = 0f;

// Pitch = W/S (forward/back)
if (Input.GetKey(KeyCode.W)) rollPitch.y = 1f;
else if (Input.GetKey(KeyCode.S)) rollPitch.y = -1f;
else rollPitch.y = 0f;

playerInput.RollPitch = rollPitch;

// Yaw (Q/E)
if (Input.GetKey(KeyCode.Q)) playerInput.Yaw = 1f;
else if (Input.GetKey(KeyCode.E)) playerInput.Yaw = -1f;
else playerInput.Yaw = 0f;

// Throttle (Z/X)
if (Input.GetKey(KeyCode.Z)) playerInput.Throttle = 1f;
else if (Input.GetKey(KeyCode.X)) playerInput.Throttle = -1f;
else playerInput.Throttle = 0f;

// Flaps toggle (F key)
playerInput.Flaps = Input.GetKeyDown(KeyCode.F);

// Weapons
playerInput.FireMissile = Input.GetMouseButtonDown(0); // LMB
playerInput.FireCannon = Input.GetMouseButton(1);      // RMB hold

// Camera input (mouse delta)
playerInput.Camera = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));

// Send struct to Fusion
input.Set(playerInput);
}
PlayerController.cs

Код: Выделить всё

    public override void FixedUpdateNetwork()
{
if (Player &&  Player.InputEnabled)
{
if (GetInput(out PlayerInput data)) {

if (plane != null)
{

plane.SetControlInput(new Vector3(data.RollPitch.y, data.Yaw, -data.RollPitch.x));
plane.SetThrottleInput(data.Throttle);

if (data.Flaps)
plane.ToggleFlaps();

if (data.FireMissile)
plane.TryFireMissile();

plane.SetCannonInput(data.FireCannon);

}
}

}
}
}
Plane.cs

Код: Выделить всё

using Fusion;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Plane : NetworkBehaviour {
[SerializeField]
float maxHealth;
[SerializeField]
float health;
[SerializeField]
float maxThrust;
[SerializeField]
float throttleSpeed;
[SerializeField]
float gLimit;
[SerializeField]
float gLimitPitch;

[Header("Lift")]
[SerializeField]
float liftPower;
[SerializeField]
AnimationCurve liftAOACurve;
[SerializeField]
float inducedDrag;
[SerializeField]
AnimationCurve inducedDragCurve;
[SerializeField]
float rudderPower;
[SerializeField]
AnimationCurve rudderAOACurve;
[SerializeField]
AnimationCurve rudderInducedDragCurve;
[SerializeField]
float flapsLiftPower;
[SerializeField]
float flapsAOABias;
[SerializeField]
float flapsDrag;
[SerializeField]
float flapsRetractSpeed;

[Header("Steering")]
[SerializeField]
Vector3 turnSpeed;
[SerializeField]
Vector3 turnAcceleration;
[SerializeField]
AnimationCurve steeringCurve;

[Header("Drag")]
[SerializeField]
AnimationCurve dragForward;
[SerializeField]
AnimationCurve dragBack;
[SerializeField]
AnimationCurve dragLeft;
[SerializeField]
AnimationCurve dragRight;
[SerializeField]
AnimationCurve dragTop;
[SerializeField]
AnimationCurve dragBottom;
[SerializeField]
Vector3 angularDrag;
[SerializeField]
float airbrakeDrag;

[Header("Misc")]
[SerializeField]
List landingGear;
[SerializeField]
PhysicMaterial landingGearBrakesMaterial;
[SerializeField]
List graphics;
[SerializeField]
GameObject damageEffect;
[SerializeField]
GameObject deathEffect;
[SerializeField]
bool flapsDeployed;
[SerializeField]
float initialSpeed;

[Header("Weapons")]
[SerializeField]
List hardpoints;
[SerializeField]
float missileReloadTime;
[SerializeField]
float missileDebounceTime;
[SerializeField]
GameObject missilePrefab;
[SerializeField]
Target target;
[SerializeField]
float lockRange;
[SerializeField]
float lockSpeed;
[SerializeField]
float lockAngle;
[SerializeField]
[Tooltip("Firing rate in Rounds Per Minute")]
float cannonFireRate;
[SerializeField]
float cannonDebounceTime;
[SerializeField]
float cannonSpread;
[SerializeField]
Transform cannonSpawnPoint;
[SerializeField]
GameObject bulletPrefab;

new PlaneAnimation animation;

float throttleInput;
Vector3 controlInput;

Vector3 lastVelocity;
PhysicMaterial landingGearDefaultMaterial;

int missileIndex;
List missileReloadTimers;
float missileDebounceTimer;
Vector3 missileLockDirection;

bool cannonFiring;
float cannonDebounceTimer;
float cannonFiringTimer;

public float MaxHealth {
get {
return maxHealth;
}
set {
maxHealth = Mathf.Max(0, value);
}
}

public float Health {
get {
return health;
}
private set {
health = Mathf.Clamp(value, 0, maxHealth);

if (health   0) {
damageEffect.SetActive(true);
} else {
damageEffect.SetActive(false);
}

if (health == 0 && MaxHealth != 0 && !Dead) {
Die();
}
}
}

public bool Dead { get; private set; }

public Rigidbody Rigidbody;
public float Throttle { get; private set; }
public Vector3 EffectiveInput { get; private set; }
public Vector3 Velocity { get; private set; }
public Vector3 LocalVelocity { get; private set; }
public Vector3 LocalGForce { get; private set; }
public Vector3 LocalAngularVelocity { get; private set; }
public float AngleOfAttack { get; private set; }
public float AngleOfAttackYaw { get; private set; }
public bool AirbrakeDeployed { get; private set; }

public bool FlapsDeployed {
get {
return flapsDeployed;
}
private set {
flapsDeployed = value;

foreach (var lg in landingGear) {
lg.enabled = value;
}
}
}

public bool MissileLocked { get; private set; }
public bool MissileTracking { get; private set; }
public Target Target {
get {
return target;
}
}
public Vector3 MissileLockDirection {
get {
return Rigidbody.rotation * missileLockDirection;
}
}

void Awake() {
animation = GetComponent
();
Rigidbody = GetComponent();

if (landingGear.Count > 0) {
landingGearDefaultMaterial = landingGear[0].sharedMaterial;
}

missileReloadTimers = new List(hardpoints.Count);

foreach (var h in hardpoints) {
missileReloadTimers.Add(0);
}

missileLockDirection = Vector3.forward;

Rigidbody.velocity = Rigidbody.rotation * new Vector3(0, 0, initialSpeed);
}

public void SetThrottleInput(float input) {
if (Dead) return;
throttleInput = input;
}

public void SetControlInput(Vector3 input) {
if (Dead) return;
controlInput = Vector3.ClampMagnitude(input, 1);
}

public void SetCannonInput(bool input) {
if (Dead) return;
cannonFiring = input;
}

public void ToggleFlaps() {
if (LocalVelocity.z < flapsRetractSpeed) {
FlapsDeployed = !FlapsDeployed;
}
}

public void ApplyDamage(float damage) {
Health -= damage;
}

void Die() {
throttleInput = 0;
Throttle = 0;
Dead = true;
cannonFiring = false;

damageEffect.GetComponent().Pause();
deathEffect.SetActive(true);
}

void UpdateThrottle(float dt) {
float target = 0;
if (throttleInput > 0) target = 1;

//throttle input is [-1, 1]
//throttle is [0, 1]
Throttle = Utilities.MoveTo(Throttle, target, throttleSpeed * Mathf.Abs(throttleInput), dt);

AirbrakeDeployed = Throttle == 0 && throttleInput == -1;

if (AirbrakeDeployed) {
foreach (var lg in landingGear) {
lg.sharedMaterial = landingGearBrakesMaterial;
}
} else {
foreach (var lg in landingGear) {
lg.sharedMaterial = landingGearDefaultMaterial;
}
}
}

void UpdateFlaps() {
if (LocalVelocity.z > flapsRetractSpeed) {
FlapsDeployed = false;
}
}

void CalculateAngleOfAttack() {
if (LocalVelocity.sqrMagnitude <  0.1f) {
AngleOfAttack = 0;
AngleOfAttackYaw = 0;
return;
}

AngleOfAttack = Mathf.Atan2(-LocalVelocity.y, LocalVelocity.z);
AngleOfAttackYaw = Mathf.Atan2(LocalVelocity.x, LocalVelocity.z);
}

void CalculateGForce(float dt) {
var invRotation = Quaternion.Inverse(Rigidbody.rotation);
var acceleration = (Velocity - lastVelocity) / dt;
LocalGForce = invRotation * acceleration;
lastVelocity = Velocity;
}

void CalculateState(float dt) {
var invRotation = Quaternion.Inverse(Rigidbody.rotation);
Velocity = Rigidbody.velocity;
LocalVelocity = invRotation * Velocity;  //transform world velocity into local space
LocalAngularVelocity = invRotation * Rigidbody.angularVelocity;  //transform into local space

CalculateAngleOfAttack();
}

void UpdateThrust() {
Rigidbody.AddRelativeForce(Throttle * maxThrust * Vector3.forward);
}

void UpdateDrag() {
var lv = LocalVelocity;
var lv2 = lv.sqrMagnitude;  //velocity squared

float airbrakeDrag = AirbrakeDeployed ? this.airbrakeDrag : 0;
float flapsDrag = FlapsDeployed ? this.flapsDrag : 0;

//calculate coefficient of drag depending on direction on velocity
var coefficient = Utilities.Scale6(
lv.normalized,
dragRight.Evaluate(Mathf.Abs(lv.x)), dragLeft.Evaluate(Mathf.Abs(lv.x)),
dragTop.Evaluate(Mathf.Abs(lv.y)), dragBottom.Evaluate(Mathf.Abs(lv.y)),
dragForward.Evaluate(Mathf.Abs(lv.z)) + airbrakeDrag + flapsDrag,   //include extra drag for forward coefficient
dragBack.Evaluate(Mathf.Abs(lv.z))
);

var drag = coefficient.magnitude * lv2 * -lv.normalized;    //drag is opposite direction of velocity

Rigidbody.AddRelativeForce(drag);
}

Vector3 CalculateLift(float angleOfAttack, Vector3 rightAxis, float liftPower, AnimationCurve aoaCurve, AnimationCurve inducedDragCurve) {
var liftVelocity = Vector3.ProjectOnPlane(LocalVelocity, rightAxis);    //project velocity onto YZ plane
var v2 = liftVelocity.sqrMagnitude;                                     //square of velocity

//lift = velocity^2 * coefficient * liftPower
//coefficient varies with AOA
var liftCoefficient = aoaCurve.Evaluate(angleOfAttack * Mathf.Rad2Deg);
var liftForce = v2 * liftCoefficient * liftPower;

//lift is perpendicular to velocity
var liftDirection = Vector3.Cross(liftVelocity.normalized, rightAxis);
var lift = liftDirection * liftForce;

//induced drag varies with square of lift coefficient
var dragForce = liftCoefficient * liftCoefficient;
var dragDirection = -liftVelocity.normalized;
var inducedDrag = dragDirection * v2 * dragForce * this.inducedDrag * inducedDragCurve.Evaluate(Mathf.Max(0, LocalVelocity.z));

return lift + inducedDrag;
}

void UpdateLift() {
if (LocalVelocity.sqrMagnitude < 1f) return;

float flapsLiftPower = FlapsDeployed ? this.flapsLiftPower : 0;
float flapsAOABias = FlapsDeployed ? this.flapsAOABias : 0;

var liftForce = CalculateLift(
AngleOfAttack + (flapsAOABias * Mathf.Deg2Rad), Vector3.right,
liftPower + flapsLiftPower,
liftAOACurve,
inducedDragCurve
);

var yawForce = CalculateLift(AngleOfAttackYaw, Vector3.up, rudderPower, rudderAOACurve, rudderInducedDragCurve);

Rigidbody.AddRelativeForce(liftForce);
Rigidbody.AddRelativeForce(yawForce);
}

void UpdateAngularDrag() {
var av = LocalAngularVelocity;
var drag = av.sqrMagnitude * -av.normalized;    //squared, opposite direction of angular velocity
Rigidbody.AddRelativeTorque(Vector3.Scale(drag, angularDrag), ForceMode.Acceleration);   //ignore rigidbody mass
}

Vector3 CalculateGForce(Vector3 angularVelocity, Vector3 velocity) {
//estiamte G Force from angular velocity and velocity
//Velocity = AngularVelocity * Radius
//G = Velocity^2 / R
//G = (Velocity * AngularVelocity * Radius) / Radius
//G = Velocity * AngularVelocity
//G = V cross A
return Vector3.Cross(angularVelocity, velocity);
}

Vector3 CalculateGForceLimit(Vector3 input) {
return Utilities.Scale6(input,
gLimit, gLimitPitch,    //pitch down, pitch up
gLimit, gLimit,         //yaw
gLimit, gLimit          //roll
) * 9.81f;
}

float CalculateGLimiter(Vector3 controlInput, Vector3 maxAngularVelocity) {
if (controlInput.magnitude < 0.01f) {
return 1;
}

//if the player gives input with magnitude less than 1, scale up their input so that magnitude == 1
var maxInput = controlInput.normalized;

var limit = CalculateGForceLimit(maxInput);
var maxGForce = CalculateGForce(Vector3.Scale(maxInput, maxAngularVelocity), LocalVelocity);

if (maxGForce.magnitude > limit.magnitude) {
//example:
//maxGForce = 16G, limit = 8G
//so this is 8 / 16 or 0.5
return limit.magnitude / maxGForce.magnitude;
}

return 1;
}

float CalculateSteering(float dt, float angularVelocity, float targetVelocity, float acceleration) {
var error = targetVelocity - angularVelocity;
var accel = acceleration * dt;
return Mathf.Clamp(error, -accel, accel);
}

void UpdateSteering(float dt) {
var speed = Mathf.Max(0, LocalVelocity.z);
var steeringPower = steeringCurve.Evaluate(speed);

var gForceScaling = CalculateGLimiter(controlInput, turnSpeed * Mathf.Deg2Rad * steeringPower);

var targetAV = Vector3.Scale(controlInput, turnSpeed * steeringPower * gForceScaling);
var av = LocalAngularVelocity * Mathf.Rad2Deg;

var correction = new Vector3(
CalculateSteering(dt, av.x, targetAV.x, turnAcceleration.x * steeringPower),
CalculateSteering(dt, av.y, targetAV.y, turnAcceleration.y * steeringPower),
CalculateSteering(dt, av.z, targetAV.z, turnAcceleration.z * steeringPower)
);

Rigidbody.AddRelativeTorque(correction * Mathf.Deg2Rad, ForceMode.VelocityChange);    //ignore rigidbody mass

var correctionInput = new Vector3(
Mathf.Clamp((targetAV.x - av.x) / turnAcceleration.x, -1, 1),
Mathf.Clamp((targetAV.y - av.y) / turnAcceleration.y, -1, 1),
Mathf.Clamp((targetAV.z - av.z) / turnAcceleration.z, -1, 1)
);

var effectiveInput = (correctionInput + controlInput) * gForceScaling;

EffectiveInput = new Vector3(
Mathf.Clamp(effectiveInput.x, -1, 1),
Mathf.Clamp(effectiveInput.y, -1, 1),
Mathf.Clamp(effectiveInput.z, -1, 1)
);
}

public void TryFireMissile() {
if (Dead) return;

//try all available missiles
for (int i = 0; i < hardpoints.Count; i++) {
var index = (missileIndex + i) % hardpoints.Count;
if (missileDebounceTimer == 0 &&  missileReloadTimers[index] == 0) {
FireMissile(index);

missileIndex = (index + 1) % hardpoints.Count;
missileReloadTimers[index] = missileReloadTime;
missileDebounceTimer = missileDebounceTime;

animation.ShowMissileGraphic(index, false);
break;
}
}
}

void FireMissile(int index) {
var hardpoint = hardpoints[index];
var missileGO = Instantiate(missilePrefab, hardpoint.position, hardpoint.rotation);
var missile = missileGO.GetComponent();
missile.Launch(this, MissileLocked ? Target : null);
}

void UpdateWeapons(float dt) {
UpdateWeaponCooldown(dt);
UpdateMissileLock(dt);
UpdateCannon(dt);
}

void UpdateWeaponCooldown(float dt) {
missileDebounceTimer = Mathf.Max(0, missileDebounceTimer - dt);
cannonDebounceTimer = Mathf.Max(0, cannonDebounceTimer - dt);
cannonFiringTimer = Mathf.Max(0, cannonFiringTimer - dt);

for (int i = 0; i < missileReloadTimers.Count; i++) {
missileReloadTimers[i] = Mathf.Max(0, missileReloadTimers[i] - dt);

if (missileReloadTimers[i] == 0)
{
animation.ShowMissileGraphic(i, true);
}
}
}

void UpdateMissileLock(float dt) {
//default neutral position is forward
Vector3 targetDir = Vector3.forward;
MissileTracking = false;

if (Target != null && !Target.Plane.Dead) {
var error = target.Position - Rigidbody.position;
var errorDir = Quaternion.Inverse(Rigidbody.rotation) * error.normalized; //transform into local space

if (error.magnitude 

Подробнее здесь: [url]https://stackoverflow.com/questions/79780889/unity-fusion-network-transform-jitter[/url]
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»