0

As of currently the enemy sprites just spawn on the axis, and "move" with the player which is actually a scrolling background, and I'd like for the enemies to move only along the X axis so it doesn't destroy the immersion.

I'd also like for the sprites to spawn "Off the map" and whenever the map scrolls towards them they move towards the players set X axis? I think that would keep things simple, but isn't really the question at hand right now.

The current code I was trying to get working for the movement was :

def move_towards_player(self, player):
        # Find direction vector (dx, dy) between enemy and player.
        dx, dy = player.rect.x - self.rect.x, player.rect.y - self.rect.y
        dist = math.hypot (dx, dy)
        dx, dy = dx / dist, dy / dist # Normalize
        # Move along this normalized vector towards the player
        self.rect.x += dx * self.speed
        self.rect.y += dy * self.speed

But it wouldn't work, this is with importing the math module. (I know I don't need the y movements just wanted to get it working first)

Here is the rest of the code --

Zombie.py:

import pygame
from pygame.locals import *
import random
import math

class ZombieEnemy(pygame.sprite.Sprite):
    def __init__(self, x=300, y=360):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load('images/zombie.png')
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)

all_zombies = pygame.sprite.Group()


for i in range( 50 ):
    new_x = random.randrange( 0, 10000)       # random x-position
    # new_y = random.randrange( 0, )      # random y-position
    all_zombies.add(ZombieEnemy(new_x))         # create, and add to group

I wasn't sure if I should create a whole new class for enemy movement, or what my partner is currently working on the Player, and getting the sprite animations and movement working right.

But here is the main code I have as of now:

