0

I know this has been asked before but I can't get it to work with my code.

I think this is where to have the enemy follow the player should be. I'm not sure how exactly to implement it.

I want the enemies to follow the player and when they run into the player the game ends. I also want this to be able to work with multiple enemies as well.

# player class
class player:
    def __init__(self, x, y, w, h, xChange, yChange, vel):
        self.x = x # plater x value
        self.y = y # player y value
        self.w = w # player w (width)
        self.h = h # player h (height)
        self.xChange = xChange # player xChange (to add to x value to move player horizontally)
        self.yChange = yChange # player yChange (to aad to y value to move player vertically)
        self.vel = vel # velocity of player (needed for collision)

# enemy class
class enemy:
    def __init__(self, x, y, w, h):
        self.x = x # enemy x value
        self.y = y # enemy y value 
        self.w = w # enemy w (width) value
        self.h = h # enemy h (height) value

# ----------------------------------------------------------------

"""enemy's x value (random value) (we pick 750 because the enemy width is 50 and
the screen width is 800. If we set the random value to 800, then the enemy has a
chance of spawning outside of the screen.)"""
enemyX = random.randint(0, 700)

"""enemy's y value (random value) (we pick 540 because the enemy height is 60
and the screen height is 600. If we set the random value to 600, the enemy has a
chance of spawning outside of the screen.)"""
enemyY = random.randint(0, 540) # enemy's y value

score = 0 # score set to 0. Will update in while loop.

rec = player(50, 50, 24, 32, 0, 0, 5) # the player's values (x, y, w, h, xChange, yChange, vel)
redRec = enemy(enemyX, enemyY, 24, 32) # the enemy's values (x, y, w, h)

# mainloop #
def mainloop():
    global running, score, intro, sprite, next_zombie_time

    while running:
        """keeps filling window with the background image"""
        window.blit(background, (0, 0))
        pygame.time.delay(25) # delay
        for event in pygame.event.get(): # for every event in game
            if event.type == pygame.QUIT: # if I exit the game
                quitGame()

            if event.type == pygame.KEYUP: # if any keys are let go
                if event.key == pygame.K_a: # if key a
                        rec.xChange = 0 # set xChange to 0 (stop moving rec)

                if event.key == pygame.K_d: # if key d
                    rec.xChange = 0 # set xChange to 0 (stop moving rec)

                if event.key == pygame.K_w: # if key w
                    rec.yChange = 0 # set xChange to 0 (stop moving rec)

                if event.key == pygame.K_s: # if key s
                    rec.yChange = 0 # set xChange to 0 (stop moving rec)

            if event.type == pygame.KEYDOWN: # if any keys are pressed
                if event.key == pygame.K_F4: # if key F4
                    pygame.quit() # set running to false

                if event.key == pygame.K_a: # if key a
                    rec.xChange += -5 # add -5 to xChange (move rec left)
                    sprite = spriteLeft

                if event.key == pygame.K_d: # if key a
                    rec.xChange += 5 # adds 5 to xChange (move rec right)
                    sprite = spriteRight

                if event.key == pygame.K_w: # if key a
                    #adds -5 to yChange (moves rec up). Yes, this is supposed to say up.
                    rec.yChange += -5
                    sprite = spriteUp

                if event.key == pygame.K_s: # if key a
                    # adds 5 to yChange (moves rec down). Yes, this is supposed to say down.
                    rec.yChange += 5
                    sprite = spriteDown

                # pause key to pause game 
                if event.key == pygame.K_o: # if key o
                    running = False # set running to false
                    intro = False # intro set to False
                    pauseMenu() # pauseMenu is called




        rec.x += rec.xChange # add rec's xChange to x (to do the moving)
        rec.y += rec.yChange # adds rec's yChange to y (to do the moving)


        # ----------------BOUNDARIES------------------------------
        if rec.x <= 0: # if rec's x is less than or equal to 0 (if tries to escape screen)
            rec.x  = 0 # rec's x is set to 0 so it won't go off screen.

        """(we pick 750 because the player width is 50 and the screen width is 800.
        If we set it to 800, then the player can go outside of screen."""   
        if rec.x  >= 750: # if rec's x is greater than or equal to 750 (if tries to escape screen)
            rec.x  = 750  # set rec's x to 750 so it won't go off screen

        if rec.y <= 0: # if rec's y is less than or equal to 0 (if tries to escape screen)
            rec.y = 0 # set rec's y to 0 so it won't go off screen
        """we pick 540 because the player height is 60 and the screen height is 600.
            If we set it to 600, then the player can go outside of screen"""
        if rec.y >= 540: # if rec'y is greater than or equal to 540 (if tries to escape screen) 
            rec.y = 540 # set rec's y to 540 so it won't go off screen  

        #enemy.update(delta_time, player)
        collisions = detCollision(rec.x, rec.y, rec.w, rec.h, redRec.x, redRec.y, redRec.w, redRec.h)
        # activate the redrawWin function
        redrawWin(collisions)



