add action loop
|
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 712 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 606 B After Width: | Height: | Size: 606 B |
|
Before Width: | Height: | Size: 604 B After Width: | Height: | Size: 604 B |
|
Before Width: | Height: | Size: 604 B After Width: | Height: | Size: 604 B |
|
Before Width: | Height: | Size: 578 B After Width: | Height: | Size: 578 B |
4
requierements.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
PyOpenGL
|
||||||
|
PyGObject-stubs
|
||||||
|
PyQt5
|
||||||
|
PyQt5-stubs
|
||||||
74
transparent_widget.py
Normal 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
@ -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"""
|
||||||
|
|||||||
117
window_qt.py
@ -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))
|
||||||
|
|
||||||
|
def loop(self):
|
||||||
|
self.v_pet.action_loop()
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
async def start():
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
image_path = 'pets_sprites/demonite/demonite_idle1.png' # Ersetze dies mit deinem Bildpfad
|
window = MainWindow()
|
||||||
window = MainWindow(image_path)
|
|
||||||
await window.loop()
|
|
||||||
app.exec_()
|
app.exec_()
|
||||||
|
|
||||||
asyncio.run(start())
|
|
||||||
|
|||||||