pet_data/components/pixel/PetScreen.vue

248 lines
4.0 KiB
Vue

<template>
<PixelCard size="large" class="pet-screen">
<div class="screen-header">
<h2 class="pet-name">{{ petName }}</h2>
</div>
<div class="pet-viewport">
<div class="background-animation">
<!-- CSS animated background -->
<div class="cloud cloud-1"></div>
<div class="cloud cloud-2"></div>
<div class="cloud cloud-3"></div>
</div>
<div class="pet-sprite" :class="petEmotion">
<!-- CSS-based pet pixel art -->
<div class="pet-body"></div>
<div class="pet-eye-left"></div>
<div class="pet-eye-right"></div>
<div class="pet-mouth"></div>
</div>
<div v-if="poopCount > 0" class="poop-container">
<div v-for="i in Math.min(poopCount, 4)" :key="i" class="poop-pile">
<div class="poop-base"></div>
<div class="poop-stink"></div>
</div>
</div>
</div>
</PixelCard>
</template>
<script setup>
import PixelCard from './PixelCard.vue'
const props = defineProps({
petName: {
type: String,
default: 'Pet'
},
petStage: {
type: String,
default: 'egg'
},
petEmotion: {
type: String,
default: 'happy'
},
poopCount: {
type: Number,
default: 0
}
})
</script>
<style scoped>
.pet-screen {
width: 100%;
max-width: 600px;
margin: 0 auto;
}
.screen-header {
text-align: center;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 3px solid #000;
}
.pet-name {
font-size: 16px;
text-transform: uppercase;
}
.pet-viewport {
position: relative;
width: 100%;
height: 300px;
background: linear-gradient(180deg, #87CEEB 0%, #E0F6FF 100%);
overflow: hidden;
border: 3px solid #000;
}
/* Background clouds animation */
.background-animation {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.cloud {
position: absolute;
background: white;
border: 2px solid #ddd;
border-radius: 50%;
opacity: 0.7;
animation: float 20s infinite linear;
}
.cloud-1 {
width: 60px;
height: 30px;
top: 20%;
left: -60px;
}
.cloud-2 {
width: 80px;
height: 40px;
top: 40%;
left: -80px;
animation-delay: -7s;
animation-duration: 25s;
}
.cloud-3 {
width: 50px;
height: 25px;
top: 60%;
left: -50px;
animation-delay: -14s;
animation-duration: 30s;
}
@keyframes float {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(600px + 100%));
}
}
/* Pet sprite */
.pet-sprite {
position: absolute;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 80px;
image-rendering: pixelated;
}
.pet-body {
width: 60px;
height: 60px;
background: #FFD700;
border: 3px solid #000;
position: absolute;
bottom: 0;
left: 10px;
border-radius: 8px;
}
.pet-eye-left,
.pet-eye-right {
width: 8px;
height: 8px;
background: #000;
border-radius: 50%;
position: absolute;
top: 20px;
}
.pet-eye-left {
left: 25px;
}
.pet-eye-right {
right: 25px;
}
.pet-mouth {
width: 20px;
height: 10px;
border: 2px solid #000;
border-top: none;
border-radius: 0 0 10px 10px;
position: absolute;
bottom: 15px;
left: 30px;
}
/* Emotions */
.pet-sprite.happy .pet-mouth {
border-radius: 0 0 20px 20px;
height: 12px;
}
.pet-sprite.sad .pet-mouth {
border-radius: 20px 20px 0 0;
border-top: 2px solid #000;
border-bottom: none;
bottom: 20px;
}
.pet-sprite.sick {
filter: hue-rotate(90deg);
}
/* Poop */
.poop-container {
position: absolute;
bottom: 60px;
left: 20px;
display: flex;
gap: 10px;
}
.poop-pile {
position: relative;
width: 30px;
height: 30px;
}
.poop-base {
width: 24px;
height: 24px;
background: #8B4513;
border: 2px solid #000;
border-radius: 50% 50% 40% 40%;
position: absolute;
bottom: 0;
}
.poop-stink {
width: 4px;
height: 12px;
background: #888;
opacity: 0.5;
position: absolute;
top: -12px;
left: 10px;
animation: stinkWave 1.5s infinite;
}
@keyframes stinkWave {
0%, 100% {
transform: translateY(0);
opacity: 0.5;
}
50% {
transform: translateY(-8px);
opacity: 0.2;
}
}
</style>