2013-04-10 45 views
0

我一直在努力在概念上如何在游戏中实现简单的方形碰撞检测我正在写作,同时避免Pygame;我想学习如何做到而不是作弊。预期的程序结构看起来是这样的: 游戏加载一个包含关卡的文本文件。每个级别由25行25位数字(总共625位数字)组成。它被提取到二维数组中以模拟与屏幕相对应的笛卡尔网格。从那里程序在屏幕上的适当位置绘制一个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 

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

感谢您的帮助。要问很多,但我被困在这个问题上!

回答

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 
+0

我没有直接测试网格的位置,因为如果玩家正在向下移动,它将不会注册碰撞,直到它一直在可碰撞的正方形中,因为它们是从tkinter的左上角绘制的。我会检查你发布的第二个!谢谢回复。 – 2013-04-10 01:02:39

+0

请注意,通过使用equalities而不是if/else语句,这段代码可以被简化很多。例如(不是平等,但它提供了正确的想法),最后四行可以写成“return collide_x和collide_y”。 – 2013-04-10 01:04:43

+0

无意中删除了我说方法1需要连接到网格的玩家的部分,方法2应该适合您。另外,是的,代码可以做得更好一点,但是如果你愿意,你所描述的将会消除任何对函数中的碰撞采取行动的能力。 – Serdalis 2013-04-10 01:05:50

0
几乎相同

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

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

如果它们的符号不同,除了使用运动向量的端点而不是线的端点外,请执行与上面相同的操作。 (并用整条线代替运动矢量)。

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

我希望这有助于(如果没有意义,只是评论)。