def find_target_position(origin_pos, initial_velocity, wanted_z=0):
    """
	Find and return target ball position with a specified initial velocity and position.
	
	:param pygame.Vector3 origin_pos: initial ball position in world coordinates
	:param pygame.Vector3 initial_velocity: initial ball velocity in world coordinates
	:param float wanted_z: specify at which z value target position will be found
	:return: target ball position
	:rtype pygame.Vector3:
	"""
    # z_t
    z_t = wanted_z - origin_pos.z

    # u vector : unit vector in XY plane from origin to target position
    u = Vector3(initial_velocity)
    u.z = 0
    u = u.normalize() if u.length_squared() != 0 else Vector3()

    # get final time t_t
    t_t = get_time_at_z(initial_velocity.z, origin_pos.z, wanted_z)

    # u_t
    u_t = t_t * initial_velocity.dot(u)

    return u_t * u + origin_pos + Vector3(0, 0, z_t)
    def shade(self, pos):
        L = Vector3(self.x * sin(t), self.y, self.z * cos(t))
        L = L.normalize()

        dt = 1e-6
        current_val = surface_distance(pos)

        x = Vector3(pos.x + dt, pos.y, pos.z)
        dx = surface_distance(x) - current_val
        y = Vector3(pos.x, pos.y + dt, pos.z)
        dy = surface_distance(y) - current_val
        z = Vector3(pos.x, pos.y, pos.z + dt)
        dz = surface_distance(z) - current_val
        # normal
        N = Vector3(
            (dx - pos.x) / dt,
            (dy - pos.y) / dt,
            (dz - pos.z) / dt,
        )
        if N.length() < 1e-9:
            return PIXELS[0]
        N = N.normalize()
        diffuse = L.x * N.x + L.y * N.y + L.z * N.z
        diffuse = (diffuse + 1) / 2 * len(PIXELS)
        return PIXELS[int(diffuse) % len(PIXELS)]
def test_world_to_pixel_coords(horizontal_camera, oblique_camera,
                               not_centered_camera):
    w, h = (100, 100)
    for cam in (horizontal_camera, oblique_camera, not_centered_camera):
        # center
        center_pt = Vector3(cam.focus_point)
        u, v = cam.world_to_pixel_coords(center_pt, (w, h))
        assert u == w / 2 or u == w / 2 - 1  # -1 because of imprecision due to continuous/discrete conversion
        assert v == h / 2 or v == h / 2 - 1  # same thing

        # point in 4 screen areas (top-left, top-right, bottom-left and bottom-right)
        tl_pt = Vector3(0, -1, 1) + cam.focus_point
        tr_pt = Vector3(0, 1, 1) + cam.focus_point
        bl_pt = Vector3(0, -1, -1) + cam.focus_point
        br_pt = Vector3(0, 1, -1) + cam.focus_point

        # test if points are in correct area
        u, v = cam.world_to_pixel_coords(tl_pt, (w, h))
        assert u < w / 2 and v < h / 2

        u, v = cam.world_to_pixel_coords(tr_pt, (w, h))
        assert u > w / 2 and v < h / 2

        u, v = cam.world_to_pixel_coords(bl_pt, (w, h))
        assert u < w / 2 and v > h / 2

        u, v = cam.world_to_pixel_coords(br_pt, (w, h))
        assert u > w / 2 and v > h / 2
Exemple #4
0
 def calculatePerspective(self, location: pygame.Vector3):
     translation = pygame.Vector2(self.getLocation().x + self.getWidth() / 2, self.getLocation().y + self.getHeight() / 2)
     #ray = Ray(self.getFocus(), location)
     location = location - self.getLocation()
     ray = Ray(pygame.Vector3(0, 0, -self.__focus_distance),
               pygame.Vector3(location.dot(self.getHorisontal()), location.dot(self.getVertical()), location.dot(self.getFacing())))
     return ray.projection(self.__focus_distance) + translation
