Skip to main content

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

Winning condition : Exiting the room

To finish a level, you simply need to reach the exit of the room you are in. To detect the exit of the room, I created a body, and when the hero collides with this body, the room is exited !

First, an Exit class, that is a subclass from myObstacle class is created.

Here is the Exit.java :

public class Exit extends Obstacle{
    
    public Exit(World world, Camera camera, MapObject rectangleObject) {
        super(world, camera, rectangleObject);
        
        body.getFixtureList().get(0).setSensor(true);
        body.getFixtureList().get(0).setUserData("Exit");
        body.setUserData("Exit");
    }
}

The difference between an Exit and an Obstacle are :

  • The Exit is a sensor (body.getFixtureList().get(0).setSensor(true);). That means that the Exit body will detect collisions but there won’t be any physical response to this collision : The hero can pass throug the Exit.
  • The user data of the Exit’s body and fixture are set to "Exit" instead of "Obstacle" (.setUserData("Exit")): This will allow us to make the difference between the collision with an Obstacle and the Exit.
Once the Exit class created, we need to add an Exit to our level
For that we use the Tiled editor and create a rectangle. Then, we'll use one of the most useful feature of Tiled : We'll create a property in our rectangle and we'll call it "Type" and we'll give the value "Exit" :

Then the TiledMapReader needs to recognize the Exit

Here is the new TiledMapReader.java :

public class TiledMapReader {

    private OrthographicCamera camera;
    private World world;
    private MapObjects objects;
    public Array<Obstacle> obstacles;
    public Hero hero;
    
    public TiledMapReader(final MyGdxGame game, TiledMap tiledMap, World world, OrthographicCamera camera){
        this.camera = camera;
        this.world = world;
        
        hero = new Hero(world, camera, tiledMap);
        
        objects = tiledMap.getLayers().get("Objects").getObjects();

        obstacles = new Array<Obstacle>();    
        
        for (RectangleMapObject rectangleObject : objects.getByType(RectangleMapObject.class)) {
            if(rectangleObject.getProperties().get("Type") != null){
                //End of the level
                if(rectangleObject.getProperties().get("Type").equals("Exit")){
                    Exit finish = new Exit(world, camera, rectangleObject);
                    obstacles.add(finish);
                }
            }
            else{
                Obstacle obstacle = new Obstacle(world, camera, rectangleObject);
                obstacles.add(obstacle);
            }
        }
    }
}

Modifications with the previous TiledMapReader.java :

  • In the for loop we add an if, that will check if the rectangle has a property called "Type". To access to the properties of a rectangle object, you need to do : rectangleObject.getProperties()
  • If the rectangle has a property called "Type", we check if the "Type" property as the value "Exit"
  • If the value of Type is Exit, we create an Exit, and add it to the obstacles Array
  • If the rectangle doesn’t have a property called "Type", we create an Obstacle.
Finally, in the GameScreen, we set a contactListener detecting the collision between bodies
The contactListener will be in the show() of the GameScreen.java :
@Override
    public void show() {
        world.setContactListener(new ContactListener(){
            @Override
            public void beginContact(Contact contact) {
                Body bodyA = contact.getFixtureA().getBody();
                Body bodyB = contact.getFixtureB().getBody();
                
                if(bodyA.getUserData() != null && bodyB.getUserData() != null) {
                    //Finish the level
                    if(bodyA.getUserData().equals("Tom") && bodyB.getUserData().equals("Exit"))
                        System.out.println("LEVEL FINISHED !!!!");
                    else if(bodyB.getUserData().equals("Tom") && bodyA.getUserData().equals("Exit"))
                        System.out.println("LEVEL FINISHED !!!!");
                }
            }

            @Override
            public void endContact(Contact contact) {
            }

            @Override
            public void preSolve(Contact contact, Manifold oldManifold) {
            }

            @Override
            public void postSolve(Contact contact, ContactImpulse impulse) {               
            }
        });
    }

The contactListener includes 4 methods :

  1. beginContact : Called when two fixtures start collide. You can trigger events when two bodies collide.
  2. endContact : Called when two fixtures stop being in contact. Same thing, you can trigger whatever you want at this moment.
  3. preSolve : Called before the contact is processed, it means before the simulation of this collision runs, before the beginContact. Very useful to ignore some contacts.
  4. postSolve : Called after the contact is processed.
In our case we use the beginContact to detect collisions between the Hero and the Exit. For that, we check if the UserData of the fixtures that collide are "Exit" and "Tom". If yes, we print "LEVEL FINISHED !!!!" in the console.

That's it ! So far, so good. We have a fully playable game :
  • A start point
  • A finish point
  • We can control the hero
  • We have winning and losing conditions
Now, we need to add fun to this !