首页 > 解决方案 > 如何在pygame中检查我的类的所有实例之间的冲突?

问题描述

我目前正在尝试在发生碰撞时在屏幕上打印,但不知道如何仅针对 1 个班级进行打印。我知道如何让 2 个对象从不同的类中碰撞,但我不知道如何为一个有 1000 个不同对象的类做到这一点

我尝试在游戏中使用一些 pygame 函数,例如 pygame.rect.contain,但我不知道从那里去哪里。谢谢你们帮助我。

代码如下:

import pygame
import random
import sys
import time

Height = 800
Width = 800
Steps = 0
running = True

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

pygame.init()
display = pygame.display.set_mode((Height, Width))
clock = pygame.time.Clock()
pygame.display.set_caption("Game")


class Ball(object):

    def __init__(self, x, y, delta_x, delta_y):
        self.x = x
        self.y = y
        self.delta_x = delta_x
        self.delta_y = delta_y

    def draw(self):

        pygame.draw.rect(display, WHITE, (self.x, self.y, 1, 1))

    def update(self):
        self.x += self.delta_x
        self.y += self.delta_y

        if self.x < 0:
            self.delta_x = self.delta_x * -1
        if self.x > Width - 5:
            self.delta_x = self.delta_x * -1

        if self.y < 0:
            self.delta_y = self.delta_y * -1
        if self.y > Height - 5:
            self.delta_y = self.delta_y * -1


list = []
for i in range(1000):
    ball = Ball(random.randrange(0, Width - 5), random.randrange(0, Height - 5),
                random.randint(-10, 10), random.randint(-10, 10))

    list.append(ball)

while running:
    display.fill(BLACK)
    clock.tick(60)

    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            pygame.quit()

    # Update

    # Draw
    for ball in list:

        ball.draw()
        ball.update()

    pygame.display.update()

    pygame.display.update()
    print(clock.tick(60))

标签: pythonpygame

解决方案


如果要找到相等的点,则必须比较点的 x 和 y 坐标。

例如

for i in range(len(list)):
    eq_list = [j for j in range(len(list)) if i != j and list[i].x == list[j].x and list[i].y == list[j].y]

例如,您可以为这种方法在 read 中绘制碰撞点:

class Ball(object):

    # [...]

    def draw(self, color):
        pygame.draw.rect(display, color, (self.x, self.y, 1, 1))
for i in range(len(list)):
    ball = list[i]

    collide = any([j for j in range(len(list)) if i != j and list[i].x == list[j].x and list[i].y == list[j].y])
    ball.draw(RED if collide else WHITE)

    ball.update()

请注意,这种方法对于 1000 点和 1000*1000 碰撞测试会很慢。

更好的解决方案是使用 1000x1000 字段并在字段中设置状态(如果对象在其上)。如果设置了字段中的状态,这会将碰撞测试减少到一些测试。

创建一个具有布尔状态的字段:

obj_grid = [[False for i in range(Height)] for j in range(Width)]

获取对象的位置列表并在字段中设置相应的状态。将字段传递给Ball.update方法。更新和绘制后,必须清除该字段,因为位置已更改。为此使用位置列表,因为这比“清除”整个字段要快得多。我添加了一些绑定检查,因为您的某些对象似乎超出了范围(可能这个错误也必须修复)。

# collect the postions of the items
poslist = [(ball.x, ball.y) for ball in list]

# set the positions in the field
for pos in poslist:
    if pos[0] < Width and pos[1] < Height:
        obj_grid[pos[0]][pos[1]] = True

# update and draw
for ball in list:
    ball.update(obj_grid)
    ball.draw()

# set the positions in the field
for pos in poslist:
    if pos[0] < Width and  pos[1] < Height:
        obj_grid[pos[0]][pos[1]] = False

在该Ball.update方法中,必须测试路径的未决路径上的位置。如果声明了任何字段,则对象会发生碰撞。我将状态存储在一个属性self.collide中。如果设置了状态,则对象被放大并涂成红色,以可视化碰撞。当然你也可以做一些别的事情,比如改变方向:

class Ball(object):

    def __init__(self, x, y, delta_x, delta_y):
        self.x = x
        self.y = y
        self.delta_x = delta_x
        self.delta_y = delta_y
        self.collide = False

    def draw(self):
        color, size = (RED, 5) if self.collide else (WHITE, 1)
        pygame.draw.rect(display, color, (self.x, self.y, size, size))

    def update(self, obj_grid):

        # check if the object is colliding on his way
        pos = [self.x, self.y] 
        new_pos = [self.x + self.delta_x, self.y + self.delta_y]
        self.collide = False
        while not self.collide and pos != new_pos:
            if abs(pos[0]-new_pos[0]) > abs(pos[1]-new_pos[1]):
                pos[0] += 1 if self.delta_x > 0 else -1
            else:
                pos[1] += 1 if self.delta_y > 0 else -1
            self.collide = pos[0] < Width and pos[1] < Height and obj_grid[pos[0]][pos[1]]

        self.x += self.delta_x
        self.y += self.delta_y
        if self.x < 0:
            self.delta_x = self.delta_x * -1
        if self.x > Width - 5:
            self.delta_x = self.delta_x * -1
        if self.y < 0:
            self.delta_y = self.delta_y * -1
        if self.y > Height - 5:
            self.delta_y = self.delta_y * -1

推荐阅读