摘要碰撞检测

时间:2013-04-10 00:42:59

标签: python

我一直在努力思考如何在我正在编写的游戏中实现简单的方形碰撞检测,同时避免使用Pygame;我想学习如何在不作弊的情况下做到这一点。预期的程序结构如下: 游戏加载包含级别的文本文件。每个级别由25行25位数组成(总共625位)。将其提取到2D阵列中以模拟与屏幕对应的笛卡尔网格。程序从那里在屏幕上的适当位置绘制一个32x32块。例如,如果位置[2] [5]处的数字是1,它将在像素坐标(96,192)处绘制白色正方形(正方形的计数从零开始,因为它是一个数组)。它还为对应于原始数组的每个位置生成一个由True或False组成的碰撞数组。

我有一个可以沿网格自由移动的玩家对象,不限于32x32方格。我的问题是:我如何实现方碰撞检测?我已经尝试了很多方法,但我不太确定我会遇到什么问题。我将在下面发布我的最新版本和相关代码。

碰撞代码:

def checkPlayerEnvCollision(self,player):
    p = player
    c = self.cLayer #this is the collision grid generated when loading the level
    for row in range(25):
        for col in range (25):
            print("checkEnvCollision")
            if c[row][col] != False:
                tileleftx = row*32
                tilerightx = tileleftx + 32
                tilelefty = col*32
                tilerighty = tilelefty+32
                if (abs(tileleftx - p.x) * 2 < (tilerightx + (p.x + 32))) and (abs(tilelefty - p.y) * 2 < (tilerighty + (p.y + 32))):
                    print("OH NO, COLLISION")

将文本文件中的切片加载到数组中的代码:

def loadLevel(self, level):
    print("Loading Level")
    levelFile = open(level)
    count=0
    for line in levelFile:
        tempArray = []
        if line.startswith("|"):
            dirs = line.split('|')
            self.north = dirs[1]
            self.south = dirs[2]
            self.east = dirs[3]
            self.west = dirs[4]
            continue

        for item in line:
            if item in self.tileValues:
                tempArray.append(int(item))
        self.tileLayer[count] = tempArray
        count+=1
    for items in self.tileLayer:
        if len(items) > 25:
            print("Error: Loaded Level Too Large")

    count = 0
    for line in self.tileLayer:
        tempArray = []
        for item in line:
            if self.tilePassableValues[item] == False:
                tempArray.append(False)
            else:
                tempArray.append(True)
        self.collisionLayer[count] = tempArray
        count += 1

不确定这是否有用,但这里是绘图方法的简单演示:

def levelTiles(self, level):
    row = 0
    for t in level:
        col = 0
        for r in t:
            color = "white"
            if r == 0:
                col+=1
                continue
            elif r == 1:
                color = "red"
            elif r == 2:
                color = "white"
            elif r == 3:
                color = "green"
            self.Canvas.create_rectangle(row*32, col*32, row*32+32, col*32+32, fill=color, width=1,tags='block')
            col += 1
        row += 1

最后,这是我用它测试的文本文件:

1111111111111111111111111
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222233332222222222222221
1222233332222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222233332222222221
1222222222333332332222221
1222222222222222332222221
1222222222222222332222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1111111111111111111111111
|onescreen2|onescreen2|onescreen2|onescreen2

(最后一行是当到达关卡边缘时将地图加载到北,南,东和西;你可以忽略它。)

感谢您的帮助。这要问很多,但我坚持这个!

2 个答案:

答案 0 :(得分:0)

如果玩家与网格绑定,为什么不测试网格位置:

if grid[player.x][player.y] == some_collidable_thing:
    # there was a collision

如果没有,
我还提供了This question

中几乎完全相同的答案
def check_col(self, rect):
    for row in self.cLayer:
        for column in row:
            grid_position = (row*element_size, column*element_width)
            collide_x = False
            collide_y = False

            # check x axis for collision
            if self.rect.x + self.rect.w > grid_position[0]:
                collide_x = True
            elif self.rect.x < grid_position[0] + element_width:
                collide_x = True

            # check y axis for collision
            if self.rect.y < grid_position[1] + element_height:
                collide_y = True
            elif self.rect.y + self.rect.h > grid_position[1]:
                collide_y = True

            # act on a collision on both axis
            if collide_x and collide_y:
                # act on the collision
                return True
            else:
                # act on no collision
                return False

答案 1 :(得分:0)

更简单的方法是为玩家的移动定义向量,为对象的边界定义线条。然后检查向量是否与任何行碰撞(不应该有很多行要检查),如下所示(我假设玩家/对象可以在另一个对象的边界上):

取运动矢量所形成的三角形的行列式和正在检查碰撞的线的终点,并通过行列式获取其面积。将其面积与另一个端点形成的三角形区域进行比较。如果他们都是正面/负面,那么就没有交集。如果他们的标志不同,那么可能是一个交叉点。

如果它们的符号不同,请执行与上述相同的操作,除非使用运动矢量的端点而不是线的端点。 (并使用整行而不是运动矢量)。

如果他们的标志不同,那么肯定有一个交叉点,如果它们是相同的,那么就没有交叉点。

我希望这会有所帮助(如果没有意义,只需评论)。