EntityFactory.java
package com.devcharles.piazzapanic.utility;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.HashMap;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.PooledEngine;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.devcharles.piazzapanic.components.*;
import com.devcharles.piazzapanic.components.FoodComponent.FoodType;
import com.devcharles.piazzapanic.utility.box2d.Box2dSteeringBody;
import com.devcharles.piazzapanic.utility.box2d.CollisionCategory;
/**
* Factory pattern class that creates entities used in the game.
*/
public class EntityFactory {
private final PooledEngine engine;
private final World world;
private FixtureDef movingFixtureDef;
private BodyDef movingBodyDef;
private CircleShape circleShape;
public EntityFactory(PooledEngine engine, World world) {
this.engine = engine;
this.world = world;
createDefinitions();
}
private static final Map<FoodType, TextureRegion> foodTextures = new HashMap<FoodType, TextureRegion>();
/**
* Create reusable definitions for bodies and fixtures. These can be then be
* used while creating the bodies for entities.
*/
private void createDefinitions() {
// Moving bodies
// BodyDef
movingBodyDef = new BodyDef();
movingBodyDef.type = BodyType.DynamicBody;
movingBodyDef.linearDamping = 20f;
movingBodyDef.fixedRotation = true;
// Shape - needs to be disposed
circleShape = new CircleShape();
circleShape.setRadius(0.5f);
// FixtureDef
movingFixtureDef = new FixtureDef();
movingFixtureDef.shape = circleShape;
movingFixtureDef.density = 20f;
movingFixtureDef.friction = 0.4f;
movingFixtureDef.filter.categoryBits = CollisionCategory.ENTITY.getValue();
movingFixtureDef.filter.maskBits = (short) (CollisionCategory.BOUNDARY.getValue()
| CollisionCategory.ENTITY.getValue());
}
/**
* Creates cook entity, and adds it to the engine.
*
* @return Reference to the entity.
*/
public Entity createCook(int x, int y) {
Entity entity = engine.createEntity();
B2dBodyComponent b2dBody = engine.createComponent(B2dBodyComponent.class);
TransformComponent transform = engine.createComponent(TransformComponent.class);
ControllableComponent controllable = engine.createComponent(ControllableComponent.class);
TextureComponent texture = engine.createComponent(TextureComponent.class);
AnimationComponent an = engine.createComponent(AnimationComponent.class);
WalkingAnimationComponent animation = engine.createComponent(WalkingAnimationComponent.class);
// PowerUpComponent powerUp = engine.createComponent(PowerUpComponent.class);
controllable.currentFood.init(engine);
animation.animator = new CookAnimator();
// Texture
TextureRegion[][] tempRegions = TextureRegion.split(new Texture("droplet.png"), 32, 32);
texture.region = tempRegions[0][0];
// TODO: Set size in viewport units instead of scale
texture.scale.set(0.1f, 0.1f);
// Box2D body
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.linearDamping = 20f;
bodyDef.fixedRotation = true;
bodyDef.awake = true;
bodyDef.position.set(x, y);
b2dBody.body = world.createBody(bodyDef);
// Create a circle shape and set its radius to 1
CircleShape circle = new CircleShape();
circle.setRadius(0.5f);
// Create a fixture definition to apply our shape to
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.density = 20f;
fixtureDef.friction = 0.4f;
fixtureDef.filter.categoryBits = CollisionCategory.ENTITY.getValue();
fixtureDef.filter.maskBits = (short) (CollisionCategory.BOUNDARY.getValue()
| CollisionCategory.NO_SHADOWBOUNDARY.getValue()
| CollisionCategory.ENTITY.getValue());
// Create our fixture and attach it to the body
b2dBody.body.createFixture(fixtureDef).setUserData(entity);
// BodyDef and FixtureDef don't need disposing, but shapes do.
circle.dispose();
entity.add(b2dBody);
entity.add(transform);
entity.add(controllable);
entity.add(texture);
entity.add(an);
entity.add(animation);
engine.addEntity(entity);
return entity;
}
/**
* Create the food entity at 0,0.
*
* @param foodType The type of food to create.
* @return reference to the {@link Entity}
*/
public Entity createFood(FoodType foodType) {
Entity entity = engine.createEntity();
TextureComponent texture = engine.createComponent(TextureComponent.class);
TransformComponent transform = engine.createComponent(TransformComponent.class);
FoodComponent food = engine.createComponent(FoodComponent.class);
// Texture
texture.region = getFoodTexture(foodType);
// TODO: Set size in viewport units instead of scale
texture.scale.set(0.05f, 0.05f);
// food creation
food.type = foodType;
// add components to the entity
entity.add(transform);
entity.add(texture);
entity.add(food);
engine.addEntity(entity);
return entity;
}
/**
* Create a station entity with interactable features enabled. This does not
* render the station as it is rendered in the tilemap.
*
* @param type Type of station to create. See
* {@link Station.StationType}.
* @param position position vector (z is set to 0).
* @param ingredientType (optional) if this is an Ingredient station, which
* ingredient should it spawn.
*/
public Entity createStation(Station.StationType type, Vector2 position, FoodType ingredientType, Vector2 tileOnMap, boolean locked) {
Entity entity = engine.createEntity();
float[] size = { 1f, 1f };
B2dBodyComponent b2dBody = engine.createComponent(B2dBodyComponent.class);
TextureComponent texture = engine.createComponent(TextureComponent.class);
TransformComponent transform = engine.createComponent(TransformComponent.class);
StationComponent station = engine.createComponent(StationComponent.class);
if(type != Station.StationType.ingredient){
station.tileMapPosition =tileOnMap;
}
station.type=type;
station.locked=locked;
if (type == Station.StationType.ingredient) {
station.ingredient = ingredientType;
}
// Box2D body
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.StaticBody;
bodyDef.position.set(position.x, position.y);
b2dBody.body = world.createBody(bodyDef);
// Create a PolygonShape and set it to be a box of 1x1
PolygonShape stationBox = new PolygonShape();
stationBox.setAsBox(size[0], size[1]);
// Create our fixture and attach it to the body
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = stationBox;
fixtureDef.isSensor = true;
fixtureDef.filter.categoryBits = CollisionCategory.NO_SHADOWBOUNDARY.getValue();
fixtureDef.filter.maskBits = CollisionCategory.ENTITY.getValue();
b2dBody.body.createFixture(fixtureDef).setUserData(station);
// BodyDef and FixtureDef don't need disposing, but shapes do.
stationBox.dispose();
// add components to the entity
entity.add(b2dBody);
entity.add(transform);
entity.add(texture);
entity.add(station);
engine.addEntity(entity);
return entity;
}
/**
* Cut the food textures, run at game initialisation.
*
* @param path (optional) custom path for food textures.
*/
public static void cutFood(String path) {
if (path == null) {
path = "v2/food.png";
}
Texture foodSheet = new Texture(path);
TextureRegion[][] tmp = TextureRegion.split(foodSheet, 32, 32);
int rows = tmp.length;
int cols = tmp[0].length;
// Flatten the array
TextureRegion[] frames = new TextureRegion[rows * cols];
int index = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
frames[index++] = tmp[i][j];
}
}
for (int i = 1; i < 26; i++) {
foodTextures.put(FoodType.from(i), frames[i]);
}
}
/**
* Get the texture associated with a certain food.
*
* @return {@link TextureRegion} of the food.
*/
public static TextureRegion getFoodTexture(FoodType type) {
return foodTextures.get(type);
}
/**
* Create an AI customer entity. The entity will not walk until it receives a
* {@link com.badlogic.gdx.ai.steer.SteeringBehavior}.
*
* @param position of the customer at spawn point.
* @return reference to the entity.
*/
public Entity createCustomer(Vector2 position) {
Entity entity = engine.createEntity();
B2dBodyComponent b2dBody = engine.createComponent(B2dBodyComponent.class);
TextureComponent texture = engine.createComponent(TextureComponent.class);
TransformComponent transform = engine.createComponent(TransformComponent.class);
AnimationComponent an = engine.createComponent(AnimationComponent.class);
CustomerComponent customer = engine.createComponent(CustomerComponent.class);
WalkingAnimationComponent walkingAnimation = engine.createComponent(WalkingAnimationComponent.class);
AIAgentComponent aiAgent = engine.createComponent(AIAgentComponent.class);
walkingAnimation.animator = new CustomerAnimator();
// Reuse existing body definition
movingBodyDef.position.set(position.x, position.y);
b2dBody.body = world.createBody(movingBodyDef);
b2dBody.body.createFixture(movingFixtureDef).setUserData(entity);
texture.region = new TextureRegion(new Texture("droplet.png"));
texture.scale.set(0.1f, 0.1f);
transform.isHidden = false;
// Create a steering body with no behaviour (to be set later)
aiAgent.steeringBody = new Box2dSteeringBody(b2dBody.body, true, 0.5f);
FoodType[] s = Station.serveRecipes;
int orderIndex = ThreadLocalRandom.current().nextInt(0, s.length);
customer.order = FoodType.from(s[orderIndex].getValue());
Gdx.app.log("Order received", customer.order.name());
entity.add(b2dBody);
entity.add(transform);
entity.add(texture);
entity.add(an);
entity.add(walkingAnimation);
entity.add(aiAgent);
entity.add(customer);
engine.addEntity(entity);
return entity;
}
// public static TextureRegion getPowerUpTexture(PowerUpType type){
// return powerupTextures.get(type);
// }
/**
* Cut the powerup textures, run at game initialisation.
*
* @param path (optional) custom path for powerup textures.
*/
// public static void cutPowerUp(String path) {
// if (path == null) {
// path = "v2/powerups.png";
// }
// Texture PowerUpSheet = new Texture(path);
// TextureRegion[][] tmp = TextureRegion.split(PowerUpSheet, 32, 32);
// int rows = tmp.length;
// int cols = tmp[0].length;
// // Flatten the array
// TextureRegion[] frames = new TextureRegion[rows * cols];
// int index = 0;
// for (int i = 0; i < rows; i++) {
// for (int j = 0; j < cols; j++) {
// frames[index++] = tmp[i][j];
// }
// }
// for (int i = 1; i < 6; i++) {
// powerupTextures.put(PowerUpType.from(i), frames[i]);
// }
// }
// public Entity createPowerup(PowerUpType powerUpType){
// Entity entity = engine.createEntity();
// PowerUpComponent powerUp = engine.createComponent(PowerUpComponent.class);
// entity.add(powerUp);
// engine.addEntity(entity);
// return entity;
// }
}