def draw_sphere(center, radius, col=None):
    """
	Draw a filled sphere on camera screen.
	
	:param pygame.Vector3 center: center of sphere
	:param float radius: radius (world scale, not in pixel) of sphere
	:param tuple(int, int, int) col: drawing color. default is :var DBG_COLOR_SPHERE:
	:return: rect bounding the changed pixels
	:rtype pygame.Rect:
	"""
    display_manager = DisplayManager.get_instance()
    if col is None:
        col = DBG_COLOR_SPHERE

    # process r_px : radius in pixel
    camera = display_manager.camera
    surface = display_manager.debug_3d.image
    surface_size = surface.get_size()

    c_pos = Vector3(center)
    if SIZE_INDEPENDENT_FROM_Y_POS:
        c_pos.y = camera.position.y
    if SIZE_INDEPENDENT_FROM_Z_POS:
        c_pos.z = camera.position.z
    r_px = int((Vector2(
        camera.world_to_pixel_coords(c_pos, surface_size) - Vector2(
            camera.world_to_pixel_coords(c_pos + radius * Vector3(0, 1, 0),
                                         surface_size))).magnitude()))

    return draw.circle(surface, col,
                       camera.world_to_pixel_coords(center, surface_size),
                       r_px)
Exemple #6
0
 def update_physics(self, dt):
     self.previous_position = Vector3(self.position)
     if not self.will_be_served:
         self.add_velocity(Vector3(0, 0, -0.001 * dt * G))
         self.move_rel(0.001 * dt * self.velocity)
     else:
         self.velocity = Vector3()
    def _set_n_debug_3d_points(self, n):
        """
		Process n 3D-points in ball trajectory.

		:param int n: points count
		:return: n points in list
		:rtype list(Vector3):
		"""
        if self.origin_pos is None or self.target_pos is None or self.initial_velocity is None:
            self.debug_pts = []
        else:
            assert n > 1

            # u vector : unit vector in XY plane from origin to target position
            u = Vector3(self.initial_velocity)
            u.z = 0
            u = u.normalize() if u.length_squared() != 0 else Vector3(0, 0, 0)

            # get t_t : final time
            t_t = self.get_final_time()

            dt = t_t / (n - 1)
            self.debug_pts = []
            for i in range(n):
                t_i = i * dt
                u_i = t_i * self.initial_velocity.dot(u)
                z_i = -t_i**2 / 2 * G + t_i * self.initial_velocity.z
                self.debug_pts.append(
                    Vector3(u_i * u + self.origin_pos + Vector3(0, 0, z_i)))
Exemple #8
0
 def explode(self):
     explode_force = randint(10, 30)
     for i in range(300):
         r = (random() * 360) * math.pi / 180
         f = random() * explode_force + 1
         self.particles.append(
             Particle(self.screen, False, Vector3(self.firework.pos),
                      Vector3(math.sin(r) * f,
                              math.cos(r) * f, 0)))
Exemple #9
0
 def __init__(self,
              location: pygame.Vector3 = pygame.Vector3(0, 0, 0),
              facing: pygame.Vector3 = pygame.Vector3(1, 0, 0),
              vertical: pygame.Vector3 = pygame.Vector3(0, 1, 0),
              **kwargs):
     super().__init__(**kwargs)
     self.__centre: pygame.Vector3 = location
     self.__facing: pygame.Vector3 = facing.normalize()
     self.__vertical: pygame.Vector3 = vertical.normalize()
def test_world_to_cam_3d_coords(horizontal_camera, oblique_camera,
                                not_centered_camera):
    center_pt = Vector3(0, 0, 0)
    assert horizontal_camera.world_to_cam_3d_coords(center_pt) == Vector3(
        0, 0, -5)
    assert oblique_camera.world_to_cam_3d_coords(center_pt) == Vector3(
        0, 0, -5)

    assert not_centered_camera.world_to_cam_3d_coords(
        not_centered_camera.focus_point) == Vector3(0, 0, -5)
Exemple #11
0
    def __init__(self, screen, width, height, gravity):
        self.screen = screen
        self.width = width
        self.height = height
        self.gravity = gravity

        self.firework = Particle(screen, True,
                                 Vector3(randint(0, width), height, 0),
                                 Vector3(0, randint(-16, -10), 0))
        self.exploded = False
        self.particles = []
    def _rotate(vec, angle, axis):
        """Rotate vec around axis by the given angle in radians."""

        # We are using the Pygame's vectors here
        # because pyglm documentation is SHIT and
        # I can't find a way do do the same SIMPLE thing.

        vec = Vector3(vec)
        axis = Vector3(axis)
        vec.rotate_ip(angle * 180 / pi, axis)

        return vec3(vec)
Exemple #13
0
    def __init__(self, pos, WW, WH):
        gluPerspective(50, (WW / WH), 0.1, 50)
        glTranslatef(pos[0], pos[1], pos[2])
        glRotatef(0, 0, 0, 0)

        self.pos = Vector3(pos)

        self.rot = Vector3(0, 0, 0)
        self.rot_angle = 0

        self.velocity = Vector3(0, 0, 0)
        self.rot_velocity = Vector3(0, 0, 0)
