Rockets and other fast moving objects

Hello!

I am currently doing a space game project and I am creating it in single player and multiplayer. I am using Photon Network for multiplayer.
I however have come across a couple of problems. 1, which I never thought would be a problem.

First problem is synchronization. I haven't managed to quite synchronize player ships and rockets over the network nicely. It's as if there are 2 easy choices and then some difficult/longer ones.

1. choice: Players are either synchronized so that I can see other players move smoothly BUT they appear to be in the past. For example when I am player 1 and I move and shoot then player 2 sees laser "bullets" come from 5 meters or so further from where they are supposed to be fired(when player is moving!). Pros: Smooth movement, Cons: Player's ship is not where it is supposed to be. It appears to be in the past.

2. choice: Player ships are completely synchronized while Photon View looks at player's Transform component. This of course causes player to teleport and not move smoothly however player appears to be in the right position. This I think is even worse than first one.

At the moment I am using first one to sync players. I realize this "getting left behind in the past" lag can be fixed with some calculations including ping and so on. For example, player's ship accelerates. So make acceleration faster at the beginning of movement(on other player's client) to sync ship into position. However this isn't my main problem. Main problem is lasers and rockets.

Let me start with lasers. As I've read on the forums I've come to conclusion not to Photon.Instantiate my laser bullets. So instead what is happening at the moment:
1) Player clicks the mouse, which activates an RPC for all other players.
2) Laser is instantiated(NOT PHOTON INSTANTIATE) for all players(it also has a photon view).
3) If it hits the enemy player, an RPC is called, which reduces enemy player's health and if enemy's health falls below 0, then laser's
owner is awarded for the kill.
4) Player's local laser is destroyed(again, NOT through photon.destroy!)

This means that every player gets a new laser object into their scene, while none of these lasers are connected. For example if you instantiate with photon.instantiate then all players "share" the same laser(using photon view ID). In this case they don't. Now...laser's owner is awarded for the kill, using an RPC(for that reason laser object has a photonview(to make an RPC call)). Now let's say there are 5 players in game. 1 player shoots. 5 lasers are instantiated(none of them are connected because of no photon.instantiate!). Let's say this 1 laser hits another player. What now happens is where things get bad...I, in my scene see that other player got hit with my local laser--Boom, he loses health. My local laser is destroyed, but all other 4 lasers in other player's scene still remain. So another player sees in their scene that my laser hit them--Boom another health reduction. And now third player sees my laser(which is local in their client) sees that player got hit--Boom! More health lost. And so this one poor sob loses laser damage*5 health. This is one of the main problems. Another one is that if I see in my scene that I hit him, he loses health. BUT if he moves too fast then in his own scene he doesn't see me hitting him because as I mentioned above, player's locations are not synced. I realize that the only way to fix this is to sync player's ships.
1 point to mention is that there are ALOT of lasers shot and they are pretty fast so the last problem really doesn't bother me much. It's unlikely that the player who got shot understands whether the laser hit him or not, if there is alot of action going on. The main thing is that laser's shooter scores the kill if he sees that laser hit the enemy. And I have fixed that.

tl;dr Lasers aren't synched correctly but are also instantiated*players.

Now about the rockets. Rockets move slower and create an explosion after colliding with stuff. It is obvious that while I can ignore some unhit lasers in a tense action I can't ignore rockets. Rocket hits are controlled by rocket owners like they are supposed to be. Another important point is that if my rocket object collides, it creates rocket explosion instace for 0.1 seconds that detects any enemies hit in its collision box. That explosion is created through an RPC. So if rocket hits something, it calls an RPC, which instantiates(NOT PHOTON.INSTANTIATE) explosion area for this short amount of time. As you can see again, there are 2 separate rockets(local...1 in my scene, different one in other player's scene).

