Esempio n. 1
0
def two_way_lidar_rect(tpl1: Tuple[float, float],
                       tpl2: Tuple[float, float],
                       lst_rect: List[FloatRect]) -> Tuple[float, float]:
    """
    Returns the distance to the nearest object (FloatRect) along the line formed by the two points. This is "two way" so
    two values are returned for both "forwards" (1->2) and "backwards" (2->1).
    """
    start = Point(*tpl1)
    end = Point(*tpl2)

    lst_front = [float("inf")]
    lst_back = [float("inf")]
    for rect in lst_rect:
        for side in rect.sides:
            intersection = Point(*get_line_intersection(side, (start, end)))
            if intersection.x is None or intersection.y is None:
                pass  # doesn't intersect

            else:
                dist_endpoint = distance(intersection, end)
                dist_startpoint = distance(intersection, start)
                if dist_endpoint <= dist_startpoint:
                    lst_front.append(dist_endpoint)
                if dist_startpoint <= dist_endpoint:
                    lst_back.append(dist_startpoint)

    return min(lst_front), min(lst_back)
Esempio n. 2
0
    def _robot_state(self, sprRobot: Robot) -> List[float]:
        b = self.lstPosBalls[0]  # type: Ball
        ball_angle = (angle_degrees(sprRobot.rectDbl.center, b.rectDbl.center)
                      + 360) % 360
        ball_dist = abs(distance(sprRobot.rectDbl.center, b.rectDbl.center))
        """ Calc super primitive lidar extending front/back from center of bot """
        top_a, top_b = sprRobot.rectDbl.side(FloatRect.SideType.TOP)
        bottom_a, bottom_b = sprRobot.rectDbl.side(FloatRect.SideType.BOTTOM)
        mid_top = Point(x=(top_a.x + top_b.x) / 2, y=(top_a.y + top_b.y) / 2)
        mid_bot = Point(x=(bottom_a.x + bottom_b.x) / 2,
                        y=(bottom_a.y + bottom_b.y) / 2)
        """ Define list of things to check with lidar """
        other_bots = filter(lambda x: not x is sprRobot, self.lstRobots)
        lst_objects = list(map(lambda x: x.rectDbl,
                               other_bots)) + [self.rect_walls]

        lidar_front, lidar_back = TrashyPhysics.two_way_lidar_rect(
            mid_bot, mid_top, lst_objects)

        return [
            float(sprRobot.dblRotation),
            float(ball_angle),
            float(ball_dist),
            float(lidar_front),
            float(lidar_back)
        ]
Esempio n. 3
0
def ball_robot_collided(ball: 'Ball', bot: 'Robot') -> bool:
    """
    If the ball/robot collided, either:
        (1) One of the corners of the bot is inside the ball -OR-
        (2) One of the edges of the bot is intersecting the circle -OR-
        (3) Entire ball is within the bot

    3 should never happen (unless our ball speed goes nuts) and, if it does,
    the collision logic won't work anyways so... ignore for now.
    """
    for corner in bot.rectDbl.corners:
        if distance(corner, ball.rectDbl.center) < const.BALL_RADIUS:
            return True

    # get diameters parallel/perp to the robot sides
    _rectBallInner.center = ball.rectDbl.center
    _rectBallInner.rotation = bot.rectDbl.rotation + 45
    lst_diameters = [
        Line(a=_rectBallInner.corner(FloatRect.CornerType.TOP_LEFT),
             b=_rectBallInner.corner(FloatRect.CornerType.BOTTOM_RIGHT)),
        Line(a=_rectBallInner.corner(FloatRect.CornerType.TOP_RIGHT),
             b=_rectBallInner.corner(FloatRect.CornerType.BOTTOM_LEFT))
    ]
    # if those lines intersect, ball is colliding
    for side in bot.rectDbl.sides:
        for diameter in lst_diameters:
            tpl_i = get_line_intersection(side, diameter)
            if point_within_line(tpl_i, side) and point_within_line(tpl_i, diameter):
                return True

    return False
Esempio n. 4
0
    def on_step_end(self):
        super(ChasePosBall, self).on_step_end()

        for sprRobot in self.lstHappyBots:
            for sprBall in self.lstPosBalls:
                dist_now = distance(sprRobot.rectDbl.center,
                                    sprBall.rectDbl.center)
                dist_prior = distance(sprRobot.rectDblPriorStep.center,
                                      sprBall.rectDbl.center)
                self.reward_happy += (
                    dist_prior - dist_now) * const.POINTS_ROBOT_TRAVEL_MULT

        for sprRobot in self.lstGrumpyBots:
            for sprBall in self.lstPosBalls:
                dist_now = distance(sprRobot.rectDbl.center,
                                    sprBall.rectDbl.center)
                dist_prior = distance(sprRobot.rectDblPriorStep.center,
                                      sprBall.rectDbl.center)
                self.reward_grumpy += (
                    dist_prior - dist_now) * const.POINTS_ROBOT_TRAVEL_MULT
Esempio n. 5
0
    def __ponder():
        Stephen.__assignments = {}
        lst_dist = []
        for ball in Stephen.__env.lstBalls:
            if Stephen.__env.sprGrumpyGoal.ball_in_goal(ball) or \
                    Stephen.__env.sprHappyGoal.ball_in_goal(ball):
                pass  # ignore
            else:
                for stephen in Stephen.__hive:
                    lst_dist.append(
                        (stephen, ball, distance(ball.rectDbl.center, stephen.robot.rectDbl.center))
                    )

        lst_dist.sort(key=lambda s: s[2])  # sort by distance, asc
        claimed_balls = set()
        for stephen, ball, _ in lst_dist:
            if ball in claimed_balls:
                pass
            elif stephen in Stephen.__assignments:
                pass
            else:
                claimed_balls.add(ball)
                Stephen.__assignments[stephen] = ball
