Путаница с координатами, фреймами и дочерними узлами в 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 " выше, я получу следующее:

Версия 1

Который является явно ошибся. Но если я закомментирую из строки, помеченной" VERSION 1 "выше, и вместо этого использую строку, помеченную "VERSION 2", я получу то, что хочу:

Версия 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 7

3 ответа:

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

let debugFrame = SKShapeNode(rectOfSize: spaceship.size)

Вместо того, чтобы использовать каркас космического корабля, debugFrame будет центрироваться на космическом корабле независимо от того, когда вы устанавливаете положение корабля. Кроме того, debugFrame будет масштабироваться/двигаться соответственно с кораблем.

В ответ на ваше "я не понимаю". Ваш код в порядке, но имеет логическую проблему. "Кадр" подсчитывается относительно родительских координат. Пожалуйста, поймите, что родитель космического корабля и родитель окна отладки отличаются в вашем коде.

Два способа решить вашу проблему:

  1. Добавьте нулевое смещение для окна отладки и используйте космический корабль в качестве родителя. Преимущество этого заключается в том, что окно отладки будет перемещаться, масштабироваться вместе с космический корабль: let rectDebug = CGRectMake( 0, 0, spaceship.frame.size.width, spaceship.frame.size.height) let debugFrame = SKShapeNode(rect:rectDebug) spaceship.addChild(debugFrame)
  2. Добавьте окно отладки с координатами космического корабля '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 - это свойство, содержащее a position и A size. Оба они подвержены масштабированию узла-предка. Прочитайте раздел "узел применяет многие из своих свойств к своим потомкам" в https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Nodes/Nodes.html#//apple_ref/doc/uid/TP40013043-CH3-SW13

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