import pygame
from Zombie import *
import math
from pygame.locals import *
pygame.init()
​
win = pygame.display.set_mode((900,567))
​
pygame.display.set_caption("Power Rangers ZOMBIES")
​
walkRight = [pygame.image.load('images/walk1.png'), pygame.image.load('images/walk2.png'), pygame.image.load('images/walk3.png'), pygame.image.load('images/walk4.png'), pygame.image.load('images/walk5.png'), pygame.image.load('images/walk6.png')]
walkLeft = [pygame.image.load('images/leftwalk2.png'), pygame.image.load('images/leftwalk3.png'), pygame.image.load('images/leftwalk4.png'), pygame.image.load('images/leftwalk5.png'), pygame.image.load('images/leftwalk6.png'), pygame.image.load('images/leftwalk7.png')]
bg = pygame.image.load('images/background.png')
char = pygame.image.load('images/standingstill.png')
clock = pygame.time.Clock()
​
class Player(pygame.sprite.Sprite):
    def __init__(self,x,y,width,height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.vel = 0
        self.isJump = False
        self.left = False
        self.right = False
        self.walkCount = 0
        self.jumpCount = 10
​
    def draw(self, win):
        if self.walkCount + 1 >= 18:
            self.walkCount = 0
​
        if self.left:
            win.blit(walkLeft[self.walkCount//3], (self.x,self.y))
            self.walkCount += 1
        elif self.right:
            win.blit(walkRight[self.walkCount//3], (self.x,self.y))
            self.walkCount +=1
        else:
            win.blit(char, (self.x,self.y))
​
class Background(pygame.sprite.Sprite):
    def __init__(self, image_file, location):
        pygame.sprite.Sprite.__init__(self)  #call Sprite initializer
        self.image = pygame.image.load('images/background.png')
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location
​
BackGround = Background('images/background.png', [0,0])
​
# def redrawGameWindow():
#     win.blit(bg, (0,0))
#     man.draw(win)

#     pygame.display.update()
​
#mainloop
man = Player(100, 340, 40, 60)
run = True
while run:
    clock.tick(27)
​
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
​
    keys = pygame.key.get_pressed()
​
    if keys[pygame.K_LEFT] and man.x > man.vel:
        BackGround.rect.left = BackGround.rect.left + int(10)
        man.x -= man.vel
        man.left = True
        man.right = False
    elif keys[pygame.K_RIGHT]: #and man.x < 500 - man.width - man.vel:
        BackGround.rect.left = BackGround.rect.left - int(10)
        man.x += man.vel
        man.right = True
        man.left = False
    else:
        man.right = False
        man.left = False
        man.walkCount = 0

    if not(man.isJump):
        if keys[pygame.K_SPACE]:
            man.isJump = True
            man.right = False
            man.left = False
            man.walkCount = 0
    else:
        if man.jumpCount >= -10:
            neg = 1
            if man.jumpCount < 0:
                neg = -1
            man.y -= (man.jumpCount ** 2) * 0.5 * neg
            man.jumpCount -= 1
        else:
            man.isJump = False
            man.jumpCount = 10

    # redrawGameWindow()
    for zombie in all_zombies:
        zombie.move_towards_player(Player)
    all_zombie.update()
    win.blit(BackGround.image, BackGround.rect)
    man.draw(win)
    pygame.display.flip()
    all_zombies.draw(screen)
​
pygame.quit()
Blue
  • 243
  • 1
  • 8
  • 26
  • 2
    all zombie's functions should be inside class `ZombieEnemy` - so `move_towards_player` should be inside `ZombieEnemy` but you have it outside this class. You can't use `self` outside class. – furas Jan 24 '20 at 16:38
  • @furas I had tired that and whenever I run the game the zombies still just spawn spawn on the screen and do not move with the background, or whenever player inputs anything. – Blue Jan 24 '20 at 16:41
  • 1
    you never use `move_towards_player` so enemy never move. – furas Jan 24 '20 at 16:42
  • @furas So, would I make a if statement? If player moves move towards player? Like add it into the Game loop? Sorry bare with me, and thanks for all the help! – Blue Jan 24 '20 at 16:45
  • 1
    you have to use like this `for zombie in all_zombies: zombie.move_towards_player(player)` - but first you have to put `move_towards_player` inside class `ZombieEnemy` – furas Jan 24 '20 at 16:46

1 Answers1

1

I can't run code but I see two problems

1 - move_towards_player has to be inside class ZombieEnemy

# --- classes ---

class ZombieEnemy(pygame.sprite.Sprite):

    def __init__(self, x=300, y=360):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load('images/zombie.png')
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)

    def move_towards_player(self, player):
        # Find direction vector (dx, dy) between enemy and player.
        dx, dy = player.rect.x - self.rect.x, player.rect.y - self.rect.y
        dist = math.hypot (dx, dy)
        dx, dy = dx / dist, dy / dist # Normalize
        # Move along this normalized vector towards the player
        self.rect.x += dx * self.speed
        self.rect.y += dy * self.speed 

 # --- other ---

 all_zombies = pygame.sprite.Group()

2 - you have to use it in main loop

    for zombie in all_zombies:
        zombie.move_towards_player(player)

in main loop

while running:

    # --- events ---

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    # If keystroke is pressed check right, left.
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_LEFT:
            #playerX_change = -2.0
            BackGround.rect.left = BackGround.rect.left + 2.5
        if event.key == pygame.K_RIGHT:
            #playerX_change = 2.0
            BackGround.rect.left = BackGround.rect.left - 2.5
    # if event.type == pygame.KEYUP:
    #     if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
    #         BackGround.rect.left = 0

    # --- updates/moves ---

    playerX += playerX_change

    for zombie in all_zombies:
        zombie.move_towards_player(player)
    all_zombies.update()

    # --- draws ---

    screen.blit(BackGround.image, BackGround.rect)
    player(playerX,playerY)
    all_zombies.draw(screen)
    pygame.display.flip()

But here I see other problem - your function expects player as class instance with self.rect inside (similar to ZombieEnemy) but you keep player as separated variables playerImg, playerX, playerY, playerX_change

So you have to create class Player or you have to use playerx, playery in move_towards_player instead of player.rect.x, player.rect.y

furas
  • 134,197
  • 12
  • 106
  • 148
  • Yes, that is the problem I am on now, and I'll have to pass that over to my partner as he is working with the player now. Will that also be for making hitboxes? – Blue Jan 24 '20 at 16:54
  • Traceback (most recent call last): File "fighting_game.py", line 55, in zombie.move_towards_player(player) File "/Users/blue/DigitalCrafts/Pygame_Project/Zombie.py", line 15, in move_towards_player dx, dy = player.rect.x - self.rect.x, player.rect.y - self.rect.y AttributeError: 'function' object has no attribute 'rect' – Blue Jan 24 '20 at 16:55
  • This the error I would I receive assuming, we get the player defined and all that everything should work correctly? – Blue Jan 24 '20 at 16:55
  • you have to convert player to class `Player` similar to `ZombieEnemy` and then you can use `player = Player()` and `player.rect.x`, `player.rect.y` - or use `playerx, playery` instead of `player.rect.x`, `player.rect.y` . Currenty you have function `player()` and you get error `function' object has no attribute 'rect'` when you try to use `player.rect` – furas Jan 24 '20 at 16:58
  • Okay, sorry was away for lunch, my partner is working on getting his player into a class now, and then we'll see if everything comes together. Thank you! – Blue Jan 24 '20 at 17:56
  • `Player` should be very similary to `ZombieEnemy`. As I remeber I even made this class `Player` in some answer for one of your previous question. OR maybe it was similar question with similar code. – furas Jan 24 '20 at 19:03
  • You had done that yes, but I am working with a Partner who is working on the Player class, and we have a whole new code. I would like to have you look at. – Blue Jan 24 '20 at 19:19
  • I'm going to update the post with the new code, and comment once done. – Blue Jan 24 '20 at 19:20
  • Okay I've updated the main code line with the code as of now. It's saying that all_zombies is not defined. – Blue Jan 24 '20 at 19:24
  • 1
    strange - you define `all_zombies` in `Zombie.py` and you do `from Zombies import *` – furas Jan 24 '20 at 19:34
  • read full error message to see in which line it makes problem. Maybe it it in some class/function and it treats it as local variable instead of global variable. – furas Jan 24 '20 at 19:41
  • I found problem - there is `all_zombie.update()` without `s` - add `s` in `all_zombies` – furas Jan 24 '20 at 19:45
  • BTW: it should be `man` instead of `Player` in line `zombie.move_towards_player(man)`. But `Player` doesn't have `self.rect` with `self.rect.x`, `self.rect.y` – furas Jan 24 '20 at 19:47
  • We have got the zombies on the screen now, and are now trying to get them to move towards the player, slowly working through it. Had fixed some of the problems you just listed. – Blue Jan 24 '20 at 19:53