1

現在、pygame の抽象化レイヤーに取り組んでおり、マップとの衝突をチェックしようとすると問題が発生しました。マップを読み込んで表示したり、衝突可能な長方形を保存したりできます。四角形のリストを印刷すると、すべてが適切に配置されていることがわかりますが、すべての四角形を反復処理して別の四角形との衝突をチェックしようとすると、四角形が衝突しなくても常に true が返されます。また、赤枠の四角形をそれぞれの上に描画してすべての四角形をデバッグしようとすると、四角形を印刷しても存在する四角形が印刷されますが、何も描画されません。

フレームワークの一部を次に示します。

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

プレーヤーの作成元のスプライト クラス:

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)

これらは関連する 3 つの主要なスニペットです。毎回衝突が返される理由はわかりませんが、そうなるようです。なぜこれが起こるのかについて、誰かが答え、または少なくとも説明を持っている場合は、兄弟を助けてください!

4

2 に答える 2

1

and衝突チェックにはいくつかの 's が必要です。

例えば:

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
于 2013-04-09T01:05:51.733 に答える
1

check_col 関数はすべて「or」演算子を使用しています。つまり、条件が 1 つでも満たされている限り、衝突に対して 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 の Rect クラスには独自の衝突検出関数のセットがあることも指摘しておく価値があります。2 つの rect 間の衝突を検出するには、rect.colliderect(Rect) を使用できます。

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

于 2013-04-09T17:12:25.690 に答える