feat(intro): implement intro screen
This commit is contained in:
@@ -7,7 +7,10 @@ const app = useAppStore();
|
||||
const { assets } = useAssets();
|
||||
|
||||
onRender((ctx) => {
|
||||
ctx.globalAlpha = app.booted ? 1 : store.intro.stage1Opacity;
|
||||
ctx.fillStyle = "#fbfbfb"
|
||||
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
||||
|
||||
ctx.globalAlpha = store.isIntro? store.intro.stage1Opacity:1;
|
||||
assets.images.home.bottomScreen.background.draw(ctx, 0, 0);
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ const app = useAppStore();
|
||||
const { assets } = useAssets();
|
||||
|
||||
onRender((ctx) => {
|
||||
ctx.globalAlpha = app.booted ? 1 : store.intro.stage1Opacity;
|
||||
ctx.fillStyle = "#fbfbfb"
|
||||
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
||||
|
||||
ctx.globalAlpha = store.isIntro? store.intro.stage1Opacity:1;
|
||||
assets.images.home.topScreen.background.draw(ctx, 0, 0);
|
||||
});
|
||||
|
||||
|
||||
100
app/components/Intro/BottomScreen/BottomScreen.vue
Normal file
100
app/components/Intro/BottomScreen/BottomScreen.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<script setup lang="ts">
|
||||
import gsap from "gsap";
|
||||
|
||||
const app = useAppStore();
|
||||
const store = useIntroStore();
|
||||
const { onRender, onClick } = useScreen();
|
||||
const { assets } = useAssets();
|
||||
|
||||
const TITLE_Y = 25;
|
||||
const TEXT_Y = 63;
|
||||
const HINT_Y = 167;
|
||||
|
||||
const hintTextOpacity = ref(0);
|
||||
|
||||
store.$subscribe((_, state) => {
|
||||
if (!state.isIntro && !state.isOutro) {
|
||||
gsap.to(hintTextOpacity, {
|
||||
value: 1,
|
||||
duration: 0.5,
|
||||
repeat: -1,
|
||||
yoyo: true,
|
||||
ease: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onRender((ctx) => {
|
||||
ctx.textBaseline = "top";
|
||||
|
||||
ctx.fillStyle = "#fbfbfb";
|
||||
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
||||
|
||||
ctx.fillStyle = "#000000";
|
||||
|
||||
// title
|
||||
ctx.font = "12px NDS12 Bold";
|
||||
ctx.letterSpacing = "1px";
|
||||
|
||||
const TEXT = "WARNING - COPYRIGHT";
|
||||
const { actualBoundingBoxRight: width } = ctx.measureText(TEXT);
|
||||
|
||||
const logoWidth = assets.images.intro.warning.rect.width;
|
||||
const logoX = Math.floor(LOGICAL_WIDTH / 2 - (width + logoWidth + 3) / 2);
|
||||
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.textOpacity
|
||||
: store.isOutro
|
||||
? store.outro.textOpacity
|
||||
: 1;
|
||||
|
||||
assets.images.intro.warning.draw(ctx, logoX, TITLE_Y - 1);
|
||||
ctx.fillText(TEXT, logoX + logoWidth + 3, TITLE_Y);
|
||||
|
||||
ctx.letterSpacing = "0px";
|
||||
|
||||
// text
|
||||
ctx.font = "10px NDS10";
|
||||
const TEXT2 =
|
||||
"THIS IS A NON-COMMERCIAL FAN-MADE\nRECREATION. NOT AFFILIATED WITH\nOR ENDORSED BY NINTENDO.\nNINTENDO DS IS A TRADEMARK OF\nNINTENDO CO., LTD.";
|
||||
const lines = TEXT2.split("\n");
|
||||
for (let i = 0, y = TEXT_Y; i < lines.length; i += 1, y += 18)
|
||||
fillTextHCentered(ctx, lines[i]!, 0, y, LOGICAL_WIDTH);
|
||||
|
||||
// hint
|
||||
ctx.font = "10px NDS10";
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? 0
|
||||
: store.isOutro
|
||||
? store.outro.textOpacity
|
||||
: hintTextOpacity.value;
|
||||
fillTextHCentered(
|
||||
ctx,
|
||||
"Touch the Touch Screen to continue.",
|
||||
0,
|
||||
HINT_Y,
|
||||
LOGICAL_WIDTH,
|
||||
);
|
||||
});
|
||||
|
||||
onClick(() => {
|
||||
if (store.isIntro || store.isOutro) return;
|
||||
|
||||
store.animateOutro();
|
||||
});
|
||||
|
||||
useKeyDown((key) => {
|
||||
if (store.isIntro || store.isOutro) return;
|
||||
|
||||
switch (key) {
|
||||
case "NDS_A":
|
||||
case "NDS_START":
|
||||
store.animateOutro();
|
||||
break;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div />
|
||||
</template>
|
||||
35
app/components/Intro/TopScreen/TopScreen.vue
Normal file
35
app/components/Intro/TopScreen/TopScreen.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
const { onRender } = useScreen();
|
||||
const { assets } = useAssets();
|
||||
const store = useIntroStore();
|
||||
|
||||
const frames = Object.keys(assets.images.intro.logoAnimated).sort();
|
||||
|
||||
onMounted(() => {
|
||||
store.$reset();
|
||||
store.animateIntro();
|
||||
});
|
||||
|
||||
onRender((ctx) => {
|
||||
ctx.fillStyle = "#fbfbfb";
|
||||
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
||||
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.textOpacity
|
||||
: store.isOutro
|
||||
? store.outro.textOpacity
|
||||
: 1;
|
||||
|
||||
const frameIndex = Math.floor(store.intro.logoFrameIndex);
|
||||
const frameKey = frames[
|
||||
frameIndex
|
||||
] as keyof typeof assets.images.intro.logoAnimated;
|
||||
const frame = assets.images.intro.logoAnimated[frameKey];
|
||||
|
||||
frame.draw(ctx, 0, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div />
|
||||
</template>
|
||||
Reference in New Issue
Block a user