Exemple #14
0
    def _create_gradient_steps(self, *colors):
        current = Vector3(colors[0][:3])
        self.gradient_steps = []
        distance = 0

        for color in colors[1:]:
            vector = Vector3(color)
            gradient_step = GradientStep(current, vector, distance)
            self.gradient_steps.append(gradient_step)
            distance += gradient_step.distance
            current = Vector3(vector)

        return distance
Exemple #15
0
 def __init__(self,
              screen,
              fire,
              pos=Vector3(0, 0, 0),
              vel=Vector3(0, 0, 0),
              col=white):
     self.screen = screen
     self.firework = fire
     self.pos = pos
     self.vel = vel
     self.acc = Vector3(0, 0, 0)
     self.col = col
     self.transparency = 255
def find_initial_velocity(origin_pos, target_pos, wanted_height):
    """
	Return initial velocity to apply to a ball to reach a target from an origin position and a specified height.
	
	Process initial velocity in world coordinates to apply on a ball. The specified height is taken in account for the
	ball trajectory. If target and origin y sign values are different, the wanted height will be on y = 0 (net
	position). Else, the wanted height will be on the middle of trajectory, or at apogee trajectory during a
	vertical throw.
	
	:param pygame.Vector3 origin_pos: origin position, the point where the ball will be thrown from
	:param pygame.Vector3 target_pos: the desired target position the ball will reach
	:param float wanted_height: height desired on net place, middle of trajectory or at apogee
	:return: velocity to apply to the ball
	:rtype pygame.Vector3:
	"""
    assert wanted_height > origin_pos.z
    assert wanted_height > target_pos.z

    if target_pos.x == origin_pos.x and target_pos.y == origin_pos.y:  # vertical throw
        zh = wanted_height - origin_pos.z
        vo_z = sqrt(2 * G * zh)
        return Vector3(0, 0, vo_z)
    else:
        # u vector : unit vector in XY plane from origin to target position
        u = Vector3(target_pos - origin_pos)
        u.z = 0
        u = u.normalize()

        # ut, zt : coordinates of target point in (u, z) ref
        to_vect = (target_pos - origin_pos)
        to_vect.z = 0

        ut = to_vect.length()
        zt = target_pos.z - origin_pos.z

        # uh, zh : coordinates of point above the net in (u, z) ref
        alpha = 0.5
        if origin_pos.y * target_pos.y < 0:  # if target and origin points are not in the same court side
            alpha = abs(origin_pos.y / (target_pos.y - origin_pos.y))
        uh = alpha * ut
        zh = wanted_height - origin_pos.z

        # process initial velocity to apply in (u, z) ref : vo_u, vo_z
        # not trivial equations, from math and physics resolutions
        a = (ut / uh * zh - zt)
        c = G * ut / 2 * (uh - ut)
        delta = -4 * a * c
        vo_u = sqrt(delta) / (2 * a)
        vo_z = zh * (vo_u / uh) + uh / vo_u * G / 2

        return Vector3(vo_u * u + Vector3(0, 0, vo_z))
    def __init__(self,
                 origin_pos=None,
                 target_pos=None,
                 initial_velocity=None):
        self.origin_pos = Vector3(
            origin_pos) if origin_pos is not None else None
        self.target_pos = Vector3(
            target_pos) if target_pos is not None else None
        self.initial_velocity = Vector3(
            initial_velocity) if initial_velocity is not None else None

        self.t0 = None
        self.debug_pts = None

        self._create()
Exemple #18
0
 def __init__(self):
     #self.modelcanon = pygame.image.load('Model/canon.png')
     self.vitesse = 0
     self.position = Vector2(400, 450)
     self.direction = Vector2()
     self.couleur = Vector3()
     self.pointdevie = 3
Exemple #19
0
    def __init__(self, w, h, net_z1, net_z2):
        self.w = w
        self.h = h
        self.net_z1 = net_z1
        self.net_z2 = net_z2
        self.collider = AABBCollider(Vector3(0, 0, (net_z1 + net_z2) / 2),
                                     (h, 0, net_z2 - net_z1))

        # sprite
        self.rects = [pg.Rect(0, 0, 0, 0) for _ in range(10)]