rahsut
  • 41
  • 1
  • 7
  • Please provide a minimal reproducible example: https://stackoverflow.com/help/minimal-reproducible-example – Hoog Jan 20 '20 at 17:59
  • @Hoog There isn't a problem with the code it self (or the code producing any). I just want to know how to make the enemy follow the player. – rahsut Jan 20 '20 at 20:16
  • 1
    "...but I can't get it to work with my code." What have you tried? If you have tried something, and it didn't work, that attempt can be written as a reproducible example, and we can explain why what you tried did not work the way you wanted it to. If you have not tried anything, then you are blatantly asking us to write your program for you. Without some context as to what your problem is, we can not do any better than whatever tutorial comes up with a search for "How to make enemy follow player in pygame" – Hoog Jan 20 '20 at 20:43
  • @Hoog I tried this but it didn't work for me: https://stackoverflow.com/questions/54734679/enemy-doesnt-follow-player-pygame – rahsut Jan 23 '20 at 20:57

1 Answers1

1

You need a few peices of information to do this. Firstly, you will need the distance between the player and the enemy. You can work out the distance using math.hypot function like this distance = (math.hypot(enemy.x - player.x, enemy.y - player.y) ). Then you would want to work out the angle between them in radians by using math.atan2 funciton. Note that this function takes y positional argument first. You can use this as follows

angle_radians = (math.atan2(enemy.y - player.y , enemy.x - player.x))

Now to get the enemy to move in the direction of the player, you can do this

     enemy.y += math.sin(angle_radians) 
     enemy.x += math.cos(angle_radians)

See why this works http://setosa.io/ev/sine-and-cosine/. You can even add a range on how close you want the player to be to the enemy when it starts following by setting a condition on distance between them like this.

if distance < range:

You can also control the speed by multiplying both the sin and cosine by the same number and this works because they are ratios.It can looks something like this

 enemy.y += math.sin(angle_radians) * speed # Note both speeds must be the same nnumber
 enemy.x += math.cos(angle_radians) * speed

For the last part of your question, if you want this to work for all the enemies, i would recommend adding your game objects to a list. For exmple, you can add enemies to a list and make them follow the player. Lets say you make a list of all the enemies by doing this

all_enemies = []
for i in range(number of enemies you want):
    all_enemies.append(enemy())

You could have an end result that looks something like this:

 def Follow_player(self):
        for  e in all_enemies:
              distance = (math.hypot(e.x  - player.x, e.y - player.y) )
              angle_radians = (math.atan2(e.y - player.y , e.x - player.x))

              e.y += math.sin(angle_radians) 
              e.x += math.cos(angle_radians)  

              if distance < 1:
                  # they have collided 

EDIT Here's a link to a very good youtube video that describes all of this https://www.youtube.com/watch?v=DVYDkHdsTIM

  • Would I call the function in the mainloop? Such as Follow_player() ? – rahsut Jan 20 '20 at 20:57
  • @rashut yes, you would have to call it in the main loop because you want the values to change every frame –  Jan 20 '20 at 21:54
  • What should I put as a parameter in the Follow_player() function? – rahsut Jan 24 '20 at 20:20
  • It dosent take any parameters the way i have done it –  Jan 24 '20 at 20:54
  • It does "weird" movement. I've most likely missed something but the enemy keeps moving down right and that's it. I'm not sure why this is happening? The for loop you told me about, is that supposed to be in mainloop as well? If so, I get errors. Please help. – rahsut Jan 25 '20 at 15:23
  • I cant help you without looping at your code. You should probably post another question with your code and problems explained –  Jan 25 '20 at 15:38