의 충돌을 피하의 QGraphicsItem 모양으로 이동 마우스

0

질문

흥미로운 토론이 제기되었 에 대해 충돌을 방지하기 원로 만든 QGraphicsEllipseItems,에 QGraphicsScene. 질문의 범위를 좁 2 항목이 충돌하지만 큰 목표는 여전히 남아 있었, 에 대해 무엇의 수에 대한 충돌?

이것은 원하는 동작:

  • 을 때의 항목이 끌고 다른 항목들을 겹치지 않도록 해야 합 대신에 이동해야 주위에 사람들 항목을 가능한 한 가깝습니다.
  • 그것은"텔레"얻는 경우에 차단하여 다른 항목입니다.
  • 어야 한 부드럽고 예측 가능한 운동입니다.

으로 이것이 점점 더 복잡한을 찾기 위해 최"안전한"위치를 원하는 동안 그것이 이동하고 싶은 다른 구현하는 방법을 사용하여 물리학 시뮬레이터입니다.

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

최고의 응답

3

주어진 동작을 위에 설명된 그것의 좋은 후보에 대한 2D 강체 물리학,어쩌면 그것없이 수행 할 수 있습니다 하지만 어렵게 될 것이라 그것을 얻을 완벽하다. 내가 사용하 pymunk 이 예제에서이기 때문에 나는 그것에 익숙하지만 같은 개념이 다른 라이브러리입니다.

현장에 있는 동체를 대표하우스 마우스와 원가로 표시되는 정적 기관입니다. 는 동안 원형을 선택한 이 스위치를 동적체 제한을 마우스로 감쇠 봄입니다. 그 위치를 업데이트로의 공간입 업데이트로 주어진 시간에 단계 각각의 제한 시간 간격입니다.

항목은 실제로 이동과 같은 방법으로 ItemIsMovable 깃발이 활성화되지 않음을 의미,그것은 더 이상 움직임으로 즉시 마우스입니다. 그것의 아주 가까이 있지만,거기 작은 지연될 수도 있지만이 선호하는 더 나은 어떻게 반응하는지 확인하는 충돌 사고로 이어질 수 있습니다. (그럼에도 불구하고,당신은 세밀하게 조정할 수 있습니다 매개 변수는 그것을 가지고 빠르게 이동/에 가까운 마우스보다 내가 못했**).

에 다른 한편으로는,충돌은 완벽하게 처리하는 것이 이미 다른 종류의 모양입니다.

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_())

**을 조정할 수 있습 다음과 같다:

  • stiffnessdamping
  • massmoment 의 관성
  • 공간 damping
  • Space.step 시간을 단계/얼마나 많은 통화당 QTimer 시간 제한
  • QTimer interval
2021-12-01 01:57:12

이것은 완벽합니다!!
drivereye

다른 언어로

이 페이지는 다른 언어로되어 있습니다

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