Как обрабатывать z-позиции нескольких спрайтов, когда они перемещаются друг вокруг друга?
Я новичок в программировании на Swift. Я пытаюсь создать игру, в которой у меня есть куча спрайтов, которые случайно перемещаются по экрану. Допустим, у меня есть куча простых спрайтов 2D-изображений. Поскольку спрайт перемещается вверх (как в позиции y, увеличивается), я хочу, чтобы он, казалось, двигался дальше позади других спрайтов, поэтому я хочу, чтобы zPosition уменьшилось по сравнению с другими спрайтами. Как игры справляются с этим? Что если у меня на экране 100 спрайтов, которые все перемещаются случайным образом? У меня даже нет общего представления о том, как это делается, поэтому любая помощь будет высоко ценится.
Вторая более продвинутая концепция. Допустим, у каждого спрайта есть несколько слоев дочерних спрайтов, таких как руки, ноги, одежда, оружие и т. Д. (Мои спрайты очень настраиваемы.) Затем каждый спрайт перемещается случайным образом и должен отображаться в правильной позиции z, поскольку они движутся позади других. спрайты. Как сделать так, чтобы все руки, ноги, одежда и другие слои спрайтов правильно отображались спереди или позади каждого другого спрайта? Что если у меня есть спрайт с 20 слоями дочерних спрайтов, и он должен плавно перемещаться впереди и позади других спрайтов с 20 дочерними спрайтами? Возможно, это неправильное направление, но можно ли как-нибудь превратить один спрайт и его дочерние слои в один слой (или сделать все спрайты левой руки в один слой, а спрайты правой руки - в другой слой)? Я вижу игры, которые справляются с этим, но какова концепция того, как это обрабатывается? (Одна игра, которую я вижу, выполняет то, что я хочу, это Fallout Shelter, где у каждого человека есть руки, ноги, оружие и т. Д., И они идут впереди или позади других людей, и все спрайты отображаются в правильном порядке, но в отличие от Fallout Укрытие моей игры имеет полностью плоско выглядящие 2D-изображения, и я хочу, чтобы они остались.)
В третьих еще более продвинутая концепция. Что если бы я хотел, чтобы эти спрайты взаимодействовали друг с другом, как руки одного спрайта обхватывают другой спрайт (так что одна рука будет находиться за вторым человеком спрайта, но противоположная рука будет полностью перед другим человеком спрайта)? Как обрабатываются слои для отображения в правильном zPosition? Может быть, это невозможно? Хорошо, я сделал. Извините за размещение миллиона вопросов в одном посте. Я ищу концепцию этих вопросов, чтобы начать планирование и программирование. Спасибо за любую помощь.
1 ответ
1) По мере того, как спрайт перемещается вверх (как в позиции y, увеличивается), я хочу, чтобы он, казалось, двигался дальше позади других спрайтов, поэтому я хочу, чтобы zPosition уменьшилось по сравнению с другими спрайтами. Как игры справляются с этим?
Это можно просто сделать, создав собственный класс (я бы не рекомендовал расширять его) и переопределив zPosition, чтобы оно было обратным Y
НАПРИМЕР
class Player : SKSpriteNode
{
override var zPosition : CGFloat
{
get
{
//Yes it looks weird to be setting zPosition on get, but we want to ensure the variable storing zPosition is also changed in case any property reads it
super.zPosition = -super.position.y
return super.zPosition
}
set
{
//do nothing
}
}
}
2) Что если у меня есть 100 спрайтов на экране, которые все перемещаются случайным образом?
Переопределение этого будет обрабатывать каждый спрайт на экране (который имеет тип "Player" в моем примере), позиция y определяет zPosition
3) Как сделать так, чтобы все руки, ноги, одежда и другие слои спрайтов правильно отображались спереди или позади каждого другого спрайта? Теперь это становится немного сложнее. zPosition относительно его родителя, поэтому вам нужно будет учесть, сколько слоев в глубине ваш спрайт может получить zPosition, и планировать соответственно. Скажем, у нас есть спрайт с рубашками и поясом.
Если мы структурировали спрайт так:
тело
-> рубашка
-> брюки
-> ремень
Затем мы можем установить все zPositions в 0 из этих дочерних узлов, потому что порядок рендеринга будет использовать zPosition, за которым следует порядок дерева, и ничего не изменится:
Но если бы мы структурировали это так: body
-> рубашка
-> брюки
---> ремень
и мы хотим сделать так, чтобы рубашка находилась между брюками и поясом, тогда нам нужно было бы компенсировать это, установив zPosition в 1 для рубашки и пояса.
4) Что если у меня есть спрайт с 20 слоями дочерних спрайтов, и он должен плавно перемещаться впереди и позади других спрайтов с 20 дочерними спрайтами? Теперь у нас есть проблема с борьбой с другими спрайтами, поэтому нам нужно применить некоторую математику к нашей zPosition на Player, чтобы исправить это. Класс Player: SKSpriteNode {
override var zPosition : CGFloat
{
get
{
//Yes it looks weird to be setting zPosition on get, but we want to ensure the variable storing zPosition is also changed in case any property reads it
super.zPosition = -super.position.y * 2 //(We need at least 2 zPosition slots reserved for every sprite)
return super.zPosition
}
set
{
//do nothing
}
}
}
5) Но можно ли как-нибудь превратить один спрайт и его дочерние слои в один слой (или сделать все спрайты левой руки в один слой, а спрайты правой руки - в другой слой)? 6) Я вижу игры, которые справляются с этим, но какова концепция того, как это обрабатывается? Да, вы можете использовать
view.texture(from:)
преобразовать любой узел в текстуру, а затем создать новый спрайт из текстуры.7) Что если бы я хотел, чтобы эти спрайты взаимодействовали друг с другом, как руки одного спрайта, обхватывают другой спрайт (так что одна рука будет находиться за вторым человеком спрайта, но противоположная рука будет полностью перед другим человеком спрайта 8) Как слои обработано, чтобы появиться в правильном zPosition 9) Может быть, это не возможно?
Теперь эта часть становится хитрой, вместо умножения нам понадобится изменить все узлы zPosition.
Нам также необходимо вычислить абсолютную позицию каждого спрайта, чтобы узнать, где мы находимся на оси Y
Для этого у нас есть как минимум 3 варианта,
а) мы можем создать собственный протокол + пользовательские классы для каждого узла, который мы помещаем на сцену; б) можем написать расширения для типов узлов, которые мы размещаем на сцене (например, SKSpriteNode и SKShapeNode), за исключением SKNode, потому что это базовый узел класс с) мы можем сделать что-то под названием Наблюдение значения ключа, и мы должны слушать, когда position
изменения на спрайте. Причина, по которой нам нужно сделать KVO, заключается в том, что ваш спрайт может быть структурирован там, где у вас есть SKNodes, и мы не можем переопределить позицию по этому вопросу.
Все три из этих методов потребовали бы обширной работы и потребовали бы оптимизации, уникальной для вашей игровой среды, для эффективной работы, которую я не буду подробно описывать, как это сделать.