package fr.wisper.entities; import aurelienribon.tweenengine.*; import aurelienribon.tweenengine.equations.Quad; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.*; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.utils.Timer; import fr.wisper.animations.tween.ParticleEffectAccessor; import fr.wisper.assets.MenuAssets; import fr.wisper.dialog.SpeechBubble; import fr.wisper.utils.Config; import fr.wisper.utils.Debug; import java.util.ArrayList; import java.util.List; public class Wisper extends Actor { public static final int BLACK_WISPER = 0; public static final int BLUE_WISPER = 1; public static final int RED_WISPER = 2; protected ParticleEffect particleEffect; protected boolean isParticleOn = true; protected boolean isDashUp = true; protected Timer timer = new Timer(); protected Timer.Task timerTask; protected float offset; protected SpeechBubble bubbleSpeech; private List<String> speechList = new ArrayList<String>(); public Wisper(String particleFile) { particleEffect = new ParticleEffect(); init(particleFile); } public void setPosition(float x, float y) { particleEffect.setPosition(x - offset, y); } public void scale(float scaleValue) { float scaling; for (ParticleEmitter emitter : particleEffect.getEmitters()) { scaling = emitter.getScale().getHighMax(); emitter.getScale().setHigh(scaling * scaleValue); scaling = emitter.getScale().getLowMax(); emitter.getScale().setLow(scaling * scaleValue); scaling = emitter.getVelocity().getHighMax(); emitter.getVelocity().setHigh(scaling * scaleValue); scaling = emitter.getVelocity().getLowMax(); emitter.getVelocity().setLow(scaling * scaleValue); scaling = emitter.getXOffsetValue().getLowMax(); emitter.getXOffsetValue().setLow(scaling * scaleValue); scaling = emitter.getYOffsetValue().getLowMax(); emitter.getYOffsetValue().setLow(scaling * scaleValue); } } public void draw(Batch batch, float delta) { if (isParticleOn) { particleEffect.draw(batch, delta); if (bubbleSpeech != null && bubbleSpeech.isAlive()) { bubbleSpeech.act(delta); bubbleSpeech.draw(batch, delta); } else if (!speechList.isEmpty()) { speech(speechList.get(0)); speechList.remove(0); } } } public boolean isComplete() { return particleEffect.isComplete(); } public void startIntroSpeech() { speechList.add("Hello, I'm a Wisper"); speechList.add("Click the world to make me move"); speechList.add("Double click to dash!"); } public void speech(String string) { NinePatch ninePatch = MenuAssets.manager.get(MenuAssets.BubbleAtlas).createPatch("bubble"); BitmapFont bubbleFont = MenuAssets.manager.get(MenuAssets.BubbleFont); bubbleSpeech = new SpeechBubble(ninePatch, bubbleFont); bubbleSpeech.init(string, getX(), getY()); bubbleSpeech.setFollow(this); bubbleSpeech.setColor(new Color(0.3f, 0.3f, 0.3f, 0.7f)); } public float getOffset() { return offset; } public void stopDraw() { speechList.clear(); isParticleOn = false; } private void init(String particleFile) { particleEffect.load(Gdx.files.internal(particleFile), Gdx.files.internal("particles")); particleEffect.setPosition(Config.APP_WIDTH / 2, Config.APP_HEIGHT / 2); particleEffect.start(); offset = particleEffect.getEmitters().first().getXOffsetValue().getLowMax() / 2; } @Override public float getX() { return (int)particleEffect.getEmitters().first().getX(); } @Override public float getY() { return (int)particleEffect.getEmitters().first().getY(); } public void moveTo(float x, float y, TweenManager tweenManager, TweenCallback callback) { //Vector2 particlePos = Config.getProjectedCoordinates(getX(), getY(), viewport); //Vector2 requestedPos = Config.getProjectedCoordinates(x, y, viewport); Vector2 particlePos = new Vector2(getX(), getY()); Vector2 requestedPos = new Vector2(x, y); double distance = Math.sqrt( (float)Math.pow(particlePos.x - requestedPos.x, 2) + (float)Math.pow(particlePos.y - requestedPos.y, 2)); double duration = distance / Config.WISPER_SPEED; moveToWithDuration(x, y, tweenManager, duration, Quad.OUT, callback); } public void moveToWithDuration(float x, float y, TweenManager tweenManager, double duration, TweenEquation equation, TweenCallback callback) { tweenManager.killTarget(particleEffect); Tween.to(particleEffect, ParticleEffectAccessor.X, (float)duration) .target(x - (particleEffect.getEmitters().first().getXOffsetValue().getLowMax() / 2)) .ease(equation).start(tweenManager); Tween.to(particleEffect, ParticleEffectAccessor.Y, (float)duration).target(y) .ease(equation).start(tweenManager).setCallback(callback); } public void dash(final float x, final float y, final TweenManager tweenManager) { if (isDashUp) { Vector2 particlePos = new Vector2(getX(), getY()); Vector2 requestedPos = new Vector2(x, y); double distance = Math.max( Math.sqrt(Math.pow(particlePos.x - requestedPos.x, 2) + Math.pow(particlePos.y - requestedPos.y, 2)), 1); double dashDistance = Math.min(distance, Config.WISPER_DASH_DISTANCE); float alpha = (float)dashDistance / (float)distance; Vector2 AB = new Vector2(requestedPos.x - particlePos.x, requestedPos.y - particlePos.y); Vector2 ABPrim = new Vector2(alpha * AB.x, alpha * AB.y); Vector2 BPrim = new Vector2(ABPrim.x + particlePos.x, ABPrim.y + particlePos.y); tweenManager.killTarget(particleEffect); Tween.to(particleEffect, ParticleEffectAccessor.X, Config.WISPER_DASH_DURATION) .target(BPrim.x - (particleEffect.getEmitters().first().getXOffsetValue().getLowMax() / 2)) .ease(Quad.OUT).start(tweenManager); Tween.to(particleEffect, ParticleEffectAccessor.Y, Config.WISPER_DASH_DURATION).target(BPrim.y) .ease(Quad.OUT).setCallback(new TweenCallback() { @Override public void onEvent(int type, BaseTween<?> source) { moveTo(x, y, tweenManager, null); } }).start(tweenManager); timerTask = new Timer.Task() { @Override public void run() { isDashUp = true; } }; isDashUp = false; timer.scheduleTask(timerTask, (long) Config.WISPER_DASH_TIMEOUT); } else { moveTo(x, y, tweenManager, null); Debug.Log("Dash not ready yet, " + (timerTask.getExecuteTimeMillis() - System.nanoTime() / 1000000) + "ms remaining"); } } public void explode() { init("particles/spark.p"); } public void dispose() { stopDraw(); if (bubbleSpeech != null) { bubbleSpeech.dispose(); } particleEffect.dispose(); } }