2013-04-09 111 views
1

我目前正在研究pygame的抽象層,並且在嘗試檢查與地圖的碰撞時遇到了問題。我能夠加載和顯示地圖,以及存儲可碰撞的矩形。當我打印矩形列表時,我發現一切都已到位,但是當我迭代每個矩形並嘗試檢查與另一矩形的碰撞時,即使矩形不相互碰撞,它總是返回true。另外,當我嘗試通過在每個矩形上繪製一個紅色輪廓的矩形來調試所有矩形時,即使打印矩形時,也不會繪製任何矩形,它會打印一個存在的矩形。Pygame:碰撞瓷磚不工作

下面是從框架中的幾個片斷:

class Tilemap(object): 
"""This is the tilemap object, it takes an array of strings as its object, and places a surface where you have it in the strings. It only supports one surface per map, so you have to make multiple maps for floor, walls, etc.""" 
def __init__(self, level_surface,level_string = None, string_char = "#", surface = None, surface_dim = Vector2(50, 50),surface_color = (255, 255, 255)): 
    self.level = level_string 
    self.char = string_char 
    self.surface = surface 
    if self.surface is None: 
     self.surface = pygame.Surface(surface_dim) 
     self.surface.fill(surface_color) 

    self.surface_width = self.surface.get_rect().w 
    self.surface_height = self.surface.get_rect().h 
    self.collision_list = [] 
    for y in xrange(len(self.level)): 
     for x in xrange(len(self.level[y])): 
      if self.level[y][x] is self.char: 
       self.collision_list.insert(len(self.collision_list), Rect((x) * self.surface_width,(y) * self.surface_height, self.surface_width, self.surface_height)) 
    print self.collision_list 
    for y in xrange(len(self.level)): 
     for x in xrange(len(self.level[y])): 
      if self.level[y][x] is self.char: 
       level_surface.blit(self.surface.convert_alpha(), (self.surface_width * x, self.surface_height * y)) 

def replace_char_with(self, level_surface,char = ".", surface = None): 
    for y in xrange(len(self.level)): 
     for x in xrange(len(self.level[y])): 
      if self.level[y][x] is char: 
       level_surface.blit(surface.convert_alpha(), (surface.get_width() * x, surface.get_height() * y)) 

def check_col(self, rect): 
    for tilerect in self.collision_list: 
     if rect.x + rect.w > tilerect.x or rect.y + rect.h > tilerect.y or rect.x < tilerect.x + tilerect.w or rect.y < tilerect.y + tilerect.h: 
      return True 
     else: 
      return False 

def debug_draw(self, screen): 
    for rect in self.collision_list: 
     pygame.draw.rect(screen, (255, 0, 0), rect, 2) 

片段#2,測試代碼:

def main(): 
from pygame.locals import K_w, K_a, K_s, K_d 
pygame.init() 
screen = pygame.display.set_mode((640, 480)) 
clock = pygame.time.Clock() 
player = Sprite(pygame.image.load("trapdoor_tile.png"), Vector2(100, 100)) 
floor = ["########################################", 
     "########################################", 
     "#####...##.#.#..###.#.###..#############", 
     "#####.######.#.#.####.##.#.#############", 
     "######.###.#.##..##.#.###.##############", 
     "#####.####.########.####################", 
     "#####.#.##.###.#.##.#.##.#.#############", 
     "########################################", 
     "#######################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################" 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################", 
     "########################################"] 

walls = ["########################################", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "#......................................#", 
     "########################################"] 

level_surf = pygame.Surface((640, 480)) 
floor_map = Tilemap(level_surf, floor, "#", pygame.image.load("ground_tile.png").convert_alpha()) 
floor_map.replace_char_with(level_surf, ".", pygame.image.load("trapdoor_tile.png").convert_alpha()) 
wall_map = Tilemap(level_surf, walls, "#", pygame.image.load("wall_tile.png").convert_alpha()) 

while True: 
    screen.fill((0, 0, 0)) 
    milliseconds = clock.tick(60)/10. 

    for event in pygame.event.get(): 
     if event.type == pygame.locals.QUIT: 
      pygame.quit() 
      raise SystemExit 

    wall_map.debug_draw(screen); 

    screen.blit(level_surf, Vector2(0, 0)) 

    if wall_map.check_col(player.dummyrect): 
     player.colliding = True 
     print "why!" 
    else: 
     player.colliding = False 

    player.update(milliseconds) 
    player.draw(screen) 

    keystate = pygame.key.get_pressed() 

    player.apply_drag() 

    if keystate[K_w]: 
     player.set_accel_y(-5) 
    elif keystate[K_s]: 
     player.set_accel_y(5) 
    elif keystate[K_a]: 
     player.set_accel_x(-5) 
    elif keystate[K_d]: 
     player.set_accel_x(5) 

    pygame.display.flip() 

Sprite類從玩家創建:

class Sprite(object): 
def __init__(self, surface = None, initial_position = (100, 100)): 
    self.surface = surface 
    self.rect = self.surface.get_rect(center = initial_position) 
    self.acceleration = Vector2(0, 0) 
    self.delta_time = None 
    self.dummyrect = self.rect 
    self.colliding = False 

