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.
Perform the following steps to fire over a network:
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.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); }
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); }
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--; } }
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()); } }
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; }
removeBullet
method once we receive the information from the server.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).
3.133.158.32