In the previous article we implemented smoothing of player movements on both the client and server side. In this article we will implement the functionality required to allow the player to fire shots.
As per the previous articles the first class to implement is the Shot class. This class will represent a bullet flying across the screen and inherits from the Sprite base class. The Shot class has two additional properties as shown below.
The FiredById property is used to store the Id of the entity that fired the shot.
The FiredByPlayer property is used to indicate whether the player fired the shot. When we implement enemies this property will be false when an enemy ship fires at the player.
Shots are managed by the ShotManager class, meaning that the ShotManager is responsible for drawing all the shots and updating the movement of the shots. Shots are removed from the ShotManager when they move out of the screen bounds.
The FireShot method is used to fire a shot and takes as input parameter the position from where the shot is fired and the velocity (direction and speed) of the shot. Additional meta data includes the Id of the entity that fired the shot and whether the firing entity is a player. The FireShot method raises an event that is handled by the Game class to notify the client or server (depending who is firing the shot) when a shot is fired.
As per the previous articles we send messages by handling the events raised by the Manager type classes. In this case we handle the ShotFired event as follows.
The ShotFired event is handled for both the client and the server.
The ShotFiredMessage is similar to the message classes defined previously.
The above ShotFiredMessage is very similar to the other GameMessages we have defined thus far. In this case we have made provision for the FiredById and FiredByPlayer properties.
The ShotFiredMessage is handled using the same pattern as the previous message types. The ProcessNetworkMessages method in the game code is updated as follows:
With the HandleShotFired method implemented as follows:
As before, we decode the game message into our ShotFiredMessage class. We calculate the time delay and update the position of the Shot taking into account any latency. We then call the FireShot message on the ShotManager class to add the shot to the collection of shots to be managed.
Note: We are using the non event raising override of the FireShot method. This pattern is repeated in all the manager implementations. On each manager we have a version of the method that will raise the “create” or “update” event and a version that will add the object instance but not raise any events. The latter version is used when processing game network messages to update the local state in our manager classes.
By adding a few lines of code to the PlayerManager class we now have the player ship firing bullets on both the client and server.
The Update method will check if the Spacebar is pressed and call the FireShot method. We have limited the shots to be fired to fire every 200ms. Shots are fired from the SimulatedState position taking into account a GunOffset to set the initial position of the shot.
The video below shows an example of shots being fired by the client player instance and how the shots are displayed on the server-side.