Враг получает множественный урон - Swift, Xcode 8.2.1

Я нахожусь в процессе создания игры в стиле космических захватчиков и хотел бы сделать так, чтобы во врага нужно было попасть три раза, прежде чем он взорвется.

В учебнике, который я использую, показано, как заставить врагов взорваться после одного удара. Он использует функцию под названием didBegin(_ contact: SKPhysicsContact)

https://www.youtube.com/watch?v=F0kcw6eryJs&t=617s

Насколько я понимаю, эта функция оценивает каждый случай контакта, назначает двум телам две разные роли, а затем решает, что делать с каждым телом. Я предполагаю, что если враг получит три удара, будет использоваться переменная, содержащая его оставшееся здоровье. Затем при каждом контакте переменная будет уменьшаться на единицу, пока, если она не станет равной нулю, враг не будет удален.

Однако в этом есть глубокая проблема. Поскольку didBegin(_ contact: SKPhysicsContact) оценивает только один экземпляр контакта, ему ничего не известно о других предыдущих случаях контакта. По сути, когда враг получает удар, невозможно узнать, был ли он поражен раньше, вообще не был поражен или был поражен слишком много раз. Если бы был только один враг, я мог бы использовать одну переменную для отслеживания его здоровья. Однако это не так, поскольку на экране одновременно находится несколько врагов, и каждый раз, когда происходит контакт, невозможно узнать, был ли предыдущий удар по этому врагу или другому врагу.

Если на экране есть один враг, это просто, потому что каждый раз, когда происходит контакт, это должен быть один враг. Но если на экране несколько сущностей, то невозможно узнать, к какому врагу относится контакт.

Я считаю, что это потребует какой-то идентификации для каждого экземпляра врага, хотя я не знаю, как это сделать. Тем из вас, кто читает, большое спасибо за то, что зашли, и я очень благодарен, если вы можете помочь.


person cTem    schedule 06.06.2018    source источник


Ответы (2)


Нет необходимости вести отдельные словари для отслеживания состояний спрайта.

У каждого SKNode есть userData, и с его помощью вы можете отслеживать жизнь врагов

Пример:

let invader = SKSpriteNode(imageNamed:"invader")
invader.userData = ["health":3]

...


func didBeginContact(...)
{
...
  //when a contact happens
    contact.body_.node.userData["health"] -= 1
...
}

Теперь имейте в виду, что 1 пуля может поразить 1 врага два раза. Вы не хотите вызвать здесь 2 потери жизней, поэтому вам понадобится временная переменная (которую вы также можете сохранить в userData), которая позволит вам узнать, вступала ли конкретная пуля в контакт с захватчиком.

person Knight0fDragon    schedule 06.06.2018
comment
Большое спасибо за это! Мне было интересно, в func didBeginContact какое точное форматирование для вычета переменной здоровья? Когда вы ссылаетесь на body_, вы имеете в виду bodyA или bodyB, или я должен проверить оба, поскольку он говорит, что SKPhysicsContact не имеет тела члена. к тому же при попытке вычесть единицу выдает ошибку Binary operator '-=' cannot be applied to operands of type 'Any?' and 'Int'. Это сбивает с толку, так как кажется, что с типом Int можно работать. Еще раз большое спасибо за вашу помощь. - person cTem; 07.06.2018
comment
Body_ — это любое тело вашего захватчика. Категория расскажет вам об этом. - person Knight0fDragon; 07.06.2018

Вы абсолютно правы, вам как-то нужно самостоятельно отслеживать своих врагов и их здоровье. Вероятно, есть множество способов сделать это, но вот один из способов достижения того, к чему вы стремитесь:

Используйте словарь врагов с их здоровьем. Каждому врагу будет присвоен какой-либо идентификатор для его идентификации. Здоровье может быть представлено как Int. Этот словарь также можно использовать, чтобы легко определить, сколько врагов все еще вокруг.

var enemyHealth = [String:Int]()

Узлы имеют свойство имени, которому можно присвоить любое строковое значение. Вот как вы сможете идентифицировать свои узлы. При создании врага вы создаете идентификатор (например, генерируете случайное число), устанавливаете имя узла в качестве идентификатора и добавляете врага в словарь enemyHealth со значением здоровья по умолчанию.

let enemyNode = SKSpriteNode(color: UIColor.white, size: CGSize.zero)
let enemyId = "\(arc4random())"
enemyNode.name = enemyId
enemyHealth[enemyId] = 10
...

В didBegin(_ contact: SKPhysicsContact) вы можете получить доступ к участвующим в столкновении узлам, используя контактный параметр функции (contact.bodyA.node или contact.bodyB.node). Сравнив имена узлов с ключами в enemyHealth, можно выяснить, какое тело столкновения было противником и какое у него здоровье.

let enemy:SKSpriteNode

if enemyHealth.keys.contains(contact.bodyA.node?.name ?? "") {
    enemy = contact.bodyA.node as! SKSpriteNode

} else if enemyHealth.keys.contains(contact.bodyB.node?.name ?? "") {
    enemy = contact.bodyB.node as! SKSpriteNode
} else {
    return  //none of the collision partners are an enemy
}

let health = enemyHealth[enemy.name!]!
...

Теперь вы можете делать с противником все, что захотите. Когда враг убит/удален, также удалите его из словаря enemyHealth.

person Christoph    schedule 06.06.2018