package fi.hbp.angr.models.actors; import aurelienribon.bodyeditor.BodyEditorLoader; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.ParticleEffect; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.BodyDef; import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; import com.badlogic.gdx.physics.box2d.Filter; import com.badlogic.gdx.physics.box2d.FixtureDef; import com.badlogic.gdx.physics.box2d.World; import com.badlogic.gdx.scenes.scene2d.Actor; import fi.hbp.angr.AssetContainer; import fi.hbp.angr.G; import fi.hbp.angr.ItemDestruction; import fi.hbp.angr.logic.BoxDamageModel; import fi.hbp.angr.logic.DamageModel; import fi.hbp.angr.models.CollisionFilterMasks; import fi.hbp.angr.models.Destructible; import fi.hbp.angr.stage.GameStage; /** * A box for level decoration. */ public class Box extends Actor implements Destructible { /** Name of this model. */ private static final String MODEL_NAME = "box"; /** Texture file path. */ private static final String TEXTURE_PATH = "data/" + MODEL_NAME + ".png"; /** Item destruction list. */ private final ItemDestruction itdes; /** Body of this actor. */ private final Body body; /** Origin of this actor. */ private final Vector2 modelOrigin; /** Sprite of this actor. */ private final Sprite sprite; /** Damage model for this desctructible actor. */ private final DamageModel damageModel = new BoxDamageModel(); /** Font for drawing debug information. */ private BitmapFont font; /** Particle effect used as a destruction animation of this actor. */ private final ParticleEffect particleEffect; /** true if this actor is destroyed; otherwise false. */ private boolean destroyed; /** * Preload static data */ public static void preload() { G.getAssetManager().load(TEXTURE_PATH, Texture.class); } /** * Initialize assets of this object * @param as storage location for assets of this item. * @param bel Body editor loader. */ public static void initAssets(AssetContainer as, BodyEditorLoader bel) { as.texture = G.getAssetManager().get( bel.getImagePath(MODEL_NAME), Texture.class); as.bd = new BodyDef(); as.bd.type = BodyType.DynamicBody; as.bd.active = true; as.bd.position.set(0, 0); as.fd = new FixtureDef(); as.fd.density = 8.0f; as.fd.friction = 0.3f; as.fd.restitution = 0.3f; as.fd.filter.categoryBits = CollisionFilterMasks.OTHER; as.fd.filter.maskBits = CollisionFilterMasks.ALL; } /** * Class constructor. * @param stage the game stage. * @param bel a body editor loader object. * @param as preloaded assets for this class. * @param x spawn coordinate. * @param y spawn coordinate. * @param angle spawn angle. */ public Box(GameStage stage, BodyEditorLoader bel, AssetContainer as, float x, float y, float angle) { this.itdes = stage.getItemDestructionList(); World world = stage.getWorld(); as.bd.position.set(new Vector2(x * G.WORLD_TO_BOX, y * G.WORLD_TO_BOX)); body = world.createBody(as.bd); body.setUserData(this); sprite = new Sprite(as.texture); bel.attachFixture(body, MODEL_NAME, as.fd, sprite.getWidth() * G.WORLD_TO_BOX); modelOrigin = bel.getOrigin(MODEL_NAME, sprite.getWidth()).cpy(); sprite.setOrigin(modelOrigin.x, modelOrigin.y); sprite.setPosition(x, y); sprite.setRotation((float) Math.toDegrees(body.getAngle())); /* Debug */ if (G.DEBUG) { font = new BitmapFont(); font.setScale(4); } particleEffect = new ParticleEffect(); particleEffect.load(Gdx.files.internal("data/boxdestruction.p"), Gdx.files.internal("data")); } @Override public void draw(SpriteBatch batch, float parentAlpha) { if (!destroyed) { Vector2 pos = body.getPosition(); sprite.setPosition(pos.x * G.BOX_TO_WORLD - modelOrigin.x, pos.y * G.BOX_TO_WORLD - modelOrigin.y); sprite.setOrigin(modelOrigin.x, modelOrigin.y); sprite.setRotation((float)(body.getAngle() * MathUtils.radiansToDegrees)); sprite.draw(batch, parentAlpha); if (G.DEBUG) { /* Debug print health status */ font.draw(batch, this.getDatamageModel().toString(), pos.x * G.BOX_TO_WORLD, pos.y * G.BOX_TO_WORLD + 100f); } } else { if (particleEffect.isComplete()) { /* NOTE: Adding this body to a list of destroyed bodies * doesn't remove it immediately from the world. */ body.setType(BodyType.StaticBody); itdes.add(this); } particleEffect.draw(batch, Gdx.graphics.getDeltaTime()); } } @Override public DamageModel getDatamageModel() { return damageModel; } @Override public Body getBody() { return body; } @Override public void setDestroyed() { this.destroyed = true; /* Box should not collide with other game objects anymore */ Filter filter = body.getFixtureList().get(0).getFilterData(); filter.maskBits = CollisionFilterMasks.GROUND; /* But with ground */ body.getFixtureList().get(0).setFilterData(filter); /* TODO Current particle effect is bit lame. */ particleEffect.reset(); particleEffect.setPosition(sprite.getX() + sprite.getWidth() / 2f, sprite.getY() + sprite.getHeight() / 2f); particleEffect.start(); } @Override public boolean isDestroyed() { return this.destroyed; } }