add action loop

This commit is contained in:
DasMoorhuhn 2024-12-12 03:34:02 +01:00
parent 7a80477890
commit f9c15707ef
11 changed files with 192 additions and 121 deletions

1
deb.sh Executable file
View File

@ -0,0 +1 @@
sudo apt-get install -y freeglut3-dev

View File

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 712 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 606 B

View File

Before

Width:  |  Height:  |  Size: 604 B

After

Width:  |  Height:  |  Size: 604 B

View File

Before

Width:  |  Height:  |  Size: 604 B

After

Width:  |  Height:  |  Size: 604 B

View File

Before

Width:  |  Height:  |  Size: 578 B

After

Width:  |  Height:  |  Size: 578 B

4
requierements.txt Normal file
View File

@ -0,0 +1,4 @@
PyOpenGL
PyGObject-stubs
PyQt5
PyQt5-stubs

74
transparent_widget.py Normal file
View File

@ -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

115
vpet.py
View File

@ -14,13 +14,14 @@ class Dialogs:
class Frames: class Frames:
"""These strings do match to the PNGs of the VPet which are representation the frames of an animation""" """These strings do match to the PNGs of the VPet which are representation the frames of an animation"""
idle_1 = 'idle1' def __init__(self):
idle_2 = 'idle2' self.idle_1 = Image.open('pets_sprites/demonite/idle1.png')
idle_3 = 'idle3' self.idle_2 = Image.open('pets_sprites/demonite/idle2.png')
move_1 = 'moving_1' self.idle_3 = Image.open('pets_sprites/demonite/idle3.png')
move_2 = 'moving_2' self.move_1 = Image.open('pets_sprites/demonite/moving_1.png')
hearts_1 = 'heart' self.move_2 = Image.open('pets_sprites/demonite/moving_2.png')
floating = 'floating' self.hearts_1 = Image.open('pets_sprites/demonite/heart.png')
self.floating = Image.open('pets_sprites/demonite/floating.png')
class Animations: class Animations:
@ -53,27 +54,88 @@ class Animations:
pass 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: 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.screen = screen
self.pos = pos
self.x_postion = x self.x_postion = x
self.y_postion = y self.y_postion = y
self.x_destination = 0
self.y_destination = 0
self.rotation = Rotate.up self.rotation = Rotate.up
self.is_idle = True self.move = move
self.is_sleeping = False self.draw = draw
self.is_dreaming = False self.frames = Frames()
self.is_moving = False self.activity = Activity()
self.is_talking = False
self.is_thinking = False
def reset_activity_to_idle(self): def action_loop(self):
self.is_idle = True print(f'Interacting with user: {self.activity.is_interacting_with_user}')
self.is_sleeping = False if self.activity.is_interacting_with_user: return
self.is_dreaming = False
self.is_moving = False if self.activity.is_sleeping:
self.is_talking = False pass
self.is_thinking = False
def choose_walk_destination(self): def choose_walk_destination(self):
"""Decide, where the VPet should move to""" """Decide, where the VPet should move to"""
@ -83,21 +145,20 @@ class VPet:
"""Decide, what kind of activity should be done""" """Decide, what kind of activity should be done"""
pass pass
def move(self, x: int, y: int): def walk(self, x: int, y: int):
"""Move the VPet to xy""" """Move the VPet to xy"""
self.is_moving = True self.activity.is_moving = True
def sleep(self): def sleep(self):
"""Set the VPet asleep""" """Set the VPet asleep"""
self.reset_activity_to_idle() self.activity.set_sleeping()
self.is_sleeping = True
Animations.sleep(rotation=self.rotation) Animations.sleep(rotation=self.rotation)
def wakeup(self): def wakeup(self):
"""Wake up the VPet from sleep""" """Wake up the VPet from sleep"""
if not self.is_sleeping: return if not self.activity.is_sleeping: return
Animations.wakeup(rotation=self.rotation) Animations.wakeup(rotation=self.rotation)
self.reset_activity_to_idle() self.activity.set_idle()
def blink_eyes(self): def blink_eyes(self):
"""Make the VPet blink""" """Make the VPet blink"""

View File

@ -1,110 +1,35 @@
#!/bin/python3 #!/bin/python3
import datetime
import time import time
import asyncio
from PyQt5.QtWidgets import QOpenGLWidget
from PyQt5.QtWidgets import QMainWindow from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt, QTimer
from OpenGL.GL import *
from OpenGL.GLU import gluOrtho2D
from PIL import Image
from transparent_widget import TransparentGLWidget
from vpet import Rotate from vpet import Rotate
from vpet import VPet
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)
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
def __init__(self, image_path): def __init__(self):
super().__init__() super().__init__()
self.FPS = 60
# self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) # self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setWindowFlags(Qt.WindowStaysOnTopHint) self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground) self.setAttribute(Qt.WA_TranslucentBackground)
self.setCentralWidget(TransparentGLWidget(image_path))
self.click_event_time = 0 self.click_event_time = 0
img = Image.open(image_path) self.v_pet = VPet(self.move, self.pos, self.draw)
self.resize(img.width, img.height)
async def loop(self): self.loop_timer = QTimer(self)
self.move(0, 0) self.loop_timer.setSingleShot(False)
self.show() self.loop_timer.setInterval(self.FPS)
print('Loop') self.loop_timer.timeout.connect(self.loop)
self.loop_timer.start()
def mousePressEvent(self, event): def mousePressEvent(self, event):
self.click_event_time = time.time() self.click_event_time = time.time()
self.v_pet.activity.set_interacting_with_user()
if event.button() == Qt.LeftButton: if event.button() == Qt.LeftButton:
self.drag_position = event.globalPos() self.drag_position = event.globalPos()
@ -115,7 +40,9 @@ class MainWindow(QMainWindow):
print('Click left') print('Click left')
if event.button() == Qt.RightButton: if event.button() == Qt.RightButton:
print('Click right') print('Click right')
self.click_event_time = 0 self.click_event_time = 0
self.v_pet.activity.is_interacting_with_user = False
def mouseMoveEvent(self, event): def mouseMoveEvent(self, event):
self.click_event_time = 0 self.click_event_time = 0
@ -124,12 +51,16 @@ class MainWindow(QMainWindow):
self.move(self.pos() + delta) self.move(self.pos() + delta)
self.drag_position = event.globalPos() 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(): def loop(self):
app = QApplication([]) self.v_pet.action_loop()
image_path = 'pets_sprites/demonite/demonite_idle1.png' # Ersetze dies mit deinem Bildpfad self.show()
window = MainWindow(image_path)
await window.loop()
app.exec_()
asyncio.run(start())
app = QApplication([])
window = MainWindow()
app.exec_()