first push
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
__pycache__/
|
||||
.idea/
|
||||
*.swap
|
||||
57
experiments/window_gtk.py
Normal file
@ -0,0 +1,57 @@
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, Gdk, GdkPixbuf, cairo
|
||||
|
||||
|
||||
class VPetWindow(Gtk.Window):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# Fensterkonfiguration
|
||||
self.set_title("vPet")
|
||||
self.set_default_size(48, 48)
|
||||
self.set_app_paintable(True)
|
||||
self.set_decorated(False)
|
||||
self.set_keep_above(True)
|
||||
self.set_accept_focus(False)
|
||||
|
||||
# Entferne den Fensterschatten und wende RGBA-Visual an
|
||||
screen = self.get_screen()
|
||||
visual = screen.get_rgba_visual()
|
||||
if visual:
|
||||
self.set_visual(visual)
|
||||
|
||||
# Mausereignisse ignorieren
|
||||
self.connect("screen-changed", self.on_screen_changed)
|
||||
self.set_app_paintable(True)
|
||||
self.on_screen_changed(None)
|
||||
|
||||
# Lade und zeige das Sprite (virtuelles Haustier)
|
||||
self.image = Gtk.Image()
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file("vpet_sprite.png") # Ersetze mit deinem Sprite
|
||||
self.image.set_from_pixbuf(pixbuf)
|
||||
self.add(self.image)
|
||||
|
||||
self.show_all()
|
||||
|
||||
def on_screen_changed(self, screen):
|
||||
gdk_window = self.get_window()
|
||||
if gdk_window:
|
||||
# Eingabeform auf das Sprite beschränken
|
||||
region = Gdk.cairo_region_create_from_surface(self.get_mask())
|
||||
gdk_window.input_shape_combine_region(region)
|
||||
|
||||
def get_mask(self):
|
||||
# Maske für die Eingabe basierend auf der Sprite-Form erstellen
|
||||
pixbuf = self.image.get_pixbuf()
|
||||
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, pixbuf.get_width(), pixbuf.get_height())
|
||||
cr = cairo.Context(surface)
|
||||
Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
|
||||
cr.paint()
|
||||
return surface
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
win = VPetWindow()
|
||||
win.connect("destroy", Gtk.main_quit)
|
||||
Gtk.main()
|
||||
90
experiments/window_opengl.py
Normal file
@ -0,0 +1,90 @@
|
||||
import pygame
|
||||
from OpenGL.GL import *
|
||||
from OpenGL.GLU import *
|
||||
from OpenGL.GLUT import *
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
# Pet Attribute
|
||||
class VirtualPet:
|
||||
def __init__(self):
|
||||
self.happiness = 50
|
||||
self.hunger = 50
|
||||
|
||||
def feed(self):
|
||||
self.hunger -= 10
|
||||
self.happiness += 5
|
||||
|
||||
def pet(self):
|
||||
self.happiness += 10
|
||||
|
||||
def update(self):
|
||||
self.hunger += 0.1
|
||||
self.happiness -= 0.05
|
||||
|
||||
|
||||
# OpenGL-Setup
|
||||
def init_opengl():
|
||||
glEnable(GL_BLEND) # Aktiviert Transparenz
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||
glEnable(GL_DEPTH_TEST)
|
||||
glClearColor(0.2, 0.6, 0.8, 0.0) # Himmelblau mit Transparenz (Alpha = 0.5)
|
||||
gluPerspective(45, (800 / 600), 0.1, 50.0)
|
||||
|
||||
|
||||
# Pet zeichnen (Würfel als Platzhalter)
|
||||
def draw_pet():
|
||||
glPushMatrix()
|
||||
glColor4f(0, 0, 0, 0.2)
|
||||
glTranslatef(0.0, 0.0, -5)
|
||||
glRotatef(pygame.time.get_ticks() * 0.05, 0, 1, 0) # Rotation
|
||||
glutWireCube(1) # Zeichnet den Würfel
|
||||
glPopMatrix()
|
||||
|
||||
|
||||
# Hauptprogramm
|
||||
def main():
|
||||
# Setze Umgebungsvariablen für transparentes Fenster
|
||||
os.environ['SDL_VIDEODRIVER'] = 'x11'
|
||||
os.environ['SDL_VIDEO_WINDOW_POS'] = '0,0'
|
||||
os.environ['SDL_VIDEO_CENTERED'] = '1'
|
||||
|
||||
pygame.init()
|
||||
display = pygame.display.set_mode((48, 48), pygame.DOUBLEBUF | pygame.OPENGL | pygame.NOFRAME | pygame.SRCALPHA)
|
||||
pygame.display.set_caption("Transparent Virtual Pet")
|
||||
clock = pygame.time.Clock()
|
||||
display.set
|
||||
|
||||
pet = VirtualPet()
|
||||
glutInit() # Initialisiert GLUT
|
||||
init_opengl()
|
||||
|
||||
# Setze Transparenz für das Fenster
|
||||
# pygame.display.set_mode((800, 600), pygame.OPENGL | pygame.DOUBLEBUF | pygame.NOFRAME | pygame.SRCALPHA)
|
||||
|
||||
running = True
|
||||
while running:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_f:
|
||||
pet.feed()
|
||||
elif event.key == pygame.K_p:
|
||||
pet.pet()
|
||||
|
||||
pet.update()
|
||||
|
||||
# OpenGL Rendering
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
||||
draw_pet()
|
||||
pygame.display.flip()
|
||||
clock.tick(60)
|
||||
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
0
os_linux.py
Normal file
0
os_windows.py
Normal file
BIN
pets_sprites/demonite/demonite_float_correct.png
Normal file
|
After Width: | Height: | Size: 712 B |
BIN
pets_sprites/demonite/demonite_idle1.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
pets_sprites/demonite/demonite_idle2.png
Normal file
|
After Width: | Height: | Size: 581 B |
BIN
pets_sprites/demonite/demonite_idle3.png
Normal file
|
After Width: | Height: | Size: 604 B |
BIN
pets_sprites/demonite/demonite_moving_right1.png
Normal file
|
After Width: | Height: | Size: 604 B |
BIN
pets_sprites/demonite/demonite_moving_right2.png
Normal file
|
After Width: | Height: | Size: 578 B |
BIN
pets_sprites/demonite/heart_heart.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
121
vpet.py
Normal file
@ -0,0 +1,121 @@
|
||||
from PIL import Image
|
||||
|
||||
|
||||
class Rotate:
|
||||
down = 0.0
|
||||
right = 90.0
|
||||
up = 180.0
|
||||
left = 270.0
|
||||
|
||||
|
||||
class Dialogs:
|
||||
dreaming = []
|
||||
|
||||
|
||||
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'
|
||||
|
||||
|
||||
class Animations:
|
||||
@staticmethod
|
||||
def idle_1(rotation: float):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def move_right(rotation: float):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def move_left(rotation: float):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def move_up(rotation: float):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def move_down(rotation: float):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def sleep(rotation: float):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def wakeup(rotation: float):
|
||||
pass
|
||||
|
||||
|
||||
class VPet:
|
||||
def __init__(self, x=0, y=0, screen=1):
|
||||
self.screen = screen
|
||||
self.x_postion = x
|
||||
self.y_postion = y
|
||||
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
|
||||
|
||||
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 choose_walk_destination(self):
|
||||
"""Decide, where the VPet should move to"""
|
||||
pass
|
||||
|
||||
def choose_activity(self):
|
||||
"""Decide, what kind of activity should be done"""
|
||||
pass
|
||||
|
||||
def move(self, x: int, y: int):
|
||||
"""Move the VPet to xy"""
|
||||
self.is_moving = True
|
||||
|
||||
def sleep(self):
|
||||
"""Set the VPet asleep"""
|
||||
self.reset_activity_to_idle()
|
||||
self.is_sleeping = True
|
||||
Animations.sleep(rotation=self.rotation)
|
||||
|
||||
def wakeup(self):
|
||||
"""Wake up the VPet from sleep"""
|
||||
if not self.is_sleeping: return
|
||||
Animations.wakeup(rotation=self.rotation)
|
||||
self.reset_activity_to_idle()
|
||||
|
||||
def blink_eyes(self):
|
||||
"""Make the VPet blink"""
|
||||
pass
|
||||
|
||||
def detect_orientation(self):
|
||||
"""Detect the desired rotation based on the postion on the screen, like left border, bottom, etc"""
|
||||
pass
|
||||
|
||||
def talk(self, message: str):
|
||||
"""Make the VPet talk to the user via a speech bubble"""
|
||||
pass
|
||||
|
||||
def think(self):
|
||||
"""Make the VPet think"""
|
||||
pass
|
||||
|
||||
def dream(self):
|
||||
"""Make the VPet dream"""
|
||||
pass
|
||||
|
||||
135
window_qt.py
Executable file
@ -0,0 +1,135 @@
|
||||
#!/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 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)
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, image_path):
|
||||
super().__init__()
|
||||
# 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)
|
||||
|
||||
async def loop(self):
|
||||
self.move(0, 0)
|
||||
self.show()
|
||||
print('Loop')
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
self.click_event_time = time.time()
|
||||
if event.button() == Qt.LeftButton:
|
||||
self.drag_position = event.globalPos()
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
time_delta = time.time() - self.click_event_time
|
||||
if time_delta <= 0.2:
|
||||
if event.button() == Qt.LeftButton:
|
||||
print('Click left')
|
||||
if event.button() == Qt.RightButton:
|
||||
print('Click right')
|
||||
self.click_event_time = 0
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
self.click_event_time = 0
|
||||
if event.buttons() == Qt.LeftButton:
|
||||
delta = event.globalPos() - self.drag_position
|
||||
self.move(self.pos() + delta)
|
||||
self.drag_position = event.globalPos()
|
||||
|
||||
|
||||
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_()
|
||||
|
||||
asyncio.run(start())
|
||||