1

Hi i am making a game about shooting enemy's with a turret and i want to slowly turn the turret of the player so i use this piece of code:

    #if the angle is larger than the playerangle
    if getangle() > playerangle:
        playerangle += 1
    #if the angle is smaller than the playerangele
    elif getangle() < playerangle:
        playerangle -= 1
    #draw the player
    player(playerangle)

But somehow the turret isn't always choosing the shortest path: the angle goes from 0 to -269 it turns the wrong way around. How do i solve this problem?

if you need the code of the functions getangle() and player() here you go:

def player(angle):
    pos_org = [width/2, height/2]
    image_rotated = pygame.transform.rotate(playericon, -angle)
    pos_new = (pos_org[0] - image_rotated.get_rect().width / 2, pos_org[1] - image_rotated.get_rect().height / 2)
    screen.blit(image_rotated, pos_new)
def getangle():
    x = width/2
    y = height/2
    mousex, mousey = pygame.mouse.get_pos()
    angle = math.atan2((y-mousey), (x-mousex))*180/math.pi
    return int(angle - 90)
Glitch__
  • 304
  • 1
  • 10

1 Answers1

2

math.atan2(y, x) returns an angle in range -pi, pi. Probably the issue is cause by the transition form pi to -pi.

You know the vector from the center to the mouse

def mouse_direction():
    x, y = width/2, height/2
    mousex, mousey = pygame.mouse.get_pos()
    dx, dy = mousex - x, mousey - y
    return dx, dy

And you know the current direction of the player:

player_dir = math.cos(math.radians(player_angle)), math.sin(math.radians(player_angle)) 

Compute the normal (Perpendicular) direction to the current target direction

direction = mouse_direction()
normal_dir = -direction[1], direction[0] 

And compute the Dot product between the current direction and the normal to the target direction:

dot_p_n = player_dir[0]*normal_dir[0] + player_dir[1]*normal_dir[1]

Since the dot product is proportional to the cosine of the angle between the 2 vectors, the angle can be changed dependent of the sign of dot_p_n:

player_angle += -1 if dot_p_n > 0 else 1

See the example:

enter image description here

import pygame
import math

def rotate_triangle(center, scale, mouse_pos):

    dx = mouse_pos[0] - center[0]
    dy = mouse_pos[1] - center[1]
    len = math.sqrt(dx*dx + dy*dy)
    dx, dy = (dx*scale/len, dy*scale/len) if len > 0 else (1, 0)

    pts = [(-0.5, -0.866), (-0.5, 0.866), (4.0, 0.0)]
    pts = [(center[0] + p[0]*dx + p[1]*dy, center[1] + p[0]*dy - p[1]*dx) for p in pts]
    return pts

disp = pygame.display.set_mode((200,200))
width, height = disp.get_size()
clock = pygame.time.Clock()

def mouse_direction():
    x, y = width/2, height/2
    mousex, mousey = pygame.mouse.get_pos()
    dx, dy = mousex - x, mousey - y
    return dx, dy


player_angle = 0

run = True
while run:
    clock.tick(60)

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

    player_dir = math.cos(math.radians(player_angle)), math.sin(math.radians(player_angle)) 

    direction = mouse_direction()
    normal_dir = -direction[1], direction[0] 

    dot_p_n = player_dir[0]*normal_dir[0] + player_dir[1]*normal_dir[1]
    player_angle += -1 if dot_p_n > 0 else 1

    target_pos = width/2 + math.cos(math.radians(player_angle)), height/2 + math.sin(math.radians(player_angle)) 
    points = rotate_triangle((100, 100), 10, target_pos)

    pygame.Surface.fill(disp, (255,255,255))
    pygame.draw.polygon(disp, (0,0,0), points)
    pygame.display.update()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174