Esempio n. 6
0
    def get_game_state(self,
                       int_team: int = None,
                       obj_robot: Robot = None,
                       obj_ball: Ball = None) -> np.ndarray:
        """ Validate """
        if int_team == const.TEAM_HAPPY and obj_robot is None and len(
                self.lstHappyBots) == 0:
            return None
        if int_team == const.TEAM_GRUMPY and obj_robot is None and len(
                self.lstGrumpyBots) == 0:
            return None

        if obj_ball is None:
            obj_ball = self.lstPosBalls[0]
        if int_team is not None and obj_robot is not None:
            assert (obj_robot.intTeam == int_team)
        elif int_team is None and obj_robot is None:
            int_team = const.TEAM_HAPPY
            obj_robot = self.lstHappyBots[0]
        elif int_team is None:  # and obj_robot is not None
            int_team = obj_robot.intTeam
        elif obj_robot is None:  # and int_team is not None
            obj_robot = self.lstHappyBots[
                0] if int_team == const.TEAM_HAPPY else self.lstGrumpyBots[0]
        """ DO LIDAR 
        Front of the robot = Right side of rect (0 rotation)
        Left side of robot = Top side of rect (90) etc.
        """

        # TODO this shit is all f****d up
        # SideType is probably wrong
        # BUT you could still train with it, technically
        # it is reporting all the right information, it's just
        # not in the order that I'm assuming it is here... :(

        front_a, front_b = obj_robot.rectDbl.side(FloatRect.SideType.RIGHT)
        back_a, back_b = obj_robot.rectDbl.side(FloatRect.SideType.LEFT)
        mid_front = Point(x=(front_a.x + front_b.x) / 2,
                          y=(front_a.y + front_b.y) / 2)
        mid_back = Point(x=(back_a.x + back_b.x) / 2,
                         y=(back_a.y + back_b.y) / 2)
        """ Define list of things to check with lidar """
        other_bots = filter(lambda x: not x is obj_robot, self.lstRobots)
        lst_objects = list(map(lambda x: x.rectDbl,
                               other_bots)) + [self.rect_walls]

        lidar_front, lidar_back = TrashyPhysics.two_way_lidar_rect(
            mid_back, mid_front, lst_objects)

        lidar_front_l, lidar_back_r = TrashyPhysics.two_way_lidar_rect(
            obj_robot.rectDbl.corner(FloatRect.CornerType.BOTTOM_LEFT),
            obj_robot.rectDbl.corner(FloatRect.CornerType.TOP_RIGHT),
            lst_objects)

        lidar_front_r, lidar_back_l = TrashyPhysics.two_way_lidar_rect(
            obj_robot.rectDbl.corner(FloatRect.CornerType.TOP_LEFT),
            obj_robot.rectDbl.corner(FloatRect.CornerType.BOTTOM_RIGHT),
            lst_objects)

        # Cap lidar at...
        lidar_cap = 150
        lidar_front = min(lidar_front, lidar_cap)
        lidar_back = min(lidar_back, lidar_cap)
        lidar_front_l = min(lidar_front_l, lidar_cap)
        lidar_front_r = min(lidar_front_r, lidar_cap)
        lidar_back_r = min(lidar_back_r, lidar_cap)
        lidar_back_l = min(lidar_back_l, lidar_cap)
        """ Gather remaining obs """
        ball_angle = angle_degrees(obj_robot.rectDbl.center,
                                   obj_ball.rectDbl.center)
        ball_dist = distance(obj_robot.rectDbl.center, obj_ball.rectDbl.center)
        ball_dist = min(ball_dist, lidar_cap)
        goal_angle = angle_degrees(obj_robot.rectDbl.center,
                                   (const.ARENA_WIDTH, const.ARENA_HEIGHT))
        bot_angle = obj_robot.dblRotation

        goal_dist_cap = max(const.GOAL_WIDTH, const.GOAL_HEIGHT) + lidar_cap
        bad_goal_dist = distance(obj_robot.rectDbl.center, (0, 0))
        good_goal_dist = distance(obj_robot.rectDbl.center,
                                  (const.ARENA_WIDTH, const.ARENA_HEIGHT))
        if good_goal_dist <= bad_goal_dist:
            goal_dist = min(good_goal_dist, goal_dist_cap)
        else:
            goal_dist = -1 * min(bad_goal_dist, goal_dist_cap)
        """
        Standard output is for Happy bot chasing a Positive ball.
        If team is Grumpy, flip it. If ball is Negative, flip it. 
        """
        if (int_team == const.TEAM_HAPPY and obj_ball.is_negative) or \
                (int_team == const.TEAM_GRUMPY and obj_ball.is_positive):
            # flip the observation
            goal_dist *= -1
            ball_angle = (ball_angle + 180) % 360
            goal_angle = (goal_angle + 180) % 360
            bot_angle = (bot_angle + 180) % 360

        return np.asarray([
            float(bot_angle),
            float(ball_angle),
            float(ball_dist),
            float(goal_angle),
            float(goal_dist),
            float(lidar_front),
            float(lidar_front_l),
            float(lidar_front_r),
            float(lidar_back),
            float(lidar_back_l),
            float(lidar_back_r)
        ])
