first push

This commit is contained in:
DasMoorhuhn 2024-12-11 18:31:41 +01:00
parent ed89f20720
commit 7a80477890
15 changed files with 406 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
__pycache__/
.idea/
*.swap

57
experiments/window_gtk.py Normal file
View 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()

View 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
main.py Normal file
View File

0
os_linux.py Normal file
View File

0
os_windows.py Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

121
vpet.py Normal file
View 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
View 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())