0
\$\begingroup\$

Basically, I'm doing a game for a school project and I am not really sure how to make a player point towards the mouse pointer in a pygame tab. also if anyone has ideas of how i could point a bullet towards the mouse and then fire in the direction of the mouse after i click fire (without continuously changing angles towards the mouse pointer) that would be awesome

Here is my code:

import pygame
import os


WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('First Person Shooter')

WHITE = (255,255,255)

FPS = 60
VEL = 5
BULLET_VEL = 7

CHARACTER_PLAYER_ONE = pygame.image.load(os.path.join('Python', 'player_one.png'))
CHARACTER_PLAYER_ONE = pygame.transform.rotate(pygame.transform.scale(CHARACTER_PLAYER_ONE, (55, 40)), 90)

def draw_window(one):
    WIN.fill(WHITE)
    WIN.blit(CHARACTER_PLAYER_ONE, (one.x, one.y))
    pygame.display.update() 


def one_handle_movement(keys_pressed, one):
        if keys_pressed[pygame.K_a] and one.x - VEL > -15: # left
            one.x -= VEL
        if keys_pressed[pygame.K_d] and one.x + VEL + one.width < 925: # right
            one.x += VEL
        if keys_pressed[pygame.K_w] and one.y - VEL > -15: # up
            one.y -= VEL
        if keys_pressed[pygame.K_s] and one.y + VEL + one.height < 500: # down
            one.y += VEL


def main():
    one = pygame.Rect(100, 300, 55, 40)

    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()
        


        keys_pressed = pygame.key.get_pressed()
        one_handle_movement(keys_pressed, one)
        draw_window(one)

    pygame.quit()


if __name__ == '__main__':                
    main()

I would really appreciate help if you are willing to provide it!

P.S. i didn't really define the bullets yet, but the player one sprite is the main thing im looking for at the moment

Much of this code is as shown in https://www.youtube.com/watch?v=jO6qQDNa2UY

-Luckee365-

\$\endgroup\$
2
  • \$\begingroup\$ first you have to get position of mouse and gun, and calculate distance (dx, dy) between mouse and gun and value dy/dy gives you tangle of angle - and this angle you can use to rotate bullet. SO it needs some math ;) Luckly PyGame.math.Vector should have functions to calculate distance and/or angle between two points. \$\endgroup\$
    – furas
    Feb 28, 2022 at 15:27
  • \$\begingroup\$ BTW: because one is a Rect() so instead of one.x + one.width. You can use one.right. You have also one.left, one.top, one.botton. one.center, one.centerx, one,centery, one.topleft, one.size, etc. \$\endgroup\$
    – furas
    Feb 28, 2022 at 16:48

1 Answer 1

0
\$\begingroup\$

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()
```
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .