SKNode를 이름으로 찾기

SKNode의 트리탐색

씬의 노드트리에서 어떤 노드를 탐색하고 특정하는 일이 종종 필요한데, 상위 노드에 대한 참조만 가지고 하위 노드를 찾기 위해서는 각 노드에 미리 이름을 부여하는 것이 필요하다. 노드의 .name 프로퍼티는 노드의 이름을 저장하며 알파벳과 숫자로만 이루어지며 공백이나 구두점등은 포함해서는 안된다.

노드의 이름은 중복되어도 상관없다.

playerNode.name = "player"
monsterNode1.name = "goblin"
monsterNode2.name = "ogre"

위 예에서 게임에 등장하는 고블린이 여러마리라면 이 고블린 노드의 이름은 제각각 유니크하기가 힘들것이며, "goblin"이라는 공통의 이름을 갖게 된다. 하지만 플레이어 캐릭터는 게임내에서 유니크하므로 다른 노드와 이름이 중복되지 않아야 한다.

노드 이름이 요긴하게 쓰이는 경우는 다음과 같은 경우가 있다.

  • 두 노드가 충돌/접촉했을 때, 델리게이트에서는 두 오브젝트를 받게 된다. 이 때 두 오브젝트 A, B 중 어느것이 비행기이고 어느것이 미사일인지 구분하는 것은 이름을 통해서 구분하는 것이 가장 쉽다.
  • 특정한 이름을 갖는 노드를 찾을 수 있다.SKNode 클래스는 이름과 관련된 다음의 메소드들을 제공한다.
    • childNode(withName:)은 매치되는 이름을 갖는 첫번째 노드를 리턴한다. 이는 보통 유니크한 이름을 갖는 노드를 찾을 때 사용한다.
    • enumerateChildNodes(withName:using:)은 매치되는 이름을 갖는 노드들을 순회한다. 이는 중복된 이름을 갖는 노드를 찾을 때 사용한다.
    • subscript(_:) 역시 매치되는 노드의 배열을 얻을 때 사용한다.
var playerNode: SKNode? { return childNode(withName:"player") }

고급 검색

기본적인 탐색은 주어진 이름 문자열과 동일한 이름을 갖는 서브 노드를 탐색하는데 쓰인다. 하지만 SpriteKit은 고급 검색을 수행할 수 있는 보다 표현적인 탐색 문법을 제공한다. 예를 들어 특정 노드의 전체 자식 노드 중 특정 패턴을 만족하는 노드를 찾는 것이 가능하다.

/ : 부모-자식 관계의 구분자이다. 패턴의 맨 앞에 위치하면 루트 노드에서 출발하여 탐색하고, 그외의 경우에는 /의 왼쪽에 있는 부모노드의 자식 노드에 대해서 탐색한다.
// : 재귀 탐색을 수행한다. 즉 자식의 자식, 자식의 자식의 자식으로 트리의 끝까지 모두 탐색한다.
.: 현재 노드를 말한다.
.. : 현재 노드의 부모노드를 말한다.
*: 0개 이상의 글자에 매치한다.
[ ]: 컴마나 대쉬로 구분된 단어 들 중 하나에 매치할 수 있다.
알파뉴머릭: 이름에 매치하는 패턴이다.

다음은 패턴을 사용한 탐색의 예제이다.

  1. MyName: MyName이라는 이름과 일치하는 노드
  2. /MyName: 노드의 직계 자식 중에서 이름이 MyName과 일치하는 노드
  3. //MyName: 노드의 자손 전체 중에서 이름이 MyName과 일치하는 노드
  4. .//MyName: 현재 노드의 전체 자손 중에서 이름이 MyName과 일치하는 노드
  5. //Myname/..: 전체 노드 중에서 이름이 MyName과 일치하는 자식을 갖고 있는 부모 노드
  6. //*: 현재 트리의 모든 노드
  7. A[0-9]: 현재 노드의 자식 중에서 이름이 A0, A1, A2…, A9인 노드들 중 하나
  8. Abby/Normal: 현재 노드의 자식 중에서 Abby와 일치하는 노드의 자식 중에서 다시 이름이 Normal인 노드
  9. //Abby/Normal: 전체 노드 중에서 Abby라는 노드를 부모로 갖는 Normal이라는 이름의 노드

https://medium.com/swift-programming/build-tic-tac-toe-with-ai-using-swift-25c5cd3085c9#.vujee1siu

다음은 틱택토 게임을 구현하는 코드 예제 중의 일부이다. SKScene의 오버라이드인데, SKSceneSKNode의 서브 클래스 중 하나라는 점을 상기하자.


override func didMove(to view: SKView) {
    /// 이름이 "grid"로 시작하는 모든 노드에 대해서 순회한다.
    /// 
    self.enumerateChildNodes(withName: "//grid*") { (node, stop) in
        if let node = node as? SKSpriteNode {
            node.color = UIColor.clear()
        }
    }
    /// ...
}