Search code examples
pythonpygamereal-time-strategy

Two sprites spotting each other


Hello again Stack Overflow. you probably remember me from my unit spawning problem in my pygame program, "Table Wars." I decided to change the scope of my game to a real-time strategy rather than a turn-based game. I want the game to play along the lines of top Flash game: "Age of War." Almost everything works in the game: spawning units, the HUD for the game, and even base health. Unfortunately, I can't seem to figure out how to implement the ability for units to attack enemies or the enemy base. Here is the concepts going on for the units themselves:

  • The unit spawns on a keypress around the team's base: K_1 spawns a sprite from the Red_Infantry class
  • The unit, when spawned, is added to a Group class. There are two Groups, one for each team.
  • The unit moves via a move_ip call within a def update until it reaches a point close to the enemy base, where it stops.

Here is how I want combat to go for the different units:

  • The unit stops whenever it spots an enemy within it's attack range. Different units have different attack ranges
  • The unit then attacks in one-second intervals.
  • If the unit sucessfully reduces the enemy unit's health to 0, the enemy dies, and the other may continue
  • This cycle repeats until the unit reaches the enemy base, where it will then attack the enemy base on one-second intervals. One of the units will be able to deal triple the normal damage to the base.

Here is a sample of my code, showing the Red_Infantry class:

class Red_Infantry(pygame.sprite.Sprite):
def __init__(self, screen):
    pygame.sprite.Sprite.__init__(self)
    self.image, self.rect = load_image('Soldier_red.png', -1)
    self.rect.move_ip(random.randint(75, 100), random.randint(275, 325))
    self.selected = 0
    self.area = screen.get_rect()
    self.health = 100 #Soldiers are have mediocre toughness.
    self.attack_damage = 25 #The amount of damage it deals
    self.range = 20 #The attack range of the unit.
    self.update()
def update(self):
    self.rect.move_ip(1, 0)
    if self.rect.right >= 725: #This position is close to the enemy base...
        self.rect.right = 725 #...where it will then stop
    if self.health <= 0:  
        self.kill() #a simple code that kills the sprite if his health reaches 0

The main loop only contains the ability to spawn each of the units.


Solution

  • Here's a starting point

    class RedInfantry(pygame.sprite.Sprite):
        def __init__(self):
            self.screen = pygame.display.get_surface()
            self.image, self.rect = load_image('Soldier_red.png', -1)    
            self.rect.move_ip(random.randint(75, 100), random.randint(275, 325))
            self.target = None
            self.range = 20
            self.attack_cooldown = 200
            self.attack_last = 0
    
        def move_toward(self, target):
            # move toward players click destination, if one is set.
            # else toward my attack target
    
        def update(self):
            # move...
            self.find_target()
            self.move_toward(self.target)
            self.attack()
            # check HP
            if self.health <= 0:
                self.kill()
    
        def find_target(self):
            """finds new targets in range:
            for speed: only call this once every 200ms."""
            if self.target is not None: return
            for enemy in B.sprites():
                if distance(self.rect.center, enemy.rect.center) <= self.range:
                    self.target = enemy
                    return
            # else no targets in range
            self.target = None  
    
    
        def attack(self):
            """attack, if able.
            target exists? still alive? gun cooldown good?"""
            if self.target is None: return
            if self.target.health <= 0: return
            if not self.cooldown_ready(): return
    
            # all good, fire. could verify still in range. 
            self.target.damage(self.attack_damage)
    
        def cooldown_ready(self):
            # gun ready to fire? has cooldown in MS elapsed.
            now = pygame.time.get_ticks()
            if now - self.attack_last >= self.attack_cooldown:
                self.attack_last = now
                return True
            return False