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