Search code examples
pythonpython-3.xpygamepython-3.6python-3.7

How do i spawn enemies from every side of the screen pygame?


I've been working on some game code for school and was working through some tutorials and figured out how to make the player sprite tracks the mouse but now I'm having trouble figuring out how to spawn enemies from all sides of the screen instead of just the top. (To clarify code is in two parts/files, also completely unrelated). I was also wondering, how I could maybe have the mobs/NPCs chase and rotate towards the player?

import random
import math
import pygame as py
from PlayerSprite import *

WIDTH = 800
HEIGHT = 600
FPS = 60

# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# initialize pygame and create window
py.init()
py.mixer.init()
screen = py.display.set_mode((WIDTH, HEIGHT))
py.display.set_caption("Dimensional Drifter")
clock = py.time.Clock()

all_sprites = py.sprite.Group()
NPCs = py.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
    n = NPC()
    all_sprites.add(n)
    NPC.add(n)
# Game loop
running = True
while running:
    # keep loop running at the right speed
    clock.tick(FPS)

    for event in py.event.get():
        # check for closing window
        if event.type == py.QUIT:
            running = False

    # Update
    all_sprites.update()
    #
    mouse_x, mouse_y = py.mouse.get_pos()
    player.rotate(mouse_x, mouse_y)
    # render
    screen.fill(BLACK)
    all_sprites.draw(screen)
    # flip the display
    py.display.flip()

py.quit()
import pygame as py
import math
import random

WIDTH = 800
HEIGHT = 600
FPS = 60

# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)


class Player(py.sprite.Sprite):
    def __init__(self):
        py.sprite.Sprite.__init__(self)
        self.image = py.Surface((50, 50), py.SRCALPHA)
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT / 2
        self.Yspeed = 0
        self.rotatableimage = self.image

    def update(self):
        self.Xspeed = 0
        self.Yspeed = 0
        # line below allow for key press to equate to move of sprite
        keypreesed = py.key.get_pressed()
        if keypreesed[py.K_a]:
            self.Xspeed = - 11
        if keypreesed[py.K_d]:
            self.Xspeed = 11
        if keypreesed[py.K_w]:
            self.Yspeed = - 11
        if keypreesed[py.K_s]:
            self.Yspeed = 11
        self.rect.x += self.Xspeed
        self.rect.y += self.Yspeed
        # line below allow the sprite to wrap around the screen
        if self.rect.left > WIDTH:
            self.rect.right = 0
        if self.rect.right < 0:
            self.rect.left = WIDTH
        if self.rect.top > HEIGHT:
            self.rect.top = 0
        if self.rect.bottom < 0:
            self.rect.bottom = HEIGHT

    def rotate(self, mouse_x, mouse_y):
        rel_x = mouse_x - self.rect.x
        rel_y = mouse_y - self.rect.y
        angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)

        self.image = py.transform.rotate(self.rotatableimage, int(angle))
        self.rect = self.image.get_rect(center=(self.rect.centerx, self.rect.centery))
        return


class NPC(py.sprite.Sprite):
    def __init__(self):
        py.sprite.Sprite.__init__(self)
        self.image = py.Surface((30, 30))
        self.image.fill(RED)
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(WIDTH - self.rect.width)
        self.rect.y = random.randrange(-100, -40)
        self.Yspeed = random.randrange(1, 8)

    def update(self):
        self.rect.y += self.Yspeed
        if self.rect.top > HEIGHT + 10:
            self.rect.x = random.randrange(WIDTH - self.rect.width)
            self.rect.y = random.randrange(-100, -40)
            self.Yspeed = random.randrange(1, 8)

Thanks in advance.


