Beispiel #1
0
    def circle_line(body, line, screen=None):
        relative_position = body.position - line.p1

        projected_vector = line.direction * relative_position.dot(
            line.direction)
        closest_point = line.p1 + projected_vector

        cx, cy = closest_point
        lx1, ly1 = line.p1
        lx2, ly2 = line.p2

        # Make sure that closest point lies on the line
        if lx1 - lx2 > 0: cx = max(min(cx, lx1), lx2)
        else: cx = min(max(cx, lx1), lx2)
        if ly1 - ly2 > 0: cy = max(min(cy, ly1), ly2)
        else: cy = min(max(cy, ly1), ly2)
        closest_point[:] = cx, cy

        distance = V.magnitude(body.position - closest_point)

        collided = distance < body.radius
        if collided:

            # Resolve interpenetration
            orthogonal_vector = relative_position - projected_vector
            penetration = body.radius - V.magnitude(orthogonal_vector)
            disposition = V.normalize(orthogonal_vector) * penetration
            body.position += disposition

            # Resolve Velocity
            velocity = body.get_velocity() - line.normal * body.get_velocity(
            ).dot(line.normal) * 2 * body.wall_restitution
            body.set_velocity(velocity)

        return collided
Beispiel #2
0
    def circle_circle(bodies, resolve=True):
        restitution = max(bodies[0].body_restitution,
                          bodies[1].body_restitution)

        position_0 = bodies[0].position
        position_1 = bodies[1].position
        total_radius = bodies[0].radius + bodies[1].radius

        direction = position_0 - position_1
        distance = V.magnitude(direction)
        if distance <= 0.0 or distance >= (total_radius):
            return False

        normal = V.normalize(direction)
        penetration = total_radius - distance

        if resolve:
            Collision._resolve_circle_circle_velocity(bodies, normal,
                                                      restitution)
            Collision._resolve_circle_circle_interpenetration(
                bodies, normal, penetration)

        return True
Beispiel #3
0
 def set_velocity(self, velocity):
     magnitude = V.magnitude(velocity)
     # Limit velocity to prevent the body from escaping its borders
     if magnitude > self.maximum_speed:
         velocity *= self.maximum_speed / magnitude
     self._velocity[:] = velocity
Beispiel #4
0
    def move(self):

        px, py = self.mallet.position
        vx, vy = self.mallet.get_velocity()

        puck = self.puck
        puck_px, puck_py = self.puck.position
        puck_vx, puck_vy = self.puck.get_velocity()

        if self.mode is 'top':
            goal_px, goal_py = (self.dim.center[0], self.dim.rink_top + 55)
        elif self.mode == 'bottom':
            goal_px, goal_py = (self.dim.center[0], self.dim.rink_bottom - 55)

        if self.mode is 'top':
            reachable = self.dim.rink_top <= puck_py <= self.dim.center[1]
        elif self.mode == 'bottom':
            reachable = self.dim.center[1] <= puck_py <= self.dim.rink_bottom

        x, y = 0, 0
        if not reachable:
            if self.mode is 'top':
                target_px, target_py = (self.dim.center[0],
                                        self.dim.rink_top + 80)
            elif self.mode == 'bottom':
                target_px, target_py = (self.dim.center[0],
                                        self.dim.rink_bottom - 80)

            def defend_goal(goal, p):
                diff = goal - p
                if abs(diff) < 40: return 0
                elif diff > 0: return 1
                else: return -1

            x = defend_goal(target_px, px)
            y = defend_goal(target_py, py)
            # print('{:15} {:4d} {:4d}'.format('not reachable', x, y))

        else:
            if puck_vy <= 0:
                if puck_px < px: x = -1
                if puck_px > px: x = 1
                if puck_py < py: y = -1
                if puck_py > py: y = 1
#                print('{:15} {:4d} {:4d}'.format('stationary', x, y))
            else:
                too_fast = V.magnitude(
                    puck.get_velocity()) > 0.8 * P.puck_maximum_speed
                if too_fast:

                    def save_goal(goal, p):
                        diff = goal - p
                        if abs(diff) < 5: return 0
                        elif diff > 0: return 1
                        else: return -1

                    x = save_goal(goal_px, px)
                    y = save_goal(goal_py, py)
#                    print('{:15} {:4d} {:4d}'.format('too fast', x, y))
                else:
                    if puck_px < px: x = -1
                    if puck_px > px: x = 1
                    if puck_py < py: y = -1
                    if puck_py > py: y = 1
#                    print('{:15} {:4d} {:4d}'.format('slow', x, y))

        self._force[:] = x, y
        return self._force
Beispiel #5
0
    def step(self,
             robot_action=None,
             human_action=None,
             debug=False,
             use_object=default_use_object,
             n_steps=4):

        dt = np.random.ranf() + 1  # dt is randomly in interval [1, 2)

        if robot_action is not None:
            if not isinstance(robot_action, np.ndarray):
                raise Exception('Action is supposed to be a numpy array')
            elif robot_action.shape[0] != 2:
                raise Exception(
                    'Action array can only have 2 values (x and y)')
            elif robot_action.min() < -1 or robot_action.max() > 1:
                raise Exception(
                    'Values of x and y have to be in range [-1, 1]')

        if human_action is not None:
            if not isinstance(human_action, np.ndarray):
                raise Exception(
                    'Adversarial action is supposed to be a numpy array')
            elif human_action.shape[0] != 2:
                raise Exception(
                    'Adversarial action array can only have 2 values (x and y)'
                )
            elif human_action.min() < -1 or human_action.max() > 1:
                raise Exception(
                    'Adversarial values of x and y have to be in range [-1, 1]'
                )

        # Compute AI moves
        if robot_action is None:
            if use_object['puck']:
                robot_action = self.bottom_ai.move()
            else:
                robot_action = [0, 0]
        if human_action is None:
            if use_object['arm'] and use_object['top_mallet']:
                human_action = self.top_ai.move()
            elif not use_object['puck']:
                human_action = [0, 0]
            else:
                human_action = [0, 0]

        # Update forces
        self.top_ai_force.set_force(human_action)
        self.bottom_ai_force.set_force(robot_action)

        for _ in range(n_steps):

            # Clear forces from last frame
            for body in self.bodies:
                body.clear_accumulators()
            self.forces.update_forces()

            # Move bodies
            for body in self.bodies:
                body.integrate(dt)

            # Check collisions between all possible pairs of bodies

            if use_object['arm'] or use_object['top_mallet']:
                Collision.circle_circle([self.puck, self.top_mallet])
            Collision.circle_circle([self.top_mallet, self.bottom_mallet])

            if use_object['puck']:
                puck_was_hit = Collision.circle_circle(
                    [self.puck, self.bottom_mallet])
            else:
                puck_was_hit = False

            in_the_target = Collision.circle_circle(
                [self.bottom_mallet, self.bottom_target], resolve=False)

            # Make sure all bodies are within their borders
            collided = [False, False, False]
            for i, body in enumerate(self.bodies):
                for border in body.borders:
                    if (Collision.circle_line(body, border)):
                        collided[i] = True
            hit_the_border = collided[2]

            puck_is_at_the_bottom = self.puck.position[1] > self.dim.center[1]

            distance_decreased = False
            if puck_is_at_the_bottom:
                distance = V.magnitude(self.puck.position -
                                       self.bottom_mallet.position)
                distance_decreased = distance < self.distance
                self.distance = distance
            else:
                self.distance = P.max_distance

            scored = self.score.update(self.puck)
            if scored is not None:
                return self.reset(scored, puck_was_hit, puck_is_at_the_bottom,
                                  distance_decreased, hit_the_border)

            self._render(debug, use_object)

        return GameInfo(self.cropped_frame, robot_action, human_action, scored,
                        puck_was_hit, puck_is_at_the_bottom,
                        distance_decreased, hit_the_border, in_the_target)