Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags
(3 edits)

Interacting with the environment : Switches

OK, thus far I have animated obstacles like ObstaclePiston and ObstacleMoving, and I plan to have few others. It would be very interesting if we could enable/disable these animated obstacles with switches. And it would be interesting if one switch could control several obstacles at a time, and also if an obstacle could be controlled by several switches. It will allow me to create some puzzles.

Here is a video showing how that works :


As you can see in the video, to associate a switch with one or several animated object, I use an Association Number. For that, as usual, I set a property in Tiled, I give it the name "Association Number", and I give the same number to the switch and the animated object that I want to control. I can give several Association Numbers to the switch, by separating them with a comma, if I want the switch to control several objects.

Here is the code for ItemSwitch.java :

public class ItemSwitch {

    public Body swtichBody;
    private BodyDef bodyDef;
    private FixtureDef fixtureDef;
    private PolygonShape switchShape;
    private float width, height;
    private boolean isOn;
    private String[] associationNumbers;
    
    public ItemSwitch(World world,  OrthographicCamera camera, MapObject mapObject){
        create(world, camera, mapObject);
    }
    
    public void create(World world,  OrthographicCamera camera, MapObject mapObject){      
        //Is the switch on ?
        if(mapObject.getProperties().get("On") != null){
            if(Integer.parseInt((String) mapObject.getProperties().get("On")) == 1)
                isOn = true;
            else 
                isOn = false;
        }
        else
            isOn = false;
        
        //Association Numbers
        if(mapObject.getProperties().get("Association Number") != null){
            associationNumbers = mapObject.getProperties().get("Association Number").toString().split(",");
        }
        
        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.StaticBody;

        bodyDef.position.set((mapObject.getProperties().get("x", float.class) + mapObject.getProperties().get("width", float.class)/2) * GameConstants.MPP,
                            (mapObject.getProperties().get("y", float.class) + mapObject.getProperties().get("height", float.class)) * GameConstants.MPP);
        
        switchShape = new PolygonShape();
        switchShape.setAsBox(width, height);
        
        fixtureDef.shape = switchShape;
        fixtureDef.density = 0;  
        fixtureDef.friction = 0.2f;  
        fixtureDef.restitution = 0f;
        fixtureDef.isSensor = true;
        
        swtichBody = world.createBody(bodyDef);
        swtichBody.createFixture(fixtureDef).setUserData("Switch");
        swtichBody.setUserData("Switch");     
    }
    
    public void active(Array<Obstacle> obstacles){    
        isOn = !isOn;
        
        for(String number : associationNumbers){
            for(Obstacle obstacle : obstacles)
                if(obstacle.associationNumber == Integer.valueOf(number))
                    obstacle.activate();
        }
    }
}

About this code :

  • First, I read the properties of the TiledMapObject to see if the switch is on or off by default.
  • Then I read the properties to obtain all the Association Numbers of the switch. For that I set up a String array.
  • Then I create the body of the switch, that is a sensor.
  • Finally, I create the active() function that will be called if there is a contact between Major Tom and the switch. The active() function will check for evey Association Number stored in the String Array if one of the Obstacle in the map posses the same Association Number. If yes, the function modifies the Obstacle's activate() function.

To use the ItemSwitch, with the Obstacles, I need to do some modifications in Obstacle.java:

  • Add an int associationNumber
  • Add a boolean active
  • Add a function activate()

The activate() function will be defined in each type of Obstacle. For now it the same function for both ObstaclePiston and ObstacleMoving :

public void activate(){
        active = !active;
    }
And of course, the active() function of every type of Obstacle must take into account the new boolean active (I guess it starts to be really confusing between active, active() and activate()) So basicaly, the new active() of every Obstacle looks like this :
public void active(){
        if(active){
           //Do the regular stuff
        }
        else
            body.setLinearVelocity(0, 0);         
    }

Finally, we need to detect collision between Major Tom and ItemSwitch

public void beginContact(Contact contact) {
                Fixture fixtureA = contact.getFixtureA();
                Fixture fixtureB = contact.getFixtureB();
                
                if(fixtureA.getUserData() != null && fixtureB.getUserData() != null) {       
                    //Switch
                    if(fixtureA.getUserData().equals("Tom") && fixtureB.getUserData().equals("Switch")){
                        for(ItemSwitch itemSwitch : mapReader.switchs){
                            if(itemSwitch.swtichBody == fixtureB.getBody())
                                itemSwitch.active(mapReader.obstacles);
                        }
                    }
                    else if(fixtureB.getUserData().equals("Tom") && fixtureA.getUserData().equals("Switch")){
                        for(ItemSwitch itemSwitch : mapReader.switchs){
                            if(itemSwitch.swtichBody == fixtureA.getBody())
                                itemSwitch.active(mapReader.obstacles);
                        }
                    }
                }
            }

And that's it ! Here is the result :