(Python + pygame) обнаружение столкновений с помощью rects - PullRequest
3 голосов
/ 19 ноября 2011
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 пикселей от границы объекта столкновения. Я уверен, что подход неправильный, но я не могу думать о каких-либо других способах проверки столкновения.

Ответы [ 2 ]

2 голосов
/ 06 сентября 2013

Вы углубляетесь в то, что известно как AABB (Ограничивающая рамка с выравниванием по оси). Вы устанавливаете рамку вокруг своего персонажа, которая обнаруживает объекты вокруг него.

Вот некоторые ресурсы, которые могут помочь вам узнать, что происходит, а также советы, которые помогут вам лучше их реализовать:

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

Прочие Различные реализации платформ

Читайте об этом! Некоторое время я боролся с обнаружением столкновений, они действительно помогают.

1 голос
/ 21 ноября 2011

Хорошо, так что, по сути, вы правда. Ваша программа хороша, но:

  • в Pygame Doc: Rect = (PosX, PosY, Ширина, Высота)

Итак, ваш код (diff):

- 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()
...