“I’m a programmer. I like programming. And the best way I’ve found to have a positive impact on code is to write it.”
Robert C. Martin, Clean Architecture
Related Stack Overflow questions:
How can you rotate the sprite and shoot the bullets towards the mouse position?
📁 Minimal example - Rotate player and shoot bullet towards faced direction 1
calculating direction of the player to shoot PyGmae
📁 Minimal example - Rotate player and shoot bullet towards faced direction 2
Firing particles from a player at a constant speed with cos() and sin() in python pygame
Related Stack Overflow questions:
Shooting a bullet in pygame in the direction of mouse
How to shoot a projectile in the way the player is looking in a TDS
pygame.transform.rotate
does not transform the object itself, but creates a new rotated surface and returns it.
If you want to fire a bullet in a certain direction, the direction is defined the moment the bullet is fired, but it does not change continuously.
When the bullet is fired, set the starting position of the bullet and calculate the direction vector to the mouse position:
self.pos = (x, y)
mx, my = pygame.mouse.get_pos()
self.dir = (mx - x, my - y)
The direction vector should not depend on the distance to the mouse, but it has to be a Unit vector. Normalize the vector by dividing by the Euclidean distance
length = math.hypot(*self.dir)
if length == 0.0:
self.dir = (0, -1)
else:
self.dir = (self.dir[0]/length, self.dir[1]/length)
Compute the angle of the vector and rotate the bullet. In general, the angle of a vector can be computed by atan2(y, x)
. The y-axis needs to be reversed (atan2(-y, x)
) as the y-axis generally points up, but in the PyGame coordinate system the y-axis points down (see How to know the angle between two vectors?):
angle = math.degrees(math.atan2(-self.dir[1], self.dir[0]))
self.bullet = pygame.Surface((7, 2)).convert_alpha()
self.bullet.fill((255, 255, 255))
self.bullet = pygame.transform.rotate(self.bullet, angle)
To update the position of the bullet, it is sufficient to scale the direction (by a velocity) and add it to the position of the bullet:
self.pos = (self.pos[0]+self.dir[0]*self.speed,
self.pos[1]+self.dir[1]*self.speed)
To draw the rotated bullet in the correct position, take the bounding rectangle of the rotated bullet and set the center point with self.pos
(see How do I rotate an image around its center using PyGame?):
bullet_rect = self.bullet.get_rect(center = self.pos)
surf.blit(self.bullet, bullet_rect)
Related Stack Overflow questions:
pygame 2 dimensional movement of an enemy towards the player, how to calculate x and y velocity?
Pygame: Image chasing the mouse cursor from certain length
How to make smooth movement in pygame
Sprite follow another flexible way within certain distance limits
Teach enemy that the way thru screen border is shorter than going all over the screen
For a more sophisticated solution, you’ve to compute the Euclidean distance form the point to the target. Use pygame.math.Vector2
for the computation.
Compute the distance from between the follower and the sprite and the unit direction vector from (follower_x
, follower_y
) to (mainsprite_x
, mainsprite_y
). The Unit Vector can be computed by dividing the direction vector by the distance or by normalizing (normalize()
) the direction vector:
target_vector = Vector2(mainsprite_x, mainsprite_y)
follower_vector = Vector2(follower_x, follower_y)
distance = follower_vector.distance_to(target_vector)
direction_vector = target_vector - follower_vector
if distance > 0:
direction_vector /= distance
Now you can define an exact step_distance
and move to follower int direction of the sprite:
if distance > 0:
new_follower_vector = follower_vector + direction_vector * step_distance.
Define a maximum_distance
and a minimum_distance
. The minimum step distance is:
min_step = max(0, distance - maximum_distance)
The maximum step distance is
max_step = distance - minimum_distance
Put it all together:
minimum_distance = 0
maximum_distance = 10000
target_vector = Vector2(mainsprite_x, mainsprite_y)
follower_vector = Vector2(follower_x, follower_y)
new_follower_vector = Vector2(follower_x, follower_y)
distance = follower_vector.distance_to(target_vector)
if distance > minimum_distance:
direction_vector = (target_vector - follower_vector) / distance
min_step = max(0, distance - maximum_distance)
max_step = distance - minimum_distance
step_distance = min_step + (max_step - min_step) * LERP_FACTOR
new_follower_vector = follower_vector + direction_vector * step_distance
📁 Minimal example - Follow target smoothly
📁 Minimal example - Ball follow ball
repl.it/@Rabbid76/PyGame-FollowBall