Math: tan(angle) = dy/dx so angle = arctangle(dy/dx)
And as dx, dy you can use differnce between mouse position and gun/player position.
Get positions for mouse and gun/player.
mouse_x, mouse_y = pygame.mouse.get_pos() player_x, player_y = player_rect.center
Calculate distance (dx, dy) between mouse and gun/player
dx = mouse_x - player_x dy = mouse_y - player_y
Now dy/dx should give tangle or angle so I can use arctangle to get angle (in radians).
angle_radians = math.atan2(dy, dx) angle = math.degrees(angle_radians)
And now rotate image with -angle (to rotate in correct direction).
player_image = pygame.transform.rotate(original_player_image, angle).convert_alpha()
To get better quality of rotated image you should always use original image.
You also have to use convert_alpha() to get colors in RGBA with transparent background.
And new Image needs new Rect with position from previous Rect.
player_rect = player_image.get_rect(centerx=player_x, centery=player_y)
Full working code. It rotates player to mouse position (even when it moves).
I used set_caption to display positions and angle in window's title.
import pygame import os import math # --- constants --- # PEP8: `UPPER_CASE_NAMES` for constants WIDTH, HEIGHT = 900, 500 WHITE = (255, 255, 255) RED = (255, 0, 0) FPS = 60 VEL = 5 BULLET_VEL = 7 # --- main --- # PEP8: `lower_case_names` for variables pygame.init() WIN = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption('First Person Shooter') #CHARACTER_PLAYER_ONE = pygame.image.load(os.path.join('Python', 'player_one.png')) original_player_image = pygame.surface.Surface((100, 100)).convert_alpha() original_player_image.fill((255,0,0,255)) original_player_image = pygame.transform.rotate(pygame.transform.scale(original_player_image, (55, 40)), 90) player_image = original_player_image.copy() player_rect = player_image.get_rect(centerx=100, centery=300) def draw_window(): WIN.fill(WHITE) WIN.blit(player_image, player_rect) pygame.display.update() def one_handle_movement(keys_pressed, one): if keys_pressed[pygame.K_a] and one.left - VEL > -15: # left one.x -= VEL if keys_pressed[pygame.K_d] and one.right + VEL < 925: # right one.x += VEL if keys_pressed[pygame.K_w] and one.top - VEL > -15: # up one.y -= VEL if keys_pressed[pygame.K_s] and one.bottom + VEL < 500: # down one.y += VEL def main(): global player_image global player_rect bullets = [] clock = pygame.time.Clock() run = True while run: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: bullet = pygame.Rect() # get positions mouse_x, mouse_y = pygame.mouse.get_pos() player_x, player_y = player_rect.center # get angle dx = mouse_x - player_x dy = mouse_y - player_y angle = math.degrees(math.atan2(dy, dx)) pygame.display.set_caption(f"player: {player_x}, {player_y} | mouse: {mouse_x}, {mouse_y} | angle: {angle}") # rotate player_image = pygame.transform.rotate(original_player_image, -angle).convert_alpha() # assign original center to new rectagle player_rect = player_image.get_rect(centerx=player_x, centery=player_y) # --- keys_pressed = pygame.key.get_pressed() one_handle_movement(keys_pressed, player_rect) draw_window() pygame.quit() if __name__ == '__main__': main()
EDIT:
Pygame has pygame.math.Vector2.angle_to() to calculate angle (in degrees) between two verctors (points) but for some reason I got wrong results and couldn't find mistake.
mouse = pygame.mouse.get_pos() player = player_rect.center angle = pygame.math.Vector2(player).angle_to(mouse)
BTW: today pygame doc is not accessible so I used link to its copy on archive.org.
EDIT:
This gives correct angle
mouse = pygame.mouse.get_pos() player = player_rect.center dist = pygame.math.Vector2(mouse) - pygame.math.Vector2(player) angle = pygame.math.Vector2().angle_to(dist)
def main(): global player_image global player_rect bullets = [] clock = pygame.time.Clock() run = True while run: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: bullet = pygame.Rect() # get positions mouse = mouse_x, mouse_y = pygame.mouse.get_pos() player = player_x, player_y = player_rect.center # get angle wrong_angle = pygame.math.Vector2(mouse).angle_to(player) # gives results different then I expect dist = pygame.math.Vector2(mouse) - pygame.math.Vector2(player) angle = pygame.math.Vector2().angle_to(dist) # gives results different then I expect pygame.display.set_caption(f"player: {player_x}, {player_y} | mouse: {mouse_x}, {mouse_y} | angle: {angle} | wrong: {wrong_angle}") # rotate player_image = pygame.transform.rotate(original_player_image, -angle).convert_alpha() # assign original center to new rectagle player_rect = player_image.get_rect(centerx=player_x, centery=player_y) # --- keys_pressed = pygame.key.get_pressed() one_handle_movement(keys_pressed, player_rect) draw_window() pygame.quit() ```
mouseandgun, and calculate distance (dx, dy) betweenmouseandgunand valuedy/dygives youtangle of angle- and thisangleyou can use to rotatebullet. SO it needs somemath;) LucklyPyGame.math.Vectorshould have functions to calculatedistanceand/oranglebetween two points. \$\endgroup\$oneis aRect()so instead ofone.x + one.width. You can useone.right. You have alsoone.left,one.top,one.botton.one.center,one.centerx,one,centery,one.topleft,one.size, etc. \$\endgroup\$