Now here's the situation: I shoot a rocket by sending an RPC. This RPC instantiates the rocket to all players(remember that it is a local rocket for everyone, no photon instantiation!) and gives it force to move(yes, it is a rigidbody for good reasons). Now in my scene I see that I hit my enemy. We both see an explosion, hear the sound effects and he gets pushed away by the explosion. Since he however was moving too fast: 1) didn't see my rocket hit him, so my rocket(enemy's local) flew past him into far far away distances, 2) Sees that he got hit, sees the explosion, hears sound effects and loses health while thinking why the heck did all this happen when I dodged his rocket? If he were to stand still he would get hit with 2 rockets(my local and his local), we both would see 2 explosions(assuming there are only 2 players), hear sound effects twice as loud AND he loses twice as much hp(for both rockets). Damage increases * players in game. This of course is unacceptable. I'm thinking that even if I managed to sync everything really well(player locations) there still would be a chance where I see that he got hit by the rocket while in his own scene he didn't.

So if photon.instantiation puts too much pressure on bandwidth and I would quickly run out of views, how can I achieve synced rockets?

I have thought of 1 solution but I would like to know if there is a better one.
My solution:

Right now player owns just the ship. But what if instead of instantiating lasers and rockets, player would also own 2 rockets and about 5 laser shots?
These rockets would be synced with photon view. So firing a rocket looks like this:
1) Player hits fire button, RPC is sent
2) Rocket, which player already owns and which already exists in the game, is shot from player's location(other players see this)
3) If rocket hits something, effects are made, points are given.
4) Rocket is returned to its original position(near player's ship)

This way I don't need to instantiate anything. I just need some careful calculations with weapon cooldowns and such. The only downside is that I have 2 extra objects(around 10 if including all weapons) which I need to sync all the time. Or instead of syncing all the time, make rocket object a child of player's object. This means that player's rockets are synced just like players themselves.

In the end my main problem is getting rid of the problem when using normal instantiation and not letting my enemy get hit by 5 rockets at same time when only 1 was fired. If there is no way to use photon instantiation with these weapons then is my solution a good one(asking before testing, I know). Are there any better solutions?

Thank you!
Cheers, Frosty!

Comments

  • I realize this is a really long post but if you did read it and something is unclear, please say so or ask. This way I can help you understand my post and you can help me solve the problem.

    Cheers,
    Frosty!
  • Hey Frosty,
    Aside from being pretty long, your post if about problems that are very hard to tackle.
    I assume you already browsed through other forums, etc. Maybe you found that rockets can be really tricky.

    You basically nailed it:
    Due to lag, not everything is in sync. You either follow the others' movement closely but too late or you make assumptions where something is going to be now but you might be wrong.
    The best technique of lag compensation depends on your game and requirements. Slow moving objects need another solution than fast moving ones or those with arcade-like movement with abrupt direction changes.
    There are a lot of possible routes to go. E.g. you might send your input immediately but delay it locally for a moment giving the network-update a headstart of a few ms.
    I am sorry but I can't help with concrete tips about this topic. Try to research "lag compensation" and lag hiding. Experiment and pick a solution which is OK for your game.

    It's very (very) hard to avoid all disagreements about the game state. You can try to live with it, minimize it and hide the visual effects. If you really have the time, build an authoritative server that has the "one and only valid state". No matter what, the clients might show a different state until they are corrected.


    This brings us to the other topic: Authority. This is about your rockets doing up to five-times the damage they should.
    As the clients have different views because they communicate with a delay, you have to make one client authoritative about the rocket hitting someone. In simplest case, the client who shot the rocket should decide if it hit.
    I can imagine that you could also hand over authority of the "hit" of rockets to the target player. This way, that player does the full simulation of the rocket, avoids it or not and then informs everyone of a hit. Unlike the first case, this prefers local action on the side of the player who is being hunted.

    No matter which route you go, the other players want to show something during the chase.
    Any non authoritative client could run a rocket AI where hitting a target is disabled, unless it got the update "rocket hit target" maybe.

    If you need to sync the exact path of a rocket depends on some factors. If there's a lot going on and 20+ rockets move, then most likely no player will notice if a rocket took a slightly different path to its target than on other machines. In general, it's not so much about the path but about the hit then.

    In case of the lasers, I would potentially make the shooting player authoritative. This is the player who sees where the lasers go and if they hit, you could tell the others about the hit and they might bend the path of a laser just so much to make a hit possible visually.

    In the end: Only one player should decide where things move and if they hit something. It's up to you, who that user is.
  • Hey FrostyMixi,

    I've been dealing with the same issues for the last year. Tobias is right, and your assumptions are also right. You will not be able to achieve complete syncronization. If your game requires you to, then you are screwed. So you have to design your game with some wiggle room in mind to hide the network lag. This wiggle room can be created with several different methods:

    1. A short delay before firing the rocket as Tobias suggested (this can be easily hidden by a charge animation)
    2. Lot's of stuff happening so small inconsistencies are not noticed, as you've suggested yourself
    3. Slow moving projectiles with predictable flight paths (for example: if your projectile only flies forward at a set speed, you only need to know when it's spawned [PhotonNetwork.time is syncronized between all players], in which direction and how fast it flies. with these three variables you can determine the exact position on every client)
    4. The projectile is "instant" and invisible, a lot of shooters do this. You can store the positions of your colliders for the last second and basically check the shot against the hitbox at the correct time.
    5. Each projectile has two seperate visual and collider objects. This way you can try to achieve a visually smooth look but the collision is actually doing some jumps and maybe fancy prediction to achieve more accurate collisions.

    There are probably more methods but those are the ones I use most frequently. It's all smoke and mirrors when it comes to networking. Learn to embrace it. The art is to make the player "feel" like it is correct and you can cheat a lot of ways to achieve that :-)

    Regarding your first problem that a laser deals damage 5 times: That is actually quite easy to solve. Just assign a unique ID to each laser and store the IDs that have already hit a player. This way, if an RPC comes in that tells you your ship is being hit by laser ID 6, and you have already dealt damage for ID 6, just ignore it. You should tell everyone about it if you have been hit by laser 6. This way, if one random client doesn't catch the hit because he was lagging or sth like that, you can still resolve the hit on that client.

    Hope this helps.