support for juggling and multicolored cards
This commit is contained in:
parent
62c9ec2d28
commit
851c3a3451
@ -0,0 +1,29 @@
|
|||||||
|
package eu.jonahbauer.wizard.client.libgdx;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class AnimationTimings {
|
||||||
|
public static final float JUGGLE = 0.25f;
|
||||||
|
|
||||||
|
public static final float STACK_EXPAND = 0.25f;
|
||||||
|
public static final float STACK_COLLAPSE = 0.25f;
|
||||||
|
|
||||||
|
public static final float STACK_FINISH_MOVE = 0.25f;
|
||||||
|
public static final float STACK_FINISH_ROTATE = 0.1f;
|
||||||
|
public static final float STACK_FINISH_FADE = 0.5f;
|
||||||
|
public static final float STACK_HOLD = 0.5f;
|
||||||
|
|
||||||
|
public static final float PAD_OF_TRUTH_EXPAND = 0.25f;
|
||||||
|
public static final float PAD_OF_TRUTH_COLLAPSE = 0.25f;
|
||||||
|
|
||||||
|
public static final float HAND_LAYOUT = 0.15f;
|
||||||
|
|
||||||
|
public static final float OVERLAY_HOLD = 3f;
|
||||||
|
public static final float OVERLAY_FADE = 0.1f;
|
||||||
|
|
||||||
|
public static final float OVERLAY_TRUMP = .3f;
|
||||||
|
|
||||||
|
public static final float MESSAGE_HOLD = 1.5f;
|
||||||
|
public static final float MESSAGE_FADE = 0.5f;
|
||||||
|
}
|
@ -7,8 +7,6 @@ import com.badlogic.gdx.utils.Pool;
|
|||||||
import com.badlogic.gdx.utils.Pools;
|
import com.badlogic.gdx.utils.Pools;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
/** Removes an actor from the stage.
|
|
||||||
* @author Nathan Sweet */
|
|
||||||
public class ChangeParentAction extends Action {
|
public class ChangeParentAction extends Action {
|
||||||
private final Pool<Vector2> vectorPool = Pools.get(Vector2.class);
|
private final Pool<Vector2> vectorPool = Pools.get(Vector2.class);
|
||||||
|
|
||||||
@ -16,11 +14,12 @@ public class ChangeParentAction extends Action {
|
|||||||
private Group parent;
|
private Group parent;
|
||||||
private boolean finished;
|
private boolean finished;
|
||||||
|
|
||||||
public boolean act (float delta) {
|
public boolean act(float delta) {
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
finished = true;
|
finished = true;
|
||||||
var pos = vectorPool.obtain();
|
var pos = vectorPool.obtain();
|
||||||
pos.set(0, 0);
|
pos.set(target.getX(), target.getY());
|
||||||
|
target.parentToLocalCoordinates(pos);
|
||||||
target.localToStageCoordinates(pos);
|
target.localToStageCoordinates(pos);
|
||||||
parent.stageToLocalCoordinates(pos);
|
parent.stageToLocalCoordinates(pos);
|
||||||
target.setPosition(pos.x, pos.y);
|
target.setPosition(pos.x, pos.y);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.jonahbauer.wizard.client.libgdx.actors.game;
|
package eu.jonahbauer.wizard.client.libgdx.actors.game;
|
||||||
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.*;
|
import com.badlogic.gdx.scenes.scene2d.*;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.AnimationTimings;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
|
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -10,9 +11,7 @@ import java.util.*;
|
|||||||
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;
|
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;
|
||||||
|
|
||||||
public class CardStack extends Group {
|
public class CardStack extends Group {
|
||||||
private static final float EXPAND_DURATION = 0.25f;
|
|
||||||
private static final float EXPANDED_ROTATION_DEVIATION = 10;
|
private static final float EXPANDED_ROTATION_DEVIATION = 10;
|
||||||
private static final float COLLAPSE_DURATION = 0.25f;
|
|
||||||
private static final float COLLAPSED_ROTATION_DEVIATION = 60;
|
private static final float COLLAPSED_ROTATION_DEVIATION = 60;
|
||||||
private static final float COLLAPSED_POSITION_DEVIATION = 15;
|
private static final float COLLAPSED_POSITION_DEVIATION = 15;
|
||||||
|
|
||||||
@ -126,8 +125,12 @@ public class CardStack extends Group {
|
|||||||
if (action != null) actor.removeAction(action);
|
if (action != null) actor.removeAction(action);
|
||||||
|
|
||||||
action = parallel(
|
action = parallel(
|
||||||
moveTo(seat.getFrontX() - actor.getWidth() / 2, seat.getFrontY() - actor.getHeight() / 2, EXPAND_DURATION),
|
moveTo(
|
||||||
rotateTo(expandedRotation, EXPAND_DURATION)
|
seat.getFrontX() - actor.getWidth() / 2,
|
||||||
|
seat.getFrontY() - actor.getHeight() / 2,
|
||||||
|
AnimationTimings.STACK_EXPAND
|
||||||
|
),
|
||||||
|
rotateTo(expandedRotation, AnimationTimings.STACK_EXPAND)
|
||||||
);
|
);
|
||||||
|
|
||||||
actor.addAction(action);
|
actor.addAction(action);
|
||||||
@ -137,8 +140,8 @@ public class CardStack extends Group {
|
|||||||
if (action != null) actor.removeAction(action);
|
if (action != null) actor.removeAction(action);
|
||||||
|
|
||||||
action = parallel(
|
action = parallel(
|
||||||
moveTo(x, y, COLLAPSE_DURATION),
|
moveTo(x, y, AnimationTimings.STACK_COLLAPSE),
|
||||||
rotateTo(rotation, COLLAPSE_DURATION)
|
rotateTo(rotation, AnimationTimings.STACK_COLLAPSE)
|
||||||
);
|
);
|
||||||
|
|
||||||
actor.addAction(action);
|
actor.addAction(action);
|
||||||
|
@ -3,9 +3,13 @@ package eu.jonahbauer.wizard.client.libgdx.actors.game;
|
|||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
import com.badlogic.gdx.scenes.scene2d.*;
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup;
|
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup;
|
||||||
import com.badlogic.gdx.utils.Pools;
|
import com.badlogic.gdx.utils.Pools;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.AnimationTimings;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.util.Pair;
|
||||||
import eu.jonahbauer.wizard.common.model.Card;
|
import eu.jonahbauer.wizard.common.model.Card;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -13,11 +17,10 @@ import lombok.Setter;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;
|
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.moveTo;
|
||||||
|
|
||||||
public class CardsGroup extends WidgetGroup {
|
public class CardsGroup extends WidgetGroup {
|
||||||
private static final float TARGET_SPACING = -50f;
|
private static final float TARGET_SPACING = -50f;
|
||||||
private static final float LAYOUT_DURATION = 0.15f;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final float prefWidth = 0;
|
private final float prefWidth = 0;
|
||||||
@ -38,7 +41,12 @@ public class CardsGroup extends WidgetGroup {
|
|||||||
private CardActor dragTarget;
|
private CardActor dragTarget;
|
||||||
private float dragStartX;
|
private float dragStartX;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private SelectMode selectMode = SelectMode.NONE;
|
||||||
@Setter
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private Card selected;
|
||||||
|
|
||||||
private Consumer<CardActor> onClickListener;
|
private Consumer<CardActor> onClickListener;
|
||||||
|
|
||||||
public CardsGroup(List<Card> cards, TextureAtlas atlas) {
|
public CardsGroup(List<Card> cards, TextureAtlas atlas) {
|
||||||
@ -122,7 +130,8 @@ public class CardsGroup extends WidgetGroup {
|
|||||||
for (var child : getChildren()) {
|
for (var child : getChildren()) {
|
||||||
if (child instanceof CardActor card) {
|
if (child instanceof CardActor card) {
|
||||||
float height = card.getHeight();
|
float height = card.getHeight();
|
||||||
if (child == dragTarget || dragTarget == null && child == target) {
|
if (selectMode == SelectMode.NONE && (child == dragTarget || dragTarget == null && child == target)
|
||||||
|
|| selectMode == SelectMode.SINGLE && card.getCard() == selected) {
|
||||||
height += speed * delta;
|
height += speed * delta;
|
||||||
} else {
|
} else {
|
||||||
height -= speed * delta;
|
height -= speed * delta;
|
||||||
@ -140,7 +149,9 @@ public class CardsGroup extends WidgetGroup {
|
|||||||
|
|
||||||
float height = getHeight();
|
float height = getHeight();
|
||||||
float width = getWidth();
|
float width = getWidth();
|
||||||
|
if (cardX == null || cardX.length != count) {
|
||||||
cardX = new float[count];
|
cardX = new float[count];
|
||||||
|
}
|
||||||
|
|
||||||
cardWidth = height / CardActor.ASPECT_RATIO;
|
cardWidth = height / CardActor.ASPECT_RATIO;
|
||||||
spacing = width - count * cardWidth;
|
spacing = width - count * cardWidth;
|
||||||
@ -155,7 +166,7 @@ public class CardsGroup extends WidgetGroup {
|
|||||||
|
|
||||||
// position
|
// position
|
||||||
if (animate) {
|
if (animate) {
|
||||||
child.addAction(moveTo(x, y, LAYOUT_DURATION));
|
child.addAction(moveTo(x, y, AnimationTimings.HAND_LAYOUT));
|
||||||
} else {
|
} else {
|
||||||
child.setPosition(x, y);
|
child.setPosition(x, y);
|
||||||
}
|
}
|
||||||
@ -172,13 +183,27 @@ public class CardsGroup extends WidgetGroup {
|
|||||||
animate = false;
|
animate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(List<Card> cards) {
|
public Pair<List<CardActor>, List<CardActor>> update(List<Card> cards) {
|
||||||
clearChildren();
|
var added = new ArrayList<>(cards);
|
||||||
|
var removed = new ArrayList<Card>();
|
||||||
|
|
||||||
cards.stream()
|
for (var child : getChildren()) {
|
||||||
.map(card -> new CardActor(card, atlas))
|
if (child instanceof CardActor actor) {
|
||||||
.forEach(this::addActor);
|
var card = actor.getCard();
|
||||||
invalidate();
|
|
||||||
|
if (!added.remove(card)) {
|
||||||
|
removed.add(card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var removedActors = removed.stream().map(this::remove).toList();
|
||||||
|
var addedActors = added.stream().sorted().map(card -> new CardActor(card, atlas)).toList();
|
||||||
|
|
||||||
|
addedActors.forEach(this::addActor);
|
||||||
|
layout();
|
||||||
|
|
||||||
|
return Pair.of(removedActors, addedActors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CardActor remove(Card card) {
|
public CardActor remove(Card card) {
|
||||||
@ -216,4 +241,16 @@ public class CardsGroup extends WidgetGroup {
|
|||||||
public float getMinHeight() {
|
public float getMinHeight() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSelectMode(SelectMode selectMode) {
|
||||||
|
this.selectMode = Objects.requireNonNull(selectMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnClickListener(Consumer<CardActor> onClickListener) {
|
||||||
|
this.onClickListener = onClickListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SelectMode {
|
||||||
|
SINGLE, NONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,18 +5,18 @@ import com.badlogic.gdx.scenes.scene2d.Actor;
|
|||||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||||
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Touchable;
|
import com.badlogic.gdx.scenes.scene2d.Touchable;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
|
||||||
import com.badlogic.gdx.scenes.scene2d.actions.ScaleToAction;
|
import com.badlogic.gdx.scenes.scene2d.actions.ScaleToAction;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
|
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
|
||||||
import com.badlogic.gdx.utils.Align;
|
import com.badlogic.gdx.utils.Align;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.AnimationTimings;
|
||||||
|
|
||||||
public class PadOfTruth extends Table {
|
public class PadOfTruth extends Table {
|
||||||
private static final float EXPAND_DURATION = 0.25f;
|
|
||||||
private static final float EXTENDED_WIDTH = 636;
|
private static final float EXTENDED_WIDTH = 636;
|
||||||
private static final float EXTENDED_HEIGHT = 824;
|
private static final float EXTENDED_HEIGHT = 824;
|
||||||
private static final float COLLAPSE_DURATION = 0.25f;
|
|
||||||
private static final float COLLAPSED_SCALE = CardActor.PREF_HEIGHT / EXTENDED_HEIGHT;
|
private static final float COLLAPSED_SCALE = CardActor.PREF_HEIGHT / EXTENDED_HEIGHT;
|
||||||
|
|
||||||
private final Label[] names = new Label[6];
|
private final Label[] names = new Label[6];
|
||||||
@ -42,9 +42,7 @@ public class PadOfTruth extends Table {
|
|||||||
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
|
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
|
||||||
if (fromActor != null && isAscendantOf(fromActor)) return;
|
if (fromActor != null && isAscendantOf(fromActor)) return;
|
||||||
if (action != null) removeAction(action);
|
if (action != null) removeAction(action);
|
||||||
action = new ScaleToAction();
|
action = Actions.scaleTo(1, 1, AnimationTimings.PAD_OF_TRUTH_EXPAND);
|
||||||
action.setDuration(EXPAND_DURATION);
|
|
||||||
action.setScale(1);
|
|
||||||
addAction(action);
|
addAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,9 +50,7 @@ public class PadOfTruth extends Table {
|
|||||||
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
|
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
|
||||||
if (toActor != null && isAscendantOf(toActor)) return;
|
if (toActor != null && isAscendantOf(toActor)) return;
|
||||||
if (action != null) removeAction(action);
|
if (action != null) removeAction(action);
|
||||||
action = new ScaleToAction();
|
action = Actions.scaleTo(COLLAPSED_SCALE, COLLAPSED_SCALE, AnimationTimings.PAD_OF_TRUTH_COLLAPSE);
|
||||||
action.setDuration(COLLAPSE_DURATION);
|
|
||||||
action.setScale(COLLAPSED_SCALE);
|
|
||||||
addAction(action);
|
addAction(action);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.*;
|
|||||||
import com.badlogic.gdx.scenes.scene2d.ui.Container;
|
import com.badlogic.gdx.scenes.scene2d.ui.Container;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
||||||
import com.badlogic.gdx.utils.I18NBundle;
|
import com.badlogic.gdx.utils.I18NBundle;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.AnimationTimings;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.UiskinAtlas;
|
import eu.jonahbauer.wizard.client.libgdx.UiskinAtlas;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
|
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
||||||
@ -14,8 +15,6 @@ import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
|||||||
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;
|
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;
|
||||||
|
|
||||||
public abstract class Overlay extends Action {
|
public abstract class Overlay extends Action {
|
||||||
protected static final float OVERLAY_TIME = 5.0f;
|
|
||||||
|
|
||||||
protected final GameScreen screen;
|
protected final GameScreen screen;
|
||||||
protected final WizardGame.Data data;
|
protected final WizardGame.Data data;
|
||||||
protected final I18NBundle messages;
|
protected final I18NBundle messages;
|
||||||
@ -78,7 +77,7 @@ public abstract class Overlay extends Action {
|
|||||||
|
|
||||||
public void finish() {
|
public void finish() {
|
||||||
getRoot().addAction(sequence(
|
getRoot().addAction(sequence(
|
||||||
targeting(root, alpha(0.0f, .1f, Interpolation.pow2Out)),
|
targeting(root, alpha(0.0f, AnimationTimings.OVERLAY_FADE, Interpolation.pow2Out)),
|
||||||
run(this::finishInternal)
|
run(this::finishInternal)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.player.PlayCardMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.model.Card;
|
||||||
|
|
||||||
|
import java.util.EnumMap;
|
||||||
|
|
||||||
|
public class PlayColoredCardOverlay extends Overlay implements InteractionOverlay {
|
||||||
|
|
||||||
|
private final EnumMap<Card.Suit, CardActor> actors = new EnumMap<>(Card.Suit.class);
|
||||||
|
private final EnumMap<Card.Suit, Card> cards = new EnumMap<>(Card.Suit.class);
|
||||||
|
|
||||||
|
private final Card card;
|
||||||
|
|
||||||
|
public PlayColoredCardOverlay(GameScreen gameScreen, long timeout, Card card, Card red, Card green, Card blue, Card yellow) {
|
||||||
|
super(gameScreen, timeout);
|
||||||
|
this.card = card;
|
||||||
|
this.cards.put(Card.Suit.RED, red);
|
||||||
|
this.cards.put(Card.Suit.GREEN, green);
|
||||||
|
this.cards.put(Card.Suit.BLUE, blue);
|
||||||
|
this.cards.put(Card.Suit.YELLOW, yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Actor createContent() {
|
||||||
|
var root = new VerticalGroup().columnCenter().space(10);
|
||||||
|
|
||||||
|
var prompt = new Label(messages.get("game.overlay.play_colored_card.prompt"), data.skin);
|
||||||
|
var cardGroup = new HorizontalGroup().space(20);
|
||||||
|
|
||||||
|
var card = new CardActor(this.card, atlas);
|
||||||
|
root.addActorAt(0, card);
|
||||||
|
root.padTop(- CardActor.PREF_HEIGHT);
|
||||||
|
|
||||||
|
actors.put(Card.Suit.RED, new CardActor(Card.Suit.RED, atlas));
|
||||||
|
actors.put(Card.Suit.GREEN, new CardActor(Card.Suit.GREEN, atlas));
|
||||||
|
actors.put(Card.Suit.BLUE, new CardActor(Card.Suit.BLUE, atlas));
|
||||||
|
actors.put(Card.Suit.YELLOW, new CardActor(Card.Suit.YELLOW, atlas));
|
||||||
|
actors.values().forEach(cardGroup::addActor);
|
||||||
|
|
||||||
|
cardGroup.addListener(new ClickListener() {
|
||||||
|
@Override
|
||||||
|
public void clicked(InputEvent event, float x, float y) {
|
||||||
|
var target = event.getTarget();
|
||||||
|
for (Card.Suit suit : Card.Suit.values()) {
|
||||||
|
if (actors.get(suit) == target) {
|
||||||
|
screen.send(new PlayCardMessage(cards.get(suit)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
root.addActor(prompt);
|
||||||
|
root.addActor(cardGroup);
|
||||||
|
|
||||||
|
var cancel = new TextButton(messages.get("game.overlay.play_colored_card.cancel"), data.skin, "simple");
|
||||||
|
cancel.addListener(new ChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void changed(ChangeEvent event, Actor actor) {
|
||||||
|
finishInternal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
root.addActor(cancel);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.Actor;
|
|||||||
import com.badlogic.gdx.scenes.scene2d.Group;
|
import com.badlogic.gdx.scenes.scene2d.Group;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
|
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.AnimationTimings;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.actions.MyActions;
|
import eu.jonahbauer.wizard.client.libgdx.actions.MyActions;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
||||||
|
|
||||||
@ -36,8 +37,8 @@ public class StartRoundOverlay extends Overlay {
|
|||||||
|
|
||||||
var root = getRoot();
|
var root = getRoot();
|
||||||
root.addAction(sequence(
|
root.addAction(sequence(
|
||||||
delay(OVERLAY_TIME),
|
delay(AnimationTimings.OVERLAY_HOLD),
|
||||||
targeting(root, alpha(0.0f, .5f, Interpolation.pow2Out)),
|
targeting(root, alpha(0.0f, AnimationTimings.OVERLAY_FADE, Interpolation.pow2Out)),
|
||||||
run(this::finishInternal)
|
run(this::finishInternal)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import com.badlogic.gdx.scenes.scene2d.actions.ParallelAction;
|
|||||||
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup;
|
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
|
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.AnimationTimings;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.actions.MyActions;
|
import eu.jonahbauer.wizard.client.libgdx.actions.MyActions;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor;
|
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
||||||
@ -72,7 +73,13 @@ public class TrumpOverlay extends Overlay {
|
|||||||
Map.entry(Card.YELLOW_10, Card.Suit.YELLOW),
|
Map.entry(Card.YELLOW_10, Card.Suit.YELLOW),
|
||||||
Map.entry(Card.YELLOW_11, Card.Suit.YELLOW),
|
Map.entry(Card.YELLOW_11, Card.Suit.YELLOW),
|
||||||
Map.entry(Card.YELLOW_12, Card.Suit.YELLOW),
|
Map.entry(Card.YELLOW_12, Card.Suit.YELLOW),
|
||||||
Map.entry(Card.YELLOW_13, Card.Suit.YELLOW)
|
Map.entry(Card.YELLOW_13, Card.Suit.YELLOW),
|
||||||
|
Map.entry(Card.RED_JESTER, Card.Suit.NONE),
|
||||||
|
Map.entry(Card.GREEN_JESTER, Card.Suit.NONE),
|
||||||
|
Map.entry(Card.BLUE_JESTER, Card.Suit.NONE),
|
||||||
|
Map.entry(Card.YELLOW_JESTER, Card.Suit.NONE),
|
||||||
|
Map.entry(Card.BOMB, Card.Suit.NONE),
|
||||||
|
Map.entry(Card.FAIRY, Card.Suit.NONE)
|
||||||
);
|
);
|
||||||
|
|
||||||
private final String player;
|
private final String player;
|
||||||
@ -154,7 +161,7 @@ public class TrumpOverlay extends Overlay {
|
|||||||
cardAnimation.addAction(sequence(
|
cardAnimation.addAction(sequence(
|
||||||
targeting(trumpCardActor, removeActorSilently()),
|
targeting(trumpCardActor, removeActorSilently()),
|
||||||
targeting(trumpCardActor, changeParent(parent)),
|
targeting(trumpCardActor, changeParent(parent)),
|
||||||
targeting(trumpCardActor, moveTo(10, 10, .3f))
|
targeting(trumpCardActor, moveTo(10, 10, AnimationTimings.OVERLAY_TRUMP))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,9 +171,9 @@ public class TrumpOverlay extends Overlay {
|
|||||||
targeting(trumpSuitActor, changeParent(parent)),
|
targeting(trumpSuitActor, changeParent(parent)),
|
||||||
run(trumpCardActor::toFront),
|
run(trumpCardActor::toFront),
|
||||||
parallel(
|
parallel(
|
||||||
targeting(trumpSuitActor, rotateTo(-90, .3f)),
|
targeting(trumpSuitActor, rotateTo(-90, AnimationTimings.OVERLAY_TRUMP)),
|
||||||
targeting(trumpSuitActor,
|
targeting(trumpSuitActor,
|
||||||
moveTo(10, 10 + (trumpSuitActor.getHeight() + trumpSuitActor.getWidth()) / 2, .3f)
|
moveTo(10, 10 + (trumpSuitActor.getHeight() + trumpSuitActor.getWidth()) / 2, AnimationTimings.OVERLAY_TRUMP)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
@ -174,9 +181,9 @@ public class TrumpOverlay extends Overlay {
|
|||||||
|
|
||||||
var root = getRoot();
|
var root = getRoot();
|
||||||
root.addAction(sequence(
|
root.addAction(sequence(
|
||||||
delay(OVERLAY_TIME),
|
delay(AnimationTimings.OVERLAY_HOLD),
|
||||||
parallel(
|
parallel(
|
||||||
targeting(root, alpha(0.0f, .3f, Interpolation.pow2Out)),
|
targeting(root, alpha(0.0f, AnimationTimings.OVERLAY_FADE, Interpolation.pow2Out)),
|
||||||
cardAnimation
|
cardAnimation
|
||||||
),
|
),
|
||||||
run(this::finishInternal)
|
run(this::finishInternal)
|
||||||
|
@ -3,14 +3,17 @@ package eu.jonahbauer.wizard.client.libgdx.screens;
|
|||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Action;
|
import com.badlogic.gdx.scenes.scene2d.Action;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Touchable;
|
import com.badlogic.gdx.scenes.scene2d.Touchable;
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.actions.MoveToAction;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Container;
|
import com.badlogic.gdx.scenes.scene2d.ui.Container;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
|
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
||||||
import com.badlogic.gdx.utils.Align;
|
import com.badlogic.gdx.utils.Align;
|
||||||
import com.badlogic.gdx.utils.I18NBundle;
|
import com.badlogic.gdx.utils.I18NBundle;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.AnimationTimings;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.GameAtlas;
|
import eu.jonahbauer.wizard.client.libgdx.GameAtlas;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
|
import eu.jonahbauer.wizard.client.libgdx.WizardGame;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor;
|
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor;
|
||||||
@ -19,10 +22,11 @@ import eu.jonahbauer.wizard.client.libgdx.actors.game.CardsGroup;
|
|||||||
import eu.jonahbauer.wizard.client.libgdx.actors.game.PadOfTruth;
|
import eu.jonahbauer.wizard.client.libgdx.actors.game.PadOfTruth;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.actors.game.overlay.*;
|
import eu.jonahbauer.wizard.client.libgdx.actors.game.overlay.*;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.state.Game;
|
import eu.jonahbauer.wizard.client.libgdx.state.Game;
|
||||||
import eu.jonahbauer.wizard.client.libgdx.util.Pair;
|
import eu.jonahbauer.wizard.client.libgdx.util.Triple;
|
||||||
import eu.jonahbauer.wizard.common.messages.client.InteractionMessage;
|
import eu.jonahbauer.wizard.common.messages.client.InteractionMessage;
|
||||||
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
|
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
|
||||||
import eu.jonahbauer.wizard.common.messages.player.ContinueMessage;
|
import eu.jonahbauer.wizard.common.messages.player.ContinueMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.player.JuggleMessage;
|
||||||
import eu.jonahbauer.wizard.common.messages.player.PlayCardMessage;
|
import eu.jonahbauer.wizard.common.messages.player.PlayCardMessage;
|
||||||
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
||||||
import eu.jonahbauer.wizard.common.model.Card;
|
import eu.jonahbauer.wizard.common.model.Card;
|
||||||
@ -46,7 +50,7 @@ public class GameScreen extends MenuScreen {
|
|||||||
|
|
||||||
private final List<UUID> players;
|
private final List<UUID> players;
|
||||||
|
|
||||||
private Pair<UUID, UserInputMessage.Action> activePlayer;
|
private Triple<UUID, UserInputMessage.Action, Long> activePlayer;
|
||||||
|
|
||||||
private CardsGroup handCards;
|
private CardsGroup handCards;
|
||||||
private CardStack cardStack;
|
private CardStack cardStack;
|
||||||
@ -69,6 +73,9 @@ public class GameScreen extends MenuScreen {
|
|||||||
private final AtomicBoolean sending = new AtomicBoolean();
|
private final AtomicBoolean sending = new AtomicBoolean();
|
||||||
private final AtomicBoolean pendingSync = new AtomicBoolean();
|
private final AtomicBoolean pendingSync = new AtomicBoolean();
|
||||||
|
|
||||||
|
private boolean juggling;
|
||||||
|
private Card juggledCard;
|
||||||
|
|
||||||
public GameScreen(WizardGame game) {
|
public GameScreen(WizardGame game) {
|
||||||
super(game);
|
super(game);
|
||||||
this.state = (Game) game.getClient().getState();
|
this.state = (Game) game.getClient().getState();
|
||||||
@ -88,7 +95,7 @@ public class GameScreen extends MenuScreen {
|
|||||||
prepareLabels();
|
prepareLabels();
|
||||||
|
|
||||||
handCards = new CardsGroup(Collections.emptyList(), atlas);
|
handCards = new CardsGroup(Collections.emptyList(), atlas);
|
||||||
handCards.setOnClickListener(card -> send(new PlayCardMessage(card.getCard())));
|
handCards.setOnClickListener(this::onCardClicked);
|
||||||
var container = new Container<>(handCards);
|
var container = new Container<>(handCards);
|
||||||
container.setPosition(360, 75);
|
container.setPosition(360, 75);
|
||||||
container.setSize(1200, CardActor.PREF_HEIGHT);
|
container.setSize(1200, CardActor.PREF_HEIGHT);
|
||||||
@ -183,7 +190,7 @@ public class GameScreen extends MenuScreen {
|
|||||||
|
|
||||||
private void prepareLabels() {
|
private void prepareLabels() {
|
||||||
for (UUID player : players) {
|
for (UUID player : players) {
|
||||||
if (state.getSelf().equals(player)) continue;
|
if (isSelf(player)) continue;
|
||||||
var label = new Label("", game.data.skin);
|
var label = new Label("", game.data.skin);
|
||||||
var seat = seats.get(player);
|
var seat = seats.get(player);
|
||||||
label.setX(seat.getLabelX());
|
label.setX(seat.getLabelX());
|
||||||
@ -199,12 +206,54 @@ public class GameScreen extends MenuScreen {
|
|||||||
var player = players.get(i);
|
var player = players.get(i);
|
||||||
var name = state.getPlayers().get(player);
|
var name = state.getPlayers().get(player);
|
||||||
padOfTruth.setName(i, name);
|
padOfTruth.setName(i, name);
|
||||||
if (!state.getSelf().equals(player)) {
|
if (!isSelf(player)) {
|
||||||
nameLabels.get(player).setText(name);
|
nameLabels.get(player).setText(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onCardClicked(CardActor actor) {
|
||||||
|
var card = actor.getCard();
|
||||||
|
|
||||||
|
if (checkAction(PLAY_CARD)) {
|
||||||
|
var timeout = activePlayer.third();
|
||||||
|
if (card == Card.CLOUD) {
|
||||||
|
execute(new PlayColoredCardOverlay(this,
|
||||||
|
timeout,
|
||||||
|
Card.CLOUD,
|
||||||
|
Card.CLOUD_RED,
|
||||||
|
Card.CLOUD_GREEN,
|
||||||
|
Card.CLOUD_BLUE,
|
||||||
|
Card.CLOUD_YELLOW
|
||||||
|
));
|
||||||
|
} else if (card == Card.JUGGLER) {
|
||||||
|
execute(new PlayColoredCardOverlay(this,
|
||||||
|
timeout,
|
||||||
|
Card.JUGGLER,
|
||||||
|
Card.JUGGLER_RED,
|
||||||
|
Card.JUGGLER_GREEN,
|
||||||
|
Card.JUGGLER_BLUE,
|
||||||
|
Card.JUGGLER_YELLOW
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
send(new PlayCardMessage(card));
|
||||||
|
}
|
||||||
|
} else if (checkAction(JUGGLE_CARD)) {
|
||||||
|
juggledCard = card;
|
||||||
|
send(new JuggleMessage(card));
|
||||||
|
} else {
|
||||||
|
addMessage("You cannot do that right now.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkAction(UserInputMessage.Action action) {
|
||||||
|
return activePlayer != null && (activePlayer.first() == null || isSelf(activePlayer.first())) && activePlayer.second() == action;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSelf(UUID uuid) {
|
||||||
|
return state.getSelf().equals(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
public void startRound(int round) {
|
public void startRound(int round) {
|
||||||
execute(parallel(
|
execute(parallel(
|
||||||
run(() -> {
|
run(() -> {
|
||||||
@ -224,35 +273,67 @@ public class GameScreen extends MenuScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startTrick() {
|
public void startTrick() {
|
||||||
setActivePlayer(null, null, 0);
|
clearActivePlayer();
|
||||||
execute(() -> cardStack.clearChildren());
|
execute(() -> cardStack.clearChildren());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the next call to {@link #setHand(UUID, List)} should be animated.
|
||||||
|
*/
|
||||||
|
public void setJuggling(boolean juggling) {
|
||||||
|
execute(() -> {
|
||||||
|
this.juggling = juggling;
|
||||||
|
if (juggling) {
|
||||||
|
handCards.setSelectMode(CardsGroup.SelectMode.SINGLE);
|
||||||
|
} else {
|
||||||
|
handCards.setSelectMode(CardsGroup.SelectMode.NONE);
|
||||||
|
juggledCard = null;
|
||||||
|
handCards.setSelected(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void finishTrick(UUID player, List<Card> cards) {
|
public void finishTrick(UUID player, List<Card> cards) {
|
||||||
var seat = seats.get(player);
|
var seat = seats.get(player);
|
||||||
|
|
||||||
var action = parallel();
|
var action = parallel();
|
||||||
execute(sequence(
|
execute(sequence(
|
||||||
run(() -> cardStack.removeAll().forEach(card -> action.addAction(sequence(
|
run(() -> cardStack.removeAll().forEach(card -> {
|
||||||
|
var angle = (card.getRotation() % 360 + 360) % 360;
|
||||||
|
var rotation = rotateTo(angle < 90 || angle > 270 ? 0 : 180, AnimationTimings.STACK_FINISH_ROTATE);
|
||||||
|
rotation.setUseShortestDirection(true);
|
||||||
|
|
||||||
|
action.addAction(sequence(
|
||||||
targeting(card, changeParent(game.data.stage.getRoot())),
|
targeting(card, changeParent(game.data.stage.getRoot())),
|
||||||
parallel(
|
parallel(
|
||||||
targeting(card, rotateTo(0, 0.1f)),
|
targeting(card, rotation),
|
||||||
targeting(card, moveTo(
|
targeting(card, moveTo(
|
||||||
seat.getFrontX() - card.getWidth() / 2,
|
seat.getFrontX() - card.getWidth() / 2,
|
||||||
seat.getFrontY() - card.getHeight() / 2,
|
seat.getFrontY() - card.getHeight() / 2,
|
||||||
0.25f
|
AnimationTimings.STACK_FINISH_MOVE
|
||||||
))
|
))
|
||||||
),
|
),
|
||||||
targeting(card, alpha(0, 0.5f)),
|
targeting(card, alpha(0, AnimationTimings.STACK_FINISH_FADE)),
|
||||||
removeActor(card)
|
removeActor(card)
|
||||||
)))),
|
));
|
||||||
|
})),
|
||||||
action
|
action
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHand(UUID player, List<Card> cards) {
|
public void setHand(UUID player, List<Card> cards) {
|
||||||
if (state.getSelf().equals(player)) {
|
if (isSelf(player)) {
|
||||||
execute(() -> handCards.update(cards));
|
var sequence = sequence();
|
||||||
|
sequence.addAction(run(() -> {
|
||||||
|
var changes = handCards.update(cards);
|
||||||
|
|
||||||
|
// animate card changes
|
||||||
|
if (juggling) {
|
||||||
|
setJuggling(false);
|
||||||
|
sequence.addAction(animateJuggle(changes.first(), changes.second()));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
execute(sequence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +349,7 @@ public class GameScreen extends MenuScreen {
|
|||||||
String player = null;
|
String player = null;
|
||||||
if (activePlayer != null && activePlayer.second() == PICK_TRUMP) {
|
if (activePlayer != null && activePlayer.second() == PICK_TRUMP) {
|
||||||
player = state.getPlayers().get(activePlayer.first());
|
player = state.getPlayers().get(activePlayer.first());
|
||||||
setActivePlayer(null, null, 0);
|
clearActivePlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(new TrumpOverlay(this, player, trumpCard, trumpSuit));
|
execute(new TrumpOverlay(this, player, trumpCard, trumpSuit));
|
||||||
@ -276,12 +357,13 @@ public class GameScreen extends MenuScreen {
|
|||||||
|
|
||||||
public void addPrediction(int round, UUID player, int prediction) {
|
public void addPrediction(int round, UUID player, int prediction) {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
|
|
||||||
if (activePlayer != null && activePlayer.first().equals(player) && (activePlayer.second() == CHANGE_PREDICTION || activePlayer.second() == MAKE_PREDICTION)) {
|
if (activePlayer != null && activePlayer.first().equals(player) && (activePlayer.second() == CHANGE_PREDICTION || activePlayer.second() == MAKE_PREDICTION)) {
|
||||||
changed = activePlayer.second() == CHANGE_PREDICTION;
|
changed = activePlayer.second() == CHANGE_PREDICTION;
|
||||||
setActivePlayer(null, null, 0);
|
clearActivePlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.getSelf().equals(player)) {
|
if (isSelf(player)) {
|
||||||
addMessage(game.messages.format("game.action." + (changed ? "change" : "make") + "_prediction.self", prediction));
|
addMessage(game.messages.format("game.action." + (changed ? "change" : "make") + "_prediction.self", prediction));
|
||||||
} else {
|
} else {
|
||||||
var name = state.getPlayers().get(player);
|
var name = state.getPlayers().get(player);
|
||||||
@ -293,10 +375,10 @@ public class GameScreen extends MenuScreen {
|
|||||||
|
|
||||||
public void playCard(UUID player, Card card) {
|
public void playCard(UUID player, Card card) {
|
||||||
if (activePlayer != null && activePlayer.first().equals(player) && activePlayer.second() == PLAY_CARD) {
|
if (activePlayer != null && activePlayer.first().equals(player) && activePlayer.second() == PLAY_CARD) {
|
||||||
setActivePlayer(null, null, 0);
|
clearActivePlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.getSelf().equals(player)) {
|
if (isSelf(player)) {
|
||||||
addMessage(game.messages.get("game.action.play_card.self"));
|
addMessage(game.messages.get("game.action.play_card.self"));
|
||||||
} else {
|
} else {
|
||||||
var name = state.getPlayers().get(player);
|
var name = state.getPlayers().get(player);
|
||||||
@ -307,18 +389,19 @@ public class GameScreen extends MenuScreen {
|
|||||||
|
|
||||||
var sequence = sequence();
|
var sequence = sequence();
|
||||||
sequence.addAction(run(() -> {
|
sequence.addAction(run(() -> {
|
||||||
CardActor actor;
|
CardActor actor = null;
|
||||||
if (state.getSelf().equals(player)) {
|
if (isSelf(player)) {
|
||||||
actor = handCards.remove(card);
|
actor = handCards.remove(card);
|
||||||
} else {
|
|
||||||
actor = new CardActor(card, atlas);
|
|
||||||
actor.setPosition(seat.getHandX() - actor.getWidth() / 2, seat.getHandY() - actor.getHeight() / 2);
|
|
||||||
actor.setRotation(seat.getHandAngle());
|
|
||||||
}
|
|
||||||
actor.setOrigin(actor.getWidth() / 2, actor.getHeight() / 2);
|
actor.setOrigin(actor.getWidth() / 2, actor.getHeight() / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor == null) {
|
||||||
|
actor = seat.createHandCard(card, atlas);
|
||||||
|
}
|
||||||
|
|
||||||
cardStack.add(seat, actor);
|
cardStack.add(seat, actor);
|
||||||
sequence.addAction(delay(actor));
|
sequence.addAction(delay(actor));
|
||||||
sequence.addAction(delay(0.5f));
|
sequence.addAction(delay(AnimationTimings.STACK_HOLD));
|
||||||
}));
|
}));
|
||||||
execute(sequence);
|
execute(sequence);
|
||||||
}
|
}
|
||||||
@ -332,12 +415,16 @@ public class GameScreen extends MenuScreen {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearActivePlayer() {
|
||||||
|
setActivePlayer(null, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public void setActivePlayer(UUID player, UserInputMessage.Action action, long timeout) {
|
public void setActivePlayer(UUID player, UserInputMessage.Action action, long timeout) {
|
||||||
if (action == SYNC) throw new IllegalArgumentException();
|
if (action == SYNC) throw new IllegalArgumentException();
|
||||||
|
|
||||||
// reset label color
|
// reset label color
|
||||||
if (activePlayer != null && nameLabels.containsKey(activePlayer.getKey())) {
|
if (activePlayer != null && nameLabels.containsKey(activePlayer.first())) {
|
||||||
var label = nameLabels.get(activePlayer.getKey());
|
var label = nameLabels.get(activePlayer.first());
|
||||||
execute(() -> label.setStyle(labelStyleDefault));
|
execute(() -> label.setStyle(labelStyleDefault));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,14 +434,15 @@ public class GameScreen extends MenuScreen {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
activePlayer = Pair.of(player, action);
|
activePlayer = Triple.of(player, action, timeout);
|
||||||
// set label color
|
// set label color
|
||||||
if (nameLabels.containsKey(player)) {
|
if (nameLabels.containsKey(player)) {
|
||||||
var label = nameLabels.get(player);
|
var label = nameLabels.get(player);
|
||||||
execute(() -> label.setStyle(labelStyleActive));
|
execute(() -> label.setStyle(labelStyleActive));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.getSelf().equals(player)) {
|
boolean isSelf = state.getSelf().equals(player);
|
||||||
|
if (isSelf || player == null) {
|
||||||
// show interface
|
// show interface
|
||||||
setPersistentMessage(null);
|
setPersistentMessage(null);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
@ -363,8 +451,9 @@ public class GameScreen extends MenuScreen {
|
|||||||
case CHANGE_PREDICTION -> execute(new ChangePredictionOverlay(this, timeout, state.getRound(), state.getPredictions().get(state.getSelf())));
|
case CHANGE_PREDICTION -> execute(new ChangePredictionOverlay(this, timeout, state.getRound(), state.getPredictions().get(state.getSelf())));
|
||||||
case PLAY_CARD -> setPersistentMessage(game.messages.get("game.message.play_card.self"));
|
case PLAY_CARD -> setPersistentMessage(game.messages.get("game.message.play_card.self"));
|
||||||
}
|
}
|
||||||
// TODO do something
|
}
|
||||||
} else {
|
|
||||||
|
if (!isSelf) {
|
||||||
// show message
|
// show message
|
||||||
var key = switch (action) {
|
var key = switch (action) {
|
||||||
case CHANGE_PREDICTION -> "game.message.change_prediction.";
|
case CHANGE_PREDICTION -> "game.message.change_prediction.";
|
||||||
@ -391,8 +480,8 @@ public class GameScreen extends MenuScreen {
|
|||||||
public void addMessage(@Nls String text, boolean immediate) {
|
public void addMessage(@Nls String text, boolean immediate) {
|
||||||
var label = new Label(text, game.data.skin);
|
var label = new Label(text, game.data.skin);
|
||||||
label.addAction(sequence(
|
label.addAction(sequence(
|
||||||
delay(1.5f),
|
delay(AnimationTimings.MESSAGE_HOLD),
|
||||||
alpha(0, 0.25f),
|
alpha(0, AnimationTimings.MESSAGE_FADE),
|
||||||
removeActor()
|
removeActor()
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -413,15 +502,18 @@ public class GameScreen extends MenuScreen {
|
|||||||
|
|
||||||
public void setPersistentMessage(@Nls String text) {
|
public void setPersistentMessage(@Nls String text) {
|
||||||
execute(() -> {
|
execute(() -> {
|
||||||
if (text != null) {
|
if (persistentMessage != null) {
|
||||||
if (persistentMessage == null) {
|
persistentMessage.addAction(sequence(
|
||||||
persistentMessage = new Label(text, getData().skin);
|
delay(AnimationTimings.MESSAGE_HOLD),
|
||||||
} else {
|
alpha(0, AnimationTimings.MESSAGE_FADE),
|
||||||
persistentMessage.setText(text);
|
removeActor()
|
||||||
|
));
|
||||||
|
persistentMessage = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (text != null) {
|
||||||
|
persistentMessage = new Label(text, getData().skin);
|
||||||
messages.addActor(persistentMessage);
|
messages.addActor(persistentMessage);
|
||||||
} else if (persistentMessage != null) {
|
|
||||||
persistentMessage.remove();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -442,11 +534,17 @@ public class GameScreen extends MenuScreen {
|
|||||||
if (success && currentAction instanceof Overlay overlay && overlay instanceof InteractionOverlay) {
|
if (success && currentAction instanceof Overlay overlay && overlay instanceof InteractionOverlay) {
|
||||||
overlay.finish();
|
overlay.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (checkAction(JUGGLE_CARD) && juggledCard != null) {
|
||||||
|
handCards.setSelected(juggledCard);
|
||||||
|
juggledCard = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void timeout() {
|
public void timeout() {
|
||||||
addMessage(game.messages.get("game.message.timeout"));
|
addMessage(game.messages.get("game.message.timeout"));
|
||||||
ready(true);
|
ready(true);
|
||||||
|
clearActivePlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sync() {
|
public void sync() {
|
||||||
@ -467,14 +565,64 @@ public class GameScreen extends MenuScreen {
|
|||||||
return game.messages;
|
return game.messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Action animateJuggle(List<CardActor> removed, List<CardActor> added) {
|
||||||
|
// find left- and rightmost seat
|
||||||
|
Seat tmpLeft = null, tmpRight = null;
|
||||||
|
for (Seat seat : seats.values()) {
|
||||||
|
if (seat == Seat.BOTTOM) continue;
|
||||||
|
if (tmpLeft == null || tmpLeft.compareTo(seat) > 0) tmpLeft = seat;
|
||||||
|
if (tmpRight == null || tmpRight.compareTo(seat) < 0) tmpRight = seat;
|
||||||
|
}
|
||||||
|
if (tmpLeft == null) return null;
|
||||||
|
var left = tmpLeft;
|
||||||
|
var right = tmpRight;
|
||||||
|
|
||||||
|
var animation = parallel();
|
||||||
|
removed.forEach(actor -> {
|
||||||
|
getData().stage.addActor(actor);
|
||||||
|
animation.addAction(targeting(actor, left.moveToHand(AnimationTimings.JUGGLE)));
|
||||||
|
});
|
||||||
|
|
||||||
|
added.forEach(actor -> {
|
||||||
|
// capture old values taking consideration of the animated layout changes in CardsGroup
|
||||||
|
float x = actor.getX(), y = actor.getY();
|
||||||
|
var actions = actor.getActions();
|
||||||
|
for (int i = 0; i < actions.size; i ++) {
|
||||||
|
var action = actions.get(i);
|
||||||
|
if (action instanceof MoveToAction move) {
|
||||||
|
x = move.getX();
|
||||||
|
y = move.getY();
|
||||||
|
actions.removeIndex(i--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var rotation = actor.getRotation();
|
||||||
|
|
||||||
|
// apply start values
|
||||||
|
var startPos = new Vector2(right.getHandX(), right.getHandY());
|
||||||
|
handCards.stageToLocalCoordinates(startPos);
|
||||||
|
actor.setOrigin(actor.getWidth() / 2, actor.getHeight() / 2);
|
||||||
|
animation.addAction(targeting(actor, moveTo(startPos.x, startPos.y)));
|
||||||
|
animation.addAction(targeting(actor, rotateTo(right.getHandAngle())));
|
||||||
|
|
||||||
|
// animate
|
||||||
|
animation.addAction(targeting(actor, moveTo(x, y, AnimationTimings.JUGGLE)));
|
||||||
|
animation.addAction(targeting(actor, rotateTo(rotation, AnimationTimings.JUGGLE)));
|
||||||
|
});
|
||||||
|
|
||||||
|
var cleanup = parallel();
|
||||||
|
removed.forEach(actor -> cleanup.addAction(removeActor(actor)));
|
||||||
|
|
||||||
|
return sequence(animation, cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public enum Seat {
|
public enum Seat {
|
||||||
BOTTOM(WizardGame.WIDTH * 0.5f, 0, 0, 0, Align.bottom, WizardGame.WIDTH * 0.5f, 300),
|
BOTTOM(WizardGame.WIDTH * 0.5f, 0, 0, 0, Align.bottom, WizardGame.WIDTH * 0.5f, 300),
|
||||||
LEFT(0, WizardGame.HEIGHT * 0.5f, 50, WizardGame.HEIGHT * 0.5f + 110f, Align.bottomLeft, 117.5f, WizardGame.HEIGHT * 0.5f),
|
LEFT(0, WizardGame.HEIGHT * 0.5f, 50, WizardGame.HEIGHT * 0.5f + 110f, Align.bottomLeft, 117.5f, WizardGame.HEIGHT * 0.5f),
|
||||||
RIGHT(WizardGame.WIDTH, WizardGame.HEIGHT * 0.5f, WizardGame.WIDTH - 50, WizardGame.HEIGHT * 0.5f + 110f, Align.bottomRight, WizardGame.WIDTH - 117.5f, WizardGame.HEIGHT * 0.5f),
|
|
||||||
TOP_LEFT(WizardGame.WIDTH * 0.25f, WizardGame.HEIGHT, WizardGame.WIDTH * 0.25f, WizardGame.HEIGHT - 50, Align.top, WizardGame.WIDTH * 0.25f, WizardGame.HEIGHT - 200),
|
TOP_LEFT(WizardGame.WIDTH * 0.25f, WizardGame.HEIGHT, WizardGame.WIDTH * 0.25f, WizardGame.HEIGHT - 50, Align.top, WizardGame.WIDTH * 0.25f, WizardGame.HEIGHT - 200),
|
||||||
TOP(WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT, WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT - 50, Align.top, WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT - 200),
|
TOP(WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT, WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT - 50, Align.top, WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT - 200),
|
||||||
TOP_RIGHT(WizardGame.WIDTH * 0.75f, WizardGame.HEIGHT, WizardGame.WIDTH * 0.75f, WizardGame.HEIGHT - 50, Align.top, WizardGame.WIDTH * 0.75f, WizardGame.HEIGHT - 200);
|
TOP_RIGHT(WizardGame.WIDTH * 0.75f, WizardGame.HEIGHT, WizardGame.WIDTH * 0.75f, WizardGame.HEIGHT - 50, Align.top, WizardGame.WIDTH * 0.75f, WizardGame.HEIGHT - 200),
|
||||||
|
RIGHT(WizardGame.WIDTH, WizardGame.HEIGHT * 0.5f, WizardGame.WIDTH - 50, WizardGame.HEIGHT * 0.5f + 110f, Align.bottomRight, WizardGame.WIDTH - 117.5f, WizardGame.HEIGHT * 0.5f);
|
||||||
|
|
||||||
// position of the hand, should be offscreen
|
// position of the hand, should be offscreen
|
||||||
private final float handX;
|
private final float handX;
|
||||||
@ -502,5 +650,20 @@ public class GameScreen extends MenuScreen {
|
|||||||
var deltaY = WizardGame.HEIGHT * 0.5f - handY;
|
var deltaY = WizardGame.HEIGHT * 0.5f - handY;
|
||||||
this.handAngle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX) + Math.PI / 2);
|
this.handAngle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX) + Math.PI / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CardActor createHandCard(Card card, TextureAtlas atlas) {
|
||||||
|
var actor = new CardActor(card, atlas);
|
||||||
|
actor.setPosition(getHandX() - actor.getWidth() / 2, getHandY() - actor.getHeight() / 2);
|
||||||
|
actor.setRotation(getHandAngle());
|
||||||
|
actor.setOrigin(actor.getWidth() / 2, actor.getHeight() / 2);
|
||||||
|
return actor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action moveToHand(float duration) {
|
||||||
|
return parallel(
|
||||||
|
moveTo(handX, handY, duration),
|
||||||
|
rotateTo(handAngle, duration)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ public final class Game extends BaseState {
|
|||||||
case "finished", "error" -> {
|
case "finished", "error" -> {
|
||||||
return returnToSession();
|
return returnToSession();
|
||||||
}
|
}
|
||||||
|
case "juggling" -> gameScreen.setJuggling(true);
|
||||||
}
|
}
|
||||||
} else if (observerMessage instanceof HandMessage hand) {
|
} else if (observerMessage instanceof HandMessage hand) {
|
||||||
hands.put(hand.getPlayer(), hand.getHand());
|
hands.put(hand.getPlayer(), hand.getHand());
|
||||||
@ -128,13 +129,14 @@ public final class Game extends BaseState {
|
|||||||
} else if (observerMessage instanceof TimeoutMessage) {
|
} else if (observerMessage instanceof TimeoutMessage) {
|
||||||
gameScreen.timeout();
|
gameScreen.timeout();
|
||||||
} else {
|
} else {
|
||||||
|
// TODO user feedback
|
||||||
return Optional.of(new Menu());
|
return Optional.of(new Menu());
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} else if (message instanceof NackMessage nack) {
|
} else if (message instanceof NackMessage nack) {
|
||||||
int code = nack.getCode();
|
int code = nack.getCode();
|
||||||
if (code == NackMessage.ILLEGAL_ARGUMENT || code == NackMessage.ILLEGAL_STATE) {
|
if (code == NackMessage.ILLEGAL_ARGUMENT || code == NackMessage.ILLEGAL_STATE) {
|
||||||
gameScreen.addMessage(nack.getMessage());
|
gameScreen.addMessage(nack.getMessage(), true);
|
||||||
gameScreen.ready(false);
|
gameScreen.ready(false);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} else {
|
} else {
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package eu.jonahbauer.wizard.client.libgdx.util;
|
||||||
|
|
||||||
|
public record Triple<F,S,T>(F first, S second, T third) {
|
||||||
|
public static <F,S,T> Triple<F,S,T> of(F first, S second, T third) {
|
||||||
|
return new Triple<>(first, second, third);
|
||||||
|
}
|
||||||
|
}
|
@ -87,3 +87,6 @@ game.overlay.trump.blue.player={0} choose the trump suit [#0000ff]blue[#ffffff]
|
|||||||
game.overlay.trump.red.player={0} choose the trump suit [#ff0000]red[#ffffff]
|
game.overlay.trump.red.player={0} choose the trump suit [#ff0000]red[#ffffff]
|
||||||
game.overlay.trump.none.player={0} has decided there will be no trump suit this round
|
game.overlay.trump.none.player={0} has decided there will be no trump suit this round
|
||||||
game.overlay.trump.unknown.player=The trump suit is yet to be determined by {0}
|
game.overlay.trump.unknown.player=The trump suit is yet to be determined by {0}
|
||||||
|
|
||||||
|
game.overlay.play_colored_card.prompt=Pick a color
|
||||||
|
game.overlay.play_colored_card.cancel=Cancel
|
@ -87,3 +87,6 @@ game.overlay.trump.blue.player={0} hat die Trumpffarbe [#0000ff]blau[#ffffff] ge
|
|||||||
game.overlay.trump.red.player={0} hat die Trumpffarbe [#ff0000]rot[#ffffff] gewählt
|
game.overlay.trump.red.player={0} hat die Trumpffarbe [#ff0000]rot[#ffffff] gewählt
|
||||||
game.overlay.trump.none.player={0} hat entschieden, dass es diese Runde keinen Trump geben wird
|
game.overlay.trump.none.player={0} hat entschieden, dass es diese Runde keinen Trump geben wird
|
||||||
game.overlay.trump.unknown.player={0} muss die Trumpffarbe muss noch bestimmen
|
game.overlay.trump.unknown.player={0} muss die Trumpffarbe muss noch bestimmen
|
||||||
|
|
||||||
|
game.overlay.play_colored_card.prompt=Wähle eine Farbe
|
||||||
|
game.overlay.play_colored_card.cancel=Abbrechen
|
@ -2,28 +2,19 @@ package eu.jonahbauer.wizard.common.model;
|
|||||||
|
|
||||||
public enum Card {
|
public enum Card {
|
||||||
HIDDEN,
|
HIDDEN,
|
||||||
BLUE_1, RED_1, GREEN_1, YELLOW_1,
|
RED_JESTER, GREEN_JESTER, BLUE_JESTER, YELLOW_JESTER,
|
||||||
BLUE_2, RED_2, GREEN_2, YELLOW_2,
|
RED_1, RED_2, RED_3, RED_4, RED_5, RED_6, RED_7, RED_8, RED_9, RED_10, RED_11, RED_12, RED_13,
|
||||||
BLUE_3, RED_3, GREEN_3, YELLOW_3,
|
GREEN_1, GREEN_2, GREEN_3, GREEN_4, GREEN_5, GREEN_6, GREEN_7, GREEN_8, GREEN_9, GREEN_10, GREEN_11, GREEN_12, GREEN_13,
|
||||||
BLUE_4, RED_4, GREEN_4, YELLOW_4,
|
BLUE_1, BLUE_2, BLUE_3, BLUE_4, BLUE_5, BLUE_6, BLUE_7, BLUE_8, BLUE_9, BLUE_10, BLUE_11, BLUE_12, BLUE_13,
|
||||||
BLUE_5, RED_5, GREEN_5, YELLOW_5,
|
YELLOW_1, YELLOW_2, YELLOW_3, YELLOW_4, YELLOW_5, YELLOW_6, YELLOW_7, YELLOW_8, YELLOW_9, YELLOW_10, YELLOW_11, YELLOW_12, YELLOW_13,
|
||||||
BLUE_6, RED_6, GREEN_6, YELLOW_6,
|
RED_WIZARD, GREEN_WIZARD, BLUE_WIZARD, YELLOW_WIZARD,
|
||||||
BLUE_7, RED_7, GREEN_7, YELLOW_7,
|
|
||||||
BLUE_8, RED_8, GREEN_8, YELLOW_8,
|
|
||||||
BLUE_9, RED_9, GREEN_9, YELLOW_9,
|
|
||||||
BLUE_10, RED_10, GREEN_10, YELLOW_10,
|
|
||||||
BLUE_11, RED_11, GREEN_11, YELLOW_11,
|
|
||||||
BLUE_12, RED_12, GREEN_12, YELLOW_12,
|
|
||||||
BLUE_13, RED_13, GREEN_13, YELLOW_13,
|
|
||||||
BLUE_WIZARD, RED_WIZARD, GREEN_WIZARD, YELLOW_WIZARD,
|
|
||||||
BLUE_JESTER, RED_JESTER, GREEN_JESTER, YELLOW_JESTER,
|
|
||||||
CHANGELING, CHANGELING_WIZARD, CHANGELING_JESTER,
|
|
||||||
BOMB,
|
BOMB,
|
||||||
WEREWOLF,
|
CHANGELING, CHANGELING_JESTER, CHANGELING_WIZARD,
|
||||||
|
CLOUD, CLOUD_RED, CLOUD_GREEN, CLOUD_BLUE, CLOUD_YELLOW,
|
||||||
DRAGON,
|
DRAGON,
|
||||||
FAIRY,
|
FAIRY,
|
||||||
CLOUD, CLOUD_BLUE, CLOUD_RED, CLOUD_GREEN, CLOUD_YELLOW,
|
JUGGLER, JUGGLER_RED, JUGGLER_GREEN, JUGGLER_BLUE, JUGGLER_YELLOW,
|
||||||
JUGGLER, JUGGLER_BLUE, JUGGLER_RED, JUGGLER_GREEN, JUGGLER_YELLOW;
|
WEREWOLF;
|
||||||
|
|
||||||
public enum Suit {
|
public enum Suit {
|
||||||
NONE, YELLOW, RED, GREEN, BLUE
|
NONE, YELLOW, RED, GREEN, BLUE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user