Не сталкивающиеся объекты, у которых есть сталкивающиеся пары, Pymunk Pygame

Я хотел бы реализовать код, который имеет несовместимые пары с сталкивающимися объектами. Мои пары - это 2 шара, которые соединены друг с другом. Я хочу, чтобы эти две пары мячей столкнулись. Однако я не хочу, чтобы эти 2 шара сталкивались с другими парами.

Как я могу реализовать маску с таким количеством категорий в ShapeFilter pymunk? Стоит ли использовать побитовые операторы? Как вы можете видеть в моем фильтре формы, я пытался игнорировать значения, которые не входят в их категорию, за исключением их попарной категории, НО это не работает для 4 + количество шаров?

Мой код не может обрабатывать эти состояния шаров друг с другом.

import pygame 
from pygame.locals import *
from pygame.color import *
import pymunk
import pymunk.pygame_util
from pymunk import Vec2d
import  sys
#import tensorflow as tf
from time import sleep
import time
import numpy as np
from math import exp
from random import seed
from random import random
import datetime
import operator


class Game:
    def __init__(self):


        # initialize game window
        pygame.init()

        self.screen_x= 1500
        self.screen_y=  200

        # Pool Hyper Parameters
        # BE CAREFULL CHANGING THESE VARIABLES

        self.pool_size = 2
        self.pool_time = 15
        #########################################################################
        # NN lists
        #Pygame fonts
        self.font = pygame.font.SysFont("Arial", 16)
        self.screen = pygame.display.set_mode((self.screen_x,self.screen_y+200)) #screen display
        self.clock = pygame.time.Clock() ## init clock
        self.running = True
        # pymunk init
        self.space = pymunk.Space()
        self.space.gravity = (0.0, -1200.0)  #gravity setup
        self.draw_options = pymunk.pygame_util.DrawOptions(self.screen)#adds add physics to the screen


    def new(self):
        # start a new game
        ## Balls
        self.balls = []

        ## creating walls
        self.static_body = self.space.static_body
        self.static_lines = [pymunk.Segment(self.static_body, (0.0,50.0), (1500.0, 50.0), 0.0) ## road
                            ,pymunk.Segment(self.static_body, (1499.0, 150.0), (1499.0, 700.0), 0.0)
                            ,pymunk.Segment(self.static_body, (1800, 50.0), (1800, 170.0), 0.0)
                           ,pymunk.Segment(self.static_body, (0.0,50.0), (0.0, 700.0), 0.0) ## wall 1
                            ]
        ## set walls
        for line in self.static_lines:
            line.elasticity = 0.95
            line.friction = 01.5
            #line.filter = pymunk.ShapeFilter(categories=np.uint8(0))

        self.space.add(self.static_lines)
        # Go to run
        self.run()

    def run(self):
        # Game Loop
        self.playing = True
        self.no_ball = True
        while self.running:
            self.events()
            if self.no_ball == True:
                self.unit(self.pool_size)

            self.update()


    def update(self):


            self.screen.fill(THECOLORS["white"])
            ### Draw stuff
            self.balls_to_remove = []
            for ball in self.balls:
                if ball.body.position.y < 0: self.balls_to_remove.append(ball)
            for ball in self.balls_to_remove:
                self.space.remove(ball, ball.body)
                self.balls.remove(ball)
            self.space.debug_draw(self.draw_options)
            ### Update physics
            self.dt = 1.0/60.0
            for k in range(1):
                self.space.step(self.dt)

            ### Flip screen
            pygame.display.flip()
            self.clock.tick(50)
            pygame.display.set_caption("fps: " + str(self.clock.get_fps()))


    def events(self):
        for event in pygame.event.get():
            if event.type == QUIT:
                self.running = False
            if event.type == KEYDOWN:
                if event.key == K_y: ## Creates a ball
                    self.running = False
                    pass

            elif event.type == pygame.MOUSEMOTION:
                (self.mouse_x,  self.mouse_y) = pymunk.pygame_util.get_mouse_pos(self.screen)



    def unit (self, number_balls=None):
        #Mass And Radius units
        self.mass = 20
        self.radius = 10

        #Mass and Radius for joint
        self.mass_joint = 2
        self.radius_joint = 2

        #for n in number_balls
        self.objs = list()
        for i in range(number_balls):

            self.objs.append(pymunk.Body())
            self.objs.append(pymunk.Body())
            self.objs.append(pymunk.Body())

            #Inertia
            self.inertia = pymunk.moment_for_circle(self.mass, 0, self.radius, (0,0))
            self.inertia_joint = pymunk.moment_for_circle(self.mass_joint , 0, self.radius_joint, (0,0))  
            #Body
            self.objs[i], self.objs[i+1] = pymunk.Body(self.mass, self.inertia), pymunk.Body(self.mass, self.inertia)
            self.objs[i+2] = pymunk.Body(self.mass_joint, self.inertia_joint)

            #Position
            x = 100
            self.objs[i].position = x   , 90
            self.objs[i+1].position = x+24, 90
            self.objs[i+2].position = x+12, 90
            #Links
            self.link_1 = pymunk.PinJoint(self.objs[i], self.objs[i+2], (0, 0), (0, 0))
            self.link_2 = pymunk.PinJoint(self.objs[i+1], self.objs[i+2], (0, 0), (0, 0))
            # Adding Body links
            self.space.add(self.link_1)
            self.space.add(self.link_2)

            #First ball shape
            self.shape_first = pymunk.Circle(self.objs[i], self.radius, (0,0))
            self.shape_first.elasticity = 0.4
            self.shape_first.friction = 0.9
            self.space.add(self.objs[i], self.shape_first)

            #Fsecond ball shape
            self.shape_second = pymunk.Circle(self.objs[i+1], self.radius, (0,0))
            self.shape_second.elasticity = 0.4
            self.shape_second.friction = 0.9
            self.space.add(self.objs[i+1], self.shape_second)

            #Joint shape        
            self.shape_joint = pymunk.Circle(self.objs[i+2], self.radius_joint, (0,0))
            self.shape_joint.elasticity = 0.4
            self.shape_joint.friction = 0.9
            #self.shape_joint.sensor == True
            self.space.add(self.objs[i+2], self.shape_joint)


            body_first_category = (i*3)+1#"{0:b}".format(int(i+1)) 
            body_second_category = (i*3)+2
            body_joint_category = (i*3)+3
            print (body_first_category )
            print(body_second_category )
            print(body_joint_category )

            #"{0:b}".format(int(i+2))
            self.shape_first.filter = pymunk.ShapeFilter(categories=body_first_category, mask=(body_joint_category and body_second_category)  )            
            self.shape_second.filter = pymunk.ShapeFilter(categories=body_second_category, mask=(body_first_category and body_joint_category)  )
            self.shape_joint.filter = pymunk.ShapeFilter(categories=body_joint_category, mask=(body_first_category and body_second_category))  

            self.balls.append(self.shape_first)
            self.balls.append(self.shape_second)
            self.balls.append(self.shape_joint)
            self.no_ball = False



g = Game()
while g.running:
    g.new()


##pg.quit()

Пожалуйста помоги :)

P.S: Пример класса фильтра формы библиотеки:

http://www.pymunk.org/en/latest/pymunk.html#pymunk.ShapeFilter


person Meric Ozcan    schedule 12.06.2018    source источник
comment
Пожалуйста, не публикуйте так много кода на Stack Overflow. На его анализ и отладку может уйти много времени, поэтому постарайтесь сократить его до абсолютного минимума.   -  person skrx    schedule 12.06.2018
comment
Я очистил код, не могли бы вы проверить моего друга   -  person Meric Ozcan    schedule 12.06.2018
comment
Я хочу столкнуться с одной категорией и игнорировать все другие категории. Пожалуйста, проверьте мой код в функции unit (). Мой код компилируется. Я использовал операнды XOR и NOT. При столкновении один игнорирует все остальные. Однако это может быть не очень хорошо. Я знаю ваш код из предыдущего вопроса, он работает. Но это новая проблема, и она немного уникальна @skrx   -  person Meric Ozcan    schedule 12.06.2018
comment
Сколько из этих пар шаров будет существовать одновременно?   -  person skrx    schedule 12.06.2018
comment
минимум 50 мячей, но я считаю, что ваш метод может работать с 32 различными категориями из-за ALLMASK 2 ^ 32. Если вы можете помочь, я был бы очень благодарен @skrx. Как вы думаете, есть другой способ?   -  person Meric Ozcan    schedule 12.06.2018
comment
Если вам нужно более 32 категорий, этот подход, вероятно, не сработает (или, возможно, можно использовать другой тип данных?). Возможно, нам стоит взглянуть на обработчики столкновений. Я давно не использовал Pymunk в последний раз, поэтому не уверен.   -  person skrx    schedule 12.06.2018
comment
pymunk.org/en/latest/pymunk.html#pymunk.ShapeFilter Я пытаюсь понять эту логику. если я установлю маску на определенное значение, будет ли она противоречить этой категории?   -  person Meric Ozcan    schedule 12.06.2018
comment
Позвольте нам продолжить это обсуждение в чате.   -  person skrx    schedule 12.06.2018


Ответы (1)


Вы можете решить эту проблему с помощью коллбэков, я думаю, что начать обратный вызов - хороший вариант для вас. Для каждой пары фигур, которые вы хотите столкнуться, вы устанавливаете общий идентификатор, а затем проверяете это в обратном вызове и возвращаете True только тогда, когда два сталкивающихся объекта принадлежат одной и той же паре.

Что-то вроде этого:

def only_collide_same(arbiter, space, data):
    a, b = arbiter.shapes
    return a.pair_index == b.pair_index

h = space.add_collision_handler(1,1)
h.begin = only_collide_same

for i in range(10):
    # create shapes and bodies ...
    # then for each pair of shapes:
    shape1.pair_index = i
    shape1.collision_type = 1
    shape2.pair_index = i
    shape2.collision_type = 1
person viblo    schedule 13.06.2018
comment
Хорошее решение. Кстати, можно ли увеличить количество категорий ShapeFilter? - person skrx; 14.06.2018
comment
Да, но это требует некоторых изменений. У бурундука есть определение типа cpBitmask, используемое для категорий и масок. Его можно переопределить, указав желаемый тип с помощью CP_BITMASK_TYPE во время компиляции (chipmunk). Затем нужно обновить pymunk, чтобы тип cpBitmask в _chipmunk_cffi_abi соответствовал тому, что было определено. - person viblo; 14.06.2018