1

Im trying to make an enemy follow the player which is moved by the mouse. The player spawns in but does not move. Here is my (new & edited)code : This is the player class (no problem with that):

class Player(pg.sprite.Sprite):
def __init__(self):
    self.groups = all_sprites
    pg.sprite.Sprite.__init__(self, self.groups)
    self.image = pg.Surface((Player_SIZE, Player_SIZE))
    self.image.fill(BLUE)
    self.rect = self.image.get_rect()
    self.pos = vec(randint(0, WIDTH), randint(0, HEIGHT))
    self.vel = vec(MAX_SPEED, 0).rotate(uniform(0, 360))
    self.acc = vec(0, 0)
    self.rect.center = self.pos

def follow_mouse(self):
    mpos = pg.mouse.get_pos()
    self.acc = (mpos - self.pos).normalize() * 0.5

def seek(self, target):
    self.desired = (target - self.pos).normalize() * MAX_SPEED
    steer = (self.desired - self.vel)
    if steer.length() > MAX_FORCE:
        steer.scale_to_length(MAX_FORCE)
    return steer

def seek_with_approach(self, target):
    self.desired = (target - self.pos)
    dist = self.desired.length()
    self.desired.normalize_ip()
    if dist < APPROACH_RADIUS:
        self.desired *= dist / APPROACH_RADIUS * MAX_SPEED
    else:
        self.desired *= MAX_SPEED
    steer = (self.desired - self.vel)
    if steer.length() > MAX_FORCE:
        steer.scale_to_length(MAX_FORCE)
    return steer

def update(self):
    # self.follow_mouse()
    self.acc = self.seek_with_approach(pg.mouse.get_pos())
    # equations of motion
    self.vel += self.acc
    if self.vel.length() > MAX_SPEED:
        self.vel.scale_to_length(MAX_SPEED)
    self.pos += self.vel
    if self.pos.x > WIDTH:
        self.pos.x = 0
    if self.pos.x < 0:
        self.pos.x = WIDTH
    if self.pos.y > HEIGHT:
        self.pos.y = 0
    if self.pos.y < 0:
        self.pos.y = HEIGHT
    self.rect.center = self.pos
 

This is the enemy class:

class Enemy(pg.sprite.Sprite):
def __init__(self):
    self.groups = all_sprites
    pg.sprite.Sprite.__init__(self, self.groups)
    self.image = pg.Surface((Player_SIZE, Player_SIZE))
    self.image.fill(RED)
    self.rect = self.image.get_rect()
    self.pos = vec(randint(0, WIDTH), randint(0, HEIGHT))
    self.vel = vec(MAX_SPEED1, 0).rotate(uniform(0, 360))
    self.acc = vec(0, 0)
    self.rect.center = self.pos

def follow_player1(self):
    ppos = self.pos.x, self.pos.y
    self.acc = (ppos - self.pos).normalize() * 0.5

def seek1(self, target):
    self.desired = (ppos - self.pos).normalize() * MAX_SPEED1
    steer = (self.desired - self.vel)
    if steer.length() > MAX_FORCE1:
        steer.scale_to_length(MAX_FORCE1)
    return steer

def seek_with_approach1(self, target):
    self.desired = (ppos - self.pos)
    dist = self.desired.length()
    self.desired.normalize_ip()
    if dist < APPROACH_RADIUS:
        self.desired *= dist / APPROACH_RADIUS * MAX_SPEED1
    else:
        self.desired *= MAX_SPEED1
    steer = (self.desired - self.vel)
    if steer.length() > MAX_FORCE1:
        steer.scale_to_length(MAX_FORCE1)
    return steer

def update1(self):
    # self.follow_mouse()
    self.acc = self.seek_with_approach(ppos)
    # equations of motion
    self.vel += self.acc
    if self.vel.length() > MAX_SPEED1:
        self.vel.scale_to_length(MAX_SPEED1)
    self.pos += self.vel
    if self.pos.x > WIDTH:
        self.pos.x = 0
    if self.pos.x < 0:
        self.pos.x = WIDTH
    if self.pos.y > HEIGHT:
        self.pos.y = 0
    if self.pos.y < 0:
        self.pos.y = HEIGHT
    self.rect.center = self.pos

This is the main loop (Game loop, and there is no problem with it... I think):

#Main loop
all_sprites = pg.sprite.Group()
Player()
Enemy()
paused = False
running = True
while running:
    clock.tick(FPS)
    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False
               

    if not paused:
        all_sprites.update()

    screen.fill(DARKGRAY)
    all_sprites.draw(screen)

    pg.display.flip()

pg.quit()

I will be editing the code if I changed anything dramatic. Thank you in advance

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Summon
  • 77
  • 4
  • 2
    The `'''` should be `\`\`\`` for the code formatting to work correctly. Or you could simply just remove them if you've indented all code one step. – Ted Klein Bergman Mar 22 '21 at 22:05
  • 3
    Python tends to do a good job of giving descriptive error messages. That stack trace should have the line number, though just searching your code for `ppos` makes it pretty obvious you're using that variable in three places where it could only work if that variable is defined outside of this class. Which it apparently isn't, given the error. – kungphu Mar 22 '21 at 23:30
  • this still does nothing to the enemy – Summon Mar 23 '21 at 12:02
  • Related: [pygame 2 dimensional movement of an enemy towards the player, how to calculate x and y velocity?](https://stackoverflow.com/questions/66404707/pygame-2-dimensional-movement-of-an-enemy-towards-the-player-how-to-calculate-x/66406985#66406985) and [How to make smooth movement in pygame](https://stackoverflow.com/questions/64087982/how-to-make-smooth-movement-in-pygame/64088747#64088747) – Rabbid76 Sep 30 '21 at 20:50

1 Answers1

0

An option is to compute the Euclidean distance form the position of the follower 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

Minimal example:

repl.it/@Rabbid76/PyGame-FollowMouseSmoothly

import pygame

VELOCITY         = 5
LERP_FACTOR      = 0.05
minimum_distance = 25
maximum_distance = 100

def FollowMe(pops, fpos):
    target_vector       = pygame.math.Vector2(*pops)
    follower_vector     = pygame.math.Vector2(*fpos)
    new_follower_vector = pygame.math.Vector2(*fpos)

    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(max_step, max(min_step, VELOCITY))
        step_distance       = min_step + (max_step - min_step) * LERP_FACTOR
        new_follower_vector = follower_vector + direction_vector * step_distance

    return (new_follower_vector.x, new_follower_vector.y) 

pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()

follower = (100, 100)
run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    player   = pygame.mouse.get_pos()
    follower = FollowMe(player, follower)

    window.fill(0)  
    pygame.draw.circle(window, (0, 0, 255), player, 10)
    pygame.draw.circle(window, (255, 0, 0), (round(follower[0]), round(follower[1])), 10)
    pygame.display.flip()

pygame.quit()
exit()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174