def canCapture(s, point, distance, targetPlanet): if s.isParent(targetPlanet): #print "Nope, is parent" return False if targetPlanet.parent != None: #print "Nope, has parent" return False if targetPlanet == s: #print "Nope, self" return False if s in targetPlanet.children: #print "Nope, is a child already" return False vecBetweenPlanets = vec.sub(targetPlanet.loc, s.loc) # Adjust distance to measure from surface to surface, not center # to center distance += s.radius + targetPlanet.radius if vec.magSquared(vecBetweenPlanets) > (distance * distance): #print "Nope, out of range" return False # Okay we are close enough to an eligible planet, are we facing it? angleBetweenPlanets = vec.toAngle(vecBetweenPlanets) # Urrrrrg I hate this, -180 to 180 and 0-360 behave differently and both are # awful in different situations so neither one is really correct. point = (point + 360) % 360 angleBetweenPlanets = (angleBetweenPlanets + 360) % 360 #print "Point and angle:", point, angleBetweenPlanets if abs(angleBetweenPlanets - point) < 10: #print "Yep!" return True #print "Nope, angle too great", angleBetweenPlanets, point, abs(angleBetweenPlanets - point) return False vecBetweenPlanets = vec.sub(targetPlanet.loc, s.loc) vecBPU = vec.unit(vecBetweenPlanets) vecToPlanetEdge = vec.mul(vec.perpendicular(vecBPU), targetPlanet.radius) #print("Vec between planets: {0}, vec to planet edge: {1}".format(vecBPU, vec.unit(vecToPlanetEdge))) angularSize = vec.angleBetween( vecBetweenPlanets, vec.add(vecBetweenPlanets, vecToPlanetEdge)) vecToPoint = vec.mul(vec.fromAngle(point), s.radius) angularDistance = vec.angleBetween(vecBetweenPlanets, vecToPoint) #print("Angular size: {0}, angular distance: {1}".format(angularSize, angularDistance)) if angularDistance > abs(angularSize): return False else: # Check distance between planets surfaces distance = distance + (s.radius + targetPlanet.radius) # Can't capture a planet if you're overlapping it # XXX: Doesn't seem to work, but... if distance < 0: return False return vec.within(s.loc, targetPlanet.loc, distance)
def arc_left( self, arc_angle, radius=None, center=None, start_slant=None, end_slant=None, ): if ( (radius is None and center is None) or (radius is not None and center is not None) ): raise TypeError('You must specify exactly one of center or radius.') arc_angle = Angle(arc_angle) # Create a radius vector, which is a vector from the arc center to the # current position. Subtract to find the center, then rotate the radius # vector to find the arc end point. if center is None: if arc_angle < 0: radius = -abs(radius) v_radius = vec.neg(vec.perp(self._vector(radius))) center = vec.sub(self._position, v_radius) elif radius is None: v_radius = vec.vfrom(center, self._position) radius = vec.mag(v_radius) if arc_angle < 0: radius = -radius endpoint = vec.add(center, vec.rotate(v_radius, arc_angle.rad)) self._arc( center, radius, endpoint, arc_angle, start_slant=start_slant, end_slant=end_slant, )
def rebound(self, *args, **kwargs): v_initial = self.velocity super(Player, self).rebound(*args, **kwargs) v_final = self.velocity # Apply damage based on the difference in momentum. v_diff = vec.sub(v_final, v_initial) self.damage += vec.mag(v_diff) * self.mass
def capture(s, victimPlanet): # This vector points from self to the victim planet distance = vec.sub(s.loc, victimPlanet.loc) victimPlanet.parentVec = distance victimPlanet.parent = s victimPlanet.capturedFacing = victimPlanet.facing victimPlanet.capturedParentFacing = s.facing s.children.append(victimPlanet) victimPlanet.genCaptureImage()
def draw_graph(graph): gap_size = 0.25 p = canoepaddle.Pen() p.stroke_mode(0.1, 'black') for a, b in graph_edges(graph): gap = vec.norm(vec.vfrom(a, b), gap_size) p.move_to(vec.add(a, gap)) p.line_to(vec.sub(b, gap)) return p.paper
def balls_collisions(balls): collided = False for b1 in balls: for b2 in balls: if b1 is b2: continue d = vec.sub(b1.pos, b2.pos) penetration = (b1.radius + b2.radius) - vec.len(d) if penetration < 0: continue collided = True n = vec.unit(d) b1.pos = vec.add(b1.pos, vec.scale(n, penetration / 2 + 1)) b2.pos = vec.add(b2.pos, vec.scale(n, -penetration / 2 - 1)) j = vec.dot(vec.sub(b2.speed, b1.speed), n) b1.speed = vec.add(b1.speed, vec.scale(n, j)) b2.speed = vec.add(b2.speed, vec.scale(n, -j)) return collided
def project(self, points, reverse=False): if reverse: if self.H_ is None: self.H_ = mtx.lu([r[:] for r in self.H]) qs = [ mtx.solve(self.H_, vec.sub(p, self.offset) + [1]) for p in points ] return [vec.div(q[:-1], q[-1]) for q in qs] else: qs = [mtx.mul(self.H, p + [1]) for p in points] return [vec.add(self.offset, vec.div(q[:-1], q[-1])) for q in qs]
def draw(s, gs): sx, sy = gs.screenCoords(s.loc) s.sprite.x = sx s.sprite.y = sy s.sprite.rotation = s.facing s.sprite.draw() if s.parent != None: #parentSloc = gs.screenCoords(s.parent.loc) vecToParent = vec.sub(s.parent.loc, s.loc) angle = vec.toAngle(vecToParent) centerPointVec = vec.div(vecToParent, 2) actualVec = vec.add(s.loc, centerPointVec) s.captureSprite.position = gs.screenCoords(actualVec) s.captureSprite.rotation = angle s.captureSprite.draw()
def collide_wall(self, p): restitution = self.restitution * p.restitution # First, check that we haven't crossed through the wall due to # extreme speed and low framerate. intersection = intersect_segments(self.p1, self.p2, p.last_pos, p.pos) if intersection: p.pos = p.last_pos p.rebound(self.normal, intersection, restitution) return # Find vectors to each endpoint of the segment. v1 = vec.vfrom(self.p1, p.pos) v2 = vec.vfrom(self.p2, p.pos) # Find a perpendicular vector from the wall to p. v_dist = vec.proj(v1, self.normal) # Test distance from the wall. radius2 = p.radius**2 if vec.mag2(v_dist) > radius2: return # Test for collision with the endpoints of the segment. # Check whether p is too far off the end of the segment, by checking # the sign of the vector projection, then a radius check for the # distance from the endpoint. if vec.dot(v1, self.tangent) < 0: if vec.mag2(v1) <= radius2: p.rebound(v1, self.p1, restitution) return if vec.dot(v2, self.tangent) > 0: if vec.mag2(v2) <= radius2: p.rebound(v2, self.p2, restitution) return # Test that p is headed toward the wall. if vec.dot(p.velocity, v_dist) >= c.epsilon: return # We are definitely not off the ends of the segment, and close enough # that we are colliding. p.rebound(self.normal, vec.sub(p.pos, v_dist), restitution)
def genCaptureImage(s): """Builds a line sprite of the right length to go to the capturing planet.""" # Some paranoid error checking if not s.parent: raise Exception( "Tried to generate capture image with nonexistant parent!") vecToParent = vec.sub(s.parent.loc, s.loc) distanceToParent = vec.mag(vecToParent) # It appears that we can blit image_data (software image data # in main memory) to a texture (hardware image data on the GPU) # but not any other way. ropeImage = resource.getImage('line2').get_image_data() img = pyglet.image.create(ropeImage.width, int(distanceToParent)).get_texture() img.anchor_x = int(img.width // 2) img.anchor_y = int(img.height // 2) # Now we have the image, we fill it up with the # capture-rope images. for i in range(0, int(distanceToParent), ropeImage.height): #print 'foo', i, img.height, ropeImage.height img.blit_into(ropeImage, 0, i, 0) s.captureSprite = pyglet.sprite.Sprite(img)
def join_with_line(self, other): v_self = self._vector() v_other = other._vector() # Check turn angle. self_heading = Heading.from_rad(vec.heading(v_self)) other_heading = Heading.from_rad(vec.heading(v_other)) turn_angle = self_heading.angle_to(other_heading) # Special case equal widths. if( abs(turn_angle) <= MAX_TURN_ANGLE and float_equal(self.width, other.width) ): # When joints between segments of equal width are straight or # almost straight, the line-intersection method becomes very # numerically unstable, so use another method instead. # For each segment, get a vector perpendicular to the # segment, then add them. This is an angle bisector for # the angle of the joint. w_self = self._width_vector() w_other = other._width_vector() v_bisect = vec.add(w_self, w_other) # Make the bisector have the correct length. half_angle = vec.angle(v_other, v_bisect) v_bisect = vec.norm( v_bisect, (self.width / 2) / math.sin(half_angle) ) # Determine the left and right joint spots. p_left = vec.add(self.b, v_bisect) p_right = vec.sub(self.b, v_bisect) else: a, b = self.offset_line_left() c, d = other.offset_line_left() p_left = intersect_lines(a, b, c, d) a, b = self.offset_line_right() c, d = other.offset_line_right() p_right = intersect_lines(a, b, c, d) # Make sure the joint points are "forward" from the perspective # of each segment. if p_left is not None: if vec.dot(vec.vfrom(self.a_left, p_left), v_self) < 0: p_left = None if p_right is not None: if vec.dot(vec.vfrom(self.a_right, p_right), v_self) < 0: p_right = None # Don't join the outer sides if the turn angle is too steep. if abs(turn_angle) > MAX_TURN_ANGLE: if turn_angle > 0: p_right = None else: p_left = None if p_left is not None: self.b_left = other.a_left = Point(*p_left) if p_right is not None: self.b_right = other.a_right = Point(*p_right) if p_left is None or p_right is None: self.end_joint_illegal = True other.start_joint_illegal = True
def on_key_press(s, gs, key): if key == keys.SPACE: if not s.controlling: s.startControl() else: s.endControl() elif s.controlling: s.parent.on_key_press(gs, key) else: if key == keys.LEFT: s.facing = -1 s.moving = -1 elif key == keys.RIGHT: s.facing = 1 s.moving = 1 elif key == keys.X: # Try capture some nearby planet... #print("Trying capture...") for p in gs.planets: facingpoint = (s.parent.facing + s.loc) % 360 #print("Trying to capture {0} at facing {1}".format(p, facingpoint)) # XXX: Make it only capture the closest planet, dammit! # XXX: Ideally it will also go off the distance between the planet # surfaces, not the centers This needs to happen! if s.parent.canCapture(facingpoint, s.captureRange, p): print("Captured, facing {0}!".format(facingpoint)) s.parent.capture(p) sound = resource.getSound("capture") sound.play() break elif key == keys.Z: # Try uncapture # XXX: At the moment we can't uncapture from the child side... hmm. # XXX: At the moment also, if there are multiple planets # captured close to each other, it essentially releases # one at random rather than doing the one closest to # where you're standing. for p in s.parent.children: # This is a little f****d up but should work... facingpoint = (s.parent.facing + s.loc) % 360 facingvec = vec.fromAngle(facingpoint) offset = vec.sub(p.loc, s.parent.loc) diff = vec.angleBetween(facingvec, offset) if abs(diff) < 0.2: #print("Uncapturing") s.parent.uncapture(p) sound = resource.getSound("uncapture") sound.play() break elif key == keys.C: if s.attackCooldown < 0.0: s.attack(gs) s.attackCooldown = s.attackCooldownTotal s.attackSound.play() elif key == keys.UP: # Transport to captured planet. teleportAngle = 10.0 for p in s.parent.children: facingpoint = (s.parent.facing + s.loc) % 360 facingvec = vec.fromAngle(facingpoint) offset = vec.sub(p.loc, s.parent.loc) diff = vec.angleBetween(facingvec, offset) if abs(diff ) < teleportAngle and s.transportCooldown <= 0.0: s.sprayParticles(gs, particles.WarpSpark, 50, 30) facingdiff = s.parent.facing - p.facing s.loc += facingdiff + 180 s.setParent(p) s.transportCooldown = s.transportCooldownTotal s.sprayParticles(gs, particles.WarpSpark, 50, 30) s.teleportSound.play() return # Oooor, if this planet is captured, you can go back to the parent if s.parent.parent != None: p = s.parent.parent facingpoint = (s.parent.facing + s.loc) % 360 facingvec = vec.fromAngle(facingpoint) offset = vec.sub(p.loc, s.parent.loc) diff = vec.angleBetween(facingvec, offset) if abs(diff ) < teleportAngle and s.transportCooldown <= 0.0: s.sprayParticles(gs, particles.WarpSpark, 50, 30) facingdiff = s.parent.facing - p.facing s.loc += facingdiff + 180 s.setParent(p) s.transportCooldown = s.transportCooldownTotal s.sprayParticles(gs, particles.WarpSpark, 50, 30) s.teleportSound.play() return # If we've gotten this far, then you're not sitting on a connection, # So jump! if s.jumpCooldown < 0: s.jump() s.jumpSound.play()