package fi.hbp.angr.models.actors; import aurelienribon.bodyeditor.BodyEditorLoader; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.Texture; 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.FixtureDef; import fi.hbp.angr.AssetContainer; import fi.hbp.angr.G; import fi.hbp.angr.ItemDestruction; import fi.hbp.angr.logic.DamageModel; import fi.hbp.angr.models.CollisionFilterMasks; import fi.hbp.angr.models.Destructible; import fi.hbp.angr.models.Explosion; import fi.hbp.angr.models.SlingshotActor; import fi.hbp.angr.stage.GameStage; /** * A Throwable and explodable grenade model. */ public class Grenade extends SlingshotActor implements Destructible { /** * Name of this model. */ private final static String MODEL_NAME = "grenade"; /** * Texture file path. */ private final static String TEXTURE_PATH = "data/" + MODEL_NAME + ".png"; /** * Sound effect file path. */ private final static String SOUND_FX_PATH = "data/grenade.wav"; /** * Delay between release of grenade and explosion. */ private final static float EXPLOSION_DELAY = 3.0f; /** * Item destruction list. */ private final ItemDestruction itdes; /** * Origin of this actor. */ private final Vector2 modelOrigin; /** * Sprite of this actor. */ private final Sprite sprite; /* Explosion and destruction */ /** * true if explosion timer is counting. */ private boolean bExplosionTimer = false; /** * Explosion timer value. */ private float explosionTimer = 0; /** * true if this actor is destroyed. */ private boolean destroyed = false; /** * Explosion model. */ private final Explosion explosion; /** * Explosion sound. */ private static Sound explosionSound; /** * Particle effect for explosion. */ private ParticleEffect particleEffect; /** * Preload static data */ public static void preload() { G.getAssetManager().load(TEXTURE_PATH, Texture.class); G.getAssetManager().load(SOUND_FX_PATH, Sound.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 = 1.0f; as.fd.friction = 0.3f; as.fd.restitution = 0.3f; as.fd.filter.categoryBits = CollisionFilterMasks.GRENADE; explosionSound = G.getAssetManager().get(SOUND_FX_PATH); } /** * 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 Grenade(GameStage stage, BodyEditorLoader bel, AssetContainer as, float x, float y, float angle) { super(stage, stage.getWorld(), 70.0f, 2.3f); this.itdes = stage.getItemDestructionList(); as.bd.position.set(new Vector2(x * G.WORLD_TO_BOX, y * G.WORLD_TO_BOX)); body = stage.getWorld().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())); /* Explosion timer and effects */ explosion = new Explosion(body); particleEffect = new ParticleEffect(); particleEffect.load(Gdx.files.internal("data/explosion.p"), Gdx.files.internal("data")); particleEffect.setDuration(180); } @Override protected void slingshotRelease() { this.setSlingshotState(false); particleEffect.reset(); bExplosionTimer = true; } @Override public void draw(SpriteBatch batch, float parentAlpha) { /* Calculate new position */ Vector2 pos = body.getPosition(); float x = pos.x * G.BOX_TO_WORLD - modelOrigin.x; float y = pos.y * G.BOX_TO_WORLD - modelOrigin.y; /* Explosion handler */ float deltaTime = Gdx.graphics.getDeltaTime(); if (bExplosionTimer == true) { explosionTimer += deltaTime; if (explosionTimer >= EXPLOSION_DELAY) { explosionTimer = 0; bExplosionTimer = false; explosion.doExplosion(); explosionSound.play(); particleEffect.setPosition(x, y); particleEffect.start(); destroyed = true; } } /* Draw sprite and particle effect */ if (!destroyed) { sprite.setPosition(x, y); sprite.setOrigin(modelOrigin.x, modelOrigin.y); sprite.setRotation((float)(body.getAngle() * MathUtils.radiansToDegrees)); sprite.draw(batch, parentAlpha); } else { if (particleEffect.isComplete()) { /* NOTE: Adding this body to a list of destroyed bodies * doesn't remove it immediately from the world. */ itdes.add(this); } particleEffect.draw(batch, deltaTime); } } @Override public DamageModel getDatamageModel() { return null; } @Override public Body getBody() { return body; } @Override public void setDestroyed() { this.destroyed = true; } @Override public boolean isDestroyed() { return this.destroyed; } }