feat: animate home screen buttons on click
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import gsap from "gsap";
|
||||||
import GameButton from "./GameButton.vue";
|
import GameButton from "./GameButton.vue";
|
||||||
import PictochatButton from "./PictochatButton.vue";
|
import PictochatButton from "./PictochatButton.vue";
|
||||||
import DownloadPlayButton from "./DownloadPlayButton.vue";
|
import DownloadPlayButton from "./DownloadPlayButton.vue";
|
||||||
@@ -26,15 +27,44 @@ const nextBottomButton = ref<"downloadPlay" | "pictochat">("pictochat");
|
|||||||
|
|
||||||
const selectorPosition = computed(() => BUTTONS_CONFIG[selectedButton.value]);
|
const selectorPosition = computed(() => BUTTONS_CONFIG[selectedButton.value]);
|
||||||
|
|
||||||
|
const animationPercentage = ref(0);
|
||||||
|
|
||||||
|
const getButtonOffset = (button: ButtonType) => {
|
||||||
|
if (selectedButton.value === button) return animationPercentage.value * -200;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOpacity = () => (1 - animationPercentage.value) * 100;
|
||||||
|
|
||||||
useScreenClick((x: number, y: number) => {
|
useScreenClick((x: number, y: number) => {
|
||||||
for (const [buttonName, config] of Object.entries(BUTTONS_CONFIG)) {
|
if (animationPercentage.value != 0) return;
|
||||||
|
|
||||||
|
for (const [buttonName, config] of Object.entries(BUTTONS_CONFIG) as [
|
||||||
|
ButtonType,
|
||||||
|
ButtonConfig,
|
||||||
|
][]) {
|
||||||
if (
|
if (
|
||||||
x >= config.sx &&
|
x >= config.sx &&
|
||||||
x <= config.sx + config.sw &&
|
x <= config.sx + config.sw &&
|
||||||
y >= config.sy &&
|
y >= config.sy &&
|
||||||
y <= config.sy + config.sh
|
y <= config.sy + config.sh
|
||||||
) {
|
) {
|
||||||
selectedButton.value = buttonName as ButtonType;
|
if (selectedButton.value === buttonName) {
|
||||||
|
gsap.fromTo(
|
||||||
|
animationPercentage,
|
||||||
|
{ value: 0 },
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
duration: 0.35,
|
||||||
|
ease: "none",
|
||||||
|
onComplete: () => {
|
||||||
|
throw new Error("not implemented: onComplete in button click");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
selectedButton.value = buttonName;
|
||||||
|
}
|
||||||
|
|
||||||
if (buttonName === "pictochat" || buttonName === "downloadPlay") {
|
if (buttonName === "pictochat" || buttonName === "downloadPlay") {
|
||||||
nextBottomButton.value = buttonName;
|
nextBottomButton.value = buttonName;
|
||||||
@@ -99,14 +129,20 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<GameButton :x="BUTTONS_CONFIG.game.x" :y="BUTTONS_CONFIG.game.y" />
|
<GameButton
|
||||||
|
:x="BUTTONS_CONFIG.game.x"
|
||||||
|
:y="BUTTONS_CONFIG.game.y + getButtonOffset('game')"
|
||||||
|
:opacity="getOpacity()"
|
||||||
|
/>
|
||||||
<DownloadPlayButton
|
<DownloadPlayButton
|
||||||
:x="BUTTONS_CONFIG.downloadPlay.x"
|
:x="BUTTONS_CONFIG.downloadPlay.x"
|
||||||
:y="BUTTONS_CONFIG.downloadPlay.y"
|
:y="BUTTONS_CONFIG.downloadPlay.y + getButtonOffset('downloadPlay')"
|
||||||
|
:opacity="getOpacity()"
|
||||||
/>
|
/>
|
||||||
<PictochatButton
|
<PictochatButton
|
||||||
:x="BUTTONS_CONFIG.pictochat.x"
|
:x="BUTTONS_CONFIG.pictochat.x"
|
||||||
:y="BUTTONS_CONFIG.pictochat.y"
|
:y="BUTTONS_CONFIG.pictochat.y + getButtonOffset('pictochat')"
|
||||||
|
:opacity="getOpacity()"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Selector
|
<Selector
|
||||||
@@ -114,5 +150,6 @@ onUnmounted(() => {
|
|||||||
:y="selectorPosition.sy"
|
:y="selectorPosition.sy"
|
||||||
:width="selectorPosition.sw"
|
:width="selectorPosition.sw"
|
||||||
:height="selectorPosition.sh"
|
:height="selectorPosition.sh"
|
||||||
|
:opacity="getOpacity()"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
opacity: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const buttonImage = useTemplateRef("buttonImage");
|
const buttonImage = useTemplateRef("buttonImage");
|
||||||
@@ -9,6 +10,7 @@ const buttonImage = useTemplateRef("buttonImage");
|
|||||||
useRender((ctx) => {
|
useRender((ctx) => {
|
||||||
if (!buttonImage.value) return;
|
if (!buttonImage.value) return;
|
||||||
|
|
||||||
|
ctx.globalAlpha = props.opacity / 100;
|
||||||
ctx.drawImage(buttonImage.value, props.x, props.y);
|
ctx.drawImage(buttonImage.value, props.x, props.y);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
opacity: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const buttonImage = useTemplateRef("buttonImage");
|
const buttonImage = useTemplateRef("buttonImage");
|
||||||
@@ -9,6 +10,7 @@ const buttonImage = useTemplateRef("buttonImage");
|
|||||||
useRender((ctx) => {
|
useRender((ctx) => {
|
||||||
if (!buttonImage.value) return;
|
if (!buttonImage.value) return;
|
||||||
|
|
||||||
|
ctx.globalAlpha = props.opacity / 100;
|
||||||
ctx.drawImage(buttonImage.value, props.x, props.y);
|
ctx.drawImage(buttonImage.value, props.x, props.y);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
opacity: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const buttonImage = useTemplateRef("buttonImage");
|
const buttonImage = useTemplateRef("buttonImage");
|
||||||
@@ -9,6 +10,7 @@ const buttonImage = useTemplateRef("buttonImage");
|
|||||||
useRender((ctx) => {
|
useRender((ctx) => {
|
||||||
if (!buttonImage.value) return;
|
if (!buttonImage.value) return;
|
||||||
|
|
||||||
|
ctx.globalAlpha = props.opacity / 100;
|
||||||
ctx.drawImage(buttonImage.value, props.x, props.y);
|
ctx.drawImage(buttonImage.value, props.x, props.y);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const props = defineProps<{
|
|||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
opacity: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const cornerImage = useTemplateRef("cornerImage");
|
const cornerImage = useTemplateRef("cornerImage");
|
||||||
@@ -45,6 +46,8 @@ useRender((ctx) => {
|
|||||||
const w = Math.floor(currentWidth);
|
const w = Math.floor(currentWidth);
|
||||||
const h = Math.floor(currentHeight);
|
const h = Math.floor(currentHeight);
|
||||||
|
|
||||||
|
ctx.globalAlpha = props.opacity / 100;
|
||||||
|
|
||||||
ctx.drawImage(cornerImage.value, x, y);
|
ctx.drawImage(cornerImage.value, x, y);
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"lint": "eslint --fix --cache ."
|
"lint": "eslint --fix --cache ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"gsap": "^3.13.0",
|
||||||
"nuxt": "^4.2.1",
|
"nuxt": "^4.2.1",
|
||||||
"vue": "^3.5.22",
|
"vue": "^3.5.22",
|
||||||
"vue-router": "^4.6.3"
|
"vue-router": "^4.6.3"
|
||||||
|
|||||||
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@@ -7,6 +7,9 @@ settings:
|
|||||||
importers:
|
importers:
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
gsap:
|
||||||
|
specifier: ^3.13.0
|
||||||
|
version: 3.13.0
|
||||||
nuxt:
|
nuxt:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.24)(db0@0.3.4)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.8.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.53.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.2.2(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.1))(yaml@2.8.1)
|
version: 4.2.1(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.24)(db0@0.3.4)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.8.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.53.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.2.2(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.1))(yaml@2.8.1)
|
||||||
@@ -3698,6 +3701,12 @@ packages:
|
|||||||
integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==,
|
integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gsap@3.13.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw==,
|
||||||
|
}
|
||||||
|
|
||||||
gzip-size@7.0.0:
|
gzip-size@7.0.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -8869,6 +8878,8 @@ snapshots:
|
|||||||
|
|
||||||
graphemer@1.4.0: {}
|
graphemer@1.4.0: {}
|
||||||
|
|
||||||
|
gsap@3.13.0: {}
|
||||||
|
|
||||||
gzip-size@7.0.0:
|
gzip-size@7.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
duplexer: 0.1.2
|
duplexer: 0.1.2
|
||||||
|
|||||||
Reference in New Issue
Block a user