Merge branch 'master' into 'master'

[Mobile] Add Player Avatar Animation

See merge request core-developers/forge!5388
This commit is contained in:
Michael Kamensky
2021-09-19 12:22:33 +00:00
15 changed files with 322 additions and 53 deletions

View File

@@ -781,6 +781,8 @@ public class Game {
} }
public void onPlayerLost(Player p) { public void onPlayerLost(Player p) {
//set for Avatar
p.setHasLost(true);
// Rule 800.4 Losing a Multiplayer game // Rule 800.4 Losing a Multiplayer game
CardCollectionView cards = this.getCardsInGame(); CardCollectionView cards = this.getCardsInGame();
boolean planarControllerLost = false; boolean planarControllerLost = false;

View File

@@ -1306,6 +1306,7 @@ public class GameAction {
orderedNoRegCreats = true; orderedNoRegCreats = true;
} }
for (Card c : noRegCreats) { for (Card c : noRegCreats) {
c.updateWasDestroyed(true);
sacrificeDestroy(c, null, table, null); sacrificeDestroy(c, null, table, null);
} }
} }
@@ -1444,6 +1445,7 @@ public class GameAction {
// cleanup aura // cleanup aura
if (c.isAura() && c.isInPlay() && !c.isEnchanting()) { if (c.isAura() && c.isInPlay() && !c.isEnchanting()) {
c.updateWasDestroyed(true);
sacrificeDestroy(c, null, table, null); sacrificeDestroy(c, null, table, null);
checkAgain = true; checkAgain = true;
} }
@@ -1596,6 +1598,8 @@ public class GameAction {
for (Card c : list) { for (Card c : list) {
if (c.getCounters(CounterEnumType.LOYALTY) <= 0) { if (c.getCounters(CounterEnumType.LOYALTY) <= 0) {
//for animation
c.updateWasDestroyed(true);
sacrificeDestroy(c, null, table, null); sacrificeDestroy(c, null, table, null);
// Play the Destroy sound // Play the Destroy sound
game.fireEvent(new GameEventCardDestroyed()); game.fireEvent(new GameEventCardDestroyed());
@@ -1659,6 +1663,8 @@ public class GameAction {
"You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)", null); "You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)", null);
for (Card c: cc) { for (Card c: cc) {
if (c != toKeep) { if (c != toKeep) {
//for animation
c.updateWasDestroyed(true);
sacrificeDestroy(c, null, table, null); sacrificeDestroy(c, null, table, null);
} }
} }
@@ -1693,6 +1699,8 @@ public class GameAction {
} }
for (Card c : worlds) { for (Card c : worlds) {
//for animation
c.updateWasDestroyed(true);
sacrificeDestroy(c, null, table, null); sacrificeDestroy(c, null, table, null);
game.fireEvent(new GameEventCardDestroyed()); game.fireEvent(new GameEventCardDestroyed());
} }
@@ -1707,6 +1715,7 @@ public class GameAction {
c.getController().addSacrificedThisTurn(c, source); c.getController().addSacrificedThisTurn(c, source);
c.updateWasDestroyed(true);
return sacrificeDestroy(c, source, table, params); return sacrificeDestroy(c, source, table, params);
} }
@@ -1733,6 +1742,8 @@ public class GameAction {
activator = sa.getActivatingPlayer(); activator = sa.getActivatingPlayer();
} }
//for animation
c.updateWasDestroyed(true);
// Play the Destroy sound // Play the Destroy sound
game.fireEvent(new GameEventCardDestroyed()); game.fireEvent(new GameEventCardDestroyed());

View File

@@ -3029,6 +3029,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
view.updateTokenCard(this); view.updateTokenCard(this);
} }
public void updateWasDestroyed(boolean value) {
view.updateWasDestroyed(value);
}
public final Card getCopiedPermanent() { public final Card getCopiedPermanent() {
return copiedPermanent; return copiedPermanent;
} }

View File

@@ -411,6 +411,15 @@ public class CardView extends GameEntityView {
set(TrackableProperty.CurrentRoom, c.getCurrentRoom()); set(TrackableProperty.CurrentRoom, c.getCurrentRoom());
} }
public boolean wasDestroyed() {
if (get(TrackableProperty.WasDestroyed) == null)
return false;
return get(TrackableProperty.WasDestroyed);
}
void updateWasDestroyed(boolean value) {
set(TrackableProperty.WasDestroyed, value);
}
public int getClassLevel() { public int getClassLevel() {
return get(TrackableProperty.ClassLevel); return get(TrackableProperty.ClassLevel);
} }

