Zhav

Lag Compensated Projectiles

Recommended Posts

First of all I just wanted to say thank you for taking the time out to read this.

So I'm having a problem as to how I could create Lag Compensated Projectiles. The system I have is setup to send the frame of the server on which we fire, and it can rewind the hitboxes back up to 60 frames (1 second).

I'm not quite sure how exactly I should go about compensating for the lag.

What I have for my projectile script is this:

public float speed = 10;
 public float gravity = -9;
 public Vector3 oldPos;
 public Vector3 newPos;
 
 Vector3 direction;
 Vector3 velocity;
 Vector3 force;
 float distance;
 
 private void FixedUpdate()
    {
        velocity = speed * transform.forward + force;
        force += new Vector3(0, gravity, 0);

        newPos += velocity * Time.deltaTime;

        direction = newPos - oldPos;
        distance = direction.magnitude;

   		RaycastHit hit;
   		if (Physics.Raycast(oldPos, direction, out hit, distance, ~ignoreLayers))
   		{
     		Destroy(gameObject);
   		}
   		else
   		{
     		oldPos = transform.position;
     		transform.position = newPos;
   		}
    }

All it really does is move a transform and cast a ray from the previous position to the current position and adds gravity.

Edited by Zhav

Share this post


Link to post
Share on other sites

I'm assuming you want to compensate for collisions/hits from when the client fired, and not do client-side prediction.

The first thing you can try is to just "rewind" the projectile by pulling it back by velocity to test for the collision. Since you have a fixed update you should be able to calculate this fairly easily and just move the projectile back to where it was N time ago.

However, I'd probably opt for a better approach. Projectiles are fairly predictable as they typically have a trajectory that can be represented as some mathematical function (linear for most things, like rockets, and some curved towards gravity, for grenades, etc), so you don't necessarily have to simulate them with the usual physics approach (velocity, etc).

Instead you can use the initial velocity and time, and some trajectory function, to calculate the time and position that the projectile would be at when it reaches the end of its trajectory (i.e. when it hit a wall) and then interpolate through it. In your case it's a simple linear trajectory, so this is as simple as a standard linear interpolation:

p0 + (p1 - p0) * t

where p0 is the start position, p1 is the end position, and t is the 0-1 interpolation factor calculated from the start and end times.

If you do it this way then the prediction becomes a simple matter of using a different interpolation value, rather than trying to run a fully predicted physics sim. This means that if you have the time (when the client fired), you can simply run through the interpolation again. Very easy, very fast.

If you want an example of how to do something like this (albeit in C, not C#), check out the source for Quake 3/idTech3 (BG_EvaluateTrajectory function in bg_misc.c is a good place to start).

Edited by Styves

Share this post


Link to post
Share on other sites

It sounds like what you want is:

  • When receiving a new projectile from client.
  • Figure out when it was fired.
  • Rewind simulation to that point.
  • Step simulation forward for projectile until the "current frame" in server, while putting all nearby colliders at whatever positions they had at each of those time steps.
  • If the projectile hits something, apply that damage, which means you re-write history for the targeted entity (it will need a correction.)
  • Once you've rolled the projectile forward to current frame, it will run the same as any other entity until it dies.

The main optimization is "which entities need to be put temporarily back in time while the projectile simulates forward?"

You can typically answer this question by keeping a maximum-velocity value per entity, and calculate the envelope of the projectile for the travel time you're rolling forward, and only actually testing the entities whose current position plus radius plus max-velocity-times-rollback-time intersects with the projectile trajectory envelope (bounds.) Or, alternatively, inflate the projectile envelope by the maximum velocity of any target object, and check that against the current bounds of possible targets (this may be cheaper, depending on your implementation specifics.)

 

Share this post


Link to post
Share on other sites
Spoiler
8 hours ago, Styves said:

I'm assuming you want to compensate for collisions/hits from when the client fired, and not do client-side prediction.

The first thing you can try is to just "rewind" the projectile by pulling it back by velocity to test for the collision. Since you have a fixed update you should be able to calculate this fairly easily and just move the projectile back to where it was N time ago.

However, I'd probably opt for a better approach. Projectiles are fairly predictable as they typically have a trajectory that can be represented as some mathematical function (linear for most things, like rockets, and some curved towards gravity, for grenades, etc), so you don't necessarily have to simulate them with the usual physics approach (velocity, etc).

Instead you can use the initial velocity and time, and some trajectory function, to calculate the time and position that the projectile would be at when it reaches the end of its trajectory (i.e. when it hit a wall) and then interpolate through it. In your case it's a simple linear trajectory, so this is as simple as a standard linear interpolation:



p0 + (p1 - p0) * t

where p0 is the start position, p1 is the end position, and t is the 0-1 interpolation factor calculated from the start and end times.

If you do it this way then the prediction becomes a simple matter of using a different interpolation value, rather than trying to run a fully predicted physics sim. This means that if you have the time (when the client fired), you can simply run through the interpolation again. Very easy, very fast.

If you want an example of how to do something like this (albeit in C, not C#), check out the source for Quake 3/idTech3 (BG_EvaluateTrajectory function in bg_misc.c is a good place to start).

 

Spoiler
4 hours ago, hplus0603 said:

It sounds like what you want is:

  • When receiving a new projectile from client.
  • Figure out when it was fired.
  • Rewind simulation to that point.
  • Step simulation forward for projectile until the "current frame" in server, while putting all nearby colliders at whatever positions they had at each of those time steps.
  • If the projectile hits something, apply that damage, which means you re-write history for the targeted entity (it will need a correction.)
  • Once you've rolled the projectile forward to current frame, it will run the same as any other entity until it dies.

The main optimization is "which entities need to be put temporarily back in time while the projectile simulates forward?"

You can typically answer this question by keeping a maximum-velocity value per entity, and calculate the envelope of the projectile for the travel time you're rolling forward, and only actually testing the entities whose current position plus radius plus max-velocity-times-rollback-time intersects with the projectile trajectory envelope (bounds.) Or, alternatively, inflate the projectile envelope by the maximum velocity of any target object, and check that against the current bounds of possible targets (this may be cheaper, depending on your implementation specifics.)

 

 

Thank the both of you so much. I understand what I need to do, now it's time to implement it. This problem was bugging me for a while, so I really appreciate the well written and easy to understand explanations.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Announcements

  • Forum Statistics

    • Total Topics
      628354
    • Total Posts
      2982236
  • Similar Content

    • By Jim Bachalo
      Hi
      Having a huge problem trying to simply implement a working framework for a turn based (each player takes turns) board game using UNET (Unity).
      I have an Eventmanager system I am comfortable with for sending, receiving custom events.
      I want to avoid adding any unnecessary complexity, so no State machine etc.
      Just a Model class
      A Game Controller
      Perhaps a controller for each player?
      And a View for the board and game pieces.

      Not sure whether most of the game logic (calculating score, wins etc.) would go in the Game Controller or Model class.
      Will extend this for use in AR.

      Can anyone help?
      Are there any really useful MVC C# templates that would get me started?
      Any help appreciated!
    • By koto
      Hello,

      I'm developing a roguelike game. Currently it's in a playable state and I think it's a high time to show it and hopefully get some feedback.

      The game has following features:
      - turn based
      - procedurally generated levels
      - tons of loot
      - spells system
      - trading system
      - some quests
      - some limited crafting
      - door/key/lever mechanics
      - quite a lot of different (look/behaviour) monsters

      Trailer:
      Demo: http://kotogames.com/wp-content/uploads/2017/11/OuaD_demo.zip
      Regards,
      Tom
       
    • By Afambus
      Hello,
      I have a full experienced team that looking for a composer and another 3d designer, im expecting as much from you there are other people in this server that can help you we have a determined team, we have done many things in our game there is more information in the discord about everyone and there skills there region and about the game, if you join the discord pm asap
      https://discord.gg/b2teN3m
    • By idzohar
      I am trying to rotate my car sprite just slightly to the left or right depending on input up to a small maximum. When I use this code, the rotation doesn't stop at the maximum i give it. When i try to reset the rotation back to its original state when not pressing any input, the car also jitters between a z axis rotation of 0 and 2.5. I don't understand why the rotation doesn't stop at the given maximums, nor do I understand why its jittering. Can anybody provide me some insight?
              float movementHorizontal = 0f;
              float movementVertical = 0f;
              if (Input.GetKey(KeyCode.A) && Input.GetKey(KeyCode.D))
              {
              }
              else if (Input.GetKey(KeyCode.A))
              {
                  movementHorizontal = -1;
                  if (transform.rotation.z < 10f)
                  {
                      transform.Rotate(zAxis, 2.5f);
                  }            
              }
              else if (Input.GetKey(KeyCode.D))
              {
                  movementHorizontal = 1;
                  if (transform.rotation.z > -10f)
                  {
                      transform.Rotate(zAxis, -2.5f);
                  }
                  
              }
              else
              {
                  if(transform.rotation.z > 0)
                  {
                      transform.Rotate(zAxis, -2.5f);
                      //transform.rotation.Set(0, 0, 0, 0);
                  }
                  else if (transform.rotation.z < 0)
                  {
                      transform.Rotate(zAxis, 2.5f);
                      //transform.rotation.Set(0, 0, 0, 0);
                  }
                  
              }
    • By BAG Labs
      Mobile SoS

      Platform: Android
      Genre: Board
      Link: Google Play
       
      This games sharpen memory and test your strategies to place S-O-S pattern within time limit and serve 3 difficulties as Easy, Normal, and Hard.

      Goals of the game is to put S-O-S words in patterns (Horizontal, Vertical, and Diagonal) alternately with enemy.
       
      Features:
      Single Player Multiplayer Achievements Leaderboards  
       
      Screenshot:

       

       

       
      Link: Google Play
       
      Please help us improve this game with review
  • Popular Now