Feat : Beta animations

This commit is contained in:
2024-06-30 14:51:06 +02:00
parent 1fbe9a57ee
commit 28bc888cb1
9 changed files with 173 additions and 77 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ onMounted(() => {
justify-content: center; justify-content: center;
margin-bottom: 0px; margin-bottom: 0px;
margin-top: var(--margin-bottom); margin-top: var(--margin-bottom);
transition: filter .125s cubic-bezier(0.075, 0.82, 0.165, 1), rotate 0.075s cubic-bezier(1, 1.81, .59, 1.42); transition: all 0.250s cubic-bezier(1, 1.81, .59, 1.42), filter .125s cubic-bezier(0.075, 0.82, 0.165, 1), rotate 0.075s cubic-bezier(1, 1.81, .59, 1.42);
isolation: isolate; isolation: isolate;
pointer-events: all; pointer-events: all;
max-height: var(--max-height); max-height: var(--max-height);
+74 -24
View File
@@ -1,35 +1,73 @@
<script setup lang="ts"> <script setup lang="ts">
import { containerEvents } from '~/netcode/events'; import { containerEvents, delay } from '~/netcode/events';
import type { Container } from '~/netcode/interfaces'; import type { Container } from '~/netcode/interfaces';
export interface Props { export interface Props {
container: Container container: Container
wrapped?: boolean
hidden?: boolean
} }
const props = defineProps<Props>() const props = withDefaults(defineProps<Props>(), {
wrapped: () => false,
hidden: () => false
})
const settingsStore = useSettingsStore()
const cards = computed(() => {
if (props.hidden) {
return props.container.cards.map((_v, i) => ({ _id: i, cardId: undefined }))
}
return props.container.cards
})
const animationSpeed = computed(() => settingsStore.animationSpeed + 'ms')
const shuffleAnimationSpeed = computed(() => settingsStore.animationSpeed * 2 + 'ms')
function populateContainer() { function populateContainer() {
} }
function shuffleContainer() { const rotate = ref(false)
async function shuffleContainer() {
console.log("rotate")
rotate.value = true
await delay(settingsStore.animationSpeed * 2)
rotate.value = false
await delay(settingsStore.animationSpeed * 2)
} }
function hideCards(cards: CardParser[]) {
}
function showCards(cards: CardParser[]) {
}
function getCardsPosition(cards: string) { function getCardsPosition(cards: string) {
} }
containerEvents.set(props.container._id, { populateContainer, shuffleContainer, getCardsPosition, hideCards, showCards })
const animationCallbacks = ref<Array<() => void>>([])
function startAnimation() {
animationCallbacks.value.forEach(p => p())
animationCallbacks.value = []
}
function endAnimation() {
animationCallbacks.value.forEach(p => p())
}
containerEvents.set(props.container._id, { populateContainer, shuffleContainer, getCardsPosition, startAnimation, endAnimation })
async function onEnter(_el: any, done: () => void) {
animationCallbacks.value.push(done)
}
async function onLeave(_el: any, done: () => void) {
animationCallbacks.value.push(done)
}
async function onBeforeEnter() {
}
onUnmounted(() => { onUnmounted(() => {
containerEvents.delete(props.container._id) containerEvents.delete(props.container._id)
@@ -37,34 +75,46 @@ onUnmounted(() => {
</script> </script>
<template> <template>
<div class="cards_container"> <div class="cards_container" :class="{ wrapped, rotate }">
<template v-if="props.container.cards.length > 0" v-for="c in props.container.cards"> <TransitionGroup name="list" @enter="onEnter" @leave="onLeave" @before-enter="onBeforeEnter">
<CardPreview :card_id="c?.cardId" :wrapped="true"> <CardPreview :card_id="c.cardId" :wrapped="wrapped" v-for="c in cards" :key="c?._id">
<slot></slot> <slot></slot>
</CardPreview> </CardPreview>
</template> </TransitionGroup>
<template v-else> <!-- <img :class="`card_image`" :src="'/cards/background.png'" draggable="false"> -->
<div class="empty">
<img :class="`card_image`" :src="'/cards/background.png'" draggable="false">
</div>
</template>
</div> </div>
</template> </template>
<style scoped> <style scoped>
.cards_container::before { .list-enter-active,
.list-leave-active {
transition: all v-bind('animationSpeed') ease;
}
.list-leave-to,
.list-enter-from {
opacity: 0;
transform: translateX(30px);
}
.cards_container.wrapped:before {
height: calc(250px - 10px); height: calc(250px - 10px);
display: block; display: block;
content: ""; content: "";
width: 0; width: 0;
} }
.rotate {
rotate: 360deg;
}
.cards_container { .cards_container {
display: flex; display: flex;
flex-direction: column-reverse; flex-direction: column-reverse;
justify-content: center; justify-content: center;
min-width: 200px; min-width: 200px;
transition: rotate v-bind('shuffleAnimationSpeed') ease;
} }
.empty { .empty {
+1 -2
View File
@@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import goStore from '~/netcode';
const displayOptions = ref(false) const displayOptions = ref(false)
@@ -7,7 +6,7 @@ const displayOptions = ref(false)
<template> <template>
<div :class="`card_overlay`" ref="card"> <div :class="`card_overlay`" ref="card">
<img class="settings_button" src="/images/settings.png" alt="settings" @click="displayOptions = true"/> <img class="settings_button" src="/images/settings.png" alt="settings" @click="displayOptions = true" />
</div> </div>
<OptionsDialog :isVisible="displayOptions" @close="displayOptions = false" /> <OptionsDialog :isVisible="displayOptions" @close="displayOptions = false" />
</template> </template>
+12
View File
@@ -32,6 +32,18 @@ const close = () => {
<div class="dialog-body"> <div class="dialog-body">
<button @click="settingsStore.switchCardStyles">Toggle Card style</button> <button @click="settingsStore.switchCardStyles">Toggle Card style</button>
</div> </div>
<div class="dialog-footer">
<span>{{ settingsStore.cardStyle }}</span>
</div>
<div class="dialog-header">
<span>Animation Speed</span>
</div>
<div class="dialog-body">
<input type="range" min="50" max="250" step="25" v-model="settingsStore.animationSpeed">
</div>
<div class="dialog-footer">
<span>{{ settingsStore.animationSpeed }}ms</span>
</div>
<div class="dialog-header"> <div class="dialog-header">
<h3>Graphics</h3> <h3>Graphics</h3>
</div> </div>
+13 -18
View File
@@ -118,11 +118,14 @@ function checkEndTurn() {
make Discard make Discard
</button> </button>
</div> --> </div> -->
<br /> <!-- <br /> -->
<div class="cards_container"> <CardsGrouped :container="player.board" :wrapped="false">
<!-- HAND --> </CardsGrouped>
<!-- <template v-if="isSelf">
<!-- <div class="cards_container"> -->
<!-- HAND -->
<!-- <template v-if="isSelf">
<CardPreview :card_id="c?.card_id" v-for="c in props.player.hand" @click="c && playCard(c)"> <CardPreview :card_id="c?.card_id" v-for="c in props.player.hand" @click="c && playCard(c)">
<button <button
v-if="props.player.turn && c && isSelf && (props.player.turn.discard_markers + props.player.turn.fuck_u_markers) > 0" v-if="props.player.turn && c && isSelf && (props.player.turn.discard_markers + props.player.turn.fuck_u_markers) > 0"
@@ -132,12 +135,12 @@ function checkEndTurn() {
</CardPreview> </CardPreview>
</template> --> </template> -->
<!-- BOARD --> <!-- BOARD -->
<CardPreview :card_id="c.cardId" v-for="c in props.player.board.cards" <!-- <CardPreview :card_id="c.cardId" v-for="c in props.player.board.cards"
@click="console.log/*lockCard(c)*/" @click="console.log/*lockCard(c)*/"
:locked="/*props.player.turn && c.uuid in props.player.turn.cards_locked*/ false"> :locked="/*props.player.turn && c.uuid in props.player.turn.cards_locked*/ false"> -->
<!-- <template v-if="c && isSelf && isPlayerTurn && props.player.turn"> <!-- <template v-if="c && isSelf && isPlayerTurn && props.player.turn">
// Card Locked // Card Locked
<template v-if="c.uuid in props.player.turn.cards_locked"> <template v-if="c.uuid in props.player.turn.cards_locked">
<template v-for="e in clientStore.maskedServerEffects"> <template v-for="e in clientStore.maskedServerEffects">
@@ -190,8 +193,8 @@ function checkEndTurn() {
STUN STUN
</button> </button>
</template> --> </template> -->
</CardPreview> <!-- </CardPreview> -->
</div> <!-- </div> -->
</div> </div>
</div> </div>
</template> </template>
@@ -271,14 +274,6 @@ function checkEndTurn() {
} }
.discard_overlay {
grid-template-areas:
"player_stats player_stats"
"stack player";
justify-items: center;
}
#current_player_board { #current_player_board {
grid-area: player; grid-area: player;
} }
+13 -5
View File
@@ -1,14 +1,22 @@
<script setup lang="ts"> <script setup lang="ts">
import goStore, { useEffect, playCard, playAllCards, discard, lockCard, heal, damage_champion, damage_team, endTurn } from '~/netcode'; import type { Container } from '~/netcode/interfaces';
export interface Props {
container: Container
}
const props = defineProps<Props>()
</script> </script>
<template> <template>
<div class="cards_container" id="self_hand"> <div class="cards_container" id="self_hand">
<CardPreview :card_id="c?.card_id" v-for=" c in goStore.self?.hand " @click="c && playCard(c)"> <!-- <CardPreview :card_id="c.cardId" v-for="c in container.cards "> -->
<button v-if="c && goStore.self?.turn && (goStore.self.turn.fuck_u_markers ?? 0) > 0" <!-- <button v-if="c && goStore.self?.turn && (goStore.self.turn.fuck_u_markers ?? 0) > 0"
@click.stop="discard(c)">DISCARD</button> @click.stop="discard(c)">DISCARD</button> -->
</CardPreview> <!-- </CardPreview> -->
<CardsGrouped :container="container" :wrapped="false">
</CardsGrouped>
</div> </div>
</template> </template>
+8 -5
View File
@@ -1,12 +1,15 @@
import type { Container } from "./interfaces"; export function delay(delay: number) {
import type { CardParser } from "./interfaces/cards"; return new Promise((resolve) => {
setTimeout(resolve, delay);
});
}
export type ContainerHandler = { export type ContainerHandler = {
populateContainer: () => void; populateContainer: () => void;
shuffleContainer: () => void; shuffleContainer: () => void;
getCardsPosition: (cards: string) => any; getCardsPosition: (cards: string) => any;
hideCards: (cards: CardParser[]) => void; startAnimation: () => void;
showCards: (cards: CardParser[]) => void; endAnimation: () => void;
}; };
export const containerEvents = new Map<string, ContainerHandler>(); export const containerEvents = reactive(new Map<string, ContainerHandler>());
+50 -22
View File
@@ -1,10 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import LoadingScreen from '~/components/LoadingScreen.vue'; import LoadingScreen from '~/components/LoadingScreen.vue';
import { subscribe } from '~/netcode'; import { subscribe } from '~/netcode';
import { containerEvents } from '~/netcode/events'; import { containerEvents, delay } from '~/netcode/events';
import { type Container, type Game, type Player } from '~/netcode/interfaces'; import { type Container, type Game, type Player } from '~/netcode/interfaces';
const config = useRuntimeConfig() const config = useRuntimeConfig()
const settingsStore = useSettingsStore()
const route = useRoute() const route = useRoute()
const gameId = route.params.id const gameId = route.params.id
@@ -41,8 +42,24 @@ const containers = computed<Record<string, Container>>(() => ({
const eventSource = subscribe(`/games/${gameId}/subscribe`) const eventSource = subscribe(`/games/${gameId}/subscribe`)
const actions = ref<(() => Promise<any>)[]>([])
eventSource.addEventListener("message", (message) => { function queueAction(callback: (() => Promise<any>)) {
actions.value.push(callback)
if (actions.value.length == 1) {
execAction(callback)
}
}
async function execAction(callback: (() => Promise<any>)) {
await callback()
actions.value.shift()
if (actions.value.length > 0) {
execAction(actions.value[0])
}
}
eventSource.addEventListener("message", async (message) => {
const data = JSON.parse(message.data) const data = JSON.parse(message.data)
console.log(data) console.log(data)
if (data.type == 'start') { if (data.type == 'start') {
@@ -50,23 +67,36 @@ eventSource.addEventListener("message", (message) => {
} else if (data.type == "populateContainer") { } else if (data.type == "populateContainer") {
throw new Error("not implemented") throw new Error("not implemented")
} else if (data.type == "shuffleContainer") { } else if (data.type == "shuffleContainer") {
containerEvents.get(data.container._id)?.shuffleContainer() queueAction(async () => {
await containerEvents.get(data.container)?.shuffleContainer()
})
} else if (data.type == "distributeCards") { } else if (data.type == "distributeCards") {
containerEvents.get(data.from._id)?.hideCards(data.cards) // containerEvents.get(data.from)?.getCardsPosition(data.cards)
containerEvents.get(data.from._id)?.getCardsPosition(data.cards)
queueAction(async () => {
containerEvents.get(data.from)?.startAnimation()
containerEvents.get(data.to)?.startAnimation()
})
const fromContainer = containers.value[data.from as string] const fromContainer = containers.value[data.from as string]
const toContainer = containers.value[data.to as string] const toContainer = containers.value[data.to as string]
for (const card of data.cards) { for (const card of data.cards) {
const index = fromContainer.cards.findIndex(c => c._id == card._id) queueAction(async () => {
fromContainer.cards.splice(index, 1) const index = fromContainer.cards.findIndex(c => c._id == card._id)
} fromContainer.cards.splice(index, 1)
await delay(settingsStore.animationSpeed)
})
for (const card of data.cards) { queueAction(async () => {
toContainer.cards.push(card) toContainer.cards.push(card)
await delay(settingsStore.animationSpeed)
})
} }
queueAction(async () => {
containerEvents.get(data.from)?.endAnimation()
containerEvents.get(data.to)?.endAnimation()
await delay(settingsStore.animationSpeed * 2)
})
} else if (data.type == "endTurn") { } else if (data.type == "endTurn") {
throw new Error("not implemented") throw new Error("not implemented")
@@ -79,8 +109,6 @@ const authStore = useAuthStore()
const playerList = computed(() => game.value!.teams.reduce((acc, t) => acc.concat(t.players), [] as Player[])) const playerList = computed(() => game.value!.teams.reduce((acc, t) => acc.concat(t.players), [] as Player[]))
const selfPlayer = computed(() => authStore.logged ? playerList.value?.find(p => p.user.userId == authStore.selfUser.userId) : undefined) const selfPlayer = computed(() => authStore.logged ? playerList.value?.find(p => p.user.userId == authStore.selfUser.userId) : undefined)
// TODO : current turn sound // TODO : current turn sound
// TODO : winner screen // TODO : winner screen
@@ -135,32 +163,32 @@ onUnmounted(() => {
<AnimatedBackground @ready="loaded = true"></AnimatedBackground> <AnimatedBackground @ready="loaded = true"></AnimatedBackground>
<div id="stack_discard"> <div id="stack_discard">
<div id="stack"> <div id="stack">
<CardsGrouped :container="focusedPlayer.stack"> <CardsGrouped :container="focusedPlayer.stack" :wrapped="true" :hidden="true">
</CardsGrouped> </CardsGrouped>
</div> </div>
<div id="discard" :class="{ invisible: discard_unwrapped }" @click="() => discard_unwrapped = true"> <div id="discard" :class="{ invisible: discard_unwrapped }" @click="() => discard_unwrapped = true">
<CardsGrouped :container="focusedPlayer.discard"> <CardsGrouped :container="focusedPlayer.discard" :wrapped="true">
</CardsGrouped> </CardsGrouped>
</div> </div>
</div> </div>
<!-- <MarketCards :container="game.market"></MarketCards> --> <!-- <MarketCards :container="game.market"></MarketCards> -->
<div id="player_list_container"> <!-- <div id="player_list_container">
<div id="player_list"> <div id="player_list">
<!-- <PlayerListElement v-for="p in playerList" :player="p" @click="focusPlayer(p)" :focused="focusedPlayer"> <PlayerListElement v-for="p in playerList" :player="p" @click="focusPlayer(p)" :focused="focusedPlayer">
</PlayerListElement> --> </PlayerListElement>
</div> </div>
</div> </div> -->
<div id="current_player"> <div id="current_player">
<PlayerSlot v-if="focusedPlayer" :player="focusedPlayer" :game="game!"></PlayerSlot> <PlayerSlot v-if="focusedPlayer" :player="focusedPlayer" :game="game!"></PlayerSlot>
</div> </div>
<ResultDialog :isVisible="showResults" :won="isWinner" :players="playerList" @close="showResults = false"> <ResultDialog :isVisible="showResults" :won="isWinner" :players="playerList" @close="showResults = false">
</ResultDialog> </ResultDialog>
<!-- <GlobalOverlay></GlobalOverlay> <GlobalOverlay></GlobalOverlay>
<SelfView></SelfView> --> <SelfView v-if="selfPlayer" :container="selfPlayer.hand"></SelfView>
<LoadingScreen v-if="!loaded"></LoadingScreen> <LoadingScreen v-if="!loaded"></LoadingScreen>
</div> </div>
</template> </template>
+1
View File
@@ -8,6 +8,7 @@ enum CardStyles {
export const useSettingsStore = defineStore("settingstore", { export const useSettingsStore = defineStore("settingstore", {
state: () => ({ state: () => ({
cardStyle: CardStyles.HERON, cardStyle: CardStyles.HERON,
animationSpeed: 100,
shaderQuality: 3, shaderQuality: 3,
shaderFramerate: 10, shaderFramerate: 10,
shaderPixelated: true, shaderPixelated: true,