Vyhýbanie sa zrážkam z QGraphicsItem tvary dojatý myš

0

Otázka

Zaujímavá diskusia k navýšeniu tu o predchádzaní kolíziám kruhov, vyrobené z QGraphicsEllipseItems, v QGraphicsScene. Otázka zúžila priestor na 2 kolízie položky, ale väčšie cieľom ešte zostali, čo pre ľubovoľný počet zrážok?

Je to požadované správanie:

  • Keď jedna položka je ťahaný cez ďalších položiek, že by sa nemali prekrývať, namiesto toho by sa mal pohybovať okolo tých položiek, čo najbližšie k myši.
  • To by nemalo "teleport" ak sa dostane blokované v iných položiek.
  • To by mal byť hladký a predvídateľný pohybu.

Ako to stáva čoraz zložitejšie nájsť najlepšie "bezpečné" pozíciu na kruhu, zatiaľ čo v pohybe, som chcel predstaviť iný spôsob, ako realizovať pomocou fyziky simulátor.

collision pymunk pyqt5 python
2021-11-23 02:01:24
1

Najlepšiu odpoveď

3

Vzhľadom na správanie popísané vyššie, je to dobrý kandidát pre 2D pevné telo fyziky, možno sa to dá urobiť bez toho, ale bolo by ťažké sa dostať perfektné. Ja používam pymunk v tomto príklade, pretože som oboznámený s ním, ale tie isté pojmy, bude pracovať s inými knižnicami.

Na scéne sa kinematická telo predstavujú myši a kruhy sú zastúpené statické orgány spočiatku. Pri kruhu je vybrali to prepne na dynamické telo a je fixovaný na myši a tlmené jar. Jeho poloha sa aktualizuje ako priestor je aktualizovaný v danom časovom kroku na každý časový interval, interval.

Tovar nie je pohybovali rovnakým spôsobom ako ItemIsMovable vlajky nie je povolené, čo znamená, že už sa pohybuje okamžite s myšou. Je to veľmi blízko, ale tam je malé oneskorenie, hoci si to možno radšej to lepšie vidieť, ako reaguje na zrážok. (Aj tak môžete doladiť parametre majú to pohyb rýchlejší/bližšie k myši, než som urobil**).

Na druhej strane, kolízie sú spracované perfektne a už bude podporovať iné druhy tvarov.

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import pymunk

class Circle(QGraphicsEllipseItem):

    def __init__(self, r, **kwargs):
        super().__init__(-r, -r, r * 2, r * 2, **kwargs)
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.static = pymunk.Body(body_type=pymunk.Body.STATIC)
        self.circle = pymunk.Circle(self.static, r)
        self.circle.friction = 0
        mass = 10
        self.dynamic = pymunk.Body(mass, pymunk.moment_for_circle(mass, 0, r))
        self.updatePos = lambda: self.setPos(*self.dynamic.position, dset=False)

    def setPos(self, *pos, dset=True):
        super().setPos(*pos)
        if len(pos) == 1:
            pos = pos[0].x(), pos[0].y()
        self.static.position = pos
        if dset:
            self.dynamic.position = pos

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedChange:
            space = self.circle.space
            space.remove(self.circle.body, self.circle)
            self.circle.body = self.dynamic if value else self.static
            space.add(self.circle.body, self.circle)
        return super().itemChange(change, value)

    def paint(self, painter, option, widget):
        option.state &= ~QStyle.State_Selected
        super().paint(painter, option, widget)


class Scene(QGraphicsScene):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.space = pymunk.Space()
        self.space.damping = 0.02
        self.body = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
        self.space.add(self.body)
        self.timer = QTimer(self, timerType=Qt.PreciseTimer, timeout=self.step)
        self.selectionChanged.connect(self.setConstraint)

    def setConstraint(self):
        selected = self.selectedItems()
        if selected:
            shape = selected[0].circle
            if not shape.body.constraints:
                self.space.remove(*self.space.constraints)
                spring = pymunk.DampedSpring(
                    self.body, shape.body, (0, 0), (0, 0),
                    rest_length=0, stiffness=100, damping=10)
                spring.collide_bodies = False
                self.space.add(spring)

    def step(self):
        for i in range(10):
            self.space.step(1 / 30)
        self.selectedItems()[0].updatePos()

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        if self.selectedItems():
            self.body.position = event.scenePos().x(), event.scenePos().y()
            self.timer.start(1000 / 30)
            
    def mouseMoveEvent(self, event):            
        super().mouseMoveEvent(event)
        if self.selectedItems():
            self.body.position = event.scenePos().x(), event.scenePos().y()
        
    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)
        self.timer.stop()

    def addCircle(self, x, y, radius):
        item = Circle(radius)
        item.setPos(x, y)
        self.addItem(item)
        self.space.add(item.circle.body, item.circle)
        return item


if __name__ == '__main__':
    app = QApplication(sys.argv)
    scene = Scene(0, 0, 1000, 800)
    for i in range(7, 13):
        item = scene.addCircle(150 * (i - 6), 400, i * 5)
        item.setBrush(Qt.GlobalColor(i))    
    view = QGraphicsView(scene, renderHints=QPainter.Antialiasing)
    view.show()
    sys.exit(app.exec_())

**Môžete upraviť nasledovné:

  • Jar stiffness a damping
  • Telo mass a moment zotrvačnosti
  • Priestor damping
  • Space.step časový krok / počet hovorov za QTimer timeout
  • QTimer interval
2021-12-01 01:57:12

Je to perfektné!!
drivereye

V iných jazykoch

Táto stránka je v iných jazykoch

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................