Esempio n. 7
0
def apply_force_to_ball(spr_robot: 'Robot', spr_ball: 'Ball') -> None:
    rect_bot = spr_robot.rectDbl  # type: FloatRect
    rect_bot_prev = spr_robot.rectDblPriorFrame  # type: FloatRect

    # create list of diameter lines that are parallel/perpendicular to the sides of the bot's position
    _rectBallInner.rotation = 45 + rect_bot.rotation  # fudging this for simplicity's sake
    _rectBallInner.center = spr_ball.rectDbl.center
    lst_diameters = [
        Line(
            a=_rectBallInner.corner(FloatRect.CornerType.BOTTOM_LEFT),
            b=_rectBallInner.corner(FloatRect.CornerType.TOP_RIGHT)
        ),
        Line(
            a=_rectBallInner.corner(FloatRect.CornerType.BOTTOM_RIGHT),
            b=_rectBallInner.corner(FloatRect.CornerType.TOP_LEFT)
        )
    ]

    """ CHECK FOR SURFACE COLLISION """
    # if either of these lines intersect with a side of the bot,
    # treat this as a "surface collision" and not a corner collision
    dbl_contact_buffer = .5
    for enm_side in FloatRect.SideType:
        bot_side = rect_bot.side(enm_side)
        bot_side_prev = rect_bot_prev.side(enm_side)
        for diameter in lst_diameters:
            tpl_i = get_line_intersection(bot_side, diameter)
            if point_within_line(tpl_i, bot_side) and point_within_line(tpl_i, diameter, buffer=dbl_contact_buffer):
                dist_a = distance(diameter.a, rect_bot.center)
                dist_b = distance(diameter.b, rect_bot.center)
                tpl_cp_ball = diameter.a if dist_a < dist_b else diameter.b
                tpl_cp_ball_opp = diameter.a if dist_a >= dist_b else diameter.b
                tpl_contact_buffer = Vec2D(
                    x=(tpl_cp_ball_opp.x - tpl_cp_ball.x) * dbl_contact_buffer / (const.BALL_RADIUS + const.BALL_RADIUS),
                    y=(tpl_cp_ball_opp.y - tpl_cp_ball.y) * dbl_contact_buffer / (const.BALL_RADIUS + const.BALL_RADIUS)
                )
                # Calculate minimum distance for ball to leave the robot according to current contact vector
                tpl_contact = Vec2D(x=tpl_i[0] - tpl_cp_ball.x, y=tpl_i[1] - tpl_cp_ball.y)
                spr_ball.dbl_force_x += tpl_contact.x + tpl_contact_buffer.x
                spr_ball.dbl_force_y += tpl_contact.y + tpl_contact_buffer.y
                spr_ball.lngFrameMass = max(spr_robot.lngFrameMass, spr_ball.lngFrameMass)
                return  # can only be one pending collision point with this logic

    """ CHECK FOR CORNER COLLISION """
    for enm_corner in FloatRect.CornerType:
        bot_corner = rect_bot.corner(enm_corner)
        dbl_dist_center = distance(bot_corner, spr_ball.rectDbl.center)
        if dbl_dist_center < const.BALL_RADIUS + dbl_contact_buffer:
            bot_corner_prev = rect_bot_prev.corner(enm_corner)
            # Let's just... fudge this a bit... instead of actually calc'ing (weighted average)
            tpl_contact = Vec2D(
                x=spr_ball.rectDbl.centerx - (bot_corner.x * 3 + bot_corner_prev.x) / 4,
                y=spr_ball.rectDbl.centery - (bot_corner.y * 3 + bot_corner_prev.y) / 4)

            # Fudge this a bit, since we're not calc'ing the exact contact point on the ball
            contact_dist = distance((0, 0), tpl_contact)
            tpl_contact_buffer = Vec2D(
                x=tpl_contact.x * dbl_contact_buffer / contact_dist,
                y=tpl_contact.y * dbl_contact_buffer / contact_dist
            )
            exit_dist = (const.BALL_RADIUS - dbl_dist_center) * 1.2
            spr_ball.dbl_force_x += (tpl_contact.x * exit_dist / contact_dist) + tpl_contact_buffer.x
            spr_ball.dbl_force_y += (tpl_contact.y * exit_dist / contact_dist) + tpl_contact_buffer.y
            spr_ball.lngFrameMass = max(spr_robot.lngFrameMass, spr_ball.lngFrameMass)
            return
Esempio n. 8
0
def balls_collided(spr1: 'Ball', spr2: 'Ball'):
    return distance(spr1.rectDbl.center, spr2.rectDbl.center) <= const.BALL_RADIUS + const.BALL_RADIUS
