2

こんにちは、StackOverflowです。おそらく、私のpygameプログラム「TableWars」でのユニットのスポーンの問題から私を覚えているでしょう。ゲームの範囲を、ターン制のゲームではなく、リアルタイム戦略に変更することにしました。私はゲームをトップのFlashゲーム「AgeofWar」に沿ってプレイしたいと思っています。スポーンユニット、ゲームのHUD、さらには基本ヘルスなど、ほとんどすべてがゲームで機能します。残念ながら、ユニットが敵や敵の基地を攻撃する能力を実装する方法を理解できないようです。ユニット自体で行われている概念は次のとおりです。

  • ユニットはチームのベースの周りのキーを押すとスポーンします:クラスK_1からスプライトをスポーンしますRed_Infantry
  • ユニットは、スポーンされるとGroupクラスに追加されます。Groupチームごとに1つずつ、合計2つあります。
  • ユニットは、敵の基地に近い地点に到達するまで、move_ipコールを介して移動し、そこで停止します。def update

これが私がさまざまなユニットのために戦闘を行う方法です:

  • ユニットは、攻撃範囲内の敵を見つけるたびに停止します。ユニットが異なれば攻撃範囲も異なります
  • その後、ユニットは1秒間隔で攻撃します。
  • ユニットが敵ユニットの体力を0に下げることに成功した場合、敵は死亡し、他のユニットは続行する可能性があります
  • このサイクルは、ユニットが敵の基地に到達するまで繰り返され、敵の基地に1秒間隔で攻撃します。ユニットの1つは、ベースに通常の3倍のダメージを与えることができます。

これが私のコードのサンプルで、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に固有のジオメトリパッケージがあるかもしれません...私は今のところ何も考えられません。

私はよく形の良いパッケージを使用します。形を整えて使用する場合、検出範囲内にあるグループを決定する問題は、次のようなものです...

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

上記のコードはテストしていないことに注意してください...これは、ジオメトリの計算を支援するためにシェイプリーライブラリを使用するという一般的な考え方を示すためだけのものです。

ゲームプログラミングに不慣れな場合は、実行する必要のあるジオメトリ計算の量を取り除く手段として、クワッドツリーの使用を検討することもできます。

于 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 に答える