Тестирование перекрытия двух спрайтов при использовании матриц - PullRequest
2 голосов
/ 25 февраля 2020

Прямо сейчас у меня есть шар, который движется по экрану в случайном диагональном направлении и отскакивает от стены, когда сталкивается с ним.

Что я хочу сделать: Если шарик проходит над ячейкой / ячейкой в ​​сетке, заставляет ячейку / ячейку окрашиваться в красный цвет, а затем продолжает изменять цвета, пока количество раз, которое указывает c spot, не станет равным 10. Если значение равно 10, программа завершается.

Позвольте мне дать вам сценарий: скажем, у меня есть сетка 3x3, и каждая ячейка в этой сетке имеет значение 0. Каждый раз, когда шарик проходит над ячейкой, это значение увеличивается на единицу, пока не достигнет 3. Каждый раз, когда значение увеличивается, цвет этой ячейки меняется. 0 = белый, 1 = красный, 2 = зеленый и 3 = синий. Это то, что я хотел получить на выходе.

То, что у меня есть до сих пор: Весь экран становится красным вместо отдельной ячейки. Сейчас я просто тестирую его на один цвет, но затем хочу добавить множество цветов.

for row in range(GRIDY):
    for column in range(GRIDX):
        rect = [(MARGIN + WIDTH) * column + MARGIN, (MARGIN + HEIGHT) * row + MARGIN, WIDTH, HEIGHT]
        color = WHITE
        if GRIDY or GRIDX == 1:
            color = RED
        pg.draw.rect(screen, color, rect)

Вот остаток кода для справки:

import sys
import math
from random import randrange
import pygame as pg

# define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

# define measurements
WIDTH, HEIGHT, MARGIN = 10, 10, 1
GRIDX, GRIDY = 91, 36

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 = (235, 175, 76)
        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):
        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)

ballGrid = [[0, 1, 1, 1, 0],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [0, 1, 1, 1, 0]]

def main():
    #overlap = False
    screen = pg.display.set_mode((GRIDX * (WIDTH+MARGIN) + MARGIN, GRIDY * (HEIGHT+MARGIN)))
    # Set title of screen
    pg.display.set_caption("Ball With Grid")
    clock = pg.time.Clock()
    sprite_group = pg.sprite.Group()
    ball = GridObject((495, 193), ballGrid, sprite_group)
    done = False
    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
                # Used to track the grid coordinates
                if event.type == pg.MOUSEBUTTONDOWN:
                    # Get the position is screen is clicked
                    pos = pg.mouse.get_pos()
                    # Change the x/y screen coordinates to grid coordinates
                    column = pos[0] // (WIDTH + MARGIN)
                    row = pos[1] // (HEIGHT + MARGIN)
                    # Set that location to one
                    grid[row][column] = 1
                    print("Click ", pos, "Grid coordinates: ", row, column)


        screen.fill((0, 0, 0))

        # Draw the grid and add values to the cells
        for row in range(GRIDY):
            for column in range(GRIDX):
                rect = [(MARGIN + WIDTH) * column + MARGIN, (MARGIN + HEIGHT) * row + MARGIN, WIDTH, HEIGHT]
                color = WHITE
                if GRIDY or GRIDX == 1:
                    color = RED
                pg.draw.rect(screen, color, rect)

        sprite_group.update(screen.get_rect())
        sprite_group.draw(screen)

        pg.display.flip()
        clock.tick(30)

if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
    sys.exit()

Кстати, если это выглядит аналогично, мой другой аккаунт разместил этот вопрос: Использование матрицы в качестве спрайта и тестирование, если два спрайта перекрываются

Ссылка на изображения: https://imgur.com/gallery/UicBs6q

1 Ответ

2 голосов
/ 25 февраля 2020