Esempio n. 9
0
def bounce_balls(ball1: 'Ball', ball2: 'Ball') -> None:
    if ball1.rectDbl.center == ball2.rectDbl.center:
        raise Exception("Really tho?? The balls are in the EXACT same spot????")

    # Determine vector between two centers
    vec_1_2 = Vec2D(ball2.rectDbl.centerx - ball1.rectDbl.centerx, ball2.rectDbl.centery - ball1.rectDbl.centery)
    dist_1_2 = distance((0,0), vec_1_2)

    # Create vector in that direction of length radius
    vec_radius = Vec2D(vec_1_2.x * const.BALL_RADIUS / dist_1_2, vec_1_2.y * const.BALL_RADIUS / dist_1_2)

    # Determine point on Ball 1 closest to the center of Ball 2
    tplPnt1 = Point(x=ball1.rectDbl.centerx + vec_radius.x, y=ball1.rectDbl.centery + vec_radius.y)
    # and vice versa
    tplPnt2 = Point(x=ball2.rectDbl.centerx - vec_radius.x, y=ball2.rectDbl.centery - vec_radius.y)

    buffer = 1.1
    dblHalfDeltaX = (tplPnt2.x - tplPnt1.x) / 2
    dblHalfDeltaY = (tplPnt2.y - tplPnt1.y) / 2
    if ball1.lngFrameMass == ball2.lngFrameMass:
        """ Move balls out of each other. """
        ball1.rectDbl.centerx += dblHalfDeltaX * buffer
        ball1.rectDbl.centery += dblHalfDeltaY * buffer
        ball2.rectDbl.centerx -= dblHalfDeltaX * buffer
        ball2.rectDbl.centery -= dblHalfDeltaY * buffer
    else:
        """ Only one ball moves. """
        if ball1.lngFrameMass > ball2.lngFrameMass:
            ball2.rectDbl.centerx += (tplPnt1.x - tplPnt2.x) * buffer
            ball2.rectDbl.centery += (tplPnt1.y - tplPnt2.y) * buffer
            ball2.lngFrameMass = ball1.lngFrameMass  # and now they are one
        else:
            ball1.rectDbl.centerx += (tplPnt2.x - tplPnt1.x) * buffer
            ball1.rectDbl.centery += (tplPnt2.y - tplPnt1.y) * buffer
            ball1.lngFrameMass = ball2.lngFrameMass  # and now they are one

    """ Bounce! """
    # Let's conserve some momentum with vector projection (ya i totally remembered how to do this)
    # projection of 1's velocity onto contact vector:
    tplVect1to2 = Vec2D(x=ball2.rectDbl.centerx - ball1.rectDbl.centerx, y=ball2.rectDbl.centery - ball1.rectDbl.centery)
    tplVect2to1 = Vec2D(x=tplVect1to2.x * -1, y=tplVect1to2.y * -1)
    dblCenterDist_Sq = tplVect1to2.x * tplVect1to2.x + tplVect1to2.y * tplVect1to2.y
    dblProjClcTerm1 = Div0(tplVect1to2.x * ball1.dbl_velocity_x + tplVect1to2.y * ball1.dbl_velocity_y, dblCenterDist_Sq)
    tplVel1 = Vec2D(x=dblProjClcTerm1 * tplVect1to2.x, y=dblProjClcTerm1 * tplVect1to2.y)
    dblProjClcTerm2 = Div0(tplVect2to1.x * ball2.dbl_velocity_x + tplVect2to1.y * ball2.dbl_velocity_y, dblCenterDist_Sq)
    tplVel2 = Vec2D(x=dblProjClcTerm2 * tplVect2to1.x, y=dblProjClcTerm2 * tplVect2to1.y)
    tplDiff = Vec2D(x=tplVel1.x - tplVel2.x, y=tplVel1.y - tplVel2.y)
    ball1.dbl_velocity_x -= tplDiff.x * const.BOUNCE_K_BALL
    ball1.dbl_velocity_y -= tplDiff.y * const.BOUNCE_K_BALL
    ball2.dbl_velocity_x += tplDiff.x * const.BOUNCE_K_BALL
    ball2.dbl_velocity_y += tplDiff.y * const.BOUNCE_K_BALL

    """ ... but also account for force """
    if ball1.dbl_force_x > 0:
        ball1.dbl_velocity_x = max(ball1.dbl_velocity_x, ball1.dbl_force_x)
    elif ball1.dbl_force_x < 0:
        ball1.dbl_velocity_x = min(ball1.dbl_velocity_x, ball1.dbl_force_x)
    if ball1.dbl_force_y > 0:
        ball1.dbl_velocity_y = max(ball1.dbl_velocity_y, ball1.dbl_force_y)
    elif ball1.dbl_force_y < 0:
        ball1.dbl_velocity_y = min(ball1.dbl_velocity_y, ball1.dbl_force_y)
    if ball2.dbl_force_x > 0:
        ball2.dbl_velocity_x = max(ball2.dbl_velocity_x, ball2.dbl_force_x)
    elif ball2.dbl_force_x < 0:
        ball2.dbl_velocity_x = min(ball2.dbl_velocity_x, ball2.dbl_force_x)
    if ball2.dbl_force_y > 0:
        ball2.dbl_velocity_y = max(ball2.dbl_velocity_y, ball2.dbl_force_y)
    elif ball2.dbl_force_y < 0:
        ball2.dbl_velocity_y = min(ball2.dbl_velocity_y, ball2.dbl_force_y)
Esempio n. 10
0
def bounce_ball_off_bot(spr_robot: 'Robot', spr_ball: 'Ball'):
    if spr_ball.dbl_velocity_x == spr_ball.dbl_velocity_y == 0:
        return  # no velocity to "bounce"

    dbl_contact_buffer = .5
    rect_bot = spr_robot.rectDbl  # type: FloatRect
    rect_bot_prev = spr_robot.rectDblPriorFrame  # type: FloatRect

    # create list of diameter lines that are parallel/perpendicular to the sides of the bot's position
    _rectBallInner.rotation = 45 + rect_bot.rotation  # fudging this for simplicity's sake
    _rectBallInner.center = spr_ball.rectDbl.center
    lst_diameters = [
        Line(
            a=_rectBallInner.corner(FloatRect.CornerType.BOTTOM_LEFT),
            b=_rectBallInner.corner(FloatRect.CornerType.TOP_RIGHT)
        ),
        Line(
            a=_rectBallInner.corner(FloatRect.CornerType.BOTTOM_RIGHT),
            b=_rectBallInner.corner(FloatRect.CornerType.TOP_LEFT)
        )
    ]

    """ CHECK FOR SURFACE COLLISION """
    # if either of these lines intersect with a side of the bot,
    # treat this as a "surface collision" and not a corner collision
    for enm_side in FloatRect.SideType:
        bot_side = rect_bot.side(enm_side)
        bot_side_prev = rect_bot_prev.side(enm_side)
        for diameter in lst_diameters:
            tpl_i = get_line_intersection(bot_side, diameter)
            tpl_i_prev = get_line_intersection(bot_side_prev, diameter)
            if point_within_line(tpl_i, bot_side) and point_within_line(tpl_i, diameter):
                dist_a = distance(diameter.a, tpl_i_prev)
                dist_b = distance(diameter.b, tpl_i_prev)
                tpl_cp_ball = diameter.a if dist_a < dist_b else diameter.b
                tpl_cp_ball_opp = diameter.a if dist_a >= dist_b else diameter.b

                tpl_contact = Vec2D(x=tpl_cp_ball_opp.x - tpl_cp_ball.x, y=tpl_cp_ball_opp.y - tpl_cp_ball.y)
                tpl_ball_vel = Vec2D(x=spr_ball.dbl_velocity_x, y=spr_ball.dbl_velocity_y)

                # Projected components of the ball's velocity
                dbl_contact_dist_sq = tpl_contact.x ** 2 + tpl_contact.y ** 2
                dbl_ball_proj_term = ((tpl_contact.x * tpl_ball_vel.x) + (tpl_contact.y * tpl_ball_vel.y)) \
                                     / dbl_contact_dist_sq
                tpl_ball_proj = Vec2D(x=dbl_ball_proj_term * tpl_contact.x, y=dbl_ball_proj_term * tpl_contact.y)

                if (tpl_ball_proj.x < 0 and tpl_contact.x > 0) or (tpl_ball_proj.x > 0 and tpl_contact.x < 0):
                    spr_ball.dbl_velocity_x = -tpl_ball_proj.x * const.BOUNCE_K_WALL * const.BOUNCE_K_ROBOT
                if (tpl_ball_proj.y < 0 and tpl_contact.y > 0) or (tpl_ball_proj.y > 0 and tpl_contact.y < 0):
                    spr_ball.dbl_velocity_y = -tpl_ball_proj.y * const.BOUNCE_K_WALL * const.BOUNCE_K_ROBOT

                # Create a buffer vector
                tpl_contact_buffer = Vec2D(
                    x=tpl_contact.x * dbl_contact_buffer / dbl_contact_dist_sq**.5,
                    y=tpl_contact.y * dbl_contact_buffer / dbl_contact_dist_sq**.5
                )

                tpl_exit_point = Point(*tpl_i)
                spr_ball.rectDbl.centerx += (tpl_exit_point.x - tpl_cp_ball.x) + tpl_contact_buffer.x
                spr_ball.rectDbl.centery += (tpl_exit_point.y - tpl_cp_ball.y) + tpl_contact_buffer.y
                return

    """ CHECK FOR CORNER COLLISION """
    for enm_corner in FloatRect.CornerType:
        bot_corner = rect_bot.corner(enm_corner)
        dbl_dist_center = distance(bot_corner, spr_ball.rectDbl.center)
        if dbl_dist_center < const.BALL_RADIUS:
            bot_corner_prev = rect_bot_prev.corner(enm_corner)
            # Let's just... fudge this a bit... instead of actually calc'ing (weighted average)
            tpl_cp_bot = Point(x=(bot_corner.x*3 + bot_corner_prev.x)/4, y=(bot_corner.y*3 + bot_corner_prev.y)/4)
            tpl_contact = Vec2D(x=spr_ball.rectDbl.centerx - tpl_cp_bot.x, y=spr_ball.rectDbl.centery - tpl_cp_bot.y)

            # Project the ball vel onto the contact vector
            tpl_ball_vel = Vec2D(x=spr_ball.dbl_velocity_x, y=spr_ball.dbl_velocity_y)
            dbl_contact_dist_sq = tpl_contact.x ** 2 + tpl_contact.y ** 2
            dbl_ball_proj_term = ((tpl_contact.x * tpl_ball_vel.x) + (tpl_contact.y * tpl_ball_vel.y)) \
                                 / dbl_contact_dist_sq
            tpl_ball_proj = Vec2D(x=dbl_ball_proj_term * tpl_contact.x, y=dbl_ball_proj_term * tpl_contact.y)

            # Apply bounce, if applicable
            if (tpl_ball_proj.x < 0 and tpl_contact.x > 0) or (tpl_ball_proj.x > 0 and tpl_contact.x < 0):
                spr_ball.dbl_velocity_x = -tpl_ball_proj.x * const.BOUNCE_K_WALL * const.BOUNCE_K_ROBOT
            if (tpl_ball_proj.y < 0 and tpl_contact.y > 0) or (tpl_ball_proj.y > 0 and tpl_contact.y < 0):
                spr_ball.dbl_velocity_y = -tpl_ball_proj.y * const.BOUNCE_K_WALL * const.BOUNCE_K_ROBOT

            # Resolve collision - contact point is fudged, fudge travel dist accordingly (by using bot corner prev)
            dbl_exit_dist = distance(bot_corner_prev, spr_ball.rectDbl.center)
            dbl_contact_dist = dbl_contact_dist_sq ** .5
            spr_ball.rectDbl.centerx += tpl_contact.x * dbl_exit_dist / dbl_contact_dist
            spr_ball.rectDbl.centery += tpl_contact.y * dbl_exit_dist / dbl_contact_dist
            return
Esempio n. 11
0
 def _calc_ball_dist_sum(self):
     # Grumpy's goal is in the 0,0 corner, therefore higher distance is better for Grumpy team
     return sum(
         map(lambda x: distance((0, 0), x.rectDbl.center),
             self.lstPosBalls))