Skip to content Skip to sidebar Skip to footer

How To Restrict Rotation To A Set Amount Of Degrees In Pygame?

My question is related to the answer of the question below. rotating a rectangle. How do i restrict the rotation to the area marked in red as in this picture? I tried various ways

Solution 1:

Are you looking for a clamp 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 have to check if the current_angle is greater 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)

Update: Here's the example with vectors. I use the vectors to figure out in which direction the sprite needs to be rotated. Note that right is now 0 degrees, left is 180° and it goes from 0° to 360°.

And here are some interesting links that helped me to learn how to do this: 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's 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()

Solution 2:

I managed to restrict the rotation of the gun to a limited area by just adding a one line check just before rotation. The code is far from perfect. When crossing from the + quadrant to the - quadrant and vice versa, the gun rotates in the opposite direction to get to the other side. More checks before incrementing the angle will correct the direction of rotation but for now the problem is solved in a basic way. The code is given 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)

Post a Comment for "How To Restrict Rotation To A Set Amount Of Degrees In Pygame?"