dog-pet/main.py
2025-06-27 15:59:08 +08:00

382 lines
14 KiB
Python

import sys
import os
import random
import datetime
from PyQt5.QtGui import QIcon, QMovie, QCursor, QPixmap
from PyQt5.QtWidgets import (QWidget, QApplication, QSystemTrayIcon,
QMenu, QAction, QLabel, QDesktopWidget,
QProgressBar, QVBoxLayout, QHBoxLayout)
from PyQt5.QtCore import Qt, QSize, QTimer
class DesktopPet(QWidget):
def __init__(self, parent=None, **kwargs):
super(DesktopPet, self).__init__(parent)
self.init()
self.initPall()
self.action_timer = QTimer(self)
self.action_timer.setSingleShot(True)
self.action_timer.timeout.connect(self.checkInitialGif)
self.status_timer = QTimer(self)
self.status_timer.timeout.connect(self.statusTimer)
self.happiness_accumulated = 0
self.energy_accumulated = 0
self.working_timer = QTimer(self)
self.working_timer.timeout.connect(self.updateWorking)
self.boring_timer = QTimer(self)
self.boring_timer.setSingleShot(True)
self.boring_timer.timeout.connect(self.setBoring)
self.is_boring = False
self.resetBoringTimer()
self.resurrect_timer = QTimer(self)
self.resurrect_timer.setSingleShot(True)
self.resurrect_timer.timeout.connect(self.resurrectPet)
self.is_dead = False
self.initPetImage()
def init(self):
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool | Qt.NoDropShadowWindowHint)
self.setAutoFillBackground(False)
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.repaint()
def initPall(self):
icons = os.path.join('Image/MenuIcon.jpg')
self.quit_action = QAction(u'退出', self, triggered=self.quit)
self.showing = QAction(u'显示', self, triggered=self.showup)
self.hideup = QAction(u'隐藏', self, triggered=self.hide)
self.hidestats = QAction(u'显示/隐藏状态栏', self, triggered=self.hideStatsBar)
self.tray_icon_menu = QMenu(self)
self.tray_icon_menu.addAction(self.quit_action)
self.tray_icon_menu.addAction(self.showing)
self.tray_icon_menu.addAction(self.hideup)
self.tray_icon_menu.addAction(self.hidestats)
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setIcon(QIcon(icons))
self.tray_icon.setContextMenu(self.tray_icon_menu)
self.tray_icon.show()
def initPetImage(self):
self.main_layout = QVBoxLayout(self)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.setSpacing(0)
self.stats_visible = True
self.happiness_layout = QHBoxLayout()
self.happiness_layout.setContentsMargins(0, 0, 0, 0)
self.happiness_layout.setSpacing(0)
self.happiness_icon = QLabel()
self.happiness_icon.setContentsMargins(0, 0, 0, 0)
self.happiness_icon_pixmap = QPixmap("Image/Happiness.svg")
self.happiness_icon_pixmap = self.happiness_icon_pixmap.scaled(QSize(20, 20), Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.happiness_icon.setPixmap(self.happiness_icon_pixmap)
self.happiness_layout.addWidget(self.happiness_icon, alignment=Qt.AlignCenter)
self.happiness_bar = QProgressBar()
self.happiness_bar.setRange(0, 100)
self.happiness_bar.setValue(80)
self.happiness_bar.setFixedHeight(12)
self.happiness_bar.setFixedWidth(150)
self.happiness_bar.setStyleSheet("""
QProgressBar {
border: 1px solid #ccc;
border-radius: 5px;
text-align: center;
}
QProgressBar::chunk {
background-color: #FF69B4;
}
""")
self.happiness_layout.addWidget(self.happiness_bar, alignment=Qt.AlignCenter)
self.energy_layout = QHBoxLayout()
self.energy_layout.setContentsMargins(0, 0, 0, 0)
self.energy_layout.setSpacing(0)
self.energy_label = QLabel()
self.energy_label.setContentsMargins(0, 0, 0, 0)
self.energy_icon_pixmap = QPixmap("Image/Energy.svg")
self.energy_icon_pixmap = self.energy_icon_pixmap.scaled(QSize(20, 20), Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.energy_label.setPixmap(self.energy_icon_pixmap)
self.energy_layout.addWidget(self.energy_label, alignment=Qt.AlignCenter)
self.energy_bar = QProgressBar()
self.energy_bar.setRange(0, 100)
self.energy_bar.setValue(80)
self.energy_bar.setFixedHeight(12)
self.energy_bar.setFixedWidth(150)
self.energy_bar.setStyleSheet("""
QProgressBar {
border: 1px solid #ccc;
border-radius: 5px;
text-align: center;
}
QProgressBar::chunk {
background-color: #1E90FF;
}
""")
self.energy_layout.addWidget(self.energy_bar, alignment=Qt.AlignCenter)
self.image = QLabel(self)
self.image.setContentsMargins(0, 0, 0, 0)
self.checkInitialGif()
self.main_layout.addWidget(self.image)
self.main_layout.addLayout(self.happiness_layout)
self.main_layout.addLayout(self.energy_layout)
self.resize(200, 240)
self.randomPosition()
self.show()
self.pet1 = []
for filename in os.listdir("GIF"):
self.pet1.append(os.path.join("GIF", filename))
def showMenu(self):
menu = QMenu()
menu.addAction(u"贴贴", self.stick)
menu.addAction(u"拍一拍", self.call)
menu.addAction(u"锻炼", self.exercise)
menu.addAction(u"充电", self.charge)
menu.addAction(u"投喂小白", self.cake)
menu.addAction(u"吧唧", self.baji)
menu.addAction(u"随机出现", self.appear)
menu.addAction(u"遛小鸡毛", self.walkDog)
right_pos = self.mapToGlobal(self.rect().topRight())
menu.exec_(right_pos)
def stick(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/stick.gif")
self.action_timer.start(10 * 60 * 1000)
self.updateStatus(15, -5, 10 * 60 * 1000)
def call(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/call.gif")
self.action_timer.start(2000)
def exercise(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/exercise.gif")
self.action_timer.start(10 * 60 * 1000)
self.updateStatus(5, -10, 10 * 60 * 1000)
def charge(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/charge.gif")
self.action_timer.start(45 * 60 * 1000)
self.updateStatus(30, 30, 30 * 60 * 1000)
def cake(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/cake.gif")
self.action_timer.start(5 * 60 * 1000)
self.updateStatus(10, 5, 5 * 60 * 1000)
def baji(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/baji.gif")
self.action_timer.start(5 * 60 * 1000)
self.updateStatus(10, 10, 5 * 60 * 1000)
def appear(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/appear.gif")
self.action_timer.start(3500)
self.randomPosition()
def walkDog(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/walkdog.gif")
self.action_timer.start(10 * 60 * 1000)
self.updateStatus(15, -10, 10 * 60 * 1000)
def checkInitialGif(self):
current_time = datetime.datetime.now()
current_hour = current_time.hour
weekday = current_time.weekday()
self.is_working_time = (0 <= weekday <= 4) and (10 <= current_hour < 18)
happiness = self.happiness_bar.value()
energy = self.energy_bar.value()
if happiness == 0 and energy == 0:
self.petDied()
elif happiness < 20 and energy < 20:
if self.is_working_time:
self.working_timer.stop()
self.working_timer.start(60 * 1000)
return self.changeGif("GIF/angry.gif")
elif happiness < 20:
if self.is_working_time:
self.working_timer.stop()
self.working_timer.start(2 * 60 * 1000)
return self.changeGif("GIF/crying2.gif")
elif energy < 20:
if self.is_working_time:
self.working_timer.stop()
self.working_timer.start(2 * 10 * 1000)
return self.changeGif("GIF/crying.gif")
if self.is_working_time:
self.working_timer.start(3 * 60 * 1000)
return self.changeGif("GIF/working2.gif")
else:
self.working_timer.stop()
return self.changeGif("GIF/normal.gif")
def updateWorking(self):
self.updateHappiness(-1)
self.updateEnergy(-1)
if self.happiness_bar.value() <= 20 or self.energy_bar.value() <= 20:
self.checkInitialGif()
def updateStatus(self, happinesschange, energychange, duration):
self.total_happiness_change = happinesschange
self.total_energy_change = energychange
interval = 100
self.remaining = duration / interval
self.happiness_change_step = happinesschange / self.remaining
self.energy_change_step = energychange / self.remaining
self.status_timer.start(interval)
def statusTimer(self):
if self.remaining <= 0:
self.status_timer.stop()
return
self.happiness_accumulated += self.happiness_change_step
self.energy_accumulated += self.energy_change_step
if self.happiness_accumulated >= 1 or self.happiness_accumulated <= -1:
self.updateHappiness(int(self.happiness_accumulated))
self.happiness_accumulated = 0
if self.energy_accumulated >= 1 or self.energy_accumulated <= -1:
self.updateEnergy(int(self.energy_accumulated))
self.energy_accumulated = 0
self.remaining -= 1
def setBoring(self):
if not self.is_boring and not self.is_working_time:
self.is_boring = True
self.changeGif("GIF/boring.gif")
self.updateHappiness(-5)
def resetBoringTimer(self):
if self.is_boring:
self.is_boring = False
self.checkInitialGif()
self.boring_timer.stop()
self.boring_timer.start(60 * 60 * 1000)
def petDied(self):
if self.is_dead:
return
self.is_dead = True
self.working_timer.stop()
self.boring_timer.stop()
self.action_timer.stop()
self.status_timer.stop()
self.showing.setEnabled(False)
self.hidestats.setEnabled(False)
self.hideup.setEnabled(False)
self.hide()
self.resurrect_timer.start(5000)
def resurrectPet(self):
self.is_dead = False
self.happiness_bar.setValue(50)
self.energy_bar.setValue(50)
self.showing.setEnabled(True)
self.hidestats.setEnabled(True)
self.hideup.setEnabled(True)
self.showup()
self.resetBoringTimer()
self.checkInitialGif()
def randomPosition(self):
screen_geometry = QDesktopWidget().screenGeometry()
pet_geometry = self.geometry()
width = int((screen_geometry.width() - pet_geometry.width()) * random.random())
height = int((screen_geometry.height() - pet_geometry.height()) * random.random())
self.move(width, height)
def changeGif(self, path):
self.movie = QMovie(path)
self.movie.setScaledSize(QSize(200, 200))
self.image.setMovie(self.movie)
self.movie.start()
def mousePressEvent(self, event):
self.condition = 1
if event.button() == Qt.LeftButton:
self.is_follow_mouse = True
self.mouse_drag_pos = event.globalPos() - self.pos()
self.setCursor(QCursor(Qt.OpenHandCursor))
elif event.button() == Qt.RightButton:
self.showMenu()
event.accept()
def mouseMoveEvent(self, event):
if Qt.LeftButton and self.is_follow_mouse:
self.move(event.globalPos() - self.mouse_drag_pos)
event.accept()
def mouseReleaseEvent(self, event):
self.is_follow_mouse = False
self.setCursor(QCursor(Qt.ArrowCursor))
def enterEvent(self, event):
self.setCursor(Qt.ClosedHandCursor)
def updateHappiness(self, value):
current_value = self.happiness_bar.value()
new_value = max(0, min(100, current_value + value))
self.happiness_bar.setValue(new_value)
def updateEnergy(self, value):
current_value = self.energy_bar.value()
new_value = max(0, min(100, current_value + value))
self.energy_bar.setValue(new_value)
def hideStatsBar(self):
if self.is_dead:
return
self.stats_visible = not self.stats_visible
self.happiness_icon.setVisible(self.stats_visible)
self.happiness_bar.setVisible(self.stats_visible)
self.energy_label.setVisible(self.stats_visible)
self.energy_bar.setVisible(self.stats_visible)
def quit(self):
self.close()
sys.exit()
def showup(self):
self.setWindowOpacity(1)
def hide(self):
self.setWindowOpacity(0)
if __name__ == '__main__':
app = QApplication(sys.argv)
pet = DesktopPet()
sys.exit(app.exec_())