Firing over a network

An FPS wouldn't be a shooter unless there's actually some shooting possible. We'll look at an example with visible, non-instant bullets. For this, we'll be able to reuse some code from Chapter 2, Cameras and Game Controls. The recipe won't describe the actual collision as this is already described in that chapter.

How to do it...

Perform the following steps to fire over a network:

  1. To start off, we create a new message, called BulletUpdateMessage to send updates on bullet positions. It only needs two fields: a Vector3f field for position and a Boolean field for whether it's alive or not.
  2. We'll add a check in the messageReceived method of ServerMessageHandler to see whether a player is firing. Any action verification we want to do should happen prior to this:
    if(message.getAction().equals("Fire") && message.isPressed()){
      server.onFire(p);
    }
  3. We find out the direction the player is facing and create a new ServerBullet instance. It's assigned the next available object ID and added to the bullets list, as follows:
    public void onFire(NetworkedPlayerControl player){
      Vector3f direction = player.getSpatial().getWorldRotation().getRotationColumn(2);
      direction.setY(-player.getYaw());
      ServerBullet bullet = new ServerBullet(player.getSpatial().getWorldTranslation().add(0, 1, 0), direction);
      bullet.setId(nextObjectId++);
      bullets.add(bullet);
    }
  4. Now, we need to add another code block to the simpleUpdate method to maintain the bullets and send out messages, as follows:
    int nrOfBullets = bullets.size();
    for(int i = 0; i < nrOfBullets; i++){
      ServerBullet bullet = bullets.get(i);
      bullet.update(tpf);
      BulletUpdateMessage update = new BulletUpdateMessage();
      update.setId(bullet.getId());
      update.setPosition(bullet.getWorldPosition());
      update.setAlive(bullet.isAlive());
      server.broadcast(update);
      if(!bullet.isAlive()){
        bullets.remove(bullet);
        nrOfBullets--;
        i--;
      }
    }
  5. In a for loop, we first update the bullet, and then create a new BulletUpdateMessage, which is sent to all players. If the bullet is out of range, it is removed from the list. This is implemented as follows:
    if (m instanceof BulletUpdateMessage){
      BulletUpdateMessage update = (BulletUpdateMessage) m;
      ClientBullet bullet = gameClient.getBullet(update.getId());
      if(bullet == null){
        bullet = gameClient.createBullet(update.getId());
      }
      bullet.setPosition(update.getPosition());
      if(!update.isAlive()){
        gameClient.removeBullet(update.getId(), bullet.getSpatial());
      }
    }
  6. On the client side, we write a new method that creates a new bullet, once it receives information from the server:
    public ClientBullet createBullet(int id){
      final ClientBullet bulletControl = new ClientBullet();
      final Spatial g = assetManager.loadModel("Models/Banana/banana.j3o");
      g.rotate(FastMath.nextRandomFloat(), FastMath.nextRandomFloat(), FastMath.nextRandomFloat());
      g.addControl(bulletControl);
      bullets.put(id, bulletControl);
      rootNode.attachChild(g);
      return bulletControl;
    }
  7. Then, we need a removeBullet method once we receive the information from the server.

How it works...

Like in the previous recipes, it's the server that is in control of things. The client merely says it wants to fire and any checks happen on the server side (although it's fine to mimick verification on the client side to save bandwidth). The recipe doesn't contain any specific verifications (a player can fire at any time), but this is explained more in Chapter 2, Cameras and Game Controls.

Unlike in Chapter 2, Cameras and Game Controls, we can't use the camera as input; instead, we use the direction of the firing player and apply the yaw for up and down tilt.

Bullets are different on the server and client side. On the server, they are merely logical objects. Like the non-instant bullets from the Firing non-instant bullets recipe of Chapter 2, Cameras and Game Controls, they work like slow rays, moving through the world until they hit something or move out of range.

On the client, the bullet is a bit different from the server side, and is based on the control pattern. The client finds out about the bullet in ClientMessageHandler, as the first update is received. It sees if ClientBullet exists already, and if not, it will create a new one. All ClientBullet does then is update the position in the controlUpdate method.

It's not the actual fire message that creates the bullets, but the first time a BulletUpdateMessage is received on the client. The client will keep updating the Bullet's position, much like the player positions, until a message says it's no longer alive. At this point, it will be removed.

The recipe currently sends all bullets to all players. As with players, this could (and probably should) be based on a need-to-know basis to avoid cheating (and excessive bandwidth usage).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.129.194