누른 고양이가 주변의 같은 색깔 고양이들과 함께 사라지면, 그 자리를 위에 있는 고양이들을 내려 채우고 사라진 고양이 수만큼 새로 노드들을 생성하여 그리드를 꽉 채울 것이다.
우선, 고양이가 사라진 자리에 위에 있던 고양이들을 내리면서 빈자리를 채우도록 구현한다. 고양이 위치를 조절하기 위해서는 2차원배열인 columns
의 index 값을 활용해야 하기 때문에, day.03
에서 만들었던 removeMatches()
메소드에 columns
에서도 item
을 삭제하는 작업을 추가한다.
class GameScene: SKScene {
private var columns: [[Item]] = []
func removeMatches() {
guard matchedItems.count > 1 else { return }
// columns에서 item을 삭제하기 위해 row index가 큰 순으로 정렬한다. (앞에서부터 삭제하게 되면 index가 꼬이기 때문)
let sortedMatches = matchedItems.sorted { $0.row > $1.row }
for item in sortedMatches {
columns[item.column].remove(at: item.row)
item.removeFromParent()
}
}
}
columns[n]의 index
를 item.row
에 할당한 뒤 positionItem
메소드를 호출하여 노드의 위치를 변경한다. 이 때, SKAction
을 사용하여 애니메이션을 적용한다.
func moveDown() {
for (columnIndex, column) in columns.enumerated() {
for (rowIndex, item) in column.enumerated() {
// item에 바뀐 row index 적용
item.row = rowIndex
// 바뀐 row로 이동하는 애니메이션 적용
let downAction = SKAction.move(to: positionItem(for: item), duration: 0.3)
item.run(downAction)
}
}
}
move down action이 적용된 모습
func moveDown() {
for (columnIndex, column) in columns.enumerated() {
for (rowIndex, item) in column.enumerated() {
// ... //
}
// while 반복문을 통해 column의 count가 채워질 때까지 createItem
while columns[columnIndex].count < itemsPerRow {
let item = createItem(column: columnIndex, row: columns[columnIndex].count)
columns[columnIndex].append(item)
}
}
}
createItem
에 Bool
타입의 매개변수를 추가하여 애니메이션이 필요한 경우와 아닌 경우를 분기한다.func createItem(column: Int, row: Int) -> Item {
let itemImages = Items.allCases.map { $0.imageName }
let itemImage = itemImages[GKRandomSource.sharedRandom().nextInt(upperBound: itemImages.count)]
let item = Item(imageNamed: itemImage, column: column, row: row)
item.name = itemImage
item.position = positionItem(for: item) // <<< 분기될 부분
item.size = CGSize(width: itemSize, height: itemSize)
addChild(item)
return item
}
func createItem(column: Int, row: Int, startOffScreen: Bool = false) -> Item {
let itemImages = Items.allCases.map { $0.imageName }
let itemImage = itemImages[GKRandomSource.sharedRandom().nextInt(upperBound: itemImages.count)]
let item = Item(imageNamed: itemImage, column: column, row: row)
item.name = itemImage
if startOffScreen {
// 고양이 보충 시
let finalPosition = positionItem(for: item)
item.position = finalPosition
// 출발은 화면 맨 위에서 해야하기 때문에 y값 추가
item.position.y += (itemSize * CGFloat(itemsPerColumn))
// 애니메이션 적용
let downAction = SKAction.move(to: finalPosition, duration: 0.4)
item.run(downAction)
} else {
// grid 최초 생성 시 - no animation
item.position = positionItem(for: item)
}
item.size = CGSize(width: itemSize, height: itemSize)
addChild(item)
return item
}
이 챕터를 통해 SpriteKit
에서의 애니메이션인 SKAction
을 경험할 수 있었다. 다음에는 SKLabelNode
를 사용하여 점수와 이동 수 레이블을 추가할 것이다.