pygame 2 dimensional movement of an enemy towards the player, how to calculate x and y velocity?

Solution 1:

Compute the vector from the the enemy position to the the player position:

dx = player_x - enemy_x
dy = player_y - enemy_y

Compute the length of the vector (Euclidean distance):

dist = math.sqrt(dx*dx + dy*dy)

or

dist = math.hypot(dx, dy)

Normalize the vector (Unit vector). A normalized vector has a length of 1:

if dist > 0:
    dx /= dist
    dy /= dist

Move the enemy a certain distance in the direction of the vector. Make sure the moving distance is no greater than the remaining distance of the enemy to the player:

move_dist = min(enemy_vel, dist)

enemy_x += move_dist * dx
enemy_y += move_dist * dy 

For a more sophisticated solution see How to make smooth movement in pygame

See also Follow target or mouse


Minimal example:

import pygame, math

pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
player_x, player_y, player_vel = 100, 100, 5
enemy_x, enemy_y, enemy_vel = 300, 300, 3

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False          
        
    keys = pygame.key.get_pressed()
    player_x = max(10, min(390, player_x + player_vel * (keys[pygame.K_d] - keys[pygame.K_a])))
    player_y = max(10, min(390, player_y + player_vel * (keys[pygame.K_s] - keys[pygame.K_w])))

    dx = player_x - enemy_x
    dy = player_y - enemy_y
    dist = math.hypot(dx, dy)
    if dist > 0:
        enemy_x += min(enemy_vel, dist) * dx / dist
        enemy_y += min(enemy_vel, dist) * dy / dist

    window.fill(0)
    pygame.draw.circle(window, (0, 128, 255), (player_x, player_y), 10)
    pygame.draw.circle(window, (255, 32, 32), (enemy_x, enemy_y), 10)
    pygame.display.flip()

pygame.quit()
exit()

For your particular code, the calculate_enemy_movement function might look like this:

def calculate_enemy_movement(enemy_blob):
    dx = player.player_rect.x - enemy_blob.x
    dy = player.player_rect.y - enemy_blob.y
    dist = math.hypot(dx, dy)
    if dist > 0:
        move_x = min(enemy_blob.speed, dist) * dx / dist
        move_y = min(enemy_blob.speed, dist) * dy / dist
        return move_x, move_y
    return 0, 0
move_x, move_y = calculate_enemy_movement(enemy_blob)
enemy_blob.x += move_x
enemy_blob.y += move_y