• Advertisement

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
Advertisement

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


  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By Innoc uous
      I'm working on a space game, and I suck at art. I would love to get some help from someone who is more skilled than me. Things I need include modular space ship parts and GUI elements. Nothing too fancy, just functional so I can get a prototype put together. This could potentially become a serious project, but for now this is just a hobby project.
       
      In this video, you can see a few things I already completed
      :2018-02-24 20-08-13.flv2018-02-24 20-08-13.flv
    • By Innoc uous
      If you want to incorporate noise into your shaders, the Turbulance Library has you covered. Using code I gathered from this library, I made a cginc file that contains all you need to easily implement noise into your unity shaders. Who knows how this stuff works, but man, does it work well!
       
      https://pastebin.com/LLCUpJut
       
      Here is an example of what you can create using these noise functions.
       
    • By Nio Martinez
      I'll be buying a new laptop as my workstation for building games, Mostly 3D but not hard core. 
       
      I'm stuck at choosing between these 2 specs below. Does this really matter and if so, can some one tell my how and why it matters. 
      Choice1:
      Intel core i5-8250U (8th gen Kabylake refresh)(6 MB Smart Cache, 1.6 GHz Base with Turbo Boost up to 3.4 GHz) 4 cores 8 threads
      RAM 8 GB DDR4 (2400 MHz)
      GPU 2 GB DDR5 Nvidia MX150 256 bit
      SSD: yes
      Choice2:
      Intel core i7-7500U 2.70GHz Base Processor (4M Cache, up to 3.50 GHz Boost) 2 Cores, 4 Threads
      RAM 4 GB DDR4 (1800 MHz)
      GPU 2 GB DDR5 Nvidia GeForce 940MX 256 bit
      SSD: No
       
    • By Timothy Sharp
      just to test out my animations, let's say i had a trip animation. How would I code a script to where my character would fall it mud and their clothes would become all muddy? I saw this in a game on Unreal 3 but is this possible with Unity?
    • By Manuel Berger
      Hello fellow devs!
      Once again I started working on an 2D adventure game and right now I'm doing the character-movement/animation. I'm not a big math guy and I was happy about my solution, but soon I realized that it's flawed.
      My player has 5 walking-animations, mirrored for the left side: up, upright, right, downright, down. With the atan2 function I get the angle between player and destination. To get an index from 0 to 4, I divide PI by 5 and see how many times it goes into the player-destination angle.

      In Pseudo-Code:
      angle = atan2(destination.x - player.x, destination.y - player.y) //swapped y and x to get mirrored angle around the y axis
      index = (int) (angle / (PI / 5));
      PlayAnimation(index); //0 = up, 1 = up_right, 2 = right, 3 = down_right, 4 = down

      Besides the fact that when angle is equal to PI it produces an index of 5, this works like a charm. Or at least I thought so at first. When I tested it, I realized that the up and down animation is playing more often than the others, which is pretty logical, since they have double the angle.

      What I'm trying to achieve is something like this, but with equal angles, so that up and down has the same range as all other directions.

      I can't get my head around it. Any suggestions? Is the whole approach doomed?

      Thank you in advance for any input!
       
  • Advertisement