两个精灵互相发现

时间:2012-05-09 15:44:07

标签: python pygame real-time-strategy

再次问好Stack Overflow。你可能还记得我在pygame程序中的单位产生问题,“桌上战争”。我决定将我的游戏范围改为实时策略而不是回合制游戏。我希望游戏能够与顶级Flash游戏一起发挥:“战争时代”。几乎所有东西都在游戏中起作用:产卵单位,游戏的HUD,甚至基础健康。不幸的是,我似乎无法弄清楚如何实现单位攻击敌人或敌人基地的能力。以下是单位本身的概念:

  • 该单位围绕团队基地产生一个按键:K_1Red_Infantry类产生一个精灵
  • 该单位在生成时会添加到Group课程中。有两个Group,每个团队一个。
  • 该单位通过move_ip内的def update呼叫移动,直到它到达靠近敌人基地的位置,然后停在那里。

以下是我希望战斗不同单位的方法:

  • 只要在攻击范围内发现敌人,该单位就会停止。不同的单位有不同的攻击范围
  • 然后该单位以一秒的间隔攻击。
  • 如果该单位成功地将敌方单位的生命值降低到0,则敌人死亡,另一个可以继续
  • 这个循环重复直到该单位到达敌人基地,然后它会以一秒的间隔攻击敌人基地。其中一个单位将能够对基地造成三倍的正常伤害。

以下是我的代码示例,显示了Red_Infantry类:

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

主循环只包含产生每个单位的能力。

2 个答案:

答案 0 :(得分:3)

从您的问题来看,并不完全清楚群体如何与每个群体互动以进行发现。在下文中,如果A的任何成员a在B的任何成员b的某个指定范围内,我将假设A组“发现”B组。

最简单的方法是迭代所有(a,b)对。为此,您可以使用itertools库,例如......

spotted = False
for a, b in itertools.product(A.sprites( ), B.sprites( )):
    if is_in_range(a, b):
        spotted = True
        break

这种方法的问题是计算成本相当高。 (它的复杂性是n ** 2.)此外,如果没有某种修剪和优化,你必须为每对友方/敌人组运行这段代码。现在,如果保证每个组具有一些恒定的几何形状,那么我们可以使计算MUCH的成本更便宜。但是,假设组没有固定的几何体,那么我建议您考虑使用几何包来为您完成大量工作。这些包非常强大且非常高效......而且它们中的很多也非常容易使用。可能有PyGame特有的几何包...我现在想不到任何东西。

我经常使用shapely package。如果我们使用匀称,那么确定在检测范围内的组的问题更像是......

import shapely
import shapely.geometry

#-- Build a polygon envelope around the members of the group.
pointsA = shapely.geometry.MultiPoint(map(lambda r: r.center, A.sprites( )))
pointsB = shapely.geometry.MultiPoint(map(lambda r: r.center, B.sprites( )))

#-- Ask shapely to give the minimum distance between the hulls that
#-- encompass the two groups.
distance = pointsA.convex_hull.distance(pointsB.convex_hull)

if distance < RANGE_OF_DETECTION:
   detected = True
else:
   detected = False

请注意,我还没有测试过上面的代码...它只是为了演示使用shapely库来帮助进行几何计算的一般想法。

如果您不熟悉游戏编程,您可能还希望使用四叉树作为修剪需要完成多少几何计算的方法。

答案 1 :(得分:1)

这是一个起点

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