def test_(self): a = (98, 28) b = (72, 33) c = (10, -5) d = (20, 88) result = Vector.line_intersection(a, b, c, d) self.assertEqual(result.x, 15.25931928687196) self.assertEqual(result.y, 43.911669367909241)
def check_deflector_collision(self, deflector): # Here we have a collision Bullet <--> Deflector-bounding-box. But that doesn't mean # that there's a collision with the deflector LINE yet. So here's some math stuff # for the freaks :) It includes vector calculations, distance problems and trigonometry # first thing to do is: we need a vector describing the bullet. Length isn't important. bullet_position = Vector(self.center) bullet_direction = Vector(1, 0).rotate(self.angle * 360 / (2 * pi)) deflector_point1 = Vector( deflector.to_parent(deflector.point1.center[0], deflector.point1.center[1])) deflector_point2 = Vector( deflector.to_parent(deflector.point2.center[0], deflector.point2.center[1])) # then we need a vector describing the deflector line. deflector_vector = Vector(deflector_point2 - deflector_point1) # now we do a line intersection with the deflector line: intersection = Vector.line_intersection( bullet_position, bullet_position + bullet_direction, deflector_point1, deflector_point2) # now we want to proof if the bullet comes from the 'right' side. # Because it's possible that the bullet is colliding with the deflectors bounding box but # would miss / has already missed the deflector line. # We do that by checking if the expected intersection point is BEHIND the bullet position. # ('behind' means the bullets direction vector points AWAY from the vector # [bullet -> intersection]. That also means the angle between these two vectors is not 0 # -> due to some math-engine-internal inaccuracies, i have to check if the angle is greater than one: if abs(bullet_direction.angle(intersection - bullet_position)) > 1: # if the bullet missed the line already - NO COLLISION return False # now we finally check if the bullet is close enough to the deflector line: distance = abs( sin(radians(bullet_direction.angle(deflector_vector)) % (pi / 2))) * Vector(intersection - bullet_position).length() if distance < (self.width / 2): # there is a collision! # kill the animation! self.animation.unbind(on_complete=self.on_collision_with_edge) self.animation.stop(self) # call the collision handler self.on_collision_with_deflector(deflector, deflector_vector)
def check_deflector_collision(self, deflector): # Here we have a collision Bullet <--> Deflector-bounding-box. But that doesn't mean # that there's a collision with the deflector LINE yet. So here's some math stuff # for the freaks :) It includes vector calculations, distance problems and trigonometry # first thing to do is: we need a vector describing the bullet. Length isn't important. bullet_position = Vector(self.center) bullet_direction = Vector(1, 0).rotate(self.angle * 360 / (2*pi)) deflector_point1 = Vector(deflector.to_parent(deflector.point1.center[0], deflector.point1.center[1])) deflector_point2 = Vector(deflector.to_parent(deflector.point2.center[0], deflector.point2.center[1])) # then we need a vector describing the deflector line. deflector_vector = Vector(deflector_point2 - deflector_point1) # now we do a line intersection with the deflector line: intersection = Vector.line_intersection(bullet_position, bullet_position + bullet_direction, deflector_point1, deflector_point2) # now we want to proof if the bullet comes from the 'right' side. # Because it's possible that the bullet is colliding with the deflectors bounding box but # would miss / has already missed the deflector line. # We do that by checking if the expected intersection point is BEHIND the bullet position. # ('behind' means the bullets direction vector points AWAY from the vector # [bullet -> intersection]. That also means the angle between these two vectors is not 0 # -> due to some math-engine-internal inaccuracies, i have to check if the angle is greater than one: if abs(bullet_direction.angle(intersection - bullet_position)) > 1: # if the bullet missed the line already - NO COLLISION return False # now we finally check if the bullet is close enough to the deflector line: distance = abs(sin(radians(bullet_direction.angle(deflector_vector)) % (pi/2))) * Vector(intersection - bullet_position).length() if distance < (self.width / 2): # there is a collision! # kill the animation! self.animation.unbind(on_complete=self.on_collision_with_edge) self.animation.stop(self) # call the collision handler self.on_collision_with_deflector(deflector, deflector_vector)
def collide_wall(self, wall): # don't collide with this wall if we just did so; this # eliminates a huge class of weird behaviors if self.last_bounced_wall == wall and self.last_bounced_ticks < 5: return deflect_edge = None velocity_v = Vector(self.velocity) pos_v = Vector(self.pos) edge_points = zip(wall.quad_points[0::2], wall.quad_points[1::2]) edges = [ (edge_points[0], edge_points[1]), (edge_points[1], edge_points[2]), (edge_points[2], edge_points[3]), (edge_points[3], edge_points[0]), ] closest_point = None for point in edge_points: if (pos_v - Vector(point)).length() < self.r: if not closest_point or \ (pos_v - Vector(point)).length() < (Vector(closest_point) - Vector(point)).length(): closest_point = point if closest_point: # take the deflection edge to be the normal of here to the corner deflect_edge = (pos_v - Vector(point)).rotate(90) else: for edge in edges: e0 = Vector(edge[0]) e1 = Vector(edge[1]) ortho_v = (e0 - e1).rotate(90).normalize() dist_v = Vector.line_intersection(self.pos, pos_v + ortho_v, edge[0], edge[1]) # dist_v will be None if we happen to be parallel if not dist_v: continue dist_from_edge = (pos_v - dist_v).length() # if the shot touches the wall here if min(e0[0], e1[0]) <= dist_v[0] <= max(e0[0], e1[0]) and \ min(e0[1], e1[1]) <= dist_v[1] <= max(e0[1], e1[1]) and \ dist_from_edge < self.r + (wall.thickness / 2.): if not deflect_edge: deflect_edge = e0 - e1 dist_from_deflect_edge = dist_from_edge elif dist_from_edge < dist_from_deflect_edge: deflect_edge = e0 - e1 dist_from_deflect_edge = dist_from_edge if deflect_edge: self.velocity = velocity_v.rotate(-2 * velocity_v.angle(deflect_edge)) self.last_bounced_wall = wall self.last_bounced_ticks = 0
def collide_wall(self, wall): # don't collide with this wall if we just did so; this # eliminates a huge class of weird behaviors if self.last_bounced_wall == wall and self.last_bounced_ticks < 5: return deflect_edge = None velocity_v = Vector(self.velocity) pos_v = Vector(self.pos) edge_points = zip(wall.quad_points[0::2], wall.quad_points[1::2]) edges = [ (edge_points[0], edge_points[1]), (edge_points[1], edge_points[2]), (edge_points[2], edge_points[3]), (edge_points[3], edge_points[0]), ] closest_point = None for point in edge_points: if (pos_v - Vector(point)).length() < self.r: if ( not closest_point or (pos_v - Vector(point)).length() < (Vector(closest_point) - Vector(point)).length() ): closest_point = point if closest_point: # take the deflection edge to be the normal of here to the corner deflect_edge = (pos_v - Vector(point)).rotate(90) else: for edge in edges: e0 = Vector(edge[0]) e1 = Vector(edge[1]) ortho_v = (e0 - e1).rotate(90).normalize() dist_v = Vector.line_intersection(self.pos, pos_v + ortho_v, edge[0], edge[1]) # dist_v will be None if we happen to be parallel if not dist_v: continue dist_from_edge = (pos_v - dist_v).length() # if the shot touches the wall here if ( min(e0[0], e1[0]) <= dist_v[0] <= max(e0[0], e1[0]) and min(e0[1], e1[1]) <= dist_v[1] <= max(e0[1], e1[1]) and dist_from_edge < self.r + (wall.thickness / 2.0) ): if not deflect_edge: deflect_edge = e0 - e1 dist_from_deflect_edge = dist_from_edge elif dist_from_edge < dist_from_deflect_edge: deflect_edge = e0 - e1 dist_from_deflect_edge = dist_from_edge if deflect_edge: self.velocity = velocity_v.rotate(-2 * velocity_v.angle(deflect_edge)) self.last_bounced_wall = wall self.last_bounced_ticks = 0