2

你好,堆栈溢出。你可能还记得我在我的 pygame 程序“Table Wars”中的单位生成问题。我决定将我的游戏范围改为即时战略而非回合制游戏。我希望这款游戏能够像顶级 Flash 游戏:“战争时代”那样玩。游戏中的几乎所有东西都可以正常工作:生成单位、游戏的 HUD,甚至是基础生命值。不幸的是,我似乎无法弄清楚如何实现单位攻击敌人或敌人基地的能力。以下是单位本身的概念:

  • 该单位在团队基地周围的按键上K_1生成:从Red_Infantry类中生成一个精灵
  • 该单位在生成时被添加到一个Group类中。有两个Groups,每个团队一个。
  • 该单位通过 amove_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

主循环仅包含生成每个单位的能力。

4

2 回答 2

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。)此外,如果没有某种修剪和优化,您也必须为每对友好/敌人组运行此代码块。现在,如果保证每个组都有一些恒定的几何形状,那么我们可以使计算成本便宜得多。但是,假设组没有固定的几何形状,那么我建议您考虑使用几何包来为您做很多工作。这些软件包非常强大且非常高效……而且其中很多也非常易于使用。可能有特定于 PyGame 的几何包......我现在想不出任何包。

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

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 库来帮助进行几何计算的一般想法。

如果您是游戏编程的新手,您可能还想研究使用四叉树作为修剪需要完成多少几何计算的方法。

于 2012-05-09T17:04:10.590 回答
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
于 2012-05-22T00:38:35.993 回答