How to constrain rotation to a given number of degrees in pygame?

My question is related to the answer to the question below.

rotation of the rectangle.

How can I constrain the rotation to the area marked in red like in this picture? I tried different ways but it was unsatisfactory. The code always keeps the poiter in a different area. my modified code is below.

import pygame, math, base64
pygame.init()
screen = pygame.display.set_mode((200, 200))

surf = pygame.image.load("D:\\PYTHON\\SoftwareDG\\Games\\Platform_Suvivor\\assets\\rg.png").convert_alpha()

def rot_center(image, angle):
    orig_rect = image.get_rect()
    rot_image = pygame.transform.rotate(image, angle)
    rot_rect = orig_rect.copy()
    rot_rect.center = rot_image.get_rect().center
    rot_image = rot_image.subsurface(rot_rect).copy()
    return rot_image

current_angle = 0

while True:
    if pygame.event.get(pygame.QUIT): break
    pygame.event.get()

    mouseX, mouseY = pygame.mouse.get_pos()
    rect = surf.get_rect(center=(92, 92))
    target_angle = math.degrees(math.atan2(mouseY - rect.centery, mouseX - rect.centerx))
    if target_angle < -120:
        target_angle = -120
    if target_angle > 120:
        target_angle = 120
    print target_angle
    if current_angle > target_angle:
        current_angle -= 0.03
    if current_angle < target_angle:
        current_angle += 0.03

    screen.fill((40, 140, 40))
    screen.blit(rot_center(surf, -current_angle), rect)
    pygame.display.update()

      

the pointer should remain in the red area

+1


source to share


2 answers


Are you looking for a commit function like this?

def clamp(value, min_, max_):
    """Clamp value to a range between min_ and max_."""
    return max(min_, min(value, max_))

      

In your case, you also need to check if current_angle is greater than or less than 0.

if current_angle <= 0:
    current_angle = clamp(current_angle, -180, -120)
elif current_angle > 0:
    current_angle = clamp(current_angle, 120, 180)

      



Refresh . Here's an example with vectors. I am using vectors to figure out which direction the sprite should be rotated in. Notice that the right is now 0 degrees, the left is 180 °, and it goes from 0 ° to 360 °.

And here are some interesting links that helped me figure out how to do it: http://docs.godotengine.org/en/stable/tutorials/matrices_and_transforms.html http://www.wildbunny.co.uk/blog/vector- maths-a-primer-for-games-programmers /

import math
import pygame


pygame.init()
screen = pygame.display.set_mode((300, 300))
font = pygame.font.Font(None, 24)
GRAY = pygame.Color('gray90')


def clamp(value, min_value, max_value):
    """Clamp value to a range between min_value and max_value."""
    return max(min_value, min(value, max_value))


def main():
    current_angle = 0
    clock = pygame.time.Clock()
    surf = pygame.Surface((80, 50), pygame.SRCALPHA)
    pygame.draw.polygon(surf, (40, 100, 200), ((0, 0), (80, 25), (0, 50)))
    orig_surf = surf
    rect = surf.get_rect(center=(150, 150))
    orig_direction = pygame.math.Vector2(0, 1)

    playing = True

    while playing:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                playing = False

        # Here I figure out if the target is closer in clock-
        # or counterclockwise direction. `orientation` is positive
        # if the target is closer in clockwise and negative
        # if it in counterclockwise direction.
        vec_to_target = pygame.math.Vector2(pygame.mouse.get_pos()) - rect.center
        direction = orig_direction.rotate(current_angle)
        orientation = vec_to_target.dot(direction)
        # I use orientation > 3 and < -3 instead of 0 to
        # avoid jittering when the target angle is reached.
        if orientation > 3:
            current_angle += 3
        elif orientation < -3:
            current_angle -= 3

        # You can use this modulo operation to keep the angle between
        # 0° and 360°, but this is not needed because of the clamp.
        # current_angle %= 360
        # Clamp the value to the desired range.
        current_angle = clamp(current_angle, 120, 240)

        surf = pygame.transform.rotate(orig_surf, -current_angle)
        rect = surf.get_rect(center=rect.center)

        # Draw
        screen.fill((40, 40, 40))
        screen.blit(surf, rect)
        txt = font.render('angle {:.1f}'.format(current_angle), True, GRAY)
        screen.blit(txt, (10, 10))
        txt = font.render('orientation {:.1f}'.format(orientation), True, GRAY)
        screen.blit(txt, (10, 25))

        pygame.display.update()
        clock.tick(30)


if __name__ == '__main__':
    main()
    pygame.quit()

      

+1


source


I was able to limit the rotation of the pistol to a limited area by simply adding a one line check just before the rotation. The code is far from perfect. When going from quadrant + to quadrant and vice versa, the gun rotates in the opposite direction to reach the other side. Additional checks before increasing the angle will correct the direction of rotation, but for now the problem is solved in the main way. The code is shown below.



import pygame, math, base64
pygame.init()
screen = pygame.display.set_mode((200, 200))

surf = pygame.image.load("put your image here").convert_alpha()

def rot_center(image, angle):
    orig_rect = image.get_rect()
    rot_image = pygame.transform.rotate(image, angle)
    rot_rect = orig_rect.copy()
    rot_rect.center = rot_image.get_rect().center
    rot_image = rot_image.subsurface(rot_rect).copy()
    return rot_image

current_angle = -180

clock = pygame.time.Clock()
while True:
    if pygame.event.get(pygame.QUIT): break
    pygame.event.get()

    mouseX, mouseY = pygame.mouse.get_pos()
    rect = surf.get_rect(center=(92, 92))
    target_angle = math.degrees(math.atan2(mouseY - rect.centery, mouseX - rect.centerx))

    # the new line is just below
    if 180 > target_angle > 120 or - 120 > target_angle > -179:
        print "ok", target_angle
        if current_angle > target_angle:
            current_angle -= 2
        if current_angle < target_angle:
            current_angle += 2

    screen.fill((40, 140, 40))
    screen.blit(rot_center(surf, -current_angle), rect)
    pygame.display.update()
    clock.tick(60)

      

0


source







All Articles