mirror of
https://github.com/Kitito76/avatar.git
synced 2025-10-29 05:15:59 +00:00
300 lines
12 KiB
Python
300 lines
12 KiB
Python
import sys
|
|
import time
|
|
import os
|
|
import random
|
|
from threading import Thread
|
|
from PyQt5.QtWidgets import QApplication, QLabel, QWidget
|
|
from PyQt5.QtGui import QPixmap, QTransform
|
|
from PyQt5.QtCore import QTimer, Qt, QPoint
|
|
|
|
|
|
class FloatingImage(QWidget):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool)
|
|
self.setAttribute(Qt.WA_TranslucentBackground)
|
|
|
|
# Variables de mouvement et état
|
|
self.gravity = 1
|
|
self.jump_strength = -15
|
|
self.dy = 0
|
|
self.dx = 0
|
|
self.on_ground = False
|
|
self.flying = False
|
|
self.friction = 0.95
|
|
self.moving_left = False
|
|
self.moving_right = False
|
|
self.moving_up = False
|
|
self.moving_down = False
|
|
self.jump_requested = False
|
|
self.dragging = False
|
|
self.hidden_in_folder = False # Ajouté pour gérer l'entrée dans les dossiers
|
|
self.offset = QPoint()
|
|
self.last_mouse_pos = QPoint()
|
|
self.last_mouse_time = 0
|
|
|
|
# Variables pour aller vers un dossier
|
|
self.target_folder = None
|
|
self.target_position = None
|
|
self.moving_to_folder = False
|
|
|
|
# Chargement de l'image
|
|
self.label = QLabel(self)
|
|
pixmap = QPixmap("avatar_mouv1.png")
|
|
if pixmap.isNull():
|
|
print("Erreur : Impossible de charger avatar.png")
|
|
self.label.setPixmap(pixmap)
|
|
self.label.adjustSize()
|
|
self.resize(pixmap.width(), pixmap.height())
|
|
self.label.show()
|
|
self.show()
|
|
|
|
# Timer de mise à jour
|
|
self.timer = QTimer()
|
|
self.timer.timeout.connect(self.update_movement)
|
|
self.timer.start(30)
|
|
|
|
# Mode IA (désactivé au début)
|
|
self.ai_mode = False
|
|
self.ai_timer = QTimer()
|
|
self.ai_timer.timeout.connect(self.update_ai_behavior) # Appelle une fonction pour changer le comportement
|
|
|
|
self.ai_wants_to_fly = False # L'IA ne veut pas voler au départ
|
|
self.last_flight_toggle_time = time.time() # Dernière activation/désactivation du vol
|
|
|
|
self.sprint_active = False # Indique si l'avatar est en sprint
|
|
self.sprint_timer = 0 # Temps depuis lequel la touche est maintenue
|
|
self.base_speed = 3 # Vitesse normale
|
|
self.sprint_speed = 5 # Vitesse en sprint
|
|
self.current_speed = self.base_speed # Vitesse actuelle
|
|
|
|
self.bounce_factor = 0.5 # Facteur de rebond (50% de la vitesse est conservée)
|
|
self.bounce_threshold = 10 # Vitesse minimale pour rebondir
|
|
|
|
def update_ai_behavior(self):
|
|
import random
|
|
"""L'IA choisit une action et l'exécute."""
|
|
if not self.ai_mode:
|
|
return # L'IA ne bouge pas si elle est désactivée
|
|
|
|
actions = []
|
|
|
|
# Mode MARCHE (si au sol)
|
|
if self.on_ground:
|
|
actions.extend(["left", "right", "jump", "idle"]) # Il peut marcher, sauter ou rien faire
|
|
|
|
# Mode VOL (si activé)
|
|
if self.flying:
|
|
actions.extend(["fly_up", "fly_down", "fly_left", "fly_right", "idle"])
|
|
|
|
# Si l'avatar est en l'air mais pas en vol, il ne peut que tomber
|
|
if not self.on_ground and not self.flying:
|
|
actions = ["idle"] # Rien à faire, il chute tout seul
|
|
|
|
action = random.choice(actions) # Choisit une action au hasard
|
|
print(f"🤖 L'IA a choisi : {action}")
|
|
|
|
# Exécute l'action
|
|
if action == "left":
|
|
self.moving_left = True
|
|
self.moving_right = False
|
|
elif action == "right":
|
|
self.moving_right = True
|
|
self.moving_left = False
|
|
elif action == "jump" and self.on_ground:
|
|
self.dy = self.jump_strength # Applique le saut
|
|
self.on_ground = False
|
|
elif action == "fly_up" and self.flying:
|
|
self.moving_up = True
|
|
elif action == "fly_down" and self.flying:
|
|
self.moving_down = True
|
|
elif action == "fly_left" and self.flying:
|
|
self.moving_left = True
|
|
elif action == "fly_right" and self.flying:
|
|
self.moving_right = True
|
|
elif action == "idle":
|
|
self.moving_left = self.moving_right = self.moving_up = self.moving_down = False # Arrête tout
|
|
|
|
def update_movement(self):
|
|
if self.hidden_in_folder:
|
|
return # Ne rien faire si caché
|
|
|
|
|
|
if self.moving_to_folder and self.target_position:
|
|
x, y = self.x(), self.y()
|
|
target_x, target_y = self.target_position
|
|
if abs(x - target_x) > 3:
|
|
x += 3 if x < target_x else -3
|
|
if abs(y - target_y) > 3:
|
|
y += 3 if y < target_y else -3
|
|
self.move(x, y)
|
|
|
|
if abs(x - target_x) <= 5 and abs(y - target_y) <= 5:
|
|
self.moving_to_folder = False
|
|
self.flying = False
|
|
print(f"Arrivé au dossier {self.target_folder} !")
|
|
|
|
elif not self.moving_to_folder and not self.dragging:
|
|
screen = QApplication.primaryScreen().geometry()
|
|
x, y = self.x(), self.y()
|
|
|
|
if self.flying:
|
|
if self.moving_up:
|
|
y -= 5
|
|
if self.moving_down:
|
|
y += 5
|
|
if self.moving_left:
|
|
x -= 5
|
|
if self.moving_right:
|
|
x += 5
|
|
else:
|
|
self.dy += self.gravity
|
|
y += self.dy
|
|
x += self.dx
|
|
|
|
if self.moving_left:
|
|
x -= 5
|
|
if self.moving_right:
|
|
x += 5
|
|
|
|
self.dx *= self.friction
|
|
self.dy *= self.friction
|
|
|
|
if y + self.height() >= screen.height():
|
|
y = screen.height() - self.height()
|
|
self.on_ground = True
|
|
self.dy = 0
|
|
self.dx = 0
|
|
else:
|
|
self.on_ground = False
|
|
|
|
if x <= 0 or x + self.width() >= screen.width():
|
|
self.dx = 0
|
|
# Vérifier si on touche le plafond (rebond)
|
|
if y <= 0:
|
|
y = 0
|
|
if abs(self.dy) > self.bounce_threshold: # Si la vitesse est suffisante
|
|
self.dy = -self.dy * self.bounce_factor
|
|
else:
|
|
self.dy = 0
|
|
|
|
x = max(0, min(screen.width() - self.width(), x))
|
|
y = max(0, min(screen.height() - self.height(), y))
|
|
|
|
# L'IA décide d'activer ou désactiver le vol
|
|
current_time = time.time()
|
|
if current_time - self.last_flight_toggle_time > 10: # Attendre au moins 10 sec avant un changement
|
|
if self.flying: # Si elle vole déjà
|
|
if current_time - self.last_flight_toggle_time > 30: # Vol max de 1 min
|
|
self.flying = False
|
|
self.moving_up = self.moving_down = False # Arrêter les déplacements verticaux
|
|
self.last_flight_toggle_time = current_time
|
|
print("✈️ L'IA désactive le vol")
|
|
else: # Si elle est au sol
|
|
if random.random() < 0.1: # 10% de chance d'activer le vol
|
|
self.flying = True
|
|
self.last_flight_toggle_time = current_time
|
|
print("🚀 L'IA active le vol")
|
|
|
|
# Vérifier si on doit activer le sprint
|
|
if (self.moving_left or self.moving_right):
|
|
if not self.sprint_active and time.time() - self.sprint_timer >= 1: # Sprint après 1 sec
|
|
self.sprint_active = True
|
|
self.current_speed = self.sprint_speed # Augmente la vitesse
|
|
elif not self.moving_left and not self.moving_right:
|
|
self.sprint_active = False
|
|
self.current_speed = self.base_speed # Revenir à la vitesse normale
|
|
|
|
# Appliquer la vitesse actuelle
|
|
if self.moving_left:
|
|
x -= self.current_speed
|
|
if self.moving_right:
|
|
x += self.current_speed
|
|
|
|
if self.moving_right:
|
|
self.label.setPixmap(
|
|
QPixmap("avatar_mouv1.png").transformed(QTransform().scale(-1, 1))) # Retourne l'image
|
|
elif self.moving_left:
|
|
self.label.setPixmap(QPixmap("avatar_mouv1.png")) # Remet l'image normale
|
|
|
|
|
|
self.move(int(x), int(y))
|
|
|
|
def keyPressEvent(self, event):
|
|
if event.key() == Qt.Key_Left:
|
|
self.moving_left = True
|
|
self.sprint_timer = time.time() # Enregistre le moment où la touche est pressée
|
|
|
|
elif event.key() == Qt.Key_Right:
|
|
self.moving_right = True
|
|
self.sprint_timer = time.time() # Enregistre le moment où la touche est pressée
|
|
|
|
elif event.key() == Qt.Key_Up and self.flying:
|
|
self.moving_up = True
|
|
elif event.key() == Qt.Key_Down and self.flying:
|
|
self.moving_down = True
|
|
elif event.key() == Qt.Key_Space and self.on_ground:
|
|
self.dy = self.jump_strength
|
|
self.on_ground = False
|
|
elif event.key() == Qt.Key_V:
|
|
self.flying = not self.flying
|
|
if self.flying:
|
|
self.dy = 0
|
|
if event.key() == Qt.Key_I:
|
|
self.ai_mode = not self.ai_mode # Active/Désactive le mode IA
|
|
if self.ai_mode:
|
|
print("✅ Mode IA activé !")
|
|
self.ai_timer.start(2000) # Change de comportement toutes les 2 secondes
|
|
else:
|
|
print("❌ Mode IA désactivé !")
|
|
self.ai_timer.stop()
|
|
|
|
|
|
def keyReleaseEvent(self, event):
|
|
if event.key() == Qt.Key_Left:
|
|
self.moving_left = False
|
|
elif event.key() == Qt.Key_Right:
|
|
self.moving_right = False
|
|
elif event.key() == Qt.Key_Up:
|
|
self.moving_up = False
|
|
elif event.key() == Qt.Key_Down:
|
|
self.moving_down = False
|
|
if event.key() == Qt.Key_Left or event.key() == Qt.Key_Right:
|
|
self.moving_left = False
|
|
self.moving_right = False
|
|
self.sprint_active = False # Désactive le sprint
|
|
self.current_speed = self.base_speed # Remet la vitesse normale
|
|
|
|
def mousePressEvent(self, event):
|
|
if event.button() == Qt.LeftButton:
|
|
self.dragging = True
|
|
self.offset = event.globalPos() - self.pos()
|
|
self.last_mouse_pos = event.globalPos()
|
|
self.last_mouse_time = time.time()
|
|
|
|
def mouseMoveEvent(self, event):
|
|
if self.dragging:
|
|
screen = QApplication.primaryScreen().geometry()
|
|
new_x = event.globalX() - self.offset.x()
|
|
new_y = event.globalY() - self.offset.y()
|
|
new_x = max(0, min(screen.width() - self.width(), new_x))
|
|
new_y = max(0, min(screen.height() - self.height(), new_y))
|
|
self.move(new_x, new_y)
|
|
|
|
def mouseReleaseEvent(self, event):
|
|
if event.button() == Qt.LeftButton:
|
|
self.dragging = False
|
|
time_elapsed = time.time() - self.last_mouse_time
|
|
if time_elapsed < 0.15:
|
|
mouse_delta = event.globalPos() - self.last_mouse_pos
|
|
speed_factor = 0.2
|
|
self.dx = mouse_delta.x() * speed_factor
|
|
self.dy = mouse_delta.y() * speed_factor
|
|
|
|
|
|
app = QApplication(sys.argv)
|
|
window = FloatingImage()
|
|
window.show()
|
|
sys.exit(app.exec_())
|