feat(nds): add audio in all menus
This commit is contained in:
@@ -1,58 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
const { onRender } = useScreen();
|
||||
const { assets } = useAssets();
|
||||
|
||||
const app = useAppStore();
|
||||
const store = useHomeStore();
|
||||
const { assets } = useAssets();
|
||||
const tickClock = useClockTick();
|
||||
|
||||
const CENTER_X = 63;
|
||||
const CENTER_Y = 95;
|
||||
|
||||
function drawLine(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
x0: number,
|
||||
y0: number,
|
||||
x1: number,
|
||||
y1: number,
|
||||
width: number,
|
||||
) {
|
||||
const dx = Math.abs(x1 - x0);
|
||||
const dy = Math.abs(y1 - y0);
|
||||
const sx = x0 < x1 ? 1 : -1;
|
||||
const sy = y0 < y1 ? 1 : -1;
|
||||
let err = dx - dy;
|
||||
|
||||
const drawThickPixel = (x: number, y: number) => {
|
||||
const isVertical = dy > dx;
|
||||
|
||||
if (width === 1) {
|
||||
ctx.fillRect(x, y, 1, 1);
|
||||
} else if (isVertical) {
|
||||
const offset = Math.floor((width - 1) / 2);
|
||||
ctx.fillRect(x - offset, y, width, 1);
|
||||
} else {
|
||||
const offset = Math.floor((width - 1) / 2);
|
||||
ctx.fillRect(x, y - offset, 1, width);
|
||||
}
|
||||
};
|
||||
|
||||
while (true) {
|
||||
drawThickPixel(x0, y0);
|
||||
|
||||
if (x0 === x1 && y0 === y1) break;
|
||||
|
||||
const e2 = 2 * err;
|
||||
if (e2 > -dy) {
|
||||
err -= dy;
|
||||
x0 += sx;
|
||||
}
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRender((ctx) => {
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.topScreenOpacity
|
||||
@@ -66,7 +22,9 @@ onRender((ctx) => {
|
||||
: store.isOutro && store.outro.animateTop
|
||||
? store.outro.stage2Opacity
|
||||
: 1;
|
||||
|
||||
const now = new Date();
|
||||
tickClock(now);
|
||||
|
||||
const renderHand = (
|
||||
value: number,
|
||||
|
||||
@@ -58,6 +58,8 @@ const BIG_CIRCLE_DURATION = 0.09;
|
||||
const POST_DURATION = 0.07;
|
||||
|
||||
const startButtonAnimation = (type: ButtonType) => {
|
||||
assets.audio.pkmnButton.play();
|
||||
|
||||
const anim: ButtonAnimation = {
|
||||
type,
|
||||
position: BUTTONS[type].position,
|
||||
|
||||
@@ -53,13 +53,20 @@ useKeyDown(({ key }) => {
|
||||
|
||||
switch (key) {
|
||||
case "NDS_UP":
|
||||
selectedOption = "yes";
|
||||
if (selectedOption !== "yes") {
|
||||
selectedOption = "yes";
|
||||
assets.audio.pkmnSelector.play();
|
||||
}
|
||||
break;
|
||||
case "NDS_DOWN":
|
||||
selectedOption = "no";
|
||||
if (selectedOption !== "no") {
|
||||
selectedOption = "no";
|
||||
assets.audio.pkmnSelector.play();
|
||||
}
|
||||
break;
|
||||
case "NDS_A":
|
||||
case "NDS_START":
|
||||
assets.audio.pkmnSelector.play();
|
||||
setTimeout(() => {
|
||||
if (selectedOption === "yes") store.visitProject();
|
||||
store.showConfirmationPopup = false;
|
||||
@@ -90,12 +97,14 @@ onClick((x, y) => {
|
||||
const ACTIVATION_DELAY = 50;
|
||||
|
||||
if (rectContains([198, 105, 50, 14], [x, y])) {
|
||||
assets.audio.pkmnSelector.play();
|
||||
selectedOption = "yes";
|
||||
setTimeout(() => {
|
||||
store.visitProject();
|
||||
store.showConfirmationPopup = false;
|
||||
}, ACTIVATION_DELAY);
|
||||
} else if (rectContains([198, 121, 50, 14], [x, y])) {
|
||||
assets.audio.pkmnSelector.play();
|
||||
selectedOption = "no";
|
||||
setTimeout(() => (store.showConfirmationPopup = false), ACTIVATION_DELAY);
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ const handleReset = () => {
|
||||
|
||||
const handleVisitAll = () => {
|
||||
if (isAnimating.value) return;
|
||||
assets.audio.menuOpen.play();
|
||||
achievementsScreen.animateFadeToBlackIntro();
|
||||
};
|
||||
|
||||
|
||||
@@ -71,11 +71,17 @@ const { select, selected, pressed, selectorPosition } = useButtonNavigation({
|
||||
onActivate: (buttonName) => {
|
||||
if (isSubMenu(buttonName)) {
|
||||
store.openSubMenu(buttonName);
|
||||
} else if (buttonName === "touchScreen") {
|
||||
store.openSubMenu("touchScreenTapTap");
|
||||
} else {
|
||||
if (!store.menuExpanded) {
|
||||
assets.audio.settingsMenuOpen.play();
|
||||
} else {
|
||||
assets.audio.tinyClick.play(0.8);
|
||||
}
|
||||
if (buttonName === "options") select("optionsLanguage");
|
||||
if (buttonName === "clock") select("clockAchievements");
|
||||
if (buttonName === "user") select("userUserName");
|
||||
if (buttonName === "touchScreen") store.openSubMenu("touchScreenTapTap");
|
||||
}
|
||||
},
|
||||
navigation: {
|
||||
@@ -156,6 +162,21 @@ const { select, selected, pressed, selectorPosition } = useButtonNavigation({
|
||||
}
|
||||
return true;
|
||||
},
|
||||
onNavigate: (buttonName) => {
|
||||
if (isMainMenu(buttonName)) {
|
||||
if (store.menuExpanded) {
|
||||
assets.audio.settingsMenuClose.play();
|
||||
} else {
|
||||
assets.audio.tinyClick.play(0.8);
|
||||
}
|
||||
} else {
|
||||
if (!store.menuExpanded) {
|
||||
assets.audio.settingsMenuOpen.play();
|
||||
} else {
|
||||
assets.audio.tinyClick.play(0.8);
|
||||
}
|
||||
}
|
||||
},
|
||||
disabled: computed(
|
||||
() =>
|
||||
store.currentSubMenu !== null ||
|
||||
@@ -256,12 +277,17 @@ const handleActivateA = () => {
|
||||
|
||||
if (isSubMenu(selected.value)) {
|
||||
store.openSubMenu(selected.value);
|
||||
} else if (selected.value === "touchScreen") {
|
||||
store.openSubMenu("touchScreenTapTap");
|
||||
} else {
|
||||
if (!store.menuExpanded) {
|
||||
assets.audio.settingsMenuOpen.play();
|
||||
} else {
|
||||
assets.audio.tinyClick.play(0.8);
|
||||
}
|
||||
if (selected.value === "options") select("optionsLanguage");
|
||||
if (selected.value === "clock") select("clockAchievements");
|
||||
if (selected.value === "user") select("userUserName");
|
||||
if (selected.value === "touchScreen")
|
||||
store.openSubMenu("touchScreenTapTap");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -270,6 +296,7 @@ const handleActivateB = () => {
|
||||
return;
|
||||
|
||||
if (isSubmenuSelected.value) {
|
||||
assets.audio.settingsMenuClose.play();
|
||||
select(getParentMenu(selected.value));
|
||||
} else {
|
||||
store.animateOutro();
|
||||
|
||||
@@ -17,7 +17,7 @@ const handleActivateB = () => {
|
||||
onClosed: async (choice) => {
|
||||
if (choice === "A") {
|
||||
await animateOutro();
|
||||
store.closeSubMenu();
|
||||
store.closeSubMenu(true);
|
||||
}
|
||||
},
|
||||
keepButtonsDown: (choice) => choice === "A",
|
||||
@@ -460,6 +460,8 @@ const slide = (rowDir: number, colDir: number) => {
|
||||
);
|
||||
if (!changed) return;
|
||||
|
||||
assets.audio.type.play(0.35);
|
||||
|
||||
if (board.some((r) => r.some((c) => c >= 512))) {
|
||||
achievements.unlock("2048_score_512");
|
||||
}
|
||||
@@ -534,11 +536,20 @@ const slide = (rowDir: number, colDir: number) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (mergePairs.length > 0) {
|
||||
const highestMerge = Math.max(...mergePairs.map((p) => p.mergedValue));
|
||||
const boardMax = Math.max(0, ...beforeTiles.map((t) => t.value));
|
||||
if (highestMerge > boardMax) {
|
||||
assets.audio.duplicate.play(0.35);
|
||||
}
|
||||
}
|
||||
|
||||
const spawned = spawnTile();
|
||||
saveState();
|
||||
|
||||
if (isDead()) {
|
||||
buildTilesFromBoard();
|
||||
assets.audio.invalid.play();
|
||||
showRestartModal();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ const handleActivateA = () => {
|
||||
),
|
||||
onClosed: async () => {
|
||||
await animateOutro();
|
||||
store.closeSubMenu();
|
||||
store.closeSubMenu(true);
|
||||
},
|
||||
keepButtonsDown: true,
|
||||
timeout: 2000,
|
||||
|
||||
@@ -120,7 +120,7 @@ const handleActivateA = () => {
|
||||
: $t("settings.options.renderingMode.confirmation2d"),
|
||||
onClosed: async () => {
|
||||
await animateOutro();
|
||||
store.closeSubMenu();
|
||||
store.closeSubMenu(true);
|
||||
},
|
||||
keepButtonsDown: true,
|
||||
timeout: 2000,
|
||||
|
||||
@@ -6,6 +6,7 @@ const app = useAppStore();
|
||||
const store = useSettingsStore();
|
||||
const achievements = useAchievementsStore();
|
||||
const confirmationModal = useConfirmationModal();
|
||||
const { assets } = useAssets();
|
||||
|
||||
const { onRender, onClick } = useScreen();
|
||||
|
||||
@@ -161,7 +162,7 @@ const handleActivateB = () => {
|
||||
onClosed: async (choice) => {
|
||||
if (choice === "A") {
|
||||
await animateOutro();
|
||||
store.closeSubMenu();
|
||||
store.closeSubMenu(true);
|
||||
} else {
|
||||
state.value = "playing";
|
||||
}
|
||||
@@ -190,6 +191,7 @@ const handleActivateA = async () => {
|
||||
},
|
||||
});
|
||||
} else if (state.value === "waiting") {
|
||||
assets.audio.menuConfirmed.play();
|
||||
await gsap.to(animation, {
|
||||
areaOpacity: 0,
|
||||
duration: AREA_FADE_DURATION,
|
||||
@@ -264,7 +266,7 @@ const showDeathScreen = () => {
|
||||
resetGame();
|
||||
} else {
|
||||
await animateOutro();
|
||||
store.closeSubMenu();
|
||||
store.closeSubMenu(true);
|
||||
}
|
||||
},
|
||||
keepButtonsDown: (choice) => choice === "B",
|
||||
@@ -286,6 +288,7 @@ onClick((mx, my) => {
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance <= circle.radius) {
|
||||
assets.audio.type.play(0.35);
|
||||
rings.push({
|
||||
x: circle.x,
|
||||
y: circle.y,
|
||||
@@ -336,7 +339,10 @@ onRender((ctx, deltaTime) => {
|
||||
lives--;
|
||||
if (lives <= 0) {
|
||||
state.value = "ended";
|
||||
assets.audio.invalid.play();
|
||||
showDeathScreen();
|
||||
} else {
|
||||
assets.audio.eraser.play();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ const handleActivateA = () => {
|
||||
text,
|
||||
onClosed: async () => {
|
||||
await animateOutro();
|
||||
store.closeSubMenu();
|
||||
store.closeSubMenu(true);
|
||||
},
|
||||
keepButtonsDown: true,
|
||||
timeout: 2000,
|
||||
|
||||
@@ -156,16 +156,16 @@ useKeyDown(({ key }) => {
|
||||
|
||||
switch (key) {
|
||||
case "NDS_UP":
|
||||
if (selectedRow > 0) select(selectedCol, selectedRow - 1);
|
||||
if (selectedRow > 0) { assets.audio.tinyClick.play(0.8); select(selectedCol, selectedRow - 1); }
|
||||
break;
|
||||
case "NDS_RIGHT":
|
||||
if (selectedCol < GRID_SIZE - 1) select(selectedCol + 1, selectedRow);
|
||||
if (selectedCol < GRID_SIZE - 1) { assets.audio.tinyClick.play(0.8); select(selectedCol + 1, selectedRow); }
|
||||
break;
|
||||
case "NDS_DOWN":
|
||||
if (selectedRow < GRID_SIZE - 1) select(selectedCol, selectedRow + 1);
|
||||
if (selectedRow < GRID_SIZE - 1) { assets.audio.tinyClick.play(0.8); select(selectedCol, selectedRow + 1); }
|
||||
break;
|
||||
case "NDS_LEFT":
|
||||
if (selectedCol > 0) select(selectedCol - 1, selectedRow);
|
||||
if (selectedCol > 0) { assets.audio.tinyClick.play(0.8); select(selectedCol - 1, selectedRow); }
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -186,6 +186,7 @@ onClick((x, y) => {
|
||||
rectContains([0, 0, GRID_SIZE - 1, GRID_SIZE - 1], [col, row]) &&
|
||||
rectContains([0, 0, CELL_SIZE + 1, CELL_SIZE + 1], [cellLocalX, cellLocalY])
|
||||
) {
|
||||
assets.audio.tinyClick.play(0.8);
|
||||
select(col, row);
|
||||
}
|
||||
});
|
||||
@@ -288,7 +289,7 @@ const handleActivateA = () => {
|
||||
text: $t("settings.user.color.confirmation"),
|
||||
onClosed: async () => {
|
||||
await animateOutro();
|
||||
store.closeSubMenu();
|
||||
store.closeSubMenu(true);
|
||||
},
|
||||
keepButtonsDown: true,
|
||||
timeout: 2000,
|
||||
|
||||
@@ -120,7 +120,7 @@ const handleActivateB = async () => {
|
||||
onClosed: async (choice) => {
|
||||
if (choice === "A") {
|
||||
await animateOutro();
|
||||
store.closeSubMenu();
|
||||
store.closeSubMenu(true);
|
||||
} else {
|
||||
state.value = "alive";
|
||||
}
|
||||
@@ -160,6 +160,7 @@ const handleActivateA = () => {
|
||||
}
|
||||
|
||||
case "waiting": {
|
||||
atlas.audio.menuConfirmed.play();
|
||||
spawn();
|
||||
break;
|
||||
}
|
||||
@@ -207,6 +208,8 @@ const eat = () => {
|
||||
food.copy(randomFoodPos());
|
||||
score += 1;
|
||||
|
||||
atlas.audio.duplicate.play(0.35);
|
||||
|
||||
if (score === 40) {
|
||||
achievements.unlock("snake_score_25");
|
||||
}
|
||||
@@ -214,6 +217,7 @@ const eat = () => {
|
||||
|
||||
const die = () => {
|
||||
state.value = "dead";
|
||||
atlas.audio.invalid.play();
|
||||
};
|
||||
|
||||
const spawn = () => {
|
||||
@@ -351,6 +355,7 @@ useKeyDown(({ key }) => {
|
||||
|
||||
if (newDirection.clone().dot(direction) === 0) {
|
||||
nextDirection.copy(newDirection);
|
||||
atlas.audio.type.play(0.35);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,64 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
const { onRender } = useScreen();
|
||||
const { assets } = useAssets();
|
||||
|
||||
const app = useAppStore();
|
||||
const store = useSettingsStore();
|
||||
const { assets } = useAssets();
|
||||
const tickClock = useClockTick();
|
||||
|
||||
const CENTER_X = 63;
|
||||
const CENTER_Y = 95;
|
||||
|
||||
function drawLine(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
x0: number,
|
||||
y0: number,
|
||||
x1: number,
|
||||
y1: number,
|
||||
width: number,
|
||||
) {
|
||||
const dx = Math.abs(x1 - x0);
|
||||
const dy = Math.abs(y1 - y0);
|
||||
const sx = x0 < x1 ? 1 : -1;
|
||||
const sy = y0 < y1 ? 1 : -1;
|
||||
let err = dx - dy;
|
||||
|
||||
const drawThickPixel = (x: number, y: number) => {
|
||||
const isVertical = dy > dx;
|
||||
|
||||
if (width === 1) {
|
||||
ctx.fillRect(x, y, 1, 1);
|
||||
} else if (isVertical) {
|
||||
const offset = Math.floor((width - 1) / 2);
|
||||
ctx.fillRect(x - offset, y, width, 1);
|
||||
} else {
|
||||
const offset = Math.floor((width - 1) / 2);
|
||||
ctx.fillRect(x, y - offset, 1, width);
|
||||
}
|
||||
};
|
||||
|
||||
while (true) {
|
||||
drawThickPixel(x0, y0);
|
||||
|
||||
if (x0 === x1 && y0 === y1) break;
|
||||
|
||||
const e2 = 2 * err;
|
||||
if (e2 > -dy) {
|
||||
err -= dy;
|
||||
x0 += sx;
|
||||
}
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRender((ctx) => {
|
||||
ctx.translate(0, -16 + store.notificationYOffset / 3);
|
||||
|
||||
assets.images.home.topScreen.clock.draw(ctx, 13, 45);
|
||||
|
||||
const now = new Date();
|
||||
tickClock(now);
|
||||
|
||||
const renderHand = (
|
||||
value: number,
|
||||
|
||||
@@ -7,14 +7,18 @@ type Rect = [number, number, number, number];
|
||||
let atlasImage: HTMLImageElement | null = null;
|
||||
const modelCache = new Map<string, THREE.Group>();
|
||||
|
||||
const createAudio = (path: string) => ({
|
||||
play: () => {
|
||||
if (!import.meta.client) return;
|
||||
const audio = new Audio(path);
|
||||
const createAudio = (path: string) => {
|
||||
const source = import.meta.client ? new Audio(path) : null;
|
||||
return {
|
||||
play: (volume = 1) => {
|
||||
if (!source) return;
|
||||
const audio = source.cloneNode() as HTMLAudioElement;
|
||||
audio.volume = volume;
|
||||
audio.addEventListener("ended", () => audio.remove(), { once: true });
|
||||
audio.play().catch(() => {});
|
||||
},
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const loaded = ref(0);
|
||||
const total = ref({{TOTAL}});
|
||||
@@ -104,6 +108,7 @@ type ModelTree = {
|
||||
|
||||
export type AudioEntry = ReturnType<typeof createAudio>;
|
||||
|
||||
|
||||
type AudioTree = {
|
||||
[key: string]: AudioEntry | AudioTree;
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ export const useButtonNavigation = <T extends Record<string, Rect>>({
|
||||
initialButton,
|
||||
canClickButton,
|
||||
onActivate,
|
||||
onNavigate,
|
||||
navigation,
|
||||
disabled,
|
||||
selectorAnimation,
|
||||
@@ -13,6 +14,7 @@ export const useButtonNavigation = <T extends Record<string, Rect>>({
|
||||
initialButton: keyof T;
|
||||
canClickButton?: (buttonName: keyof T) => boolean;
|
||||
onActivate?: (buttonName: keyof T) => void;
|
||||
onNavigate?: (buttonName: keyof T) => void;
|
||||
navigation: Record<
|
||||
keyof T,
|
||||
{
|
||||
@@ -231,6 +233,12 @@ export const useButtonNavigation = <T extends Record<string, Rect>>({
|
||||
if (selectedButton.value === buttonName) {
|
||||
onActivate?.(buttonName);
|
||||
} else {
|
||||
if (onNavigate) {
|
||||
onNavigate(buttonName);
|
||||
} else {
|
||||
const { assets } = useAssets();
|
||||
assets.audio.tinyClick.play(0.8);
|
||||
}
|
||||
const path = findPath(graph, selectedButton.value, buttonName);
|
||||
|
||||
if (
|
||||
@@ -356,6 +364,12 @@ export const useButtonNavigation = <T extends Record<string, Rect>>({
|
||||
}
|
||||
|
||||
if (targetButton) {
|
||||
if (onNavigate) {
|
||||
onNavigate(targetButton);
|
||||
} else {
|
||||
const { assets } = useAssets();
|
||||
assets.audio.tinyClick.play(0.8);
|
||||
}
|
||||
const path = findPath(graph, selectedButton.value, targetButton);
|
||||
animateToButton(targetButton, path);
|
||||
}
|
||||
|
||||
12
app/composables/useClockTick.ts
Normal file
12
app/composables/useClockTick.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
let lastSecond = -1;
|
||||
|
||||
export const useClockTick = () => {
|
||||
const { assets } = useAssets();
|
||||
|
||||
return (now: Date) => {
|
||||
const s = now.getSeconds();
|
||||
if (s === lastSecond) return;
|
||||
lastSecond = s;
|
||||
assets.audio.clockTick.play(s === 0 ? 1 : 0.7);
|
||||
};
|
||||
};
|
||||
@@ -63,6 +63,9 @@ export const useAchievementsStore = defineStore("achievements", () => {
|
||||
|
||||
storage.value.unlocked.push(name);
|
||||
|
||||
const { assets } = useAssets();
|
||||
assets.audio.messageReceived.play(0.5);
|
||||
|
||||
if (storage.value.unlocked.length === ACHIEVEMENTS.length) {
|
||||
confetti.spawn();
|
||||
} else {
|
||||
|
||||
@@ -137,6 +137,9 @@ export const useAchievementsScreen = defineStore("achievementsScreen", {
|
||||
this.isIntro = false;
|
||||
this.isOutro = true;
|
||||
|
||||
const { assets } = useAssets();
|
||||
assets.audio.menuConfirmed.play();
|
||||
|
||||
gsap
|
||||
.timeline()
|
||||
.fromTo(
|
||||
|
||||
@@ -45,6 +45,18 @@ export const useConfirmationModal = defineStore("confirmationModal", {
|
||||
this.isClosing = false;
|
||||
this.isOpen = true;
|
||||
|
||||
const { assets } = useAssets();
|
||||
if (
|
||||
options.aLabel !== undefined ||
|
||||
options.bLabel !== undefined ||
|
||||
options.onActivateA !== undefined ||
|
||||
options.onActivateB !== undefined
|
||||
) {
|
||||
assets.audio.menuOpen.play();
|
||||
} else {
|
||||
assets.audio.menuConfirmed.play();
|
||||
}
|
||||
|
||||
gsap
|
||||
.timeline()
|
||||
// standard buttons down
|
||||
@@ -83,6 +95,20 @@ export const useConfirmationModal = defineStore("confirmationModal", {
|
||||
|
||||
this.isClosing = true;
|
||||
|
||||
if (
|
||||
this.aLabel !== null ||
|
||||
this.bLabel !== null ||
|
||||
this.onActivateA !== null ||
|
||||
this.onActivateB !== null
|
||||
) {
|
||||
const { assets } = useAssets();
|
||||
if (choice === "A") {
|
||||
assets.audio.menuConfirmed.play();
|
||||
} else {
|
||||
assets.audio.menuError.play();
|
||||
}
|
||||
}
|
||||
|
||||
const keepButtonsDown =
|
||||
typeof this.keepButtonsDown === "function"
|
||||
? this.keepButtonsDown(choice)
|
||||
|
||||
@@ -77,6 +77,9 @@ export const useContactStore = defineStore("contact", {
|
||||
pushNotification(content: string) {
|
||||
this.notifications.push(content);
|
||||
|
||||
const { assets } = useAssets();
|
||||
assets.audio.messageSent.play();
|
||||
|
||||
gsap.fromTo(
|
||||
this,
|
||||
{ notificationsYOffset: 20 },
|
||||
@@ -92,6 +95,9 @@ export const useContactStore = defineStore("contact", {
|
||||
animateOutro() {
|
||||
this.isOutro = true;
|
||||
|
||||
const { assets } = useAssets();
|
||||
assets.audio.menuConfirmed.play();
|
||||
|
||||
const timeline = gsap.timeline({
|
||||
onComplete: () => {
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -113,6 +113,9 @@ export const useCreditsStore = defineStore("credits", {
|
||||
this.isIntro = false;
|
||||
this.isOutro = true;
|
||||
|
||||
const { assets } = useAssets();
|
||||
assets.audio.menuConfirmed.play();
|
||||
|
||||
gsap
|
||||
.timeline()
|
||||
.fromTo(
|
||||
|
||||
@@ -102,6 +102,9 @@ export const useHomeStore = defineStore("home", {
|
||||
},
|
||||
|
||||
animateOutro(to: AppScreen) {
|
||||
const { assets } = useAssets();
|
||||
assets.audio.menuOpen.play();
|
||||
|
||||
if (to === "achievements") {
|
||||
const achievementsScreen = useAchievementsScreen();
|
||||
achievementsScreen.animateFadeToBlackIntro();
|
||||
|
||||
@@ -32,6 +32,15 @@ export const useIntroStore = defineStore("intro", {
|
||||
this.isIntro = false;
|
||||
},
|
||||
})
|
||||
.call(
|
||||
() => {
|
||||
const now = new Date();
|
||||
const isBirthday = now.getMonth() === 3 && now.getDate() === 25;
|
||||
(isBirthday ? assets.audio.birthdayStartup : assets.audio.startUp).play();
|
||||
},
|
||||
undefined,
|
||||
delay,
|
||||
)
|
||||
.to(
|
||||
this.intro,
|
||||
{
|
||||
@@ -59,6 +68,9 @@ export const useIntroStore = defineStore("intro", {
|
||||
animateOutro() {
|
||||
this.isOutro = true;
|
||||
|
||||
const { assets } = useAssets();
|
||||
assets.audio.tinyClick.play(0.8);
|
||||
|
||||
gsap
|
||||
.timeline()
|
||||
.to(this.outro, {
|
||||
|
||||
@@ -68,6 +68,9 @@ export const useSettingsStore = defineStore("settings", {
|
||||
},
|
||||
|
||||
async openSubMenu(submenu: SettingsSubMenu) {
|
||||
const { assets } = useAssets();
|
||||
assets.audio.menuOpen.play();
|
||||
|
||||
await gsap
|
||||
.timeline()
|
||||
.to(this.submenuTransition, {
|
||||
@@ -99,7 +102,12 @@ export const useSettingsStore = defineStore("settings", {
|
||||
}
|
||||
},
|
||||
|
||||
async closeSubMenu() {
|
||||
async closeSubMenu(silent = false) {
|
||||
if (!silent) {
|
||||
const { assets } = useAssets();
|
||||
assets.audio.menuError.play();
|
||||
}
|
||||
|
||||
await gsap
|
||||
.timeline()
|
||||
.to(this, {
|
||||
@@ -148,6 +156,8 @@ export const useSettingsStore = defineStore("settings", {
|
||||
animateIntro() {
|
||||
this.isIntro = true;
|
||||
|
||||
const { assets } = useAssets();
|
||||
|
||||
gsap
|
||||
.timeline()
|
||||
// bars
|
||||
@@ -178,6 +188,7 @@ export const useSettingsStore = defineStore("settings", {
|
||||
{ 1: 0, duration: 0.1, ease: "none" },
|
||||
0.2,
|
||||
)
|
||||
.call(() => assets.audio.settingsMenuIntro.play(), undefined, 0.2)
|
||||
.fromTo(
|
||||
this.menuOffsets,
|
||||
{ 2: -48 },
|
||||
@@ -198,8 +209,11 @@ export const useSettingsStore = defineStore("settings", {
|
||||
animateOutro() {
|
||||
this.isOutro = true;
|
||||
|
||||
const { assets } = useAssets();
|
||||
|
||||
gsap
|
||||
.timeline()
|
||||
.call(() => assets.audio.settingsMenuOutro.play())
|
||||
// title notification
|
||||
.fromTo(
|
||||
this,
|
||||
|
||||
@@ -1,3 +1,48 @@
|
||||
export const drawLine = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
x0: number,
|
||||
y0: number,
|
||||
x1: number,
|
||||
y1: number,
|
||||
width: number,
|
||||
) => {
|
||||
const dx = Math.abs(x1 - x0);
|
||||
const dy = Math.abs(y1 - y0);
|
||||
const sx = x0 < x1 ? 1 : -1;
|
||||
const sy = y0 < y1 ? 1 : -1;
|
||||
let err = dx - dy;
|
||||
|
||||
const drawThickPixel = (x: number, y: number) => {
|
||||
const isVertical = dy > dx;
|
||||
|
||||
if (width === 1) {
|
||||
ctx.fillRect(x, y, 1, 1);
|
||||
} else if (isVertical) {
|
||||
const offset = Math.floor((width - 1) / 2);
|
||||
ctx.fillRect(x - offset, y, width, 1);
|
||||
} else {
|
||||
const offset = Math.floor((width - 1) / 2);
|
||||
ctx.fillRect(x, y - offset, 1, width);
|
||||
}
|
||||
};
|
||||
|
||||
while (true) {
|
||||
drawThickPixel(x0, y0);
|
||||
|
||||
if (x0 === x1 && y0 === y1) break;
|
||||
|
||||
const e2 = 2 * err;
|
||||
if (e2 > -dy) {
|
||||
err -= dy;
|
||||
x0 += sx;
|
||||
}
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const fillTextCentered = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
text: string,
|
||||
|
||||
Reference in New Issue
Block a user