feat: animated button selector

This commit is contained in:
2025-11-12 17:57:31 +01:00
parent 92c621092d
commit 5ac696f11b
8 changed files with 122 additions and 55 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -2,11 +2,29 @@
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";
import Selector from "./Selector.vue";
type ButtonType = "game" | "downloadPlay" | "pictochat"; type ButtonConfig = {
x: number;
y: number;
sx: number;
sy: number;
sw: number;
sh: number;
};
const BUTTONS_CONFIG = {
game: { x: 33, y: 25, sx: 31, sy: 23, sw: 193, sh: 49 },
pictochat: { x: 32, y: 72, sx: 31, sy: 71, sw: 97, sh: 49 },
downloadPlay: { x: 128, y: 72, sx: 127, sy: 71, sw: 97, sh: 49 },
} as const satisfies Record<string, ButtonConfig>;
type ButtonType = keyof typeof BUTTONS_CONFIG;
const selectedButton = ref<ButtonType>("game"); const selectedButton = ref<ButtonType>("game");
const nextBottomButton = ref<Exclude<ButtonType, "game">>("downloadPlay"); const nextBottomButton = ref<"downloadPlay" | "pictochat">("pictochat");
const selectorPosition = computed(() => BUTTONS_CONFIG[selectedButton.value]);
const handleKeyPress = (event: KeyboardEvent) => { const handleKeyPress = (event: KeyboardEvent) => {
switch (event.key) { switch (event.key) {
@@ -49,8 +67,7 @@ const handleKeyPress = (event: KeyboardEvent) => {
case "Enter": case "Enter":
case " ": case " ":
event.preventDefault(); throw "Not implemented";
throw new Error("Not implemented");
} }
}; };
@@ -64,7 +81,20 @@ onUnmounted(() => {
</script> </script>
<template> <template>
<GameButton :selected="selectedButton === 'game'" /> <GameButton :x="BUTTONS_CONFIG.game.x" :y="BUTTONS_CONFIG.game.y" />
<DownloadPlayButton :selected="selectedButton === 'downloadPlay'" /> <DownloadPlayButton
<PictochatButton :selected="selectedButton === 'pictochat'" /> :x="BUTTONS_CONFIG.downloadPlay.x"
:y="BUTTONS_CONFIG.downloadPlay.y"
/>
<PictochatButton
:x="BUTTONS_CONFIG.pictochat.x"
:y="BUTTONS_CONFIG.pictochat.y"
/>
<Selector
:x="selectorPosition.sx"
:y="selectorPosition.sy"
:width="selectorPosition.sw"
:height="selectorPosition.sh"
/>
</template> </template>

View File

@@ -1,22 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps<{ const props = defineProps<{
selected: boolean; x: number;
y: number;
}>(); }>();
const buttonImage = useTemplateRef("buttonImage"); const buttonImage = useTemplateRef("buttonImage");
const selectorImage = useTemplateRef("selectorImage");
const x = 128;
const y = 72;
useRender((ctx) => { useRender((ctx) => {
if (!buttonImage.value || !selectorImage.value) return; if (!buttonImage.value) return;
ctx.drawImage(buttonImage.value, x, y); ctx.drawImage(buttonImage.value, props.x, props.y);
if (props.selected) {
ctx.drawImage(selectorImage.value, x - 1, y - 1);
}
}); });
</script> </script>
@@ -26,9 +19,4 @@ useRender((ctx) => {
src="/assets/images/home/bottom-screen/buttons/downloadPlay.png" src="/assets/images/home/bottom-screen/buttons/downloadPlay.png"
hidden hidden
/> />
<img
ref="selectorImage"
src="/assets/images/home/bottom-screen/buttons/smallSelector.png"
hidden
/>
</template> </template>

View File

@@ -1,22 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps<{ const props = defineProps<{
selected: boolean; x: number;
y: number;
}>(); }>();
const buttonImage = useTemplateRef("buttonImage"); const buttonImage = useTemplateRef("buttonImage");
const selectorImage = useTemplateRef("selectorImage");
const x = 33;
const y = 25;
useRender((ctx) => { useRender((ctx) => {
if (!buttonImage.value || !selectorImage.value) return; if (!buttonImage.value) return;
ctx.drawImage(buttonImage.value, x, y); ctx.drawImage(buttonImage.value, props.x, props.y);
if (props.selected) {
ctx.drawImage(selectorImage.value, x - 2, y - 2);
}
}); });
</script> </script>
@@ -26,9 +19,4 @@ useRender((ctx) => {
src="/assets/images/home/bottom-screen/buttons/game.png" src="/assets/images/home/bottom-screen/buttons/game.png"
hidden hidden
/> />
<img
ref="selectorImage"
src="/assets/images/home/bottom-screen/buttons/largeSelector.png"
hidden
/>
</template> </template>

View File

@@ -1,22 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps<{ const props = defineProps<{
selected: boolean; x: number;
y: number;
}>(); }>();
const buttonImage = useTemplateRef("buttonImage"); const buttonImage = useTemplateRef("buttonImage");
const selectorImage = useTemplateRef("selectorImage");
const x = 32;
const y = 72;
useRender((ctx) => { useRender((ctx) => {
if (!buttonImage.value || !selectorImage.value) return; if (!buttonImage.value) return;
ctx.drawImage(buttonImage.value, x, y); ctx.drawImage(buttonImage.value, props.x, props.y);
if (props.selected) {
ctx.drawImage(selectorImage.value, x - 1, y - 1);
}
}); });
</script> </script>
@@ -26,9 +19,4 @@ useRender((ctx) => {
src="/assets/images/home/bottom-screen/buttons/pictochat.png" src="/assets/images/home/bottom-screen/buttons/pictochat.png"
hidden hidden
/> />
<img
ref="selectorImage"
src="/assets/images/home/bottom-screen/buttons/smallSelector.png"
hidden
/>
</template> </template>

View File

@@ -0,0 +1,73 @@
<script setup lang="ts">
const props = defineProps<{
x: number;
y: number;
width: number;
height: number;
}>();
const cornerImage = useTemplateRef("cornerImage");
let currentX = props.x;
let currentY = props.y;
let currentWidth = props.width;
let currentHeight = props.height;
const animationSpeed = 0.25;
useRender((ctx) => {
if (!cornerImage.value) return;
const dx = props.x - currentX;
const dy = props.y - currentY;
const dw = props.width - currentWidth;
const dh = props.height - currentHeight;
if (
Math.abs(dx) < 0.5 &&
Math.abs(dy) < 0.5 &&
Math.abs(dw) < 0.5 &&
Math.abs(dh) < 0.5
) {
currentX = props.x;
currentY = props.y;
currentWidth = props.width;
currentHeight = props.height;
} else {
currentX += dx * animationSpeed;
currentY += dy * animationSpeed;
currentWidth += dw * animationSpeed;
currentHeight += dh * animationSpeed;
}
const x = Math.floor(currentX);
const y = Math.floor(currentY);
const w = Math.floor(currentWidth);
const h = Math.floor(currentHeight);
ctx.drawImage(cornerImage.value, x, y);
ctx.save();
ctx.scale(-1, 1);
ctx.drawImage(cornerImage.value, -(x + w), y);
ctx.restore();
ctx.save();
ctx.scale(1, -1);
ctx.drawImage(cornerImage.value, x, -(y + h));
ctx.restore();
ctx.save();
ctx.scale(-1, -1);
ctx.drawImage(cornerImage.value, -(x + w), -(y + h));
ctx.restore();
});
</script>
<template>
<img
ref="cornerImage"
src="/assets/images/home/bottom-screen/buttons/corner.png"
hidden
/>
</template>