Два спрайта замечают друг друга
Привет еще раз Переполнение стека. вы, вероятно, помните меня по проблеме порождения моего подразделения в моей программе pygame "Table Wars". Я решил изменить сферу своей игры на стратегию в реальном времени, а не на пошаговую игру. Я хочу, чтобы игра шла в русле топовой флеш игры: "Age of War". В игре работает практически все: нерестовые юниты, HUD для игры и даже базовое здоровье. К сожалению, я не могу понять, как реализовать способность юнитов атаковать врагов или вражескую базу. Вот концепции, которые применяются к самим подразделениям:
- Подразделение появляется при нажатии клавиши вокруг базы команды:
K_1
порождает спрайт изRed_Infantry
учебный класс - Единица, когда появляется, добавляется к
Group
учебный класс. Есть дваGroup
s, по одному на каждую команду. - Устройство движется через
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 ответа
Вот отправная точка
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
Из вашего вопроса не совсем понятно, как группы взаимодействуют друг с другом для выявления. Далее я собираюсь предположить, что Группа A "замечает" Группу B, если какой-либо член a из A находится в некотором указанном диапазоне любого члена b из 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
Обратите внимание, что я не тестировал приведенный выше код... это только для демонстрации общей идеи использования библиотеки shapely для помощи в вычислениях геометрии.
Если вы новичок в программировании игр, вам также может понадобиться использовать дерево квадратов в качестве средства сокращения объема вычислений геометрии.