Reputation: 91
I am trying to implement movement from my enemy class to follow the player class. Currently, the enemy class only moves in a straight line to the left. Here is some code to better understand my question.
Here is the player class
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 40))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.left = 25
self.rect.bottom = HEIGHT / 2
self.speedx = 0
self.speedy = 0
Here is the enemy class
class Enemy(pygame.sprite.Sprite):
def __init__(self2):
pygame.sprite.Sprite.__init__(self2)
self2.image = pygame.Surface((50, 40))
self2.image.fill(RED)
self2.rect = self2.image.get_rect()
self2.rect.x = random.randrange(680, 750)
self2.rect.y = random.randrange(HEIGHT - self2.rect.height)
self2.speedx = random.randrange(-5, -3)
self2.speedy = random.randrange(-5, 5)
self2.min_dist = 200
def update(self2):
self2.speedy = 0
self2.rect.x += self2.speedx
self2.rect.y += self2.speedy
if self2.rect.left < -25 or self2.rect.top < -25 or self2.rect.bottom > HEIGHT + 10:
self2.rect.x = random.randrange(680, 750)
self2.rect.y = random.randrange(HEIGHT - self2.rect.height)
self2.speedx = random.randrange(-5, -3)
def move_towards_Player(self2, Player):
delta_x = Player.rect.x - self2.rect.x
delta_y = Player.rect.y - self2.rect.y
if abs(delta_x) <= self2.min_dist and abs(delta_y) <= self2.min_dist:
enemy_move_x = abs(delta_x) > abs(delta_y)
if abs(delta_x) > self2.speedx and abs(delta_x) > self2.speedx:
enemy_move_x = random.random() < 0.5
if enemy_move_x:
self2.rect.x += min(delta_x, self2.speedx) if delta_x > 0 else max(delta_x, -self2.speedx)
else:
self2.rect.y += min(delta_y, self2.speedy) if delta_y > 0 else max(delta_y, -self2.speedy)
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(3):
e = Enemy()
all_sprites.add(e)
enemies.add(e)
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
all_sprites.update()
#Draw render
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
quit()
Sorry for the large post in code just would like to get the best answer for this.
Question 1) This is probably a very simple question but, how come when the all_sprites.Group get updated in the loop why doesn't the move_towards player get updated?
Question 2) I tried letting the update inherit Player, like this
def update(self2, Player):
why doesn't this work?
Question 3) How can I make the move_towards_Player get updated in the loop?
Upvotes: 4
Views: 58
Reputation: 101052
how come when the all_sprites.Group get updated in the loop why doesn't the move_towards player get updated?
You ask why the move_towards_Player
function is not called? Because you never call it, and it isn't magically called by anything. The update
function of Group
will call the update
function of all its sprites. Nothing more.
I tried letting the update inherit Player, like this ... why doesn't this work?
The update
function of Group
will pass all arguments to the update
function of all its sprites. So you could call it like this:
all_sprites.update(player)
and ensure that all sprite classes have their update
function take an extra argument beside self
.
How can I make the move_towards_Player get updated in the loop?
Just call it from the Enemy's update
function.
You could start with something like this:
import pygame
import random
GREEN=(0,255,0)
RED=(255,0,0)
BLACK=(0,0,0)
HEIGHT=600
WIDTH=800
FPS=120
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 40))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.left = 25
self.rect.bottom = HEIGHT / 2
self.speedx = 0
self.speedy = 0
class Enemy(pygame.sprite.Sprite):
def __init__(self, target):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 40))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(680, 750)
self.rect.y = random.randrange(HEIGHT - self.rect.height)
self.target = target
self.speed = random.randint(4, 6)
def update(self, dt):
self.move_towards_Player(dt)
def move_towards_Player(self, dt):
pos = pygame.Vector2(self.rect.center)
v = pygame.Vector2(self.target.rect.center) - pos
if (v.length() < 5):
self.kill()
else:
v.normalize_ip()
v *= self.speed * dt/10
pos += v
self.rect.center = round(pos.x), round(pos.y)
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(3):
e = Enemy(player)
all_sprites.add(e)
enemies.add(e)
clock=pygame.time.Clock()
pygame.init()
screen=pygame.display.set_mode([WIDTH, HEIGHT])
running = True
while running:
dt=clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
all_sprites.update(dt)
#Draw render
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
quit()
Note that:
self2
to self
. By convention, the first argument of a method should be called self
. Stick to it.Player
instance to the Enemy
-class' __init__
function and store it in a class member. This way, we don't have to "pollute" the update
functionVector2
class to handle the math.Upvotes: 1