Shooting

The final stage before our project is actually something that legally qualifies as a game, is to implement shooting.

To do this, we'll need two new entities, a "gun", which we'll call a MagicWand, and a bullet, which we'll call a Fireball (since we've got Wizards).  So create the following entities in code:



import com.jme3.math.Vector3f;
import com.scs.stevetech1.components.ICanShoot;
import com.scs.stevetech1.components.IEntity;
import com.scs.stevetech1.server.ClientData;
import com.scs.stevetech1.shared.IAbility;
import com.scs.stevetech1.shared.IEntityController;
import com.scs.stevetech1.weapons.AbstractMagazineGun;

public class MagicWand extends AbstractMagazineGun implements IAbility {

    public MagicWand(IEntityController game, int id, int playerID, ICanShoot owner, int avatarID, byte num, ClientData _client) {
        super(game, id, MTDClientEntityCreator.MAGIC_WAND, playerID, owner, avatarID, num, "MagicWand", 1, 1, 999, _client);
       
    }


    @Override
    protected FireballBullet createBullet(int entityid, int playerID, IEntity _shooter, Vector3f startPos, Vector3f _dir, byte side) {
        return new FireballBullet(game, entityid, playerID, _shooter, startPos, _dir, side, client);
    }
   

}

The above code creates the MagicWand "gun".  It extends AbstractMagazineGun, which will handle the bullet firing frequence and other things.


import com.jme3.asset.TextureKey;
import com.jme3.bounding.BoundingBox;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
import com.jme3.texture.Texture;
import com.scs.simplephysics.SimpleRigidBody;
import com.scs.stevetech1.components.IEntity;
import com.scs.stevetech1.components.INotifiedOfCollision;
import com.scs.stevetech1.entities.AbstractBullet;
import com.scs.stevetech1.entities.PhysicalEntity;
import com.scs.stevetech1.server.ClientData;
import com.scs.stevetech1.shared.IEntityController;

public class FireballBullet extends AbstractBullet implements INotifiedOfCollision {

    public FireballBullet(IEntityController _game, int id, int playerOwnerId, IEntity _shooter, Vector3f startPos, Vector3f _dir, byte _side, ClientData _client) {
        super(_game, id, MTDClientEntityCreator.FIREBALL_BULLET, "FireballBullet", playerOwnerId, _shooter, startPos, _dir, _side, _client, false, 0f, 0f);
    }


    @Override
    protected void createModelAndSimpleRigidBody(Vector3f dir) {
        Sphere sphere = new Sphere(8, 8, 0.1f, true, false);
        Geometry ball_geo = new Geometry("ball_geo", sphere);

        if (!game.isServer()) {
            sphere.setTextureMode(TextureMode.Projected);
            ball_geo.setShadowMode(ShadowMode.Cast);
            TextureKey key = new TextureKey("Textures/yellowsun.jpg");
            Texture tex = game.getAssetManager().loadTexture(key);
            Material mat = new Material(game.getAssetManager(),"Common/MatDefs/Light/Lighting.j3md");
            mat.setTexture("DiffuseMap", tex);
            ball_geo.setMaterial(mat);
        }

        ball_geo.setModelBound(new BoundingBox());
        this.mainNode.attachChild(ball_geo);

        this.simpleRigidBody = new SimpleRigidBody<PhysicalEntity>(this, game.getPhysicsController(), true, this);
        this.simpleRigidBody.setBounciness(0f);
        this.simpleRigidBody.setGravity(0);
        this.simpleRigidBody.setAerodynamicness(1f); // Stop us slowing down
        this.simpleRigidBody.setLinearVelocity(dir.normalize().mult(20));

    }


    @Override
    public float getDamageCaused() {
        return 1;
    }


    @Override
    public void notifiedOfCollision(PhysicalEntity pe) {
        game.markForRemoval(this);
    }

}

The above code creates the Fireball bullet, which are spheres but, if you have some good knowledge of JME, can be turned into proper fireballs, although that is beyond the scope of this tutorial.

You will also need to add some code to our MTDClientEntityCreator class to add their entity code, and tell the client how to create these entities.  Firstly we'll create the new entity type codes:-

    public static final int MAGIC_WAND = 3;
    public static final int FIREBALL_BULLET = 4;


And then add the code to actually create them, in the createEntity() method:-

         case MAGIC_WAND:
        {
            int ownerid = (int)msg.data.get("ownerid");
            byte num = (byte)msg.data.get("num");
            int playerID = (int)msg.data.get("playerID");
            MagicWand gl = new MagicWand(game, id, playerID, null, ownerid, num, null);
            return gl;
        }

        case FIREBALL_BULLET:
        {
            int playerID = (int) msg.data.get("playerID");
            if (playerID != game.getPlayerID()) {
                byte side = (byte) msg.data.get("side");
                int shooterId =  (int) msg.data.get("shooterID");
                IEntity shooter = game.entities.get(shooterId);
                Vector3f startPos = (Vector3f) msg.data.get("startPos");
                Vector3f dir = (Vector3f) msg.data.get("dir");
                FireballBullet fireball = new FireballBullet(game, game.getNextEntityID(), playerID, shooter, startPos, dir, side, null); // Notice we generate our own ID
                return fireball;
            } else {
                return null; // it's our bullet, which we've already created locally
            }
        }


You'll notice that the fireball only gets created if it's a fireball that we didn't shoot.  This is because if we did shoot it, our client creates the entity automatically and immediately without waiting for the server.

Next we need to give the Wizards their Magic Fireball-shooting wands.  In the class MTDServer, change the method createPlayersAvatarEntity() to the following, which adds a couple of lines:-

     @Override
    protected AbstractServerAvatar createPlayersAvatarEntity(ClientData client, int entityid) {
        WizardServerAvatar avatar = new WizardServerAvatar(this, client, client.remoteInput, entityid);

        IAbility abilityGun = new MagicWand(this, getNextEntityID(), client.getPlayerID(), avatar, entityid, (byte)0, client);
        this.actuallyAddEntity(abilityGun);

        return avatar;
    }


This will give them their wand.

Finally, if you haven't added it already,  you'll need to add the texture for the fireball (yellowsun.jpg in the code code above) into the Textures/ folder.

And that's it!  Run the client again and shoot away!


Have we just created our own FPS?  I think we have.

Comments