I have tried to bring back one of my old game ideas to work on so I could get familiarized with DOTS, and I still can’t seem to get it to work right.
Can anyone tell if it’s possible to have a fast paced multiplayer game with DOTS? My idea is just have a small arena and two goals and some kind of puck in the middle. The players would stay on their side and just shoot/deflect the puck. But even marking all the ghosts as Predicted and having interpolation, it seems very jitter-ly even with 50ms ping.
Here is the video of how it looks playing it with ping
https://vimeo.com/404385075
Is there anything else I can configure on the Ghost scripts to make this better? I thought since the movement is so simple and linear, with less than 100 ping it shouldn’t be jittery since the prediction wouldn’t be wrong.
The movement code looks like this,
Player:
public class FreezePlayerRotationSystem : JobComponentSystem {
protected override JobHandle OnUpdate(JobHandle inputDeps) {
inputDeps.Complete();
Entities.ForEach((
ref PhysicsMass pm,
ref PhysicsVelocity pv,
ref Rotation rotation,
ref Translation translation,
in NetPlayer netPlayer
) => {
pv.Angular = new float3();
pm.InverseInertia = new float3();
translation.Value.y = 0.3188247f;
rotation.Value = quaternion.EulerXYZ(math.radians(-90), math.radians(netPlayer.team == 0 ? 180 : 0), 0);
}).Run();
return inputDeps;
}
}
[UpdateInGroup(typeof(GhostPredictionSystemGroup))]
public class MoveMovementSystem : JobComponentSystem {
protected override JobHandle OnUpdate(JobHandle inputDeps) {
inputDeps.Complete();
var worldForward = new float3(0, 0, 1);
var worldUp = new float3(0, 1, 0);
var group = World.GetExistingSystem<GhostPredictionSystemGroup>();
var tick = group.PredictingTick;
var deltaTime = Time.DeltaTime;
Entities.ForEach((
ref MovementData movementData,
ref PhysicsMass pm,
ref PhysicsVelocity pv,
ref PredictedGhostComponent prediction,
ref Rotation rotation,
ref Translation translation,
in DynamicBuffer<MovementInput> inputBuffer,
in NetPlayer netPlayer
) => {
if (!GhostPredictionSystemGroup.ShouldPredict(tick, prediction))
return;
MovementInput input;
inputBuffer.GetDataAtTick(tick, out input);
float speed = movementData.speed;
float3 velocityChange = new float3(input.horizontal * speed * deltaTime, 0, input.vertical * speed * deltaTime * (netPlayer.team == 0 ? -1 : 1));
if (velocityChange.x != 0 || velocityChange.z != 0) {
pv.Linear += velocityChange;
}
pv.Angular = new float3();
pm.InverseInertia = new float3();
translation.Value.y = 0.3188247f;
rotation.Value = quaternion.EulerXYZ(math.radians(-90), math.radians(netPlayer.team == 0 ? 180 : 0), 0);
}).Run();
return inputDeps;
}
}
public class BallSystem : JobComponentSystem {
protected override JobHandle OnUpdate(JobHandle inputDeps) {
Entities.WithAll<BallData>().ForEach((ref Rotation rotation, ref Translation translation, ref PhysicsMass pm, ref PhysicsVelocity pv) => {
pm.InverseInertia = new float3();
pv.Angular = new float3();
rotation.Value = quaternion.EulerXYZ(math.radians(-90), 0, 0);
translation.Value.y = -0.03616257f;
}).Run();
return inputDeps;
}
}
[UpdateInGroup(typeof(GhostPredictionSystemGroup))]
public class BallPredictionSystem : JobComponentSystem {
protected override JobHandle OnUpdate(JobHandle inputDeps) {
inputDeps.Complete();
var worldForward = new float3(0, 0, 1);
var worldUp = new float3(0, 1, 0);
var group = World.GetExistingSystem<GhostPredictionSystemGroup>();
var tick = group.PredictingTick;
var deltaTime = Time.DeltaTime;
Entities.ForEach((
ref PhysicsVelocity pv,
ref PredictedGhostComponent prediction,
in BallData ballData
) => {
if (!GhostPredictionSystemGroup.ShouldPredict(tick, prediction))
return;
if (math.length(pv.Linear) > ballData.maxVelocity) {
pv.Linear = math.normalize(pv.Linear) * ballData.maxVelocity;
}
}).Run();
return inputDeps;
}
}