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 but was unsuccesfull. The code always keeps the poiter in the other area.
my modified code 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()
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()
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)