Exemple #20
0
def test_move_time(character):
    dt = 10

    origin_pos = Vector3()
    character.position = Vector3(origin_pos)

    n = 100
    # move along +y axis for n frames
    for _ in range(n):
        character.move(Vector3(0, 1, 0), dt, free_displacement=True)
    assert n * dt / 1000 == pytest.approx(
        character.get_time_to_run_to(origin_pos), 0.01)

    # move along +x +y axis for n frames
    for _ in range(n):
        character.move(Vector3(0.7071, 0.7071, 0), dt, free_displacement=True)

    assert 2 * n * dt / 1000 == pytest.approx(
        character.get_time_to_run_to(origin_pos), 0.01)
Exemple #21
0
    def draw(self, surface, vertical):
        vector = Vector3(self.color)
        step = self.start_distance
        for i in range(self.distance):
            if vertical:
                surface.set_at((0, i + step), Color(*map(int, vector)))
            else:
                surface.set_at((i + step, 0), Color(*map(int, vector)))

            vector += self.step
            self.minmax_color_vector(vector)
Exemple #22
0
def perspective_projection(pt):
    # Assuming camera has orientation along -z axis to easy calculations.
    # Thus the display surface is perpendicular to z-axis
    # display_surface_distance is the distance between camera and the display surface
    # https://en.wikipedia.org/wiki/3D_projection#Perspective_projection
    camera = Vector3(0, 0, 6)
    display_surface_distance = 0.2
    projected_point = (pt - camera) * \
        display_surface_distance / (camera.z - pt.z)
    # Return the point after normalizing
    return projected_point * camera.z / display_surface_distance
Exemple #23
0
    def draw_debug(self):
        prev_rect = self.rect
        prev_rect_shadow = self.rect_shadow

        self.rect = debug3D_utils.draw_horizontal_ellipse(
            Vector3(self.position[0], self.position[1], 0), self.radius)
        self.rect_shadow = self.collider.draw_debug()

        return [
            prev_rect.union(self.rect),
            prev_rect_shadow.union(self.rect_shadow)
        ]
Exemple #24
0
    def __init__(self, position=None, radius=0.5, sprite_groups=[]):
        pg.sprite.DirtySprite.__init__(self, *sprite_groups)
        self.radius = radius
        self.acceleration = Vector3()
        self.velocity = Vector3()
        self._position = Vector3(
            position) if position is not None else Vector3()
        self.previous_position = Vector3(self._position)
        self.collider = SphereCollider(position, radius)

        self.is_colliding_ground = False
        self.is_colliding_net = False
        self.is_colliding_character = False

        self.will_be_served = False

        # sprite
        self.rect_shadow = pg.Rect(0, 0, 0, 0)
        self.rect = pg.Rect(0, 0, 0, 0)

        # game rules
        self._current_team_touches = []
def draw_horizontal_ellipse(center, radius):
    """
	Draw a filled ellipse and a unfilled bound trapeze in XY 3D plane on camera screen.
	
	:param pygame.Vector3 center: center of ellipse
	:param float radius: radius (world scale, not in pixel) of ellipse
	:return: rect bounding the changed pixels
	:rtype pygame.Rect:
	"""
    display_manager = DisplayManager.get_instance()
    camera = display_manager.camera
    surface = display_manager.debug_3d.image
    surface_size = surface.get_size()

    # corners of shadow (trapeze)
    t_l = camera.world_to_pixel_coords(
        Vector3(center) + (-radius, -radius, 0), surface_size)
    t_r = camera.world_to_pixel_coords(
        Vector3(center) + (-radius, radius, 0), surface_size)
    b_l = camera.world_to_pixel_coords(
        Vector3(center) + (radius, -radius, 0), surface_size)
    b_r = camera.world_to_pixel_coords(
        Vector3(center) + (radius, radius, 0), surface_size)

    # approximate rect
    r_pos = [int(0.5 * (t_l[0] + b_l[0])), t_l[1]]
    r_w = int(0.5 * (t_r[0] + b_r[0]) - r_pos[0])
    r_h = b_r[1] - r_pos[1]
    if r_h < 0:
        r_pos[1] += r_h
        r_h = -r_h
    rect = Rect(r_pos, (r_w, r_h))

    if r_w >= r_h:
        draw.ellipse(surface, DBG_COLOR_HOR_ELLIPSE, rect)

    # ellipse is in polygon rect, not need to return both rects
    return draw.polygon(surface, DBG_COLOR_SHADOW_HOR_ELLIPSE_TRAPEZE,
                        [t_l, t_r, b_r, b_l], 1)