View File

@@ -559,6 +559,8 @@ public class Player extends GameEntity implements Comparable<Player> {
return 0; return 0;
} }
life -= toLose; life -= toLose;
//for Avatar animation
view.setAvatarWasDamaged(true);
view.updateLife(this); view.updateLife(this);
lifeLost = toLose; lifeLost = toLose;
if (manaBurn) { if (manaBurn) {
@@ -2636,6 +2638,8 @@ public class Player extends GameEntity implements Comparable<Player> {
public void updateAvatar() { public void updateAvatar() {
view.updateAvatarIndex(this); view.updateAvatarIndex(this);
view.updateAvatarCardImageKey(this); view.updateAvatarCardImageKey(this);
view.setAvatarWasDamaged(false);
view.setHasLost(false);
} }
public void updateSleeve() { public void updateSleeve() {
@@ -2848,6 +2852,14 @@ public class Player extends GameEntity implements Comparable<Player> {
view.setIsExtraTurn(b); view.setIsExtraTurn(b);
} }
public void setHasLost(boolean b) {
view.setHasLost(b);
}
public void setAvatarWasDamaged(boolean val) {
view.setAvatarWasDamaged(val);
}
public int getExtraTurnCount() { public int getExtraTurnCount() {
return view.getExtraTurnCount(); return view.getExtraTurnCount();
} }

View File

@@ -214,6 +214,26 @@ public class PlayerView extends GameEntityView {
set(TrackableProperty.IsExtraTurn, val); set(TrackableProperty.IsExtraTurn, val);
} }
public boolean getHasLost() {
if (get(TrackableProperty.HasLost) == null)
return false;
return get(TrackableProperty.HasLost);
}
public void setHasLost(final boolean val) {
set(TrackableProperty.HasLost, val);
}
public boolean getAvatarWasDamaged() {
if (get(TrackableProperty.WasAvatarDamaged) == null)
return false;
return get(TrackableProperty.WasAvatarDamaged);
}
public void setAvatarWasDamaged(final boolean val) {
set(TrackableProperty.WasAvatarDamaged, val);
}
public int getExtraTurnCount() { public int getExtraTurnCount() {
return get(TrackableProperty.ExtraTurnCount); return get(TrackableProperty.ExtraTurnCount);
} }

View File

@@ -78,6 +78,7 @@ public enum TrackableProperty {
GainControlTargets(TrackableTypes.CardViewCollectionType), GainControlTargets(TrackableTypes.CardViewCollectionType),
CloneOrigin(TrackableTypes.CardViewType), CloneOrigin(TrackableTypes.CardViewType),
ExiledWith(TrackableTypes.CardViewType), ExiledWith(TrackableTypes.CardViewType),
WasDestroyed(TrackableTypes.BooleanType),
ImprintedCards(TrackableTypes.CardViewCollectionType), ImprintedCards(TrackableTypes.CardViewCollectionType),
HauntedBy(TrackableTypes.CardViewCollectionType), HauntedBy(TrackableTypes.CardViewCollectionType),
@@ -199,6 +200,8 @@ public enum TrackableProperty {
ExtraTurnCount(TrackableTypes.IntegerType), ExtraTurnCount(TrackableTypes.IntegerType),
HasPriority(TrackableTypes.BooleanType), HasPriority(TrackableTypes.BooleanType),
HasDelirium(TrackableTypes.BooleanType), HasDelirium(TrackableTypes.BooleanType),
WasAvatarDamaged(TrackableTypes.BooleanType),
HasLost(TrackableTypes.BooleanType),
//SpellAbility //SpellAbility
HostCard(TrackableTypes.CardViewType), HostCard(TrackableTypes.CardViewType),

View File

@@ -39,7 +39,7 @@ public class Graphics {
private int failedClipCount; private int failedClipCount;
private float alphaComposite = 1; private float alphaComposite = 1;
private int transformCount = 0; private int transformCount = 0;
private String sVertex = "uniform mat4 u_projTrans;\n" + private final String sVertex = "uniform mat4 u_projTrans;\n" +
"\n" + "\n" +
"attribute vec4 a_position;\n" + "attribute vec4 a_position;\n" +
"attribute vec2 a_texCoord0;\n" + "attribute vec2 a_texCoord0;\n" +
@@ -55,7 +55,7 @@ public class Graphics {
" v_texCoord = a_texCoord0;\n" + " v_texCoord = a_texCoord0;\n" +
" v_color = a_color;\n" + " v_color = a_color;\n" +
"}"; "}";
private String sFragment = "#ifdef GL_ES\n" + private final String sFragment = "#ifdef GL_ES\n" +
"precision mediump float;\n" + "precision mediump float;\n" +
"precision mediump int;\n" + "precision mediump int;\n" +
"#endif\n" + "#endif\n" +
@@ -103,8 +103,38 @@ public class Graphics {
"\n" + "\n" +
" gl_FragColor = vec4(u_color,alpha);\n" + " gl_FragColor = vec4(u_color,alpha);\n" +
"}"; "}";
private final String vertexShaderGray = "attribute vec4 a_position;\n" +
"attribute vec4 a_color;\n" +
"attribute vec2 a_texCoord0;\n" +
"\n" +
"uniform mat4 u_projTrans;\n" +
"\n" +
"varying vec4 v_color;\n" +
"varying vec2 v_texCoords;\n" +
"\n" +
"void main() {\n" +
" v_color = a_color;\n" +
" v_texCoords = a_texCoord0;\n" +
" gl_Position = u_projTrans * a_position;\n" +
"}";
private final String fragmentShaderGray = "#ifdef GL_ES\n" +
" precision mediump float;\n" +
"#endif\n" +
"\n" +
"varying vec4 v_color;\n" +
"varying vec2 v_texCoords;\n" +
"uniform sampler2D u_texture;\n" +
"uniform float u_grayness;\n" +
"\n" +
"void main() {\n" +
" vec4 c = v_color * texture2D(u_texture, v_texCoords);\n" +
" float grey = dot( c.rgb, vec3(0.22, 0.707, 0.071) );\n" +
" vec3 blendedColor = mix(c.rgb, vec3(grey), u_grayness);\n" +
" gl_FragColor = vec4(blendedColor.rgb, c.a);\n" +
"}";
private final ShaderProgram shaderOutline = new ShaderProgram(sVertex, sFragment); private final ShaderProgram shaderOutline = new ShaderProgram(sVertex, sFragment);
private final ShaderProgram shaderGrayscale = new ShaderProgram(vertexShaderGray, fragmentShaderGray);
public Graphics() { public Graphics() {
ShaderProgram.pedantic = false; ShaderProgram.pedantic = false;
@@ -632,6 +662,16 @@ public class Graphics {
shapeRenderer.end(); shapeRenderer.end();
} }
public void setColorRGBA(float r, float g, float b, float alphaComposite0) {
alphaComposite = alphaComposite0;
batch.setColor(new Color(r, g, b, alphaComposite));
}
public void resetColorRGBA(float alphaComposite0) {
alphaComposite = alphaComposite0;
batch.setColor(Color.WHITE);
}
public void setAlphaComposite(float alphaComposite0) { public void setAlphaComposite(float alphaComposite0) {
alphaComposite = alphaComposite0; alphaComposite = alphaComposite0;
batch.setColor(new Color(1, 1, 1, alphaComposite)); batch.setColor(new Color(1, 1, 1, alphaComposite));
@@ -662,6 +702,76 @@ public class Graphics {
image.draw(this, x, y, w, h); image.draw(this, x, y, w, h);
fillRoundRect(borderColor, x+1, y+1, w-1.5f, h-1.5f, (h-w)/10);//used by zoom let some edges show... fillRoundRect(borderColor, x+1, y+1, w-1.5f, h-1.5f, (h-w)/10);//used by zoom let some edges show...
} }
public void drawAvatarImage(FImage image, float x, float y, float w, float h, boolean drawGrayscale) {
if (!drawGrayscale) {
image.draw(this, x, y, w, h);
} else {
batch.end();
shaderGrayscale.bind();
shaderGrayscale.setUniformf("u_grayness", 1f);
batch.setShader(shaderGrayscale);
batch.begin();
//draw gray
image.draw(this, x, y, w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
}
}
public void drawCardImage(FImage image, float x, float y, float w, float h, boolean drawGrayscale) {
if (!drawGrayscale) {
image.draw(this, x, y, w, h);
} else {
batch.end();
shaderGrayscale.bind();
shaderGrayscale.setUniformf("u_grayness", 1f);
batch.setShader(shaderGrayscale);
batch.begin();
//draw gray
image.draw(this, x, y, w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
}
}
public void drawCardImage(Texture image, float x, float y, float w, float h, boolean drawGrayscale) {
if (!drawGrayscale) {
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
} else {
batch.end();
shaderGrayscale.bind();
shaderGrayscale.setUniformf("u_grayness", 1f);
batch.setShader(shaderGrayscale);
batch.begin();
//draw gray
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
}
}
public void drawCardImage(TextureRegion image, float x, float y, float w, float h, boolean drawGrayscale) {
if (image != null) {
if (!drawGrayscale) {
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
} else {
batch.end();
shaderGrayscale.bind();
shaderGrayscale.setUniformf("u_grayness", 1f);
batch.setShader(shaderGrayscale);
batch.begin();
//draw gray
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
}
}
}
public void drawImage(FImage image, float x, float y, float w, float h) { public void drawImage(FImage image, float x, float y, float w, float h) {
drawImage(image, x, y, w, h, false); drawImage(image, x, y, w, h, false);
} }

View File

@@ -39,6 +39,7 @@ public class FSkin {
private static boolean loaded = false; private static boolean loaded = false;
public static Texture hdLogo = null; public static Texture hdLogo = null;
public static Texture overlay_alpha = null; public static Texture overlay_alpha = null;
public static Texture scratch = null;
public static void changeSkin(final String skinName) { public static void changeSkin(final String skinName) {
final ForgePreferences prefs = FModel.getPreferences(); final ForgePreferences prefs = FModel.getPreferences();
@@ -142,6 +143,14 @@ public class FSkin {
} else { } else {
overlay_alpha = null; overlay_alpha = null;
} }
final FileHandle scratch_overlay = getDefaultSkinFile("scratch.png");
if (scratch_overlay.exists()) {
Texture txScratch = new Texture(scratch_overlay, true);
txScratch.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
scratch = txScratch;
} else {
scratch = null;
}
if (splashScreen != null) { if (splashScreen != null) {
final FileHandle f = getSkinFile("bg_splash.png"); final FileHandle f = getSkinFile("bg_splash.png");

View File

@@ -590,9 +590,9 @@ public class CardRenderer {
g.setAlphaComposite(oldAlpha); g.setAlphaComposite(oldAlpha);
} else if (showsleeves) { } else if (showsleeves) {
if (!card.isForeTold()) if (!card.isForeTold())
g.drawImage(sleeves, x, y, w, h); g.drawCardImage(sleeves, x, y, w, h, card.wasDestroyed());
else else
g.drawImage(image, x, y, w, h); g.drawCardImage(image, x, y, w, h, card.wasDestroyed());
} else { } else {
if(FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON) if(FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON)
&& (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane()) && rotate){ && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane()) && rotate){
@@ -610,19 +610,19 @@ public class CardRenderer {
} else { } else {
if (Forge.enableUIMask.equals("Full") && canshow) { if (Forge.enableUIMask.equals("Full") && canshow) {
if (ImageCache.isBorderlessCardArt(image)) if (ImageCache.isBorderlessCardArt(image))
g.drawImage(image, x, y, w, h); g.drawCardImage(image, x, y, w, h, card.wasDestroyed());
else { else {
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors(); boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
g.drawBorderImage(ImageCache.getBorderImage(image.toString(), canshow), ImageCache.borderColor(image), ImageCache.getTint(card, image), x, y, w, h, t); //tint check for changed colors g.drawBorderImage(ImageCache.getBorderImage(image.toString(), canshow), ImageCache.borderColor(image), ImageCache.getTint(card, image), x, y, w, h, t); //tint check for changed colors
g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea); g.drawCardImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea, card.wasDestroyed());
} }
} else if (Forge.enableUIMask.equals("Crop") && canshow) { } else if (Forge.enableUIMask.equals("Crop") && canshow) {
g.drawImage(ImageCache.croppedBorderImage(image), x, y, w, h); g.drawCardImage(ImageCache.croppedBorderImage(image), x, y, w, h, card.wasDestroyed());
} else { } else {
if (canshow) if (canshow)
g.drawImage(image, x, y, w, h); g.drawCardImage(image, x, y, w, h, card.wasDestroyed());
else // draw card back sleeves else // draw card back sleeves
g.drawImage(sleeves, x, y, w, h); g.drawCardImage(sleeves, x, y, w, h, card.wasDestroyed());
} }
} }
} }

View File

@@ -1,12 +1,15 @@
package forge.screens.match.views; package forge.screens.match.views;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Align;
import forge.Forge; import forge.Forge;
import forge.Graphics; import forge.Graphics;
import forge.animation.ForgeAnimation;
import forge.assets.FImage; import forge.assets.FImage;
import forge.assets.FSkin;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.game.card.CounterEnumType; import forge.game.card.CounterEnumType;
import forge.game.player.PlayerView; import forge.game.player.PlayerView;
@@ -21,19 +24,61 @@ public class VAvatar extends FDisplayObject {
private final PlayerView player; private final PlayerView player;
private final FImage image; private final FImage image;
private AvatarAnimation avatarAnimation;
public VAvatar(PlayerView player0) { public VAvatar(PlayerView player0) {
player = player0; player = player0;
image = MatchController.getPlayerAvatar(player); image = MatchController.getPlayerAvatar(player);
setSize(WIDTH, HEIGHT); setSize(WIDTH, HEIGHT);
avatarAnimation = new AvatarAnimation();
} }
public VAvatar(PlayerView player0, float size) { public VAvatar(PlayerView player0, float size) {
player = player0; player = player0;
image = MatchController.getPlayerAvatar(player); image = MatchController.getPlayerAvatar(player);
setSize(size, size); setSize(size, size);
avatarAnimation = new AvatarAnimation();
} }
private class AvatarAnimation extends ForgeAnimation {
private static final float DURATION = 0.6f;
private float progress = 0;
private boolean finished;
Texture scratch = FSkin.scratch;
private void drawAvatar(Graphics g, FImage image, float x, float y, float w, float h) {
float percentage = progress / DURATION;
if (percentage < 0) {
percentage = 0;
} else if (percentage > 1) {
percentage = 1;
//animation finished clear avatar red overlay
player.setAvatarWasDamaged(false);
}
float mod = w/2f;
if (scratch == null) {
g.setColorRGBA(1, percentage, percentage, g.getfloatAlphaComposite());
g.drawAvatarImage(image, x, y, w, h, player.getHasLost());
g.resetColorRGBA(g.getfloatAlphaComposite());
} else {
g.drawAvatarImage(image, x, y, w, h, player.getHasLost());
g.setAlphaComposite(1-(percentage*1));
g.drawImage(scratch, x-mod/2, y-mod/2, w+mod, h+mod);
g.resetAlphaComposite();
}
}
@Override
protected boolean advance(float dt) {
progress += dt;
return progress < DURATION;
}
@Override
protected void onEnd(boolean endingAll) {
finished = true;
}
}
@Override @Override
public boolean tap(float x, float y, int count) { public boolean tap(float x, float y, int count) {
ThreadUtil.invokeInGameThread(new Runnable() { //must invoke in game thread in case a dialog needs to be shown ThreadUtil.invokeInGameThread(new Runnable() { //must invoke in game thread in case a dialog needs to be shown
@@ -68,7 +113,19 @@ public class VAvatar extends FDisplayObject {
public void draw(Graphics g) { public void draw(Graphics g) {
float w = getWidth(); float w = getWidth();
float h = getHeight(); float h = getHeight();
g.drawImage(image, 0, 0, w, h);
if (avatarAnimation != null && !MatchController.instance.getGameView().isMatchOver()) {
if (player.getAvatarWasDamaged() && avatarAnimation.progress < 1) {
avatarAnimation.start();
avatarAnimation.drawAvatar(g, image, 0, 0, w, h);
} else {
avatarAnimation.progress = 0;
g.drawAvatarImage(image, 0, 0, w, h, player.getHasLost());
}
} else {
g.drawAvatarImage(image, 0, 0, w, h, player.getHasLost());
}
if (Forge.altPlayerLayout && !Forge.altZoneTabs && Forge.isLandscapeMode()) if (Forge.altPlayerLayout && !Forge.altZoneTabs && Forge.isLandscapeMode())
return; return;

View File

@@ -1,8 +1,10 @@
package forge.toolbox; package forge.toolbox;
import com.badlogic.gdx.graphics.Texture;
import forge.Forge; import forge.Forge;
import forge.Graphics; import forge.Graphics;
import forge.animation.ForgeAnimation; import forge.animation.ForgeAnimation;
import forge.assets.FSkin;
import forge.card.CardRenderer; import forge.card.CardRenderer;
import forge.card.CardRenderer.CardStackPosition; import forge.card.CardRenderer.CardStackPosition;
import forge.game.card.CardView; import forge.game.card.CardView;
@@ -22,6 +24,7 @@ public class FCardPanel extends FDisplayObject {
private boolean wasTapped; private boolean wasTapped;
CardTapAnimation tapAnimation; CardTapAnimation tapAnimation;
CardUnTapAnimation untapAnimation; CardUnTapAnimation untapAnimation;
CardDestroyedAnimation cardDestroyedAnimation;
public FCardPanel() { public FCardPanel() {
this(null); this(null);
@@ -30,6 +33,7 @@ public class FCardPanel extends FDisplayObject {
card = card0; card = card0;
tapAnimation = new CardTapAnimation(); tapAnimation = new CardTapAnimation();
untapAnimation = new CardUnTapAnimation(); untapAnimation = new CardUnTapAnimation();
cardDestroyedAnimation = new CardDestroyedAnimation();
} }
public CardView getCard() { public CardView getCard() {
@@ -84,7 +88,46 @@ public class FCardPanel extends FDisplayObject {
protected CardStackPosition getStackPosition() { protected CardStackPosition getStackPosition() {
return CardStackPosition.Top; return CardStackPosition.Top;
} }
private class CardDestroyedAnimation extends ForgeAnimation {
private static final float DURATION = 0.6f;
private float progress = 0;
private boolean finished;
private Texture scratch = FSkin.scratch;
private void drawCard(Graphics g, CardView card, float x, float y, float w, float h, float edgeOffset) {
float percentage = progress / DURATION;
if (percentage < 0) {
percentage = 0;
} else if (percentage > 1) {
percentage = 1;
}
float mod = (w/3f)*percentage;
float oldAlpha = g.getfloatAlphaComposite();
if (tapped) {
g.startRotateTransform(x + edgeOffset, y + h - edgeOffset, getTappedAngle());
}
CardRenderer.drawCardWithOverlays(g, card, x-mod/2, y-mod/2, w+mod, h+mod, getStackPosition());
if (scratch != null) {
g.setAlphaComposite(0.6f);
g.drawCardImage(scratch, x-mod/2, y-mod/2, w+mod, h+mod, true);
g.setAlphaComposite(oldAlpha);
}
if (tapped) {
g.endTransform();
}
}
@Override
protected boolean advance(float dt) {
progress += dt;
return progress < DURATION;
}
@Override
protected void onEnd(boolean endingAll) {
finished = true;
}
}
private class CardUnTapAnimation extends ForgeAnimation { private class CardUnTapAnimation extends ForgeAnimation {
private static final float DURATION = 0.14f; private static final float DURATION = 0.14f;
private float progress = 0; private float progress = 0;
@@ -163,8 +206,21 @@ public class FCardPanel extends FDisplayObject {
w = h / ASPECT_RATIO; w = h / ASPECT_RATIO;
} }
float edgeOffset = w / 2f; float edgeOffset = w / 2f;
if (isGameFast) {
//don't animate if fast if (card.wasDestroyed()) {
if (cardDestroyedAnimation != null) {
if (cardDestroyedAnimation.progress < 1) {
cardDestroyedAnimation.start();
cardDestroyedAnimation.drawCard(g, card, x, y, w, h, edgeOffset);
} else {
cardDestroyedAnimation.progress = 0;
}
}
return;
}
if (isGameFast || MatchController.instance.getGameView().isMatchOver()) {
//don't animate if game is fast or match is over
if (tapped) { if (tapped) {
g.startRotateTransform(x + edgeOffset, y + h - edgeOffset, getTappedAngle()); g.startRotateTransform(x + edgeOffset, y + h - edgeOffset, getTappedAngle());
} }
@@ -198,12 +254,14 @@ public class FCardPanel extends FDisplayObject {
tapAnimation.progress = 0; tapAnimation.progress = 0;
} }
//draw untapped //draw untapped
if (untapAnimation.progress < 1 && animate) { if (untapAnimation != null) {
untapAnimation.start(); if (untapAnimation.progress < 1 && animate) {
untapAnimation.drawCard(g, card, x, y, w, h, edgeOffset); untapAnimation.start();
} else { untapAnimation.drawCard(g, card, x, y, w, h, edgeOffset);
wasTapped = false; } else {
CardRenderer.drawCardWithOverlays(g, card, x, y, w, h, getStackPosition()); wasTapped = false;
CardRenderer.drawCardWithOverlays(g, card, x, y, w, h, getStackPosition());
}
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

View File

@@ -306,6 +306,7 @@ public class HostedMatch {
game = null; game = null;
for (final PlayerControllerHuman humanController : humanControllers) { for (final PlayerControllerHuman humanController : humanControllers) {
humanController.getGui().setGameSpeed(false);
if (FModel.getPreferences().getPref(FPref.UI_AUTO_YIELD_MODE).equals(ForgeConstants.AUTO_YIELD_PER_CARD) || isMatchOver()) { if (FModel.getPreferences().getPref(FPref.UI_AUTO_YIELD_MODE).equals(ForgeConstants.AUTO_YIELD_PER_CARD) || isMatchOver()) {
// when autoyielding per card, we need to clear auto yields between games since card IDs change // when autoyielding per card, we need to clear auto yields between games since card IDs change
humanController.getGui().clearAutoYields(); humanController.getGui().clearAutoYields();

View File

@@ -13,41 +13,7 @@ import forge.game.Game;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.game.event.GameEvent; import forge.game.event.*;
import forge.game.event.GameEventAnteCardsSelected;
import forge.game.event.GameEventAttackersDeclared;
import forge.game.event.GameEventBlockersDeclared;
import forge.game.event.GameEventCardAttachment;
import forge.game.event.GameEventCardChangeZone;
import forge.game.event.GameEventCardCounters;
import forge.game.event.GameEventCardDamaged;
import forge.game.event.GameEventCardPhased;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.event.GameEventCardTapped;
import forge.game.event.GameEventCombatChanged;
import forge.game.event.GameEventCombatEnded;
import forge.game.event.GameEventCombatUpdate;
import forge.game.event.GameEventGameFinished;
import forge.game.event.GameEventGameOutcome;
import forge.game.event.GameEventLandPlayed;
import forge.game.event.GameEventManaBurn;
import forge.game.event.GameEventManaPool;
import forge.game.event.GameEventPlayerControl;
import forge.game.event.GameEventPlayerCounters;
import forge.game.event.GameEventPlayerLivesChanged;
import forge.game.event.GameEventPlayerPoisoned;
import forge.game.event.GameEventPlayerPriority;
import forge.game.event.GameEventPlayerStatsChanged;
import forge.game.event.GameEventShuffle;
import forge.game.event.GameEventSpellAbilityCast;
import forge.game.event.GameEventSpellRemovedFromStack;
import forge.game.event.GameEventSpellResolved;
import forge.game.event.GameEventSubgameEnd;
import forge.game.event.GameEventTokenStateUpdate;
import forge.game.event.GameEventTurnBegan;
import forge.game.event.GameEventTurnPhase;
import forge.game.event.GameEventZone;
import forge.game.event.IGameEventVisitor;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerView; import forge.game.player.PlayerView;
import forge.game.zone.Zone; import forge.game.zone.Zone;
@@ -506,6 +472,13 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
return processPlayer(event.receiver, livesUpdate); return processPlayer(event.receiver, livesUpdate);
} }
@Override
public Void visit(final GameEventPlayerDamaged event) {
//for avatar animation
event.target.setAvatarWasDamaged(event.amount > 0);
return processEvent();
}
@Override @Override
public Void visit(final GameEventPlayerCounters event) { public Void visit(final GameEventPlayerCounters event) {
return processPlayer(event.receiver, livesUpdate); return processPlayer(event.receiver, livesUpdate);