Beispiel #1
0
  def bounce_collision(self, otherball):
    """work out resultant velocities using 17th.C phsyics"""
    # relative positions
    dx = self.unif[0] - otherball.unif[0]
    dy = self.unif[1] - otherball.unif[1]
    rd = self.radius + otherball.radius
    # check sign of a.b to see if converging
    dotP = Utility.dotproduct(dx, dy, 0,
                              (self.vx - otherball.vx),
                              (self.vy - otherball.vy), 0)
    if dx * dx + dy * dy <= rd * rd and dotP < 0:
      R = otherball.mass / self.mass #ratio of masses
      """Glancing angle for equating angular momentum before and after collision.
      Three more simultaneous equations for x and y components of momentum and
      kinetic energy give:
      """
      if dy:
        D = dx / dy
        delta2y = 2 * (D * self.vx + self.vy -
                       D * otherball.vx - otherball.vy) / (
          (1 + D * D) * (R + 1))
        delta2x = D * delta2y
        delta1y = -1 * R * delta2y
        delta1x = -1 * R * D * delta2y
      elif dx:
        # Same code as above with x and y reversed.
        D = dy / dx
        delta2x = 2 * (D * self.vy + self.vx -
                       D * otherball.vy - otherball.vx) / (
          (1 + D * D) * (R + 1))
        delta2y = D * delta2x
        delta1x = -1 * R * delta2x
        delta1y = -1 * R * D * delta2x
      else:
        delta1x = delta1y = delta2x = delta2y = 0

      self.vx += delta1x
      self.vy += delta1y
      otherball.vx += delta2x
      otherball.vy += delta2y
Beispiel #2
0
    def clashTest(self, px, py, pz, rad):
        """Works out if an object at a given location and radius will overlap
    with the map surface. Returns four values:
    
    * boolean whether there is a clash
    * x, y, z components of the normal vector
    * the amount of overlap at the x,z location

    Arguments:
      *px, py, pz*
        Location of object to test in world coordinates.
      *rad*
        Radius of object to test.
    """
        radSq = rad**2
        # adjust for map not set at origin
        px -= self.unif[0]
        py -= self.unif[1]
        pz -= self.unif[2]
        ht = self.height / 255
        halfw = self.width / 2.0
        halfd = self.depth / 2.0
        dx = self.width / self.ix
        dz = self.depth / self.iy

        # work out x and z ranges to check, x0 etc correspond with vertex indices in grid
        x0 = int(math.floor((halfw + px - rad) / dx + 0.5)) - 1
        if x0 < 0: x0 = 0
        x1 = int(math.floor((halfw + px + rad) / dx + 0.5)) + 1
        if x1 > self.ix - 1: x1 = self.ix - 1
        z0 = int(math.floor((halfd + pz - rad) / dz + 0.5)) - 1
        if z0 < 0: z0 = 0
        z1 = int(math.floor((halfd + pz + rad) / dz + 0.5)) + 1
        if z1 > self.iy - 1: z1 = self.iy - 1

        # go through grid around px, pz
        minDist, minLoc = 1000000, (0, 0)
        for i in xrange(x0 + 1, x1):
            for j in xrange(z0 + 1, z1):
                # use the locations stored in the one dimensional vertices matrix
                #generated in __init__. 3 values for each location
                p = j * self.ix + i  # pointer to the start of xyz for i,j in the vertices array
                p1 = j * self.ix + i - 1  # pointer to the start of xyz for i-1,j
                p2 = (j - 1
                      ) * self.ix + i  # pointer to the start of xyz for i, j-1
                vertp = self.buf[0].vertices[p]
                normp = self.buf[0].normals[p]
                # work out distance squared from this vertex to the point
                distSq = (px - vertp[0])**2 + (py - vertp[1])**2 + (
                    pz - vertp[2])**2
                if distSq < minDist:  # this vertex is nearest so keep a record
                    minDist = distSq
                    minLoc = (i, j)
                #now find the distance between the point and the plane perpendicular
                #to the normal at this vertex
                pDist = Utility.dotproduct((px - vertp[0]), (py - vertp[1]),
                                           (pz - vertp[2]), -normp[0],
                                           -normp[1], -normp[2])
                #and the position where the normal from point crosses the plane
                xIsect = px - normp[0] * pDist
                zIsect = pz - normp[2] * pDist

                #if the intersection point is in this rectangle then the x,z values
                #will lie between edges
                if xIsect > self.buf[0].vertices[p1][0] and \
                   xIsect < self.buf[0].vertices[p][0] and \
                   zIsect > self.buf[0].vertices[p2][2] and \
                   zIsect < self.buf[0].vertices[p][2]:
                    pDistSq = pDist**2
                    # finally if the perpendicular distance is less than the nearest so far
                    #keep a record
                    if pDistSq < minDist:
                        minDist = pDistSq
                        minLoc = (i, j)

        gLevel = self.calcHeight(
            px, pz)  #check it hasn't tunnelled through by going fast
        if gLevel > (py - rad):
            minDist = py - gLevel
            minLoc = (int((x0 + x1) / 2), int((z0 + z1) / 2))

        if minDist <= radSq:  #i.e. near enough to clash so return normal
            p = minLoc[1] * self.ix + minLoc[0]
            normp = self.buf[0].normals[p]
            if minDist < 0:
                jump = rad - minDist
            else:
                jump = 0
            return (True, normp[0], normp[1], normp[2], jump)
        else:
            return (False, 0, 0, 0, 0)
