Skip to content

Commit

Permalink
Booster Opening Animation (#597)
Browse files Browse the repository at this point in the history
Adds a booster opening animation (replaces sliding animation on the first pick of each pack).
Use it to display Rares & Mythics when opening a sealed pool.
Slight API update: `setCardSelection` renamed to `setCardPool`, addition of `sealedBoosters` for the sealed pool opening animation.
  • Loading branch information
Senryoku authored Oct 17, 2023
1 parent 838300a commit f311106
Show file tree
Hide file tree
Showing 14 changed files with 364 additions and 35 deletions.
36 changes: 25 additions & 11 deletions client/src/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
copyToClipboard,
escapeHTML,
sortableUpdate,
onEnterBoosterCards,
} from "./helper";
import { eraseCookie, getCookie, setCookie } from "./cookies";
import { ButtonColor, Alert, fireToast } from "./alerts";
Expand All @@ -64,6 +65,7 @@ import HousmanDialog from "./components/HousmanDialog.vue";
import MinesweeperDialog from "./components/MinesweeperDraftDialog.vue";
import RotisserieDraftDialog from "./components/RotisserieDraftDialog.vue";
import SealedDialog from "./components/SealedDialog.vue";
import SealedPresentation from "./components/SealedPresentation.vue";
import SolomonDialog from "./components/SolomonDialog.vue";
import WinchesterDialog from "./components/WinchesterDraftDialog.vue";
import WinstonDialog from "./components/WinstonDraftDialog.vue";
Expand Down Expand Up @@ -1292,20 +1294,19 @@ export default defineComponent({

this.socket.on("selectJumpstartPacks", this.selectJumpstartPacks);

this.socket.on("setCardSelection", (data) => {
if (!data) return;
const cards = data.reduce((acc, val) => acc.concat(val), []); // Flatten if necessary
if (cards.length === 0) return;
this.clearState();
// Let vue react to changes to card pools
this.$nextTick(() => {
this.addToDeck(cards);
this.draftingState = DraftState.Brewing;
fireToast("success", "Cards received!");
this.pushNotification("Cards received!");
this.socket.on("sealedBoosters", (boosters) => {
const cards = boosters.reduce((acc, val) => acc.concat(val), []);
this.spawnDialog(SealedPresentation, {
boosters: false // Note: SealedPresentation has the ability to present boosters one by one, we're not using it, yet.
? boosters
: [cards.filter((c) => c.rarity !== "common" && c.rarity !== "uncommon")],
title: "Sealed - Rares and Mythics",
});
this.setCardPool(cards);
});

this.socket.on("setCardPool", this.setCardPool);

this.socket.on("addCards", (message, cards) => {
fireToast("info", `${message} ${cards.map((c) => c.name).join(", ")}`);
this.addToDeck(cards);
Expand Down Expand Up @@ -1491,6 +1492,17 @@ export default defineComponent({
});
this.currentChatMessage = "";
},
setCardPool(cards: UniqueCard[]) {
if (!cards || cards.length === 0) return;
this.clearState();
// Let vue react to changes to card pools
this.$nextTick(() => {
this.addToDeck(cards);
this.draftingState = DraftState.Brewing;
fireToast("success", "Cards received!");
this.pushNotification("Cards received!");
});
},
// Draft Methods
async startDraft() {
if (this.userID != this.sessionOwner) return false;
Expand Down Expand Up @@ -3408,6 +3420,8 @@ export default defineComponent({
else fireToast("success", "Takeover request succeeded!");
});
},

onEnterBoosterCards: onEnterBoosterCards,
},
computed: {
deckDisplay(): typeof CardPool | null {
Expand Down
17 changes: 15 additions & 2 deletions client/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,14 @@
<div class="main-content">
<!-- Draft Controls -->
<div v-show="drafting || draftingState === DraftState.Watching" class="generic-container">
<transition :name="`slide-fade-${boosterNumber % 2 ? 'left' : 'right'}`" mode="out-in">
<transition
:name="
pickNumber > 0
? `slide-fade-${passingOrder === PassingOrder.Left ? 'left' : 'right'}`
: 'booster-fade-in'
"
mode="out-in"
>
<div v-if="draftingState === DraftState.Watching" key="draft-watching" class="draft-watching">
<div class="draft-watching-state">
<h1 v-if="!drafting">Draft Completed</h1>
Expand Down Expand Up @@ -1012,12 +1019,16 @@
</div>
<scale-slider v-model.number="boosterCardScale" style="float: right" />
</div>
<!-- Note: Duration for booster-open can't be determined by Vue since it's composite. Be sure to keep that in sync :) -->
<transition-group
tag="div"
name="booster-cards"
:name="pickNumber === 0 ? 'booster-open' : 'booster-cards'"
class="booster card-container"
:class="{ 'booster-waiting': draftingState === DraftState.Waiting, skipped: skipPick }"
:style="`--booster-card-scale: ${boosterCardScale};`"
:duration="pickNumber === 0 ? 500 + 500 + 400 + Math.min(20, booster.length) * 40 : 0"
@enter="onEnterBoosterCards"
appear
>
<div class="wait" key="wait" v-if="draftingState === DraftState.Waiting">
<font-awesome-icon
Expand Down Expand Up @@ -1083,6 +1094,7 @@
idx === botScores.chosenOption
"
:scale="boosterCardScale"
:renderCommonBackside="pickNumber === 0"
></booster-card>
</transition-group>
</div>
Expand Down Expand Up @@ -2893,6 +2905,7 @@
<style src="./css/style.css"></style>
<style src="./css/tooltip.css"></style>
<style src="./css/app.css"></style>
<style src="./css/booster-open.css"></style>
<style src="./css/chat.css"></style>

<style scoped>
Expand Down
2 changes: 2 additions & 0 deletions client/src/components/BoosterCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
:class="{ selected: selected, burned: burned, 'bot-picked': botpicked }"
class="booster-card"
:style="`--booster-card-scale: ${scale}`"
:renderCommonBackside="renderCommonBackside"
>
<div v-if="slotName" class="slot-name">{{ slotName }}</div>
<div
Expand Down Expand Up @@ -55,6 +56,7 @@ export default defineComponent({
botscore: { type: Number, default: null },
botpicked: { type: Boolean, default: false },
scale: { type: Number, default: 1 },
renderCommonBackside: { type: Boolean, default: false },
},
methods: {
burnCard(e: Event) {
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/Card.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
:language="language"
:lazyLoad="lazyLoad"
:displayCardText="displayCardText"
:renderCommonBackside="renderCommonBackside"
ref="image"
/>
<div v-if="notes || notedColors" class="additional-notes">
Expand Down Expand Up @@ -42,6 +43,7 @@ export default defineComponent({
card: { type: Object as PropType<UniqueCard>, required: true },
language: { type: String as PropType<Language>, default: "en" },
lazyLoad: { type: Boolean, default: false },
renderCommonBackside: { type: Boolean, default: false },
conditionalClasses: { type: Function },
},
data() {
Expand Down Expand Up @@ -188,7 +190,9 @@ export default defineComponent({
.fade-enter-active.card,
.fade-leave-active.card {
transition: transform 0.25s ease, opacity 0.5s;
transition:
transform 0.25s ease,
opacity 0.5s;
}
.foil .card-image {
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/CardImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@
<div v-if="card.layout === 'split-left'" class="split-left-button">
<img src="../assets/img/tap-icon.svg" class="split-left-icon" />
</div>
<div :class="{ 'flip-container': hasBack }">
<div :class="{ 'flip-container': hasBack || renderCommonBackside }">
<clazy-load
:ratio="0"
margin="200px"
:src="imageURI"
loadingClass="card-loading"
:forceLoad="!lazyLoad"
:class="{ 'flip-front': hasBack }"
:class="{ 'flip-front': hasBack || renderCommonBackside }"
>
<img class="front-image" :src="imageURI" />
<template v-slot:placeholder>
Expand All @@ -62,6 +62,9 @@
<card-placeholder :card="card.back"></card-placeholder>
</template>
</clazy-load>
<div class="flip-back" v-else-if="renderCommonBackside">
<card-placeholder />
</div>

<template v-if="cardAdditionalData && displayCardText">
<template v-if="cardAdditionalData.status === 'pending'">
Expand Down Expand Up @@ -123,6 +126,7 @@ export default defineComponent({
lazyLoad: { type: Boolean, default: false },
fixedLayout: { type: Boolean, default: false },
displayCardText: { type: Boolean, default: false },
renderCommonBackside: { type: Boolean, default: true }, // Render standard card back, mostly for animation purposes.
},
computed: {
imageURI() {
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/MinesweeperDraft.vue
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,15 @@ export default /*#__PURE__*/ defineComponent({
}
.turnover-enter-active {
transition: transform 0.3s ease-out, scale 0.3s ease-in-out !important;
transition:
transform 0.3s ease-out,
scale 0.3s ease-in-out !important;
}
.turnover-leave-active {
transition: transform 0.3s ease-in, scale 0.3s ease-in-out !important;
transition:
transform 0.3s ease-in,
scale 0.3s ease-in-out !important;
}
.turnover-enter-from,
Expand Down
1 change: 0 additions & 1 deletion client/src/components/SealedDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,3 @@ watch(boostersPerPlayer, () => {
padding: 0;
}
</style>
../../../src/SetInfos
75 changes: 75 additions & 0 deletions client/src/components/SealedPresentation.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<template>
<modal @close="close">
<template v-slot:header>
<h2 v-if="title">{{ title }}</h2>
<h2 v-else>Sealed - Booster # {{ currentBooster + 1 }} / {{ boosters.length }}</h2>
</template>
<template v-slot:body>
<transition-group
tag="div"
name="booster-open"
class="booster"
:duration="500 + 500 + 400 + Math.min(20, boosters[currentBooster].length) * 40"
@enter="onEnterBoosterCards"
appear
:key="currentBooster"
>
<CardComponent
v-for="card in boosters[currentBooster]"
:key="card.uniqueID"
:card="card"
:lazyLoad="true"
:renderCommonBackside="true"
/>
</transition-group>
</template>
<template v-slot:footer>
<div class="actions">
<button v-if="currentBooster < boosters.length - 1" class="confirm" @click="next">Next</button>
<button v-else class="confirm" @click="close">Build!</button>
</div>
</template>
</modal>
</template>

<script setup lang="ts">
import { ref } from "vue";
import Modal from "./Modal.vue";
import { UserID } from "@/IDTypes";
import { SetCode } from "../../../src/Types";
import { UniqueCard } from "@/CardTypes";
import CardComponent from "./Card.vue";
import { onEnterBoosterCards } from "../helper";
const props = defineProps<{
title: string | undefined;
boosters: UniqueCard[][];
}>();
const currentBooster = ref(0);
const emit = defineEmits<{
(e: "close"): void;
(e: "distribute", boostersPerPlayer: number, customBoosters: SetCode[], teams: UserID[][]): void;
}>();
// Methods
const next = () => {
currentBooster.value = (currentBooster.value + 1) % props.boosters.length;
};
const close = () => {
emit("close");
};
</script>

<style scoped>
.booster {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.card {
margin: 0.75em;
}
</style>
11 changes: 11 additions & 0 deletions client/src/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,7 @@ ul.player-list {

/* Booster passing animation */

.booster-fade-in-enter-active,
.slide-fade-right-enter-active,
.slide-fade-right-leave-active,
.slide-fade-left-enter-active,
Expand All @@ -1037,6 +1038,11 @@ ul.player-list {
opacity: 0;
}

.booster-fade-in-enter-from {
opacity: 0;
}

.booster-open-leave-active,
.booster-cards-enter-active,
.booster-cards-leave-active {
pointer-events: none; /* Avoid picking cards during transition */
Expand All @@ -1047,16 +1053,19 @@ ul.player-list {
opacity: 0;
}

.booster-open-leave-active.selected,
.booster-cards-leave-active.selected {
transition: all 0.5s;
width: calc(var(--booster-card-scale) * 200px);
overflow: visible;
}

.booster-open-leave-active.selected .card-image,
.booster-cards-leave-active.selected .card-image {
width: calc(var(--booster-card-scale) * 200px);
}

.booster-open-leave-to.selected,
.booster-cards-leave-to.selected {
transform: translateY(250px) translateX(calc(var(--booster-card-scale) * -100px)); /* translateX compensates for width change */
z-index: 2;
Expand All @@ -1065,10 +1074,12 @@ ul.player-list {
margin: 0;
}

.booster-open-leave-active.burned,
.booster-cards-leave-active.burned {
animation: card-burn 0.5s;
}

.booster-open-leave-to.burned,
.booster-cards-leave-to.burned {
margin: 0;
}
Expand Down
Loading

0 comments on commit f311106

Please sign in to comment.