скажем, у меня есть сетка 3x3, и каждая ячейка в этой сетке имеет значение 0. Каждый раз, когда шарик проходит над ячейкой, это значение увеличивается на единицу, пока не достигнет 3. Каждый раз, когда значение идет вверх, цвет для этой ячейки меняется. 0 = белый, 1 = красный, 2 = зеленый и 3 = синий. Это то, что я хотел получить на выходе.

У вас есть как часто шарик находится в ячейке, для каждой ячейки. Поскольку шарик покрывает более 1 ячейки (размер шарика больше 1 ячейки), счетчик ячеек будет увеличиваться несколько раз в последовательных кадрах, когда шарик переворачивается на ячейку.
Таким образом, вы должны убедиться, что шарик покинул ячейку, прежде чем его счетчик снова может быть увеличен.

Создание двумерного массива (вложенного списка) целых значений, инициализированного 0 с размером поля. Поданные раны счетчики посещений для клеток. Кроме того, создайте список (hitList), в котором хранятся индексы ячеек, попавших в кадр.

hitGrid = [[0 for i in range(GRIDX)] for j in range(GRIDY)]
hitList = []

Сетка (hitGrid) и список (hitList) имеют быть переданным методу update класса GridObject. Если мяч касается поля, а поле не было затронуто в предыдущем кадре, то соответствующая запись в поле должна быть увеличена. Более того, функция может установить глобальную переменную max_hit с наибольшим количеством совпадений в текущем кадре:

class GridObject(pg.sprite.Sprite):
    # [...]

    def update(self, boundrect, gridHit):
        # [...]

        # increment touched filed
        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]])

Оценить max_hit после вызова update для объектов GridObject:

sprite_group.update(screen.get_rect(), hitGrid, hitList)
if max_hit >= 4:
    print("game over")
    done = True

Оттенок цвета поля в зависимости от значения в gridHit:

for row in range(GRIDY):
    for column in range(GRIDX):
        rect = [(MARGIN + WIDTH) * column + MARGIN, (MARGIN + HEIGHT) * row + MARGIN, WIDTH, HEIGHT]
        colorlist = [WHITE, RED, GREEN, BLUE]
        color = colorlist[min(len(colorlist)-1, hitGrid[row][column])]
        pg.draw.rect(screen, color, rect)

См. Пример:

from random import randrange
import pygame as pg

# define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# define measurements
WIDTH, HEIGHT, MARGIN = 10, 10, 1
GRIDX, GRIDY = 36, 36

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 = (235, 175, 76)
        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 filed
        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]])

ballGrid = [[0, 1, 1, 1, 0],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [0, 1, 1, 1, 0]]

def main():
    #overlap = False
    screen = pg.display.set_mode((GRIDX * (WIDTH+MARGIN) + MARGIN, GRIDY * (HEIGHT+MARGIN)))
    # Set title of screen
    pg.display.set_caption("Ball With Grid")
    clock = pg.time.Clock()
    sprite_group = pg.sprite.Group()
    ball = GridObject((screen.get_width()//2, screen.get_height()//2), ballGrid, sprite_group)
    hitGrid = [[0 for i in range(GRIDX)] for j in range(GRIDY)]
    hitList = []
    done = False
    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            if event.type == pg.KEYDOWN and event.key == pg.K_SPACE:
                hitGrid = [[0 for i in range(GRIDX)] for j in range(GRIDY)] 

        screen.fill((0, 0, 0))

        # Draw the grid and add values to the cells
        for row in range(GRIDY):
            for column in range(GRIDX):
                rect = [(MARGIN + WIDTH) * column + MARGIN, (MARGIN + HEIGHT) * row + MARGIN, WIDTH, HEIGHT]
                colorlist = [WHITE, RED, GREEN, BLUE]
                color = colorlist[min(len(colorlist)-1, hitGrid[row][column])]
                pg.draw.rect(screen, color, rect)

        sprite_group.update(screen.get_rect(), hitGrid, hitList)
        if max_hit >= 4:
            print("game over")
            done = True
        sprite_group.draw(screen)

        pg.display.flip()
        clock.tick(30)

if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
    sys.exit()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...