1
votes

I'm working on a basic pygame but I'm not sure where I want to take it. So as of now I'm only working on the basic mechanics.

The issue I've ran into is that I need to have enemy sprites move towards the player sprite. I've already figured out the basic vectoring but because the sprites move along a vector, they also slow down the closer they get to their target.

Here is a snip of my code.

#Enemy Mechanics
for enemy in enemy_list:
    pygame.draw.rect(screen, green, (enemy.rect.x, enemy.rect.y-5, enemy.Health/4, 3), 0)
    pygame.draw.rect(screen, green, (enemy.rect.x, enemy.rect.y-5, 25, 3), 1)

    ppos = pPlayer.rect.x, pPlayer.rect.y
    epos = enemy.rect.x, enemy.rect.y
    etarget = epos[1] - ppos[1], epos[0] - ppos[0]

    enemy.rect.x -= etarget[1]/20 #This is the problem
    enemy.rect.y -= etarget[0]/20


#Bullet Mechanics
for bullet in bullet_list:
    mpos = pygame.mouse.get_pos()
    bpos = bullet.rect.x, bullet.rect.y
    target = bpos[1] - mpos[1], bpos[0] - mpos[0]
    dist = math.sqrt(((bpos[0] - mpos[0])**2) + ((bpos[1] - mpos[1])**2))

    bullet.rect.x -= target[1]/20
    bullet.rect.y -= target[0]/20

    if dist < 30:
        bExplode(bullet.rect.x, bullet.rect.y)
        blist.remove(bullet)
        bullet.kill()

    enemy_hit_list = (pygame.sprite.spritecollide(bullet, enemy_list, False))
    for enemy in enemy_hit_list:
        enemy.Health -= 25
        print(enemy.Health)
        if enemy.Health <= 0:
            enemy_list.remove(enemy)
            all_sprites_list.remove(enemy)

        bullet_list.remove(bullet)
        all_sprites_list.remove(bullet)
        blist.remove(bullet)

As you can see, I've been dividing the vectors by 20 because it slows them down to a reasonable speed but they also stop before reaching their target. I need help in making the sprites move at a constant, set speed towards the player.

1
Why is this tagged "performance"? Your current implementation may be incorrect, but… is it taking too much CPU time as well? That doesn't seem likely. - abarnert
Sorry, when I typed in Speed it defaulted to performance. - Isaacashtox
Ah, you meant the speed as in the scalar velocity of the bullets. Yeah, sometimes SO is a bit overzealous at guessing aliases. You probably don't want to optimize the performance of the bullets. If you do, maybe try polygonal rifling in the muzzle of your for loops. :) - abarnert

1 Answers

1
votes

Your code means the enemies always move 1/20th of the way to their target. You want them to move 1 fixed-size step in the same direction.

The answer here is to normalize your vector—that is, use a unit vector in the same direction as the distance vector, instead of using the distance vector directly.

The easy way to do this is by just dividing the vector by its length. And to get the vector's length, that's just the Pythagorean theorem.

So:

def vector_length(x, y):
    return math.sqrt(x*x + y*y)

def normalize_vector(x, y):
    norm = vector_length(x, y)
    return x/norm, y/norm

target = normalize_vector(bpos[1] - mpos[1], bpos[0] - mpos[0])

This makes the bullets move at 1 space unit per time unit (e.g., pixel per frame). If you want them to go faster or slower, just define an bullet speed in the same units and multiply by it:

bullet.rect.x -= target[1] * BULLET_SPEED 
bullet.rect.y -= target[0] * BULLET_SPEED 

In fact, you're already doing most of this, you're just not using it:

dist = math.sqrt(((bpos[0] - mpos[0])**2) + ((bpos[1] - mpos[1])**2))

So, if you find it clearer, just change the next two lines to:

bullet.rect.x -= target[1] / dist * BULLET_SPEED
bullet.rect.y -= target[0] / dist * BULLET_SPEED