【问题标题】:(Python + pygame) collision detection with rects(Python + pygame) 使用矩形进行碰撞检测
【发布时间】:2011-11-19 16:57:23
【问题描述】:
import pygame
import random

red = [255,0,0]
green = [0,255,0]
blue = [0,0,255]
white = [255,255,255]
black = [0,0,0]
UP = [0,-1]
DOWN = [0,1]
LEFT = [-1,0]
RIGHT = [1,0]
NOTMOVING = [0,0]
#constants end
#classes
class collidable:
    x = 0
    y = 0
    w = 0
    h = 0
    rect = pygame.Rect(x,y,w,h)
    color = [0,0,0]
    def __init__(self,x,y,w,h,color):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.color = color
        self.rect = pygame.Rect(x,y,w,h)
    def draw(self):
        pygame.draw.rect(screen,self.color,[self.x,self.y,self.w,self.h],6)

class player:
    x = 0
    y = 0
    speed = 0
    rect = pygame.Rect(x,y,x+20,y+20)
    def __init__(self,x,y,speed):
        self.x = x
        self.y = y
        self.speed = speed
        self.rect = pygame.Rect(self.x,self.y,self.x+20,self.y+20)
    def draw(self):
        if player_moving==LEFT:
        pygame.draw.polygon(screen,black,[(self.x-10,self.y),(self.x+10,self.y-10),(self.x+10,self.y+10)])
        elif player_moving==RIGHT:
            pygame.draw.polygon(screen,black,[(self.x+10,self.y),(self.x-10,self.y-10),(self.x-10,self.y+10)])
        elif player_moving==UP:
            pygame.draw.polygon(screen,black,[(self.x,self.y-10),(self.x+10,self.y+10),(self.x-10,self.y+10)])
        elif player_moving==DOWN:
            pygame.draw.polygon(screen,black,[(self.x,self.y+10),(self.x+10,self.y-10),(self.x-10,self.y-10)])
        else:
            pygame.draw.rect(screen,black,pygame.Rect(self.x-10,self.y-10,20,20),6)
    def setpos(self,x,y):
        self.x = x
        self.y = y
    def move(self,direction):
        self.x = self.x + direction[0]*self.speed
        self.y = self.y + direction[1]*self.speed
#classes end

#globals
pygame.init()
screenSize = [800,600]
screenBGColor = white
screen=pygame.display.set_mode(screenSize)
pygame.display.set_caption("Move the Block")
player = player(screenSize[0]/2,screenSize[1]/2,9)
collidables = []
clock=pygame.time.Clock()
for i in range(10):
    collidables.append(collidable(random.randrange(0,screenSize[0]),random.randrange(0,screenSize[1]),random.randrange(10,200),random.randrange(10,200),blue))

running = True
#globals end

#functions
def render():
    screen.fill(screenBGColor)
    clock.tick(60)
    player.draw()
    for c in collidables:
        c.draw()
    pygame.display.flip()
def tick():                                           #----------------HERE
    for c in collidables:
        if player.rect.colliderect(c.rect):
            player_moving = NOTMOVING
            print("hit")
    player.move(player_moving)

#functions end

#main loop
while running==True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            running = False
        if event.type==pygame.KEYDOWN:
            if event.key==pygame.K_LEFT:
                player_moving = LEFT
            if event.key==pygame.K_RIGHT:
                player_moving = RIGHT
            if event.key==pygame.K_UP:
                player_moving = UP
            if event.key==pygame.K_DOWN:
                player_moving = DOWN
        else:
            player_moving = NOTMOVING
    tick()
    render()
#main loop end

pygame.quit()

我正在尝试进行简单的碰撞检测,以在触摸可碰撞对象时禁用玩家移动。但是无论碰撞对象位于何处,碰撞总是会被触发。我不知道为什么玩家不移动,如果玩家的中心距离可碰撞的边界 10 像素,则此代码应该只阻止移动。我确信这种方法是错误的,但我想不出任何其他方法来检查碰撞。

【问题讨论】:

  • 你在看这本书吗:inventwithpython.com?
  • 真的,您希望我们为您调试程序吗? :o
  • 对不起,我不是那个意思。我确定代码是错误的,我需要一种更好的碰撞检测方法。我的帖子缺少这一点,因为我现在的互联网太慢了,以至于当我不小心按 Enter 发送时,它并没有取消。
  • 转换 print("hit") 以查看命中发生的位置(看看它是否不正确。您的代码看起来不错。
  • @A.H 对不起,我不明白。我是python新手,你说的转换是什么意思?

标签: python pygame collision-detection


【解决方案1】:

您正在研究所谓的 AABB(Axis Aligned Bounding Box)。你在你的角色周围设置了一个框来检测周围的物体。

这里有一些资源可以帮助您了解正在发生的事情,以及帮助您更好地实施它们的技巧:

http://www.gamasutra.com/view/feature/3426/when_two_hearts_collide_.php

http://www.gamefromscratch.com/post/2012/11/26/GameDev-math-recipes-Collision-detection-using-an-axis-aligned-bounding-box.aspx

Other Various platforming implementations

阅读这些!我在碰撞检测方面苦苦挣扎了一段时间,这些确实有帮助。

【讨论】:

    【解决方案2】:

    好的,所以,基本上,你是对的。你的程序很好,但是:

    • 在 pygame 文档中: 矩形 = (PosX, PosY, 宽度, 高度)

    所以,你的代码(差异):

    - self.rect = pygame.Rect(self.x,self.y,self.x+20,self.y+20)
    + self.rect = pygame.Rect(self.x,self.y,self.20,self.20)
    

    还有:

      def move(self,direction):
          self.x = self.x + direction[0]*self.speed
          self.y = self.y + direction[1]*self.speed
    +     self.rect = pygame.Rect(self.x,self.y,self.20,self.20)
    

    您的代码中还有另一个小问题。例如,在您的tick() 函数中,您使用player_moving,但在第一次迭代中,此变量永远不会存在。

    代码(运行):

    import pygame
    import random
    
    red = [255,0,0]
    green = [0,255,0]
    blue = [0,0,255]
    white = [255,255,255]
    black = [0,0,0]
    UP = [0,-1]
    DOWN = [0,1]
    LEFT = [-1,0]
    RIGHT = [1,0]
    NOTMOVING = [0,0]
    #constants end
    #classes
    class collidable:
        x = 0
        y = 0
        w = 0
        h = 0
        rect = pygame.Rect(x,y,w,h)
        color = [0,0,0]
        def __init__(self,x,y,w,h,color):
            self.x = x
            self.y = y
            self.w = w
            self.h = h
            self.color = color
            self.rect = pygame.Rect(x,y,w,h)
        def draw(self):
            pygame.draw.rect(screen,self.color,[self.x,self.y,self.w,self.h],6)
    
    class player:
        x = 0
        y = 0
        speed = 0
        rect = pygame.Rect(x,y,20,20)
        def __init__(self,x,y,speed):
            self.x = x
            self.y = y
            self.speed = speed
            self.rect = pygame.Rect(self.x,self.y,20,20)
        def draw(self):
            if player_moving==LEFT:
                    pygame.draw.polygon(screen,black,[(self.x-10,self.y),(self.x+10,self.y-10),(self.x+10,self.y+10)])
            elif player_moving==RIGHT:
                pygame.draw.polygon(screen,black,[(self.x+10,self.y),(self.x-10,self.y-10),(self.x-10,self.y+10)])
            elif player_moving==UP:
                pygame.draw.polygon(screen,black,[(self.x,self.y-10),(self.x+10,self.y+10),(self.x-10,self.y+10)])
            elif player_moving==DOWN:
                pygame.draw.polygon(screen,black,[(self.x,self.y+10),(self.x+10,self.y-10),(self.x-10,self.y-10)])
            else:
                pygame.draw.rect(screen,black,pygame.Rect(self.x-10,self.y-10,20,20),6)
        def setpos(self,x,y):
            self.x = x
            self.y = y
        def move(self,direction):
            self.x = self.x + direction[0]*self.speed
            self.y = self.y + direction[1]*self.speed
            self.rect = pygame.Rect(self.x,self.y,20,20)
    #classes end
    
    #globals
    pygame.init()
    screenSize = [800,600]
    screenBGColor = white
    screen=pygame.display.set_mode(screenSize)
    pygame.display.set_caption("Move the Block")
    player = player(screenSize[0]/2,screenSize[1]/2,9)
    collidables = []
    clock=pygame.time.Clock()
    for i in range(10):
        collidables.append(collidable(random.randrange(0,screenSize[0]),random.randrange(0,screenSize[1]),random.randrange(10,200),random.randrange(10,200),blue))
    
    running = True
    #globals end
    player_moving = NOTMOVING
    #functions
    def render():
        screen.fill(screenBGColor)
        clock.tick(60)
        player.draw()
        for c in collidables:
            c.draw()
        pygame.display.flip()
    def tick(player_moving):                                           #----------------HERE
        for c in collidables:
            if player.rect.colliderect(c.rect):
                player_moving = NOTMOVING
                print("hit"+str(c.rect)+" with "+str(player.rect))
        player.move(player_moving)
    
    #functions end
    
    #main loop
    while running==True:
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                running = False
            if event.type==pygame.KEYDOWN:
                if event.key==pygame.K_LEFT:
                    player_moving = LEFT
                if event.key==pygame.K_RIGHT:
                    player_moving = RIGHT
                if event.key==pygame.K_UP:
                    player_moving = UP
                if event.key==pygame.K_DOWN:
                    player_moving = DOWN
            else:
                player_moving = NOTMOVING
        tick(player_moving)
        render()
    #main loop end
    
    pygame.quit()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2013-10-12
      相关资源
      最近更新 更多