From af3109b9d90559cc4e8033a7c9e850b580736cc1 Mon Sep 17 00:00:00 2001 From: OMGeeky Date: Sat, 7 Sep 2024 14:32:00 +0200 Subject: [PATCH] Fix visual Bugs & slowdowns --- .../controller/VisualEffectController.java | 108 +++++++++--------- .../listeners/VisualEffectFrameListener.java | 2 +- .../listeners/VisualEffectFrameListeners.java | 9 +- .../gpl/rpg/AndorsTrail/view/MainView.java | 35 +++--- 4 files changed, 75 insertions(+), 79 deletions(-) diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/VisualEffectController.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/VisualEffectController.java index b88b7a3c0..3ecbd5fa2 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/VisualEffectController.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/VisualEffectController.java @@ -26,13 +26,18 @@ import java.util.ArrayList; import java.util.List; public final class VisualEffectController { + private static final long EFFECT_UPDATE_INTERVAL = 25; private int effectCount = 0; - private final List activeAnimations = new ArrayList<>(); private final ControllerContext controllers; private final WorldContext world; private final VisualEffectCollection effectTypes; + private final Handler animationHandler = new Handler(); + private final List activeAnimations = new ArrayList<>(); public final VisualEffectFrameListeners visualEffectFrameListeners = new VisualEffectFrameListeners(); + private long getEffectUpdateInterval() { + return EFFECT_UPDATE_INTERVAL * controllers.preferences.attackspeed_milliseconds / AndorsTrailPreferences.ATTACKSPEED_DEFAULT_MILLISECONDS; + } public VisualEffectController(ControllerContext controllers, WorldContext world) { this.controllers = controllers; @@ -43,25 +48,41 @@ public final class VisualEffectController { public void startEffect(Coord position, VisualEffectCollection.VisualEffectID effectID, String displayValue, VisualEffectCompletedCallback callback, int callbackValue) { ++effectCount; VisualEffectAnimation animation = new VisualEffectAnimation(effectTypes.getVisualEffect(effectID), position, displayValue, callback, callbackValue); - activeAnimations.add(animation); animation.start(); } - public void collectAndSendAnimations(VisualEffectAnimation animation) { - List tileIDs = new ArrayList<>(); - List yOffsets = new ArrayList<>(); - //There are more elegant ways to fix this, but to get multiple effects to work, this is the quickest fix: increase all other effects that are being played - //TODO: if someone got time to make this look nice, be my guest - for (VisualEffectAnimation vanimation : activeAnimations) { - if (vanimation != animation && vanimation.currentFrame < vanimation.effect.lastFrame) vanimation.currentFrame++; - tileIDs.add(vanimation.effect.frameIconIDs[vanimation.currentFrame]); - yOffsets.add(-2 * vanimation.currentFrame); - L.log("VisualEffectController: collectAndSendAnimations: " + vanimation.currentFrame + " currentFrame, effectCount = " + effectCount); + private void startAnimation(VisualEffectAnimation animation) { + activeAnimations.add(animation); + animation.update(); + if (activeAnimations.size() == 1) { + animationHandler.postDelayed(animationRunnable, 0); } - L.log("VisualEffectController: collectAndSendAnimations: " + activeAnimations.size() + " animations to send, effectCount = " + effectCount); - visualEffectFrameListeners.onNewAnimationFrames(activeAnimations, tileIDs, yOffsets); } + private final Runnable animationRunnable = new Runnable() { + @Override + public void run() { + if(!activeAnimations.isEmpty()) { + long updateInterval = getEffectUpdateInterval(); + animationHandler.postDelayed(this, updateInterval); + + for (int i = 0; i < activeAnimations.size(); i++) { + VisualEffectAnimation animation = activeAnimations.get(i); + animation.durationPassed += updateInterval; + animation.updateFrame(); + animation.update(); + if (animation.currentFrame >= animation.effect.lastFrame) { + animation.onCompleted(); + activeAnimations.remove(i); + effectCount--; + i--; + } + } + visualEffectFrameListeners.onNewAnimationFrames(activeAnimations); + } + } + }; + private VisualEffectCollection.VisualEffectID enqueuedEffectID = null; private int enqueuedEffectValue = 0; public void enqueueEffect(VisualEffectCollection.VisualEffectID effectID, int displayValue) { @@ -85,8 +106,8 @@ public final class VisualEffectController { .start(); } - public final class SpriteMoveAnimation extends Handler implements Runnable { - + public final class SpriteMoveAnimation implements Runnable { + private final Handler handler = new Handler(); // private static final int millisecondsPerFrame=25; private final VisualEffectCompletedCallback callback; @@ -140,7 +161,7 @@ public final class VisualEffectController { visualEffectFrameListeners.onSpriteMoveStarted(this); if (duration == 0 || !controllers.preferences.enableUiAnimations) onCompleted(); else { - postDelayed(this, duration); + handler.postDelayed(this, duration); } } @@ -155,58 +176,41 @@ public final class VisualEffectController { textPaint.setTextAlign(Align.CENTER); } - public static class VisualEffectData { - public final VisualEffectAnimation effect; - public final int tileID; - public final int textYOffset; + public final class VisualEffectAnimation { + public int tileID; + public int textYOffset; + public long durationPassed = 0; - public VisualEffectData(VisualEffectAnimation effect, int tileID, int textYOffset) { - this.effect = effect; - this.tileID = tileID; - this.textYOffset = textYOffset; - } - } - - public final class VisualEffectAnimation extends Handler implements Runnable { - - @Override - public void run() { - if (currentFrame >= effect.lastFrame) { - onCompleted(); - } else { - postDelayed(this, effect.millisecondPerFrame * controllers.preferences.attackspeed_milliseconds / AndorsTrailPreferences.ATTACKSPEED_DEFAULT_MILLISECONDS); - update(); + private void updateFrame() { + long frameDuration = (long) effect.millisecondPerFrame * controllers.preferences.attackspeed_milliseconds / AndorsTrailPreferences.ATTACKSPEED_DEFAULT_MILLISECONDS; + while (durationPassed > frameDuration) { + currentFrame++; + durationPassed -= frameDuration; } } - private void update() { - ++currentFrame; - int frame = currentFrame; + if (currentFrame >= effect.lastFrame) { + return; + } -// int tileID = effect.frameIconIDs[frame]; -// int textYOffset = -2 * (frame); + tileID = effect.frameIconIDs[currentFrame]; + textYOffset = -2 * (currentFrame); - if (frame >= beginFadeAtFrame && displayText != null) { - textPaint.setAlpha(255 * (effect.lastFrame - frame) / (effect.lastFrame - beginFadeAtFrame)); + if (currentFrame >= beginFadeAtFrame && displayText != null) { + textPaint.setAlpha(255 * (effect.lastFrame - currentFrame) / (effect.lastFrame - beginFadeAtFrame)); } area.topLeft.y = position.y - 1; - - //Fall back to onNewAnimationFrame if the new effect handle process is no longer desired -// visualEffectFrameListeners.onNewAnimationFrame(this, tileID, textYOffset); - collectAndSendAnimations(this); } private void onCompleted() { - --effectCount; - activeAnimations.remove(this); visualEffectFrameListeners.onAnimationCompleted(this); if (callback != null) callback.onVisualEffectCompleted(callbackValue); } public void start() { if (!controllers.preferences.enableUiAnimations) onCompleted(); - else postDelayed(this, 0); + else startAnimation(this); } private int currentFrame = 0; @@ -235,7 +239,7 @@ public final class VisualEffectController { this.area = new CoordRect(new Coord(position.x - (widthNeededInTiles / 2), position.y - 1), new Size(widthNeededInTiles, 2)); this.beginFadeAtFrame = effect.lastFrame / 2; } - + public Paint getTextPaint(){ return textPaint; } diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/listeners/VisualEffectFrameListener.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/listeners/VisualEffectFrameListener.java index 5d06aef20..55a6a16a3 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/listeners/VisualEffectFrameListener.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/listeners/VisualEffectFrameListener.java @@ -8,7 +8,7 @@ import java.util.List; public interface VisualEffectFrameListener { void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset); - void onNewAnimationFrames(List animations, List tileIDs, List textYOffsets); + void onNewAnimationFrames(List effects); void onAnimationCompleted(VisualEffectAnimation animation); void onSpriteMoveStarted(SpriteMoveAnimation animation); void onNewSpriteMoveFrame(SpriteMoveAnimation animation); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/listeners/VisualEffectFrameListeners.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/listeners/VisualEffectFrameListeners.java index 60b6614aa..5a3554c1f 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/listeners/VisualEffectFrameListeners.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/controller/listeners/VisualEffectFrameListeners.java @@ -1,5 +1,6 @@ package com.gpl.rpg.AndorsTrail.controller.listeners; +import com.gpl.rpg.AndorsTrail.controller.VisualEffectController; import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.SpriteMoveAnimation; import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.VisualEffectAnimation; import com.gpl.rpg.AndorsTrail.util.CoordRect; @@ -13,8 +14,8 @@ public final class VisualEffectFrameListeners extends ListOfListeners, List, List> onNewAnimationFrames = new Function3, List, List>() { - @Override public void call(VisualEffectFrameListener listener, List animations, List tileIDs, List textYOffsets) { listener.onNewAnimationFrames(animations, tileIDs, textYOffsets); } + private final Function1> onNewAnimationFrames = new Function1>() { + @Override public void call(VisualEffectFrameListener listener, List effects) { listener.onNewAnimationFrames(effects); } }; private final Function1 onAnimationCompleted = new Function1() { @@ -43,8 +44,8 @@ public final class VisualEffectFrameListeners extends ListOfListeners animations, List tileIDs, List textYOffsets) { - callAllListeners(this.onNewAnimationFrames, animations, tileIDs, textYOffsets); + public void onNewAnimationFrames(List effects) { + callAllListeners(this.onNewAnimationFrames, effects); } @Override diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/view/MainView.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/view/MainView.java index 1e3adf451..93f67b180 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/view/MainView.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/view/MainView.java @@ -81,7 +81,6 @@ public final class MainView extends SurfaceView private final CoordRect p1x1 = new CoordRect(new Coord(), new Size(1,1)); private boolean hasSurface = false; - private List activeEffects = new ArrayList<>(); //DEBUG // private Coord touchedTile = null; @@ -164,8 +163,8 @@ public final class MainView extends SurfaceView // this.surfaceSize = new Size(w, h); this.surfaceSize = new Size((int) (getWidth() / scale), (int) (getHeight() / scale)); this.screenSizeTileCount = new Size( - (int) Math.floor(getWidth() / scaledTileSize) - ,(int) Math.floor(getHeight() / scaledTileSize) + getWidth() / scaledTileSize + ,getHeight() / scaledTileSize ); if (sh.getSurfaceFrame().right != surfaceSize.width || sh.getSurfaceFrame().bottom != surfaceSize.height) { @@ -308,7 +307,7 @@ public final class MainView extends SurfaceView } } - private void redrawArea_(CoordRect area, final List effects, List tileIDs, List textYOffsets) { + private void redrawArea_(CoordRect area, final List effects) { if (!hasSurface) return; @@ -346,28 +345,22 @@ public final class MainView extends SurfaceView c.translate(screenOffset.x + xScroll, screenOffset.y + yScroll); doDrawRect(c, area); // Render each effect - renderEffects(c); + renderEffects(c, effects); } } } finally { if (c != null) holder.unlockCanvasAndPost(c); } } - private void renderEffects(Canvas canvas) { - for (VisualEffectController.VisualEffectData data : activeEffects) { - VisualEffectAnimation effect = data.effect; - int tileID = data.tileID; - int textYOffset = data.textYOffset; - - L.log("Rendering effect at position: " + effect.position + " with tileID: " + tileID + " and textYOffset: " + textYOffset); - + private void renderEffects(Canvas canvas ,List effects) { + for (VisualEffectAnimation effect : effects) { + int tileID = effect.tileID; + int textYOffset = effect.textYOffset; drawFromMapPosition(canvas, effect.area, effect.position, tileID); if (effect.displayText != null) { drawEffectText(canvas, effect.area, effect, textYOffset, effect.getTextPaint()); } } - L.log("Total effects rendered: " + activeEffects.size()); - activeEffects.clear(); } private boolean isRedrawRectWholeScreen(Rect redrawRect) { @@ -390,11 +383,10 @@ public final class MainView extends SurfaceView // if (shouldRedrawEverythingForVisualEffect()) area = mapViewArea; redrawArea_(area, effect, tileID, textYOffset); } - private void redrawAreaWithEffect(List effects, List tileIDs, List textYOffsets) { + private void redrawAreaWithEffect(List effects) { CoordRect area = null; for (int i = 0; i < effects.size(); i++) { VisualEffectAnimation effect = effects.get(i); - activeEffects.add(new VisualEffectController.VisualEffectData(effect, tileIDs.get(i), textYOffsets.get(i))); if (area == null) { area = effect.area; } else { @@ -402,7 +394,7 @@ public final class MainView extends SurfaceView } } if (area != null) { - redrawArea_(area, effects, tileIDs, textYOffsets); + redrawArea_(area, effects); } } @@ -878,14 +870,13 @@ public final class MainView extends SurfaceView } @Override - public void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset) { + public void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset){ redrawAreaWithEffect(animation, tileID, textYOffset); } @Override - public void onNewAnimationFrames(List animations, List tileIDs, List textYOffsets) { - L.log("Rendering " + animations.size() + " effects"); - redrawAreaWithEffect(animations, tileIDs, textYOffsets); + public void onNewAnimationFrames(List effects) { + redrawAreaWithEffect(effects); } @Override