Путаница с координатами, фреймами и дочерними узлами в SpriteKit на iOS?
Я все еще играю с изучением SpriteKit в iOS и много читаю и много экспериментирую. Меня смущает кое-что еще, что я нашел* относительно координат, фреймов и дочерних узлов.
Рассмотрим этот фрагмент кода, в котором я пытаюсь нарисовать зеленую рамку вокруг моего космического спрайта для отладки:func addSpaceship()
{
let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
spaceship.name = "spaceship"
// VERSION 1
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
let debugFrame = SKShapeNode(rect: spaceship.frame)
debugFrame.strokeColor = SKColor.greenColor()
spaceship.addChild(debugFrame)
// VERSION 2
// spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
spaceship.setScale(0.50)
self.addChild(spaceship)
}
Если я добавлю к набору космический спрайт со строкой, помеченной" VERSION 1 " выше, я получу следующее:
Который является явно ошибся. Но если я закомментирую из строки, помеченной" VERSION 1 "выше, и вместо этого использую строку, помеченную "VERSION 2", я получу то, что хочу:
Обратите внимание, что фактический код для строк, помеченных Version 1 и Version 2, идентичен: космический корабль.позиция = CGPointMake (CGRectGetMidX (self.фрейм), CGRectGetMidY (self.кадр))
Так почему же это имеет значение, когда я устанавливаю положение космического спрайта?По моему образу мыслей, положение космического корабля спрайт не имеет отношения к размещению отладочного фрейма, потому что отладочный фрейм является дочерним по отношению к космическому спрайту и, следовательно, его координаты должны быть относительно фрейма космического спрайта-верно?
Спасибо WM
*это несколько связано с вопросом, который я задал вчера:
В SpriteKit на iOS масштабирование текстурированного спрайта создает неверный кадр?
Но а) я понимаю, что один теперь, и Б) это другой достаточно, что он заслуживает своего собственного вопрос.
Обновление:
Хммм-спасибо, ребята за идеи ниже, но я все еще не понимаю, и, возможно, это поможет.
Я изменил свой код, чтобы распечатать релавантные позиции и кадры:
func addSpaceship()
{
let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png")
spaceship.name = "spaceship"
println("Spaceship0 Pos (spaceship.position) Frame = (spaceship.frame)")
// VERSION 1 (WRONG)
spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
println("Spaceship1 Pos (spaceship.position) Frame = (spaceship.frame)")
let debugFrame = SKShapeNode(rect: spaceship.frame)
println("DEBUG Pos (debugFrame.position) Frame = (debugFrame.frame)")
debugFrame.strokeColor = SKColor.greenColor()
spaceship.addChild(debugFrame)
// VERSION 2 (RIGHT)
// spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
// println("Spaceship2 Pos (spaceship.position) Frame = (spaceship.frame)")
spaceship.setScale(0.50)
self.addChild(spaceship)
}
Затем я запустил его в обе стороны и получил эти результаты. Поскольку я понимаю версию 2, Давайте начнем с нее.
Запуск с кодом " VERSION 2 (RIGHT)", я получил:
Spaceship0 Pos (0.0,0.0) Frame = (-159.0,-300.0,318.0,600.0)
DEBUG Pos (0.0,0.0) Frame = (-159.5,-300.5,319.0,601.0)
Spaceship2 Pos (384.0,512.0) Frame = (225.0,212.0,318.0,600.0)
Узел космического корабля по умолчанию начинается с его позиции в левом нижнем углу экрана. экран (Spaceship0). Его кадр также выражается в терминах его якорной точки (центра), установленной в левом нижнем углу экрана, следовательно, отрицательные числа для начала его кадра rect.
Затем создается отладочный фрейм, положение которого по умолчанию равно 0, 0, и его фрейм должен быть таким же, как у космического корабля.
Затем код (Spaceship2) перемещает узел космического корабля в положение в координатах вида (384.0,512.0), а начало координат его кадра перемещается путем добавления нового положение к старому началу координат (то есть 384 + -159 = 225).
Все хорошо.
К сожалению, я все еще не получаю версию 1.
Когда я запускаю код" VERSION 1 (WRONG)", я получаю
Spaceship0 Pos (0.0,0.0) Frame = (-159.0,-300.0,318.0,600.0)
Spaceship1 Pos (384.0,512.0) Frame = (225.0,212.0,318.0,600.0)
DEBUG Pos (0.0,0.0) Frame = (0.0,0.0,543.5,812.5)
Как и выше, узел космического корабля по умолчанию запускается с его позиции в левом нижнем углу экрана (Spaceship0). Его кадр также выражается в терминах его якорной точки (центра), установленной в левом нижнем углу экрана, следовательно, отрицательные числа для начала его кадра прямоугольник.
Код (Spaceship1) затем перемещает узел космического корабля в положение в координатах вида (384.0,512.0), а начало координат его кадра перемещается путем добавления нового положения к старому началу координат (т. е. 384 + -159 = 225).Затем создается отладочный фрейм, положение которого по умолчанию равно 0, 0, а его фрейм имеет странную ширину (543,5) и странную высоту (812,5). Так как я инициализирую отладочный фрейм.кадр с космическим кораблем.frame (я думаю вот что по умолчанию инициализатор делает), я ожидал бы новый debugFrame.рама должна быть такой же, как у космического корабля - но это не так! Значения ширины и высоты отладочного кадра, по-видимому, получаются из добавления фактической ширины и высоты к исходному кадру узла космического корабля (543.5 = 225 + 318.5). Но если это так, то почему начало координат кадра t все еще 0, 0 и не то же самое сложение (225.0 + 0 = 225.0)???
Я не понимаю.
3 ответа:
Вы создаете узел формы, используя фрейм спрайта, который находится в координатах сцены. Поскольку фигура будет дочерним элементом спрайта, вы должны создать узел в координатах спрайта. Например, если вы создадите
SKShapeNode
с размером космического корабляlet debugFrame = SKShapeNode(rectOfSize: spaceship.size)
Вместо того, чтобы использовать каркас космического корабля,
debugFrame
будет центрироваться на космическом корабле независимо от того, когда вы устанавливаете положение корабля. Кроме того,debugFrame
будет масштабироваться/двигаться соответственно с кораблем.
В ответ на ваше "я не понимаю". Ваш код в порядке, но имеет логическую проблему. "Кадр" подсчитывается относительно родительских координат. Пожалуйста, поймите, что родитель космического корабля и родитель окна отладки отличаются в вашем коде.
Два способа решить вашу проблему:
- Добавьте нулевое смещение для окна отладки и используйте космический корабль в качестве родителя. Преимущество этого заключается в том, что окно отладки будет перемещаться, масштабироваться вместе с космический корабль:
let rectDebug = CGRectMake( 0, 0, spaceship.frame.size.width, spaceship.frame.size.height) let debugFrame = SKShapeNode(rect:rectDebug) spaceship.addChild(debugFrame)
- Добавьте окно отладки с координатами космического корабля 'frame' к родительскому объекту космического корабля (который является 'self'). Недостатком этого, является то, что вам придется перемещать, масштабировать окно отладки самостоятельно в коде, так как оно не будет прикреплено к космическому кораблю.:
let debugFrame = SKShapeNode(rect:spaceship.frame) self.addChild(debugFrame)
Оба решения широко используются. Вы должны выбрать то, что лучше для вас в вашем случае. Могут возникнуть еще три проблемы:
1.В моем коде могут быть ошибки кода, я просто набрал их в веб-окне непосредственно без проверки синтаксиса xcode.
2.Точки привязки этих двух объектов могут быть разными. Поэтому для этого может потребоваться выравнивание в коде.
3.Следует также учитывать расположение объектов, чтобы эти объекты не были скрыты под другими объектами.
В ответ на проблему, которую вы пытаетесь решить, возможно, showPhysics поможет:
skView.showsFPS = YES; skView.showsNodeCount = YES; skView.showsPhysics = YES;
Это почти та же проблема, что и в другом вопросе, который вы упомянули.
frame
- это свойство, содержащее aposition
и Asize
. Оба они подвержены масштабированию узла-предка. Прочитайте раздел "узел применяет многие из своих свойств к своим потомкам" в https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Nodes/Nodes.html#//apple_ref/doc/uid/TP40013043-CH3-SW13Еще раз : никогда не применяйте масштабирование к узлу, никогда не перемещайте узел до того, как полностью построил свою иерархию, за исключением того, если вы хотите какой-то особый или странный эффект.