Adding some fun : Light Obstacles
The next step in the development of this game is adding several types of obstacles to enhance the gameplay. I’ll start by adding light obstacles, that hero can push.
For that, let’s start by creating the ObstacleLight, that is obviously a subclass of Obstacle.
Here is the ObstacleLight.java :
public class ObstacleLight extends Obstacle{ public ObstacleLight(World world, Camera camera, MapObject rectangleObject) { super(world, camera, rectangleObject); body.setUserData("ObstacleLight"); body.getFixtureList().get(0).setUserData("ObstacleLight"); //Weight if(rectangleObject.getProperties().get("Weight") != null){ body.getFixtureList().get(0).setDensity( body.getFixtureList().get(0).getDensity() * Float.parseFloat(rectangleObject.getProperties().get("Weight").toString()) ); body.resetMassData(); } } @Override public BodyType getBodyType(){ return BodyType.DynamicBody; } }
Differences with the Obstacle class :
- The UserData of the body and fixture ane "ObstacleLight" instead of "Obstacle"
- The BodyType is a DynamicBody, which means that the body will move under the action of forces (collision, gravity...)
- The ObstacleLight can have various weights, depending on the value we give to the property "Weight" in the Tiled map editor. If we don’t put a property "Weight", the ObstacleLight will have a default weight, which is the same weight as the hero.
fixtureDef.densityand the weight is calculated like this : weight = density * area of the shape.
The shape is also included in the Fixture by
fixtureDef.shape = shape
For that you use a Shape you created earlier, that can be a PolygonShape or a CircleShape.
Thus, for example, for a rectangle, the weight will be : weight = density * width * height.
The bigger, the heavier. Which is logical.
But, for my game I want a way to control precisely the weight of every Obstacle in my game, without having to do some calculation. Therefore, in my game, EVERY bodies will have the exact same weight by default. For that, I create a constant in the GameConstants, for the density :
public static float DENSITY = 1.0f;
And the default density of the fixture of every object is defined like this (Example of a rectangle box):
fixtureDef.density = (float)(GameConstants.DENSITY/(width * height));
I divide GameConstants.Density by the area of the fixture : The bigger, the least dense, and the weight is stable.
Why the hell do I need to work like that ?
Because it’s very easy to manage. For example, when I put obstacles in my level editor, and I want my hero to interact with the object, I don’t need to calculate what density I need to give to each obstacle, according to the difficulty I want the hero having to push these objects. With my system, every object will have the same weight as the hero by default. Thus I know that the hero can push them with a moderate effort, meaning, a moderate fuel consumption. If I want the hero to have trouble pushing an object I only need to add a property "Weight", and attribute it a high value, say 10, and I’ll know that this object will weigh 10 times more than the hero. If I want a really light object, I’ll attribute a low value to "Weight", say 0.1f, and I’ll know that the hero can displace it with no effort. And I can do that independently of the size of the object, which gives a great liberty for designing levels.
Then we need to modify the TiledMapReader to recognize the ObstacleLight
Thus, the for loop of the TiledMapReader.java becomes :
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); } //Light obstacles else if(rectangleObject.getProperties().get("Type").equals("Light")){ ObstacleLight obstacle = new ObstacleLight(world, camera, rectangleObject); obstacles.add(obstacle); } } else{ Obstacle obstacle = new Obstacle(world, camera, rectangleObject); obstacles.add(obstacle); } }
All that remains is to add ObstacleLight to the level in Tiled
For that, you only need to create rectangles and give a property "Type" with the value "Light". The created ObstacleLight will have the same weight as the hero by default, but just add a property "Weight" with any value to modify their weight.
And here is the result !