Search code examples
pythonmathpygamegame-physicsangle

Pygame - Python - 360-degree angle on a cube, cursor / pointer / mouse orientation


I am trying to solve this problem of the angle, I noticed that there are two 0,0 in the coordinates, maybe that is what is preventing the cube from making a 360 degree turn, follows the video and the code.

Can someone help me?

video here

import pygame
import sys
import os
import math

def main():
    pygame.init()

    clock = pygame.time.Clock()
    screen = pygame.display.set_mode([1000, 500])
    pygame.display.set_caption('Example 1')

    player = pygame.image.load(os.path.join('img', 'rect.png')).convert_alpha() #path to cube ./img/rect.png

    pygame.font.init()

    font = pygame.font.get_default_font()
    font_angle = pygame.font.SysFont(font, 44, True)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()


        clock.tick(60)
        screen.fill((255, 255, 255)) #screen background color

        player_rect = player.get_rect() #player rect (for center position)

        mouse_x, mouse_y = pygame.mouse.get_pos() #mouse position (x, y)

        #to define angle - start
        hypo = math.sqrt(math.pow(mouse_x - (player_rect[0] + player_rect.centerx), 2) +
                         math.pow(mouse_y - (player_rect[1] + player_rect.centery), 2))

        cos = (mouse_x - (player_rect[0] + player_rect.centerx)) / hypo
        sin = (mouse_y - (player_rect[1] + player_rect.centery)) / hypo

        angle = (180 / math.pi) * - math.atan2(sin, cos)
        #end

        newplayer = pygame.transform.rotate(player, angle) #rotate cube


        screen.blit(newplayer, [300, 100]) #show cube in screen

        text = font_angle.render(str("%.2f" % angle), 1, (255, 0, 0)) #show angle in mouse position

        screen.blit(text, ((mouse_x+20), mouse_y)) #show text

        pygame.display.update() #update frames

main()

Solution

  • You can just subtract the player_rect.centerx position from the mouse_x position (the same for y) and pass it to math.atan2:

    dist_x = mouse_x - player_rect.centerx
    dist_y = mouse_y - player_rect.centery
    angle = -math.degrees(math.atan2(dist_y, dist_x))
    

    Create the rect before the while loop starts and pass the desired center coordinates. Use get_rect to create a new rect after the image is rotated and pass the center coords of the previous rect to keep it centered. And blit the image at the player_rect (that means at its topleft coordinates).

    import pygame
    import sys
    import os
    import math
    
    
    def main():
        pygame.init()
        clock = pygame.time.Clock()
        screen = pygame.display.set_mode([1000, 500])
    
        # player = pygame.image.load(os.path.join('img', 'rect.png')).convert_alpha() #path to cube ./img/rect.png
        player = pygame.Surface((50, 30), pygame.SRCALPHA)
        pygame.draw.polygon(player, (100, 200, 255), [(0, 0), (50, 15), (0, 30)])
        player_rect = player.get_rect(center=(500, 250)) # player rect (for center position)
    
        font = pygame.font.get_default_font()
        font_angle = pygame.font.SysFont(font, 44, True)
    
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
    
            clock.tick(60)
            screen.fill((255, 255, 255))
            mouse_x, mouse_y = pygame.mouse.get_pos()
            dist_x = mouse_x - player_rect.centerx
            dist_y = mouse_y - player_rect.centery
            angle = -math.degrees(math.atan2(dist_y, dist_x))
    
            newplayer = pygame.transform.rotate(player, angle)
            # Create a new rect and pass the center of the old rect.
            player_rect = newplayer.get_rect(center=player_rect.center)
    
            screen.blit(newplayer, player_rect) # Blit it at the player_rect.
            text = font_angle.render(str("%.2f" % angle), 1, (255, 0, 0))
            screen.blit(text, ((mouse_x+20), mouse_y))
            pygame.display.update()
    
    main()