From f9c15707eff91bd4a7241fee7e5797846d870fa2 Mon Sep 17 00:00:00 2001 From: DasMoorhuhn Date: Thu, 12 Dec 2024 03:34:02 +0100 Subject: [PATCH] add action loop --- deb.sh | 1 + .../{demonite_float_correct.png => float.png} | Bin .../demonite/{heart_heart.png => heart.png} | Bin .../{demonite_idle1.png => idle1.png} | Bin .../{demonite_idle3.png => idle3.png} | Bin ...emonite_moving_right1.png => moving_1.png} | Bin ...emonite_moving_right2.png => moving_2.png} | Bin requierements.txt | 4 + transparent_widget.py | 74 +++++++++++ vpet.py | 115 +++++++++++++---- window_qt.py | 119 ++++-------------- 11 files changed, 192 insertions(+), 121 deletions(-) create mode 100755 deb.sh rename pets_sprites/demonite/{demonite_float_correct.png => float.png} (100%) rename pets_sprites/demonite/{heart_heart.png => heart.png} (100%) rename pets_sprites/demonite/{demonite_idle1.png => idle1.png} (100%) rename pets_sprites/demonite/{demonite_idle3.png => idle3.png} (100%) rename pets_sprites/demonite/{demonite_moving_right1.png => moving_1.png} (100%) rename pets_sprites/demonite/{demonite_moving_right2.png => moving_2.png} (100%) create mode 100644 requierements.txt create mode 100644 transparent_widget.py diff --git a/deb.sh b/deb.sh new file mode 100755 index 0000000..f8c00c6 --- /dev/null +++ b/deb.sh @@ -0,0 +1 @@ +sudo apt-get install -y freeglut3-dev diff --git a/pets_sprites/demonite/demonite_float_correct.png b/pets_sprites/demonite/float.png similarity index 100% rename from pets_sprites/demonite/demonite_float_correct.png rename to pets_sprites/demonite/float.png diff --git a/pets_sprites/demonite/heart_heart.png b/pets_sprites/demonite/heart.png similarity index 100% rename from pets_sprites/demonite/heart_heart.png rename to pets_sprites/demonite/heart.png diff --git a/pets_sprites/demonite/demonite_idle1.png b/pets_sprites/demonite/idle1.png similarity index 100% rename from pets_sprites/demonite/demonite_idle1.png rename to pets_sprites/demonite/idle1.png diff --git a/pets_sprites/demonite/demonite_idle3.png b/pets_sprites/demonite/idle3.png similarity index 100% rename from pets_sprites/demonite/demonite_idle3.png rename to pets_sprites/demonite/idle3.png diff --git a/pets_sprites/demonite/demonite_moving_right1.png b/pets_sprites/demonite/moving_1.png similarity index 100% rename from pets_sprites/demonite/demonite_moving_right1.png rename to pets_sprites/demonite/moving_1.png diff --git a/pets_sprites/demonite/demonite_moving_right2.png b/pets_sprites/demonite/moving_2.png similarity index 100% rename from pets_sprites/demonite/demonite_moving_right2.png rename to pets_sprites/demonite/moving_2.png diff --git a/requierements.txt b/requierements.txt new file mode 100644 index 0000000..8b39345 --- /dev/null +++ b/requierements.txt @@ -0,0 +1,4 @@ +PyOpenGL +PyGObject-stubs +PyQt5 +PyQt5-stubs \ No newline at end of file diff --git a/transparent_widget.py b/transparent_widget.py new file mode 100644 index 0000000..75bcdbb --- /dev/null +++ b/transparent_widget.py @@ -0,0 +1,74 @@ +from PyQt5.QtWidgets import QOpenGLWidget +from OpenGL.GL import * +from OpenGL.GLU import gluOrtho2D + + +class TransparentGLWidget(QOpenGLWidget): + def __init__(self, img): + super().__init__() + self.img = img + self.texture = None + self.image_width = 1 + self.image_height = 1 + + def initializeGL(self): + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + glEnable(GL_DEPTH_TEST) + glClearColor(0.0, 0.0, 0.0, 0.0) + + self.texture, self.image_width, self.image_height = self.load_texture() + + def resizeGL(self, w, h): + glViewport(0, 0, w, h) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluOrtho2D(0, w, 0, h) # Orthografische Projektion für 2D + glMatrixMode(GL_MODELVIEW) + + def paintGL(self): + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glLoadIdentity() + glPushMatrix() # Matrix speichern + self.draw_textured_quad() + glPopMatrix() # Matrix wiederherstellen + + def load_texture(self): + img_data = self.img.tobytes() + width, height = self.img.size + + # Create OpenGL texture + texture_id = glGenTextures(1) + glBindTexture(GL_TEXTURE_2D, texture_id) + + # Set texture parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + + # Load texture + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data) + return texture_id, width, height + + def draw_textured_quad(self): + try: + glEnable(GL_TEXTURE_2D) + glBindTexture(GL_TEXTURE_2D, self.texture) + + width, height = self.width(), self.height() + + glBegin(GL_QUADS) + glTexCoord2f(0.0, 0.0) + glVertex2f(0, 0) # Down left corner + glTexCoord2f(1.0, 0.0) + glVertex2f(width, 0) # Down right corner + glTexCoord2f(1.0, 1.0) + glVertex2f(width, height) # Up right corner + glTexCoord2f(0.0, 1.0) + glVertex2f(0, height) # Up left corner + glEnd() + + glDisable(GL_TEXTURE_2D) + except: + pass diff --git a/vpet.py b/vpet.py index 386cd8d..5011c8d 100644 --- a/vpet.py +++ b/vpet.py @@ -14,13 +14,14 @@ class Dialogs: class Frames: """These strings do match to the PNGs of the VPet which are representation the frames of an animation""" - idle_1 = 'idle1' - idle_2 = 'idle2' - idle_3 = 'idle3' - move_1 = 'moving_1' - move_2 = 'moving_2' - hearts_1 = 'heart' - floating = 'floating' + def __init__(self): + self.idle_1 = Image.open('pets_sprites/demonite/idle1.png') + self.idle_2 = Image.open('pets_sprites/demonite/idle2.png') + self.idle_3 = Image.open('pets_sprites/demonite/idle3.png') + self.move_1 = Image.open('pets_sprites/demonite/moving_1.png') + self.move_2 = Image.open('pets_sprites/demonite/moving_2.png') + self.hearts_1 = Image.open('pets_sprites/demonite/heart.png') + self.floating = Image.open('pets_sprites/demonite/floating.png') class Animations: @@ -53,27 +54,88 @@ class Animations: pass +class Activity: + def __init__(self): + self.is_idle = True + self.is_sleeping = False + self.is_dreaming = False + self.is_moving = False + self.is_talking = False + self.is_thinking = False + self.is_interacting_with_user = False + + def set_idle(self): + self.is_idle = True + self.is_sleeping = False + self.is_dreaming = False + self.is_moving = False + self.is_talking = False + self.is_thinking = False + self.is_interacting_with_user = False + + def set_sleeping(self): + self.is_idle = False + self.is_sleeping = True + self.is_moving = False + self.is_talking = False + self.is_thinking = False + + def set_dreaming(self): + self.is_idle = False + self.is_dreaming = True + self.is_moving = False + self.is_talking = False + self.is_thinking = False + + def set_moving(self): + self.is_idle = False + self.is_moving = True + self.is_sleeping = False + self.is_dreaming = False + + def set_talking(self): + self.is_idle = False + self.is_talking = True + self.is_thinking = False + self.is_sleeping = False + + def set_thinking(self): + self.is_idle = False + self.is_talking = False + self.is_thinking = True + self.is_sleeping = False + + def set_interacting_with_user(self): + self.is_idle = False + self.is_sleeping = False + self.is_dreaming = False + self.is_moving = False + self.is_talking = False + self.is_thinking = False + self.is_interacting_with_user = True + + class VPet: - def __init__(self, x=0, y=0, screen=1): + def __init__(self, move, pos, draw, x=0, y=0, screen=1): self.screen = screen + self.pos = pos self.x_postion = x self.y_postion = y + self.x_destination = 0 + self.y_destination = 0 self.rotation = Rotate.up - self.is_idle = True - self.is_sleeping = False - self.is_dreaming = False - self.is_moving = False - self.is_talking = False - self.is_thinking = False + self.move = move + self.draw = draw + self.frames = Frames() + self.activity = Activity() - def reset_activity_to_idle(self): - self.is_idle = True - self.is_sleeping = False - self.is_dreaming = False - self.is_moving = False - self.is_talking = False - self.is_thinking = False + def action_loop(self): + print(f'Interacting with user: {self.activity.is_interacting_with_user}') + if self.activity.is_interacting_with_user: return + + if self.activity.is_sleeping: + pass def choose_walk_destination(self): """Decide, where the VPet should move to""" @@ -83,21 +145,20 @@ class VPet: """Decide, what kind of activity should be done""" pass - def move(self, x: int, y: int): + def walk(self, x: int, y: int): """Move the VPet to xy""" - self.is_moving = True + self.activity.is_moving = True def sleep(self): """Set the VPet asleep""" - self.reset_activity_to_idle() - self.is_sleeping = True + self.activity.set_sleeping() Animations.sleep(rotation=self.rotation) def wakeup(self): """Wake up the VPet from sleep""" - if not self.is_sleeping: return + if not self.activity.is_sleeping: return Animations.wakeup(rotation=self.rotation) - self.reset_activity_to_idle() + self.activity.set_idle() def blink_eyes(self): """Make the VPet blink""" diff --git a/window_qt.py b/window_qt.py index 576c3d0..4ef9064 100755 --- a/window_qt.py +++ b/window_qt.py @@ -1,110 +1,35 @@ #!/bin/python3 -import datetime import time -import asyncio - -from PyQt5.QtWidgets import QOpenGLWidget from PyQt5.QtWidgets import QMainWindow from PyQt5.QtWidgets import QApplication -from PyQt5.QtCore import Qt -from OpenGL.GL import * -from OpenGL.GLU import gluOrtho2D -from PIL import Image +from PyQt5.QtCore import Qt, QTimer +from transparent_widget import TransparentGLWidget from vpet import Rotate - - -class TransparentGLWidget(QOpenGLWidget): - def __init__(self, image_path): - super().__init__() - self.image_path = image_path - self.texture = None - self.image_width = 1 - self.image_height = 1 - - def initializeGL(self): - glEnable(GL_BLEND) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) - glEnable(GL_DEPTH_TEST) - glClearColor(0.0, 0.0, 0.0, 0.0) - - # Textur init - self.texture, self.image_width, self.image_height = self.load_texture(self.image_path) - - def resizeGL(self, w, h): - glViewport(0, 0, w, h) - glMatrixMode(GL_PROJECTION) - glLoadIdentity() - gluOrtho2D(0, w, 0, h) # Orthografische Projektion für 2D - glMatrixMode(GL_MODELVIEW) - - def paintGL(self): - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - glLoadIdentity() - glPushMatrix() # Matrix speichern - self.draw_textured_quad() - glPopMatrix() # Matrix wiederherstellen - - def load_texture(self, image_path): - img = Image.open(image_path).convert("RGBA") - img = img.rotate(angle=Rotate.up) - img_data = img.tobytes() - width, height = img.size - - # Create OpenGL texture - texture_id = glGenTextures(1) - glBindTexture(GL_TEXTURE_2D, texture_id) - - # Set texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - - # Load texture - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data) - return texture_id, width, height - - def draw_textured_quad(self): - glEnable(GL_TEXTURE_2D) - glBindTexture(GL_TEXTURE_2D, self.texture) - - width, height = self.width(), self.height() - - glBegin(GL_QUADS) - glTexCoord2f(0.0, 0.0) - glVertex2f(0, 0) # Down left corner - glTexCoord2f(1.0, 0.0) - glVertex2f(width, 0) # Down right corner - glTexCoord2f(1.0, 1.0) - glVertex2f(width, height) # Up right corner - glTexCoord2f(0.0, 1.0) - glVertex2f(0, height) # Up left corner - glEnd() - - glDisable(GL_TEXTURE_2D) +from vpet import VPet class MainWindow(QMainWindow): - def __init__(self, image_path): + def __init__(self): super().__init__() + self.FPS = 60 # self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.setAttribute(Qt.WA_TranslucentBackground) - self.setCentralWidget(TransparentGLWidget(image_path)) self.click_event_time = 0 - img = Image.open(image_path) - self.resize(img.width, img.height) + self.v_pet = VPet(self.move, self.pos, self.draw) - async def loop(self): - self.move(0, 0) - self.show() - print('Loop') + self.loop_timer = QTimer(self) + self.loop_timer.setSingleShot(False) + self.loop_timer.setInterval(self.FPS) + self.loop_timer.timeout.connect(self.loop) + self.loop_timer.start() def mousePressEvent(self, event): self.click_event_time = time.time() + self.v_pet.activity.set_interacting_with_user() if event.button() == Qt.LeftButton: self.drag_position = event.globalPos() @@ -115,7 +40,9 @@ class MainWindow(QMainWindow): print('Click left') if event.button() == Qt.RightButton: print('Click right') + self.click_event_time = 0 + self.v_pet.activity.is_interacting_with_user = False def mouseMoveEvent(self, event): self.click_event_time = 0 @@ -124,12 +51,16 @@ class MainWindow(QMainWindow): self.move(self.pos() + delta) self.drag_position = event.globalPos() + def draw(self, img): + img = img.rotate(Rotate.up) + self.resize(img.width, img.height) + self.setCentralWidget(TransparentGLWidget(img)) -async def start(): - app = QApplication([]) - image_path = 'pets_sprites/demonite/demonite_idle1.png' # Ersetze dies mit deinem Bildpfad - window = MainWindow(image_path) - await window.loop() - app.exec_() + def loop(self): + self.v_pet.action_loop() + self.show() -asyncio.run(start()) + +app = QApplication([]) +window = MainWindow() +app.exec_()