Solution

  • You have to add a random direction and a separate speed (self.Xspeed, self.Yspeed) for the x and y direction:

    self.direction = random.randrange(4)
    

    and to set self.rect.x, self.rect.y, self.Xspeed and self.Yspeed dependent on the random direction:

    if self.direction == 0:
        self.rect.x = random.randrange(WIDTH - self.rect.width)
        self.rect.y = random.randrange(-100, -40)
        self.Xspeed = 0
        self.Yspeed = random.randrange(1, 8)
    elif self.direction == 1:
        # [...]
    elif self.direction == 2:
        # [...]
    elif self.direction == 3:
        # [...]
    

    Create a method spawn, which spawns a enemy with a random direction and a random speed and call it in the constructor of NPC:

    class NPC(py.sprite.Sprite):
        def __init__(self):
            # [...]        
    
            self.spawn()
    
        def spawn(self):
            self.direction = random.randrange(4)
            if self.direction == 0:
                # [...]
    

    In update the speed has to be and to the x and y position separately:

    self.rect.x += self.Xspeed
    self.rect.y += self.Yspeed
    

    Furthermore, if the object is out of the window has to be evaluated dependent on the direction. If the object is out of the window, the call spawn() again, thus the object gets a new random direction, position and speed:

    if self.direction == 0:
        if self.rect.top > HEIGHT + 10:
            self.spawn()
    elif self.direction == 1:
        if self.rect.bottom < -10:
            self.spawn()
    elif self.direction == 2:
        if self.rect.left > WIDTH + 10:
            self.spawn()
    elif self.direction == 3:
        if self.rect.right < -10:
            self.spawn()
    

    To rotate the image you have to create surface with per pixel alpha (convert_alpha()) and to keep the original surface:

    self.image = py.Surface((30, 30)).convert_alpha()
    self.image.fill(RED)
    self.originalimage = self.image  
    

    Compute the angle from the enemy to the player and rotate the image by pygame.transform.rotate(): (See also How to rotate a triangle to a certain angle in pygame?)

    dir_x, dir_y = player.rect.x - self.rect.x, player.rect.y - self.rect.y
    self.rot = (180 / math.pi) * math.atan2(-dir_x, -dir_y)
    self.image = py.transform.rotate(self.originalimage, self.rot)
    

    Class NPC:

    class NPC(py.sprite.Sprite):
        def __init__(self, player):
            py.sprite.Sprite.__init__(self)
            self.player = player 
            self.image = py.Surface((30, 30)).convert_alpha()
            self.image.fill(RED)
            self.originalimage = self.image
            self.rect = self.image.get_rect()
            self.spawn()
    
        def spawn(self):
            self.direction = random.randrange(4)
            if self.direction == 0:
                self.rect.x = random.randrange(WIDTH - self.rect.width)
                self.rect.y = random.randrange(-100, -40)
                self.Xspeed = 0
                self.Yspeed = random.randrange(1, 8)
            elif self.direction == 1:
                self.rect.x = random.randrange(WIDTH - self.rect.width)
                self.rect.y = random.randrange(HEIGHT, HEIGHT+60)
                self.Xspeed = 0
                self.Yspeed = -random.randrange(1, 8)
            elif self.direction == 2:
                self.rect.x = random.randrange(-100, -40)
                self.rect.y = random.randrange(HEIGHT - self.rect.height)
                self.Xspeed = random.randrange(1, 8)
                self.Yspeed = 0
            elif self.direction == 3:
                self.rect.x = random.randrange(WIDTH, WIDTH+60)
                self.rect.y = random.randrange(HEIGHT - self.rect.height)
                self.Xspeed = -random.randrange(1, 8)
                self.Yspeed = 0
    
        def update(self):
            self.rect.x += self.Xspeed
            self.rect.y += self.Yspeed
    
            dir_x, dir_y = self.player.rect.x - self.rect.x, self.player.rect.y - self.rect.y
            self.rot = (180 / math.pi) * math.atan2(-dir_x, -dir_y)
            self.image = py.transform.rotate(self.originalimage, self.rot)
    
            if self.direction == 0:
                if self.rect.top > HEIGHT + 10:
                    self.spawn()
            elif self.direction == 1:
                if self.rect.bottom < -10:
                    self.spawn()
            elif self.direction == 2:
                if self.rect.left > WIDTH + 10:
                    self.spawn()
            elif self.direction == 3:
                if self.rect.right < -10:
                    self.spawn()
    
    player = Player()
    all_sprites.add(player)
    for i in range(8):
        n = NPC(player)
        all_sprites.add(n)
        NPC.add(n)