#include #include #include #include #include #include #include #include #include #include #include #include #include #include BCDelightPMWidget::BCDelightPMWidget(QWidget *parent) : QObject(parent), _playGround{parent} { loadWidgetsFromResources(); } // Die Methode zum automatischen Einlesen void BCDelightPMWidget::loadWidgetsFromResources() { QString resourcePath = ":/resources/smile"; // 2. Iterator erstellen // QDir::Files sorgt dafür, dass wir nur echte Dateien finden, keine Ordner wie "." oder ".." // QDirIterator::Subdirectories würde auch in Unterordnern suchen (falls nötig) QDirIterator it(resourcePath, QDir::Files); //QFileInfoList fileList: // 3. Schleife: Solange es noch Einträge gibt while (it.hasNext()) { // Iteriert zum nächsten Eintrag und gibt den kompletten virtuellen Pfad zurück // z.B. ":/icons/ball_red.png" QString fullPath = it.next(); // Eine Zufallsfarbe für den Button-Hintergrund generieren QStringList colors = {"#ff5555", "#50fa7b", "#8be9fd", "#ffb86c"}; QString randomColor = colors.at(QRandomGenerator::global()->bounded(colors.size())); // Ihre Funktion aufrufen und den Pfad übergeben createFlyingWidget(fullPath, randomColor); } } void BCDelightPMWidget::createFlyingWidget(const QString& iconPath, const QString &color) { // 1. Button als Kind des Playground erstellen QPushButton *btn = new QPushButton(_playGround); // 2. Das Icon laden und setzen QPixmap pixmap(iconPath); QIcon icon(pixmap); btn->setIcon(icon); // 3. WICHTIG: Icon-Größe und Button-Größe synchronisieren // Damit das Bild den Button voll ausfüllt QSize size(128, 128); btn->setFixedSize(size); // Die Klick-Fläche btn->setIconSize(size); // Das Bild darin // 4. Stylesheet: Alle Standard-Rahmen und Hintergründe entfernen // "border: none" entfernt den 3D-Rahmen // "background: transparent" macht den Rest unsichtbar btn->setStyleSheet( "QPushButton {" " border: none;" " background-color: transparent;" " outline: none;" /* Entfernt den Fokus-Rahmen beim Klicken */ "}" // Optional: Kleiner visueller Effekt beim Drücken (Bild bewegt sich leicht) "QPushButton:pressed {" " padding-top: 4px;" " padding-left: 4px;" "}" ); btn->show(); // --- NEU: Opacity Effekt hinzufügen --- // 1. Effekt erstellen. 'btn' wird der Parent und kümmert sich ums Löschen. QGraphicsOpacityEffect *opacityEff = new QGraphicsOpacityEffect(btn); // 2. Startwert setzen (1.0 = voll sichtbar) opacityEff->setOpacity(1.0); // 3. Dem Widget zuweisen. WICHTIG: Das Widget übernimmt den Besitz. btn->setGraphicsEffect(opacityEff); // -------------------------------------- btn->show(); // ... (Rest der Funktion: move und append) ... btn->move(50 + _flyingWidgets.size() * 60, 50); _flyingWidgets.append(btn); // Startzustand: Unsichtbar in der Mitte btn->move(_playGround->width()/2, _playGround->height()/2); opacityEff->setOpacity(0.0); } void BCDelightPMWidget::onStartChaos() { // Master-Gruppe, damit alle Widgets gleichzeitig starten QParallelAnimationGroup *masterGroup = new QParallelAnimationGroup(this); // Gemeinsamer Startpunkt berechnen (Mitte des Playgrounds) // Wir ziehen die halbe Größe eines Widgets (ca. 25px) ab, damit sie wirklich zentriert sind int centerX = (_playGround->width() / 2) - 25; int centerY = (_playGround->height() / 2) - 25; QPoint startPoint(centerX, centerY); for (QWidget *widget : std::as_const(_flyingWidgets)) { QParallelAnimationGroup *widgetGroup = new QParallelAnimationGroup(masterGroup); // --------------------------------------------------------- // 1. Die Bogen-Animation (QVariantAnimation statt QPropertyAnimation) // --------------------------------------------------------- // ZIELE UND STÜTZPUNKTE BERECHNEN int maxX = _playGround->width() - widget->width(); int maxY = _playGround->height() - widget->height(); QPoint endPoint( QRandomGenerator::global()->bounded(qMax(0, maxX)), QRandomGenerator::global()->bounded(qMax(0, maxY)) ); // Der Kontrollpunkt bestimmt die Kurve. // Für eine Rakete muss er viel HÖHER liegen als Start und Ziel. // Wir nehmen die Mitte zwischen Start/Ziel und gehen 300px nach oben (Y minus). int controlX = (startPoint.x() + endPoint.x()) / 2; int controlY = qMin(startPoint.y(), endPoint.y()) - 300; // Pfad erstellen (Quadratische Bézierkurve) QPainterPath path; path.moveTo(startPoint); // quadTo(Kontrollpunkt, Endpunkt) path.quadTo(controlX, controlY, endPoint.x(), endPoint.y()); // Die Animation treibt den Fortschritt von 0.0 bis 1.0 QVariantAnimation *animCurve = new QVariantAnimation(); int duration = 2600 + QRandomGenerator::global()->bounded(800); animCurve->setDuration(duration); animCurve->setStartValue(0.0); animCurve->setEndValue(1.0); // Für ballistische Flugbahnen ist 'OutQuad' oder 'OutSine' realistisch // (Schneller Start, oben langsamer, unten wieder schneller - physikalisch komplex, // aber OutQuad sieht gut aus für "Wurf") animCurve->setEasingCurve(QEasingCurve::OutQuad); // WICHTIG: Lambda, um bei jedem Schritt die Position zu setzen // Wir müssen 'widget' und 'path' in das Lambda capturen (by value für path ist ok) connect(animCurve, &QVariantAnimation::valueChanged, [widget, path](const QVariant &val){ qreal progress = val.toReal(); // Magie: Berechne den Punkt auf der Kurve bei 'progress' Prozent QPointF currentPos = path.pointAtPercent(progress); widget->move(currentPos.toPoint()); }); widgetGroup->addAnimation(animCurve); // --------------------------------------------------------- // 2. Fade-Out (Bleibt fast gleich) // --------------------------------------------------------- QGraphicsOpacityEffect *eff = qobject_cast(widget->graphicsEffect()); if (eff) { QPropertyAnimation *animFade = new QPropertyAnimation(eff, "opacity"); animFade->setDuration(duration); animFade->setStartValue(1.0); animFade->setEndValue(0.0); // Erst am Ende ausblenden (ExpoCurve), damit man den Flugbogen sieht animFade->setEasingCurve(QEasingCurve::InExpo); widgetGroup->addAnimation(animFade); } masterGroup->addAnimation(widgetGroup); } // Speicher aufräumen, wenn alles vorbei ist // Hinweis: Die Widgets bleiben danach unsichtbar (Opacity 0), existieren aber noch. connect(masterGroup, &QAbstractAnimation::finished, masterGroup, &QObject::deleteLater); masterGroup->start(); }