Exemple #26
0
def test_move_rel(character):
    assert character.position == Vector3()
    assert character.collider.center == Vector3(
    ) + character.collider_relative_position

    # move
    character.move_rel(Vector3(0, 1, 0.1), free_displacement=True)
    assert character.position == Vector3(0, 1, 0.1)
    assert character.collider.center == Vector3(
        0, 1, 0.1) + character.collider_relative_position

    # move
    character.move_rel(Vector3(-0.2, 0, 0), free_displacement=True)
    assert character.position == Vector3(-0.2, 1, 0.1)
    assert character.collider.center == Vector3(
        -0.2, 1, 0.1) + character.collider_relative_position
Exemple #27
0
    def blend(self, *colors):
        if len(colors) < 2:
            return False

        vectors = []
        for color in colors:
            vectors.append(Vector3(color[:3]))

        distance = self._create_gradient_steps(*vectors)
        self.surface = self._create_surface(distance)
        for gstep in self.gradient_steps:
            gstep.draw(self.surface, self.vertical)

        return True
def run():
    global SPHERE_RADIUS
    global t
    pygame.font.init()
    clock = pygame.time.Clock()
    font = pygame.font.Font(None, 30)
    screen = pygame.display.set_mode((800, 800))
    buffer = pygame.Surface((80, 40))
    rect = buffer.get_rect()
    position = Vector3(0, 0, -2)
    step = .005
    shader = Shader()
    running = True
    while running:
        elapsed = clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_ESCAPE, pygame.K_q):
                    pygame.event.post(pygame.event.Event(pygame.QUIT))
                elif event.key == pygame.K_LEFT:
                    SPHERE_RADIUS += step
                    print(SPHERE_RADIUS)
                elif event.key == pygame.K_RIGHT:
                    SPHERE_RADIUS -= step
                    print(SPHERE_RADIUS)
        #
        pressed = pygame.key.get_pressed()
        if pressed[pygame.K_UP]:
            position.z += step
            print(position)
        elif pressed[pygame.K_DOWN]:
            position.z -= step
            print(position)
        elif pressed[pygame.K_a]:
            shader.x += 1
            print(shader.x)
        elif pressed[pygame.K_z]:
            shader.x -= 1
            print(shader.x)
        #
        buffer.fill((0, 0, 0))
        draw(rect, buffer, position, shader)
        pygame.transform.scale(buffer, screen.get_rect().size, screen)
        img = font.render(f'{t:.04f}', True, (200, 200, 200))
        screen.blit(img, (0, 0))
        pygame.display.flip()
        #
        t = (t + elapsed / 1000 * 1) % tau
Exemple #29
0
def test_change_collider(character):
    char_original_pos = Vector3(character.position)
    char_original_collider_rel_pos = Vector3(
        character.collider_relative_position)
    coll_original_size = Vector3(character.collider.size3)
    coll_original_center = Vector3(character.collider.center)

    # set default collider
    character.set_default_collider()
    assert character.collider.size3 == coll_original_size
    assert character.collider.center == coll_original_center
    assert character.position == char_original_pos
    assert character.collider_relative_position == char_original_collider_rel_pos

    # change and reset collider
    direction = Vector3(0, 1, 0)
    character.set_diving_collider(direction)
    character.set_default_collider()
    assert character.collider.size3 == coll_original_size
    assert character.collider.center == coll_original_center
    assert character.position == char_original_pos
    assert character.collider_relative_position == char_original_collider_rel_pos

    # move, change collider, move again and reset collider
    direction = Vector3(0, 1, 0)

    character.move(Vector3(1, 0, 0), 1000, free_displacement=True)
    character.set_diving_collider(direction)
    character.move(Vector3(0, 1, 0), 500, free_displacement=True)
    character.set_default_collider()
    assert character.collider.size3 == coll_original_size
    assert character.collider.center == coll_original_center + character.max_velocity * Vector3(
        1, 0.5, 0)
    assert character.position == char_original_pos + character.max_velocity * Vector3(
        1, 0.5, 0)
    assert character.collider_relative_position == char_original_collider_rel_pos
def draw(rect, surface, position, shader):
    for y in range(rect.height):
        for x in range(rect.width):
            pos = position
            target = Vector3(x / rect.width - .5, (y / rect.height - .5) *
                             (rect.height / rect.width) * 1.5, -1.5)
            ray = target - pos
            ray.normalize()
            pixel = PIXELS[0]
            max_ = 9_999
            for _ in range(15_000):
                if (fabs(pos.x) > max_ or fabs(pos.y) > max_
                        or fabs(pos.z) > max_):
                    break
                dist = surface_distance(pos)
                if dist < 1e-1:
                    pixel = shader.shade(pos)
                    break
                pos = pos + ray * dist
            surface.set_at((x, y), pixel)