pet_data/components/pixel/ScrollableScene.vue

338 lines
6.3 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="scrollable-scene">
<!-- 背景層 -->
<div class="scene-background" :style="{ transform: `translateX(${-scrollPosition}px)` }">
<!-- 遠景 -->
<div class="bg-layer far-bg">
<div class="cloud" style="left: 100px; top: 50px;"></div>
<div class="cloud" style="left: 400px; top: 80px;"></div>
<div class="cloud" style="left: 700px; top: 40px;"></div>
<div class="mountain" style="left: 200px;"></div>
<div class="mountain" style="left: 600px;"></div>
</div>
<!-- 中景 -->
<div class="bg-layer mid-bg">
<div class="tree" style="left: 150px;"></div>
<div class="tree" style="left: 550px;"></div>
<div class="tree" style="left: 900px;"></div>
</div>
</div>
<!-- 前景 - 地面 -->
<div class="scene-ground">
<div class="grass-pattern"></div>
</div>
<!-- 寵物 -->
<div
class="pet-character"
:class="[petEmotion, { walking: isWalking }]"
:style="{ left: petPosition + 'px' }"
>
<div class="pet-body"></div>
</div>
<!-- 互動物件 -->
<div class="scene-objects">
<div class="object food-bowl" style="left: 300px;" @click="$emit('interact', 'food')">
🍖
</div>
<div class="object toy" style="left: 500px;" @click="$emit('interact', 'toy')">
🎾
</div>
<div class="object bed" style="left: 700px;" @click="$emit('interact', 'bed')">
🛏
</div>
</div>
<!-- 捲軸控制 (開發用) -->
<div class="scroll-controls">
<button @click="scrollLeft" class="scroll-btn"></button>
<button @click="scrollRight" class="scroll-btn"></button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
petEmotion: {
type: String,
default: 'happy'
}
})
const emit = defineEmits(['interact'])
const scrollPosition = ref(0)
const petPosition = ref(200)
const isWalking = ref(false)
const scrollLeft = () => {
if (scrollPosition.value > 0) {
scrollPosition.value = Math.max(0, scrollPosition.value - 100)
}
}
const scrollRight = () => {
if (scrollPosition.value < 600) {
scrollPosition.value = Math.min(600, scrollPosition.value + 100)
}
}
// 自動移動寵物 (示例)
setInterval(() => {
const randomMove = Math.random() > 0.5
if (randomMove) {
isWalking.value = true
petPosition.value += (Math.random() - 0.5) * 50
petPosition.value = Math.max(50, Math.min(750, petPosition.value))
setTimeout(() => {
isWalking.value = false
}, 1000)
}
}, 3000)
</script>
<style scoped>
.scrollable-scene {
width: 100%;
height: 400px;
position: relative;
overflow: hidden;
background: linear-gradient(180deg, #87CEEB 0%, #E0F6FF 60%, #98D8C8 100%);
border: 4px solid #5a4a3a;
border-radius: 16px;
}
/* 手機直向 */
@media (max-width: 480px) {
.scrollable-scene {
height: 280px;
border: 3px solid #5a4a3a;
border-radius: 12px;
}
}
/* 手機橫向 */
@media (max-width: 768px) and (orientation: landscape) {
.scrollable-scene {
height: 220px;
}
}
/* 平板 */
@media (min-width: 481px) and (max-width: 768px) {
.scrollable-scene {
height: 320px;
}
}
.scene-background {
position: absolute;
width: 1200px;
height: 100%;
transition: transform 0.3s ease;
}
.bg-layer {
position: absolute;
width: 100%;
height: 100%;
}
/* 雲朵 */
.cloud {
position: absolute;
width: 80px;
height: 40px;
background: white;
border-radius: 50px;
opacity: 0.8;
animation: float 20s infinite linear;
}
.cloud::before,
.cloud::after {
content: '';
position: absolute;
background: white;
border-radius: 50%;
}
.cloud::before {
width: 50px;
height: 50px;
top: -25px;
left: 10px;
}
.cloud::after {
width: 60px;
height: 45px;
top: -20px;
right: 10px;
}
@keyframes float {
from { transform: translateX(0); }
to { transform: translateX(100px); }
}
/* 山 */
.mountain {
position: absolute;
bottom: 50px;
width: 0;
height: 0;
border-left: 100px solid transparent;
border-right: 100px solid transparent;
border-bottom: 150px solid #95a5a6;
}
/* 樹 */
.tree {
position: absolute;
bottom: 80px;
width: 20px;
height: 60px;
background: #8B4513;
border-radius: 4px;
}
.tree::before {
content: '';
position: absolute;
top: -30px;
left: -20px;
width: 60px;
height: 60px;
background: #55efc4;
border-radius: 50%;
}
/* 地面 */
.scene-ground {
position: absolute;
bottom: 0;
width: 100%;
height: 80px;
background: linear-gradient(180deg, #6ab04c 0%, #4cd137 100%);
border-top: 3px solid #5a4a3a;
}
.grass-pattern {
width: 100%;
height: 100%;
background-image: repeating-linear-gradient(
90deg,
transparent,
transparent 10px,
rgba(0, 0, 0, 0.05) 10px,
rgba(0, 0, 0, 0.05) 20px
);
}
/* 寵物 */
.pet-character {
position: absolute;
bottom: 80px;
width: 80px;
height: 80px;
transition: left 0.5s ease;
z-index: 10;
}
.pet-body {
width: 60px;
height: 60px;
background: linear-gradient(135deg, #ff6b9d 0%, #ff8fab 100%);
border: 3px solid #5a4a3a;
border-radius: 50%;
position: relative;
box-shadow: 0 4px 0 rgba(0, 0, 0, 0.2);
}
.pet-body::before,
.pet-body::after {
content: '';
position: absolute;
width: 10px;
height: 10px;
background: #2d3436;
border-radius: 50%;
top: 20px;
}
.pet-body::before {
left: 15px;
}
.pet-body::after {
right: 15px;
}
.pet-character.walking .pet-body {
animation: bounce 0.5s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
/* 互動物件 */
.scene-objects {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
}
.object {
position: absolute;
bottom: 80px;
font-size: 32px;
cursor: pointer;
pointer-events: all;
transition: transform 0.2s;
}
.object:hover {
transform: scale(1.2);
}
/* 捲軸控制 */
.scroll-controls {
position: absolute;
bottom: 16px;
right: 16px;
display: flex;
gap: 8px;
z-index: 20;
}
.scroll-btn {
width: 40px;
height: 40px;
background: rgba(255, 255, 255, 0.9);
border: 3px solid #5a4a3a;
border-radius: 8px;
font-size: 20px;
cursor: pointer;
transition: all 0.2s;
}
.scroll-btn:hover {
background: #ffeaa7;
transform: scale(1.1);
}
.scroll-btn:active {
transform: scale(0.95);
}
</style>