def update(self, delta_time): 
    self.dummyrect = self.rect.move(self.acceleration.x * delta_time, self.acceleration.y * delta_time) 
    if not self.colliding: 
     self.rect = self.dummyrect 
    else: 
     self.dummyrect = self.rect 
    self.delta_time = delta_time 

def draw(self, screen): 
    screen.blit(self.surface, self.rect) 

def draw_to_cam(self, screen,camera): 
    screen.blit(self.surface, camera.to_camera_coords(Vector2(self.rect.x, self.rect.y))) 

def collide(self, rectangle): 
    if self.rect.x + self.rect.w > rectangle.x: 
     self.rect.x -= 1; 
    if self.rect.x < rectangle.x + rectangle.w: 
     self.rect.x += 1 
    if self.rect.y < rectangle.y + rectangle.h: 
     self.rect.y += 1; 
    if self.rect.y + self.rect.h > rectangle.y: 
     self.rect.y -= 1; 

def set_accel_x(self, new_val): 
    self.acceleration.x = new_val 

def set_accel_y(self, new_val): 
    self.acceleration.y = new_val 

def apply_drag(self, drag_mul = 1): 
    if self.acceleration.x > 0: 
     self.acceleration.x -= self.delta_time * drag_mul 
    else: 
     self.acceleration.x += self.delta_time * drag_mul 

    if self.acceleration.y > 0: 
     self.acceleration.y -= self.delta_time * drag_mul 
    else: 
     self.acceleration.y += self.delta_time * drag_mul 

    if self.acceleration.x < 0.1 or self.acceleration.x > -0.1: 
     self.acceleration.x = 0 
    if self.acceleration.x < 0.1 or self.acceleration.x > -0.1: 
     self.acceleration.x = 0 
    if self.acceleration.y < 0.1 or self.acceleration.y > -0.1: 
     self.acceleration.y = 0 
    if self.acceleration.y < 0.1 or self.acceleration.y > -0.1: 
     self.acceleration.y = 0 

def get_center(self): 
    return Vector2(self.rect.centerx, self.rect.centery) 

這些是涉及的三個主要片段,我不知道爲什麼每次都會返回一個碰撞,但它是s eems要這樣做。如果任何人至少有答案或解釋,爲什麼發生這種情況,請幫助兄弟出去!

+1

'類的Sprite(對象):'應當從'pygame.sprite.Sprite'導出。你的碰撞應該使用'Rect'的碰撞函數,或者'Sprite'的碰撞函數,這取決於它的rect rect,還是rect on sprite。 – ninMonkey 2013-04-09 18:36:00

回答

1

你check_col功能使用所有「或」運營商,這意味着你只要甚至只是一個條件滿足碰撞返回true。這裏是你的代碼:

def check_col(self, rect): 
for tilerect in self.collision_list: 
    if rect.x + rect.w > tilerect.x or rect.y + rect.h > tilerect.y or rect.x < tilerect.x + tilerect.w or rect.y < tilerect.y + tilerect.h: 
     return True 
    else: 
     return False 

你需要的是更多的東西是這樣的:

def check_col(self, rect): 
    for tilerect in self.collision_list: 
     if ((rect.x + rect.w > tilerect.x and rect.x <= tilerect.x + tilerect.width) or 
      (tilerect.x + tilerect.width > rect.x and tilerect.x <= rect.x + rect.width)) and 
      ((rect.y + rect.h > tilerect.y and rect.y <= tilerect.y + tilerect.height) or 
      (tilerect.y + tilerect.height > rect.y and tilerect.y <= rect.y + rect.height)) 

      return true 
     else: 
      return false 

而且,它可能是值得指出的是pygame中的矩形類有它自己的一套碰撞檢測功能。要檢測2個Rect之間的碰撞,可以使用rect.colliderect(Rect)。

http://www.pygame.org/docs/ref/rect.html#pygame.Rect.colliderect

+0

我知道我正在迴應一對x2個月,但謝謝 – 2013-08-19 00:14:00

1

您的碰撞檢查需要一些and

例如:

def check_col(self, rect): 
    for tilerect in self.collision_list: 
     collide_x = False 
     collide_y = False 
     # check x axis for collision 
     if self.rect.x + self.rect.w > tilerect.x: 
      collide_x = True 
     elif self.rect.x < tilerect.x + tilerect.w: 
      collide_x = True 
     # check y axis for collision 
     if self.rect.y < tilerect.y + tilerect.h: 
      collide_y = True 
     elif self.rect.y + self.rect.h > tilerect.y: 
      collide_y = True 
     # act on a collision on both axis 
     if collide_x and collide_y: 
      return True 
     else: 
      return False 
+0

你在測試兩個矩形矩形嗎? [1] http://www.pygame.org/docs/ref/rect.html#pygame.Rect.colliderect else http://www.pygame.org/docs/ref/rect.html#pygame.Rect。碰撞點 – ninMonkey 2013-04-09 01:39:51

+0

@monkey我不完全知道他想要什麼與這些矩形(很確定它的網格基於在哪種情況下有更好的方法),所以我只是修改他的代碼工作。 – Serdalis 2013-04-09 02:18:14

+0

你改變的功能不是他的碰撞檢測功能,而是他的碰撞反應功能。執行碰撞檢測的函數是TileMap類中的check_col。 – Haz 2013-04-09 17:18:26