Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Items : Oxygen and Fuel Refill

All that is missing in this world is a little bit of hope ! During is travel, Major Tom will find oxygen and fuel refill, that will save his life, more that once.

Thus I created the OxygenRefill and FuelRefill classes, that are subclasses of an Item class.

Here is the code of the Item.java :

public class Item {
    
    protected static World world;
    public Body body;
    private BodyDef bodyDef;
    private FixtureDef fixtureDef;
    private PolygonShape polygonShape;
    private float width, height;
    public boolean used;
    
    public Item(){    
    }
    
    public void create(World world,  OrthographicCamera camera, MapObject mapObject){
        this.world = world;
        used = false;
        
        width = mapObject.getProperties().get("width", float.class)/2 * GameConstants.MPP;
        height = mapObject.getProperties().get("height", float.class)/2 * GameConstants.MPP;
        
        bodyDef = new BodyDef();
        fixtureDef = new FixtureDef();
        
        bodyDef.type = BodyType.DynamicBody;

        bodyDef.position.set((mapObject.getProperties().get("x", float.class) + mapObject.getProperties().get("width", float.class)/2) * GameConstants.MPP,
                            (mapObject.getProperties().get("y", float.class) + 1.5f*mapObject.getProperties().get("height", float.class)) * GameConstants.MPP);
        
        polygonShape = new PolygonShape();
        polygonShape.setAsBox(width, height);
        
        fixtureDef.shape = polygonShape;
        fixtureDef.density = 0.1f;  
        fixtureDef.friction = 0.2f;  
        fixtureDef.restitution = 0f;
        fixtureDef.isSensor = true;
        
        body = world.createBody(bodyDef);
        body.createFixture(fixtureDef).setUserData("Item");
        body.setUserData("Item"); 
    }
    
    public void activate(){
        //Called when Major Tom collide with the item
    }
    
    public void active(TiledMapReader tiledMapReader){
        if(used){
            body.setActive(false);
            world.destroyBody(body);
            tiledMapReader.items.removeIndex(tiledMapReader.items.indexOf(this, true));
        }
    }
}

About this code :

  • The create() function is quite basic : It reads the Tiled Map to get coordinates of the item and create the body.
  • An item possess a "used" boolean, that is set to false by default
  • The activate() function will be called when Major Tom picks up the item. It will be defined in each subclass as the activity of the item will depend on its nature.
  • The active() function will run in the render() of the GameScreen. It checks if the Item has been used, if yes, the item is removed from the level.
Item.java possesses 2 sublcasses : FuelRefill.java and OxygenRefill.java.

FuelRefill.java :

public class FuelRefill extends Item{

    private static Hero hero;
    
    public FuelRefill(World world,  OrthographicCamera camera, MapObject mapObject, Hero hero){
        this.hero = hero;       
        create(world, camera, mapObject);    
    }
    
    @Override
    public void activate(){
        used = true;
        
        System.out.println("Fuel level before refill : " + hero.getFuelLevel());
        hero.setFuelLevel(hero.getFuelLevel() + GameConstants.FUEL_REFILL);
        
        if(hero.getFuelLevel() > GameConstants.MAX_FUEL)
            hero.setFuelLevel(GameConstants.MAX_FUEL);
        System.out.println("Fuel level after refill : " + hero.getFuelLevel());
    }
}

OxygenRefill.java :

public class OxygenRefill extends Item{
    
    private static Hero hero;
    
    public OxygenRefill(World world,  OrthographicCamera camera, MapObject mapObject, Hero hero){
        this.hero = hero;      
        create(world, camera, mapObject);        
    }
    
    @Override
    public void activate(){
        used = true;
        
        System.out.println("Oxygen level before refill : " + hero.getOxygenLevel());
        hero.setOxygenLevel(hero.getFuelLevel() + GameConstants.OXYGEN_REFILL);
        
        if(hero.getOxygenLevel() > GameConstants.MAX_OXYGEN)
            hero.setOxygenLevel(GameConstants.MAX_OXYGEN);
        System.out.println("Oxygen level after refill : " + hero.getOxygenLevel());
    }
}

As you can see, these 2 subclasses are very straightforward. We only define the activate() function, to add either fuel or oxygen. A couple of "System.out.println()" are here only to monitor the fuel and oxygen level in the console, ash I still didn't create the HUD.

All we need to make the activate() function run is adding these two lines in the GameConstants.java :

public static float FUEL_REFILL = 40f;
public static float OXYGEN_REFILL = 30f;

Of course, these values are arbitrary for now. I'll do the fine tuning much later.

Recognizing items with the TiledMapReader.java :

This happens in the same for loop as the Switches recognition, as the items will be placed in the "Spawn" layer of the Tiled Map, and not in the "Object" layer. Processing like that will make it easier to visualise things when I'll create levels in the level editor.

Therefore, this for loop that reads the Spawn layer looks like that now :

//Spawned items
for(int i = 0; i < tiledMap.getLayers().get("Spawn").getObjects().getCount(); i++){
    if(tiledMap.getLayers().get("Spawn").getObjects().get(i).getProperties().get("Type") != null){   
        //Switches 
        if(tiledMap.getLayers().get("Spawn").getObjects().get(i).getProperties().get("Type").equals("Switch")){
            ItemSwitch itemSwitch = new ItemSwitch(world, camera, tiledMap.getLayers().get("Spawn").getObjects().get(i));
            switchs.add(itemSwitch);
                }
        //Oxygen Refill
        else if(tiledMap.getLayers().get("Spawn").getObjects().get(i).getProperties().get("Type").equals("Oxygen")){
            OxygenRefill oxygenRefill = new OxygenRefill(world, camera, tiledMap.getLayers().get("Spawn").getObjects().get(i), hero);
            items.add(oxygenRefill);
        }
        //Fuel Refill
        else if(tiledMap.getLayers().get("Spawn").getObjects().get(i).getProperties().get("Type").equals("Fuel")){
            FuelRefill fuelRefill = new FuelRefill(world, camera, tiledMap.getLayers().get("Spawn").getObjects().get(i), hero);
            items.add(fuelRefill);
        }
}
        

And I added a new function in the TiledMapReader.java :

public void active(){
        hero.displacement();
        
        for(Obstacle obstacle : obstacles)
            obstacle.active();
        
        for(Item item: items)
            item.active(this);
    }

This function will run in the render() of the GameScreen.java and it will replace this lines

mapReader.hero.displacement();
for(Obstacle obstacle : mapReader.obstacles){
    obstacle.active();

by this line

mapReader.active();

Finally, we only need to update the beginContact function of the ContactListener, in the GameScreen :

public void beginContact(Contact contact) {
                Body bodyA = contact.getFixtureA().getBody();
                Body bodyB = contact.getFixtureB().getBody();
                Fixture fixtureA = contact.getFixtureA();
                Fixture fixtureB = contact.getFixtureB();
                
                if(fixtureA.getUserData() != null && fixtureB.getUserData() != null) {
                    ...

                    //Items
                    if(fixtureA.getUserData().equals("Tom") && fixtureB.getUserData().equals("Item")){
                        for(Item item : mapReader.items){
                            if(item.body == fixtureB.getBody())
                                item.activate();
                        }
                    }
                    else if(fixtureB.getUserData().equals("Tom") && fixtureA.getUserData().equals("Item")){
                        for(Item item : mapReader.items){
                            if(item.body == fixtureA.getBody())
                                item.activate();
                        }
                    }
                }  
            }

And here is the result !