вычитание значений из матрицы при столкновении объекта с другим

#python #arrays #matrix #pygame

#python #массивы #матрица #pygame

Вопрос:

Прямо сейчас у меня есть класс, который создает сетку, выравнивает объект по сетке, а затем, когда объект перемещается по сетке, он подсчитывает, сколько раз объект перекрывается с определенной ячейкой.

Моя цель состоит в том, чтобы вместо подсчета количества перекрытий вычесть количество перекрытий из N-значения. Например, вместо завершения программы, когда значение в hitGrid равно 10, программа будет вычитать из 10 и завершится, когда hitGrid равно 0.

Вот мой код:

 WIDTH, HEIGHT, MARGIN = 10, 10, 1
Object = [[1]]

class GridObject(pg.sprite.Sprite):
    def __init__(self, pos, grid, *groups):
        super().__init__(groups)

        # create image from grid
        self.grid = grid
        self.gridsize = (len(grid[0]), len(grid))
        imgsize = self.gridsize[0] * (WIDTH MARGIN), self.gridsize[1] * (HEIGHT MARGIN)
        self.image = pg.Surface(imgsize, flags = pg.SRCALPHA)
        self.image.fill((0, 0, 0, 0))
        col = BLACK
        for c in range(self.gridsize[0]):
            for r in range(self.gridsize[1]):
                if self.grid[r][c] == 1:
                    rect = [(MARGIN   WIDTH) * c   MARGIN, (MARGIN   HEIGHT) * r   MARGIN, WIDTH, HEIGHT]
                    pg.draw.rect(self.image, col, rect)

        self.rect = self.image.get_rect(center=pos)
        self.vel = pg.math.Vector2(8, 0).rotate(randrange(360))
        self.pos = pg.math.Vector2(pos)

    def update(self, boundrect, hitGrid, hitList):
        self.pos  = self.vel
        self.rect.center = self.pos
        if self.rect.left <= boundrect.left or self.rect.right >= boundrect.right:
            self.vel.x *= -1                            
        if self.rect.top <= boundrect.top or self.rect.bottom >= boundrect.bottom:
            self.vel.y *= -1     

        # align rect to grid
        gridpos = round(self.rect.x / (WIDTH MARGIN)), round(self.rect.y / (HEIGHT MARGIN))
        self.rect.topleft = gridpos[0] * (WIDTH MARGIN), gridpos[1] * (HEIGHT MARGIN)

        # increment touched filled
        global max_hit
        max_hit = 0
        
        oldHitList = hitList[:]
        hitList.clear()
        for c in range(self.gridsize[0]):
            for r in range(self.gridsize[1]):
                p = gridpos[1]   r, gridpos[0]   c                
                if p in oldHitList:
                    hitList.append(p)
                elif self.grid[r][c] == 1:
                    if p[0] < len(hitGrid) and p[1] < len(hitGrid[p[0]]):
                        hitList.append(p)
                        if p not in oldHitList:
                            hitGrid[p[0]][p[1]]  =1
                            max_hit = max(max_hit, hitGrid[p[0]][p[1]])
                            print(hitGrid[p[0]][p[1]])
  

Ответ №1:

Не совсем ясно, каковы ваши намерения здесь, потому что приведенный выше код является неполным в нескольких областях… Тем не менее, есть пара стратегий, о которых вам следует подумать. И блок, в котором вы пытаетесь это вычислить, находится на пути к награде «блок уродливого кода года», поэтому нам нужно что-то сделать.

Пара вещей, о которых стоит подумать…

  1. Как вы хотите обработать случай, когда объект остается в одном и том же квадрате сетки в течение нескольких временных шагов? Возможно, вам нужно отслеживать «последний квадрат сетки» и выполнять обновление только при наличии изменений…

в псевдокоде…

 old_gridpos = None  <- set at start of game

# compute new pos in update()
if current_gridpos != old_gridpos:
    check for grid square usage (see below)
    old_gridpos = current_gridpos
    
  
  1. Я вижу, что у вас есть 2-мерный угловой вектор для скорости… Что, если объект движется достаточно быстро по диагонали или в любом направлении и «перескакивает» угол квадрата? (Это становится жестким.)
  2. Теперь ваша система отслеживания выглядит как список попаданий в сетки. С этим сложно работать в вычислительном плане. Вы должны перевернуть это и использовать 2-d индекс и вести подсчет для каждой точки. Намного проще. Вы могли бы использовать dictionary 2-d список или numpy массив. Любой из них будет достаточно быстрым для простой игры, поэтому используйте то, что вам удобно. Эта структура данных отслеживания должна быть свойством игры и инициализироваться при запуске и т. Д. Вот эскизный набросок того, как вы могли бы сделать это со словарем, что, вероятно, проще всего.
 In [12]: grid_count = {}                                                        

In [13]: max_hits = 3                                                           

In [14]: def check_max_hits(position): 
    ...:     grid_count[position] = grid_count.get(position, 0)   1 
    ...:     if grid_count[position] >= max_hits: 
    ...:         return True 
    ...:     return False 
    ...:      
    ...:                                                                        

In [15]: check_max_hits((1,2))                                                  
Out[15]: False

In [16]: check_max_hits((2,4))                                                  
Out[16]: False

In [17]: check_max_hits((1,2))                                                  
Out[17]: False

In [18]: grid_count                                                             
Out[18]: {(1, 2): 2, (2, 4): 1}

In [19]: check_max_hits((1,2))                                                  
Out[19]: True
  

Вы могли бы создать аналогичную функцию и вызвать ее из своей update функции после вычисления gridpos

Комментарии:

1. Можете ли вы привести пример с Numpy? Я хотел бы посмотреть, как это будет выглядеть. Это кажется интересным