Пример #1
0
    def turning_radius(self):
        ''' Returns the radius of the circle needed to ride over the target
        '''

        if not self.target.visible: return 1e12
        (a0, b0) = (self.target.x - self.x,  self.target.y - self.y)

        #mag: distance between Bike and it's target
        mag = hypot(a0, b0)

        #psi: angle of target relative to Bike's path of travel
        psi = util.normangle(atan2(b0, a0) - self.angle)
        self.psi_sign = 1 if psi > 0 else -1
        
        if fabs(psi) > pi / 2.0:
            # The player is looking at a point over his shoulder
            tmp = fabs(mag * sin(psi - self.psi_sign * pi/2.0))
            self.target.x += tmp * cos(self.angle)
            self.target.y += tmp * sin(self.angle)
            
            psi = self.psi_sign * pi/2.0
            # calculate as though the target is parallel with path of travel at
            # 90deg angle to the path of travel
            a0 = self.target.x - self.x
            b0 = self.target.y - self.y
            mag = hypot(a0, b0)
    
        a = mag * sin(psi)
        b = mag * cos(psi)

        if fabs(a) > 1e-12:
            return fabs((a*a + b*b) / (2.0*a))
        else: 
            return 1e12
Пример #2
0
    def update(self):
        r = self.turning_radius()
        
        r_min = self.mass * self.speed * self.speed / self.ft
        v_max = sqrt(r * self.ft / self.mass)
        dts = self.dt * 60.0 / 1000.0

        # clear the drawing callbacks
        self.draw_cb = []
        
        if r < r_min and self.target.visible:
            # Must brake in order to turn
            self.speed = max((1e-12, self.speed - self.brake * dts))
            r = 1e12

            # Draw the predicted braking vector
            brake_dist = (0.5 * ((self.speed - v_max) / self.brake) *
                          (self.speed + v_max))
            @self.draw_cb.append
            def drawme(screen):
                start = self.x, self.y
                end = (self.x + cos(self.angle) * brake_dist,
                       self.y + sin(self.angle) * brake_dist)
                pygame.draw.line(screen, (127,0,0), start, end, 10)
        else:
            # Can turn without breaking
            if not self.target.visible:
                v_max = 1e12

            # Important to keep v_max * 0.98 because otherwise, the bike is
            # really close to over accelerating with random fluctuations This
            # is a little messy, but i think i understand the behavior if not
            # the best solution.
            self.speed = min((self.speed + self.accel * dts, 
                              self.max_speed, v_max * 0.98))
        
        l = self.speed * dts
        if self.target.visible and fabs(r) < 1e9:
            # phi: angle of rotation to travel distance l over circle with
            # radius r
            phi = l / r
            self.angle = util.normangle(self.angle + (phi * self.psi_sign))
            
            # c: the chord with angle phi through circle with radius r.
            # extremely close to l for small values of l
            c = 2.0 * r * sin(phi/2.0)
            # fabs(c-l) is typically less than 1e-5 pixels
            self.x += c * cos(phi+self.angle)
            self.y += c * sin(phi+self.angle)
            
            # the remainder of this block is debug
            # find the center of the turning circle
            tmp = self.angle + (self.psi_sign * pi/2.0)
            debugx = int(self.x + r * cos(tmp))
            debugy = int(self.y + r * sin(tmp))
            
            # the turning circle
            if(r < 1000 and r > 0):
                @self.draw_cb.append
                def drawme(s):
                    pygame.draw.circle(s, (0,0,0), (debugx, debugy), int(r), 1)
                    pygame.draw.circle(s, (0,0,0), (debugx, debugy), 2, 0)

            # The vector of travel, tangent to the turning circle
            @self.draw_cb.append
            def drawme(s):
                dest = (self.x + cos(self.angle) * 100,
                        self.y + sin(self.angle) * 100)

                pygame.draw.line(s, (0,0,0), self.rect.center, dest, 1)

        else:
            self.x += l * cos(self.angle)
            self.y += l * sin(self.angle)
            
        # the rect uses ints, so it's just for drawing
        self.rect.center = (self.x, self.y)
        # rotate and recenter. the centering is magic :(
        self.image = pygame.transform.rotate(self.original, 
                                             -degrees(self.angle))
        self.rect = self.image.get_rect(center=self.rect.center)
        
        if self.target.rect.collidepoint(self.rect.center):
            self.target.unplace()