[SpriteKit] 고양이 퍼즐 게임 만들기 day.01

Emily·2025년 6월 1일
1

GridPopGame

목록 보기
1/8
post-thumbnail
출처 https://developer.apple.com/documentation/spritekit/

나는 이번에 SpriteKit을 처음 들었다. 그게 iOS 개발자라고 할 수 있냐고 물으면 할 말 없다. 하여튼 이걸 공부하게 되었는데.. 0 상태에서 혼자 시작하려니 막막하다. 영어로 공부해야 한다는 번거로움은 덤이다. 그래서 내가 제일 좋아하는 무작정 따라 만들어보면서 체득하기 방법으로 해보려 한다. 유튜브에 퍼즐 게임 만드는 영상이 있길래 따라 만들어보면서 공부하는 과정을 포스팅으로 담아보려 한다.

그래도 공식문서조차 안보고 시작하는 건 좀 아닌 거 같아서 들어가보았다.

SpriteKit

Sprite일까? 싶었다. 영영사전에 나오는 정의는 이렇다.

a computer graphic which may be moved on-screen and otherwise manipulated as a single entity

컴퓨터 그래픽이나 게임 개발에서 사용하는 특정 개념으로, 스프라이트라고 영어 단어 그대로 용어로 쓰이는 경우가 많다고 한다. 나는 겜알못에다가 게임 개발 쪽에도 문외한이다 보니 처음 들어본 개념이었다. 그래픽 객체, 화면 객체, 애니메이션 요소 정도의 느낌인 것 같다.

공식문서에 따르면, SpriteKit은 2D 게임 및 그래픽 개발을 위해 애플이 제공하는 프레임워크다. iOS, macOS, watchOS, tvOS, visionOS 환경에서의 게임을 개발하는 데 사용하며, GameplayKitSceneKit과 같은 프레임워크와 잘 통합된다.

2차원에서의 도형, 입자, 텍스트, 이미지, 비디오를 그리기 위한 범용 프레임워크로써, Metal을 활용하여 고성능 렌더링을 구현한다. (여기서 Metal은 나도 처음 들어봤는데 애플이 제공하는 저수준 그래픽 계산 API라고 한다) 또, 간단한 프로그래밍 인터페이스를 통해 게임 및 그래픽 요소를 쉽게 만들 수 있다.

이제 SpriteKit의 주요 클래스들을 살펴보겠다.

SKScene

An object that organizes all of the active SpriteKit content.

SpriteKit의 근본적인 요소라고 할 수 있다. 실제로 고양이 퍼즐 게임을 만들어보니 코드의 90% 정도가 SKScene 클래스에 들어가있었다.

이름 그대로 scene(장면)을 만드는 데 사용한다. 씬은 SKNode로 만드는 node들의 root node다. (잘 모르지만 자료구조 트리 개념인 느낌이 든다) 노드들은 씬의 애니메이션이나 렌더링을 구성하는 요소들을 제공한다. 참고로, SKSceneSKNode의 서브 클래스인 SKEffectNode를 상속한다.

씬을 화면에 띄우기 위해서는 SKViewSKRenderer, WKInterfaceSKScene (WatchOS 용)를 통해야 한다.

나는 이번 실습에 SwiftUI를 사용하는데, SwiftUI에서는 SpriteView(scene:)를 통해 scene을 띄울 수 있다.

struct ContentView: View {
    
    var scene: SKScene = GameScene()
    
    var body: some View {
        SpriteView(scene: scene)
            .ignoresSafeArea()
    }
}

SKView

A view subclass that renders a SpriteKit scene.

UIKit에서 scene을 화면에 표시하는 데 사용한다. presentScene(_:) 메소드를 호출하면 된다.

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let containerView: SKView = SKView(frame: view.bounds)
        containerView.presentScene(GameScene())
        view.addSubview(containerView)
    }
}

SKViewscene을 표시할 때 scene은 2가지 작업을 반복 수행한다.

  1. 씬의 콘텐츠 애니메이션화
  2. 화면에 콘텐츠를 렌더링하여 표시

scene을 일시정지 하기 위해서는 SKViewisPaused 속성을 true로 설정하여 두 작업을 중단시키면 된다. (쉬운 말로 게임을 일시정지하거나 특정 장면의 애니메이션을 멈추고 싶을 때 사용한다고 한다)

SKNode

The base class of all SpriteKit nodes.

위에서 SKScene 또한 노드에 속한다고 말한 바 있다. 노드는 SpriteKit의 모든 화면 요소라고 보면 될 거 같다. 모든 시각적, 논리적 객체는 SKNode를 상속한다.

UIKit으로 따지면 UIView 느낌? SKNode에 속한 서브클래스들은 UIView의 서브클래스인 뷰 컴포넌트들인 셈이다. (이건 내가 편의상 이해한 방식이고 공식문서에 나오는 표현은 아니다) 다만 단순히 화면을 그리는 요소 뿐만 아니라 효과를 내는 요소들도 있다. (ex. SKEmitterNode : 입자 효과(불꽃, 연기, 비 등)를 만들 때 사용)

https://developer.apple.com/documentation/spritekit/nodes-for-scene-building

공식문서에 들어가보면 여러가지 노드 종류를 볼 수 있다. 고양이 퍼즐 게임에서는 이미지를 그리는 노드인 SKSpriteNode를 주로 사용했다.

SKTexture

An image, decoded on the GPU, that can be used to render various SpriteKit objects.

SKTexture는 이미지 데이터를 GPU에 효율적으로 로드하고, 렌더링 시 사용하는 객체다. SKSpriteNode와 같은 노드가 화면에 이미지를 표시하려면 SKTexture가 필요하다. SKTexture는 이 이미지 데이터를 관리한다.

let texture = SKTexture(imageNamed: "cheese")
let cheeseNode = SKSpriteNode(texture: texture)

SKAction

An object that is run by a node to change its structure or content.

액션. 쉽게 말해 애니메이션이다. 노드의 애니메이션 및 동작을 정의한다. 이동하기, 회전하기, 크기 변경 효과, 페이드 효과, 소리 재생 등을 생성하고 실행할 수 있다.

let moveAction = SKAction.move(to: CGPoint(x: 100, y: 100), duration: 2.0)
node.run(moveAction)

솔직히 아무리 말로 해도 와닿지가 않는다. 만들면서 실감해보자.

01) 게임 소개 및 준비물

출처 - https://youtu.be/lYgipMRr7ws?si=k9tk3iYBI1MRFyLc

일단 내가 따라 만들기로 한 게임은 이렇게 생겼다. 똑같은 애들끼리 뭉쳐있는 부분을 눌러서 없애는 게임이다. 이미지 제공이 안되기도 하고, 나는 좀더 귀엽게 만들고 싶어서 지피티를 활용해 따로 이미지를 생성하여 프로젝트에 사용했다.

귀엽죠?

02) 배경 이미지 적용하기

SKScene 클래스의 메소드들 중 didMove를 활용한다. didMovesceneview에 의해 띄워졌을 때 호출되는 함수다. 이 시점에 배경화면 이미지 노드를 만들어 씬에 addChild를 해주면 된다. (UIKit에서 addSubview하던 게 생각났다)

  • 이 때 중요한 게 있는데, 씬의 size를 지정해주는 것이다. 기본값이 zero기 때문에 이걸 안해주면 아무리 노드를 열심히 만들어서 넣어도 화면에 나오지가 않는다. (이걸로 트러블 겪음)
class GameScene: SKScene {
	override func didMove(to view: SKView) {
    	// scene 크기를 view의 크기와 똑같이 지정 (화면을 꽉 채울 거니까)
        self.size = view.bounds.size
    
    	// 배경화면 이미지 노드 생성
        let background = SKSpriteNode(imageNamed: "background")
        
        background.position = CGPoint(x: size.width / 2, y: size.height / 2)
        background.zPosition = -1	// 다른 노드들보다 뒤에 위치하기 위함
        background.size = size		// 노드 크기를 scene 크기와 같게 지정
        
        addChild(background)
    }
}
  • 또 알아야 할 게 있다. SpriteKit에서 (0, 0) 좌표의 위치는 bottom-leading이다. (UIKit에서는 top-leading이던 것과 비교된다.)
  • 노드의 기본 anchor point는 스스로의 중심점이다. (가장자리가 아니다) 그래서 position을 지정할 때 size의 절반 만큼 더 이동시켜준 것이다.

(0, 0)으로 position 했을 때 화면

(width / 2, height / 2)로 position 했을 때 화면

배경 하나 넣는 데도 트러블을 겪으며 SKSceneSKSpriteNode에 대해 몇가지를 깨달았다. 역시 나는 직접 만들면서 배우는 게 잘 맞는다. 다음엔 고양이가 등장할 것이다.

profile
iOS Junior Developer

0개의 댓글