Beispiel #3
0
  def clashTest(self, px, py, pz, rad):
    """Works out if an object at a given location and radius will overlap
    with the map surface. Returns four values:

    * boolean whether there is a clash
    * x, y, z components of the normal vector
    * the amount of overlap at the x,z location

    Arguments:
      *px, py, pz*
        Location of object to test in world coordinates.
      *rad*
        Radius of object to test.
    """
    radSq = rad**2
    # adjust for map not set at origin
    px -= self.unif[0]
    py -= self.unif[1]
    pz -= self.unif[2]
    ht = self.height/255
    halfw = self.width/2.0
    halfd = self.depth/2.0
    dx = self.width/self.ix
    dz = self.depth/self.iy

    # work out x and z ranges to check, x0 etc correspond with vertex indices in grid
    x0 = int(math.floor((halfw + px - rad)/dx + 0.5)) - 1
    if x0 < 0: x0 = 0
    x1 = int(math.floor((halfw + px + rad)/dx + 0.5)) + 1
    if x1 > self.ix-1: x1 = self.ix-1
    z0 = int(math.floor((halfd + pz - rad)/dz + 0.5)) - 1
    if z0 < 0: z0 = 0
    z1 = int(math.floor((halfd + pz + rad)/dz + 0.5)) + 1
    if z1 > self.iy-1: z1 = self.iy-1

    # go through grid around px, pz
    minDist, minLoc = 1000000, (0, 0)
    for i in xrange(x0+1, x1):
      for j in xrange(z0+1, z1):
        # use the locations stored in the one dimensional vertices matrix
        #generated in __init__. 3 values for each location
        p = j*self.ix + i # pointer to the start of xyz for i,j in the vertices array
        p1 = j*self.ix + i - 1 # pointer to the start of xyz for i-1,j
        p2 = (j-1)*self.ix + i # pointer to the start of xyz for i, j-1
        vertp = self.buf[0].vertices[p]
        normp = self.buf[0].normals[p]
        # work out distance squared from this vertex to the point
        distSq = (px - vertp[0])**2 + (py - vertp[1])**2 + (pz - vertp[2])**2
        if distSq < minDist: # this vertex is nearest so keep a record
          minDist = distSq
          minLoc = (i, j)
        #now find the distance between the point and the plane perpendicular
        #to the normal at this vertex
        pDist = Utility.dotproduct((px - vertp[0]), (py - vertp[1]), (pz - vertp[2]),
                                  -normp[0], -normp[1], -normp[2])
        #and the position where the normal from point crosses the plane
        xIsect = px - normp[0]*pDist
        zIsect = pz - normp[2]*pDist

        #if the intersection point is in this rectangle then the x,z values
        #will lie between edges
        if xIsect > self.buf[0].vertices[p1][0] and \
           xIsect < self.buf[0].vertices[p][0] and \
           zIsect > self.buf[0].vertices[p2][2] and \
           zIsect < self.buf[0].vertices[p][2]:
          pDistSq = pDist**2
          # finally if the perpendicular distance is less than the nearest so far
          #keep a record
          if pDistSq < minDist:
            minDist = pDistSq
            minLoc = (i,j)

    gLevel = self.calcHeight(px, pz) #check it hasn't tunnelled through by going fast
    if gLevel > (py-rad):
      minDist = py - gLevel
      minLoc = (int((x0+x1)/2), int((z0+z1)/2))

    if minDist <= radSq: #i.e. near enough to clash so return normal
      p = minLoc[1]*self.ix + minLoc[0]
      normp = self.buf[0].normals[p]
      if minDist < 0:
        jump = rad - minDist
      else:
        jump = 0
      return(True, normp[0], normp[1], normp[2],  jump)
    else:
      return (False, 0, 0, 0, 0)