Home > 3D World & Physics

3D World & Physics

SpriteKit, SceneKit, CAEmitterLayer์„ ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์— ๋ชจ์•„ 2D/3D ์žฅ๋ฉด๊ณผ ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ์„ ๋น„๊ตํ•˜๋ฉฐ ๋ฐฐ์›๋‹ˆ๋‹ค.


์„น์…˜ ๊ตฌ์„ฑ

์„ธ ๊ฐ€์ง€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๊ฐ๊ฐ์˜ ์„น์…˜์œผ๋กœ ๊ตฌ๋ถ„ํ•ด ๊ฐ™์€ ๋ชจ๋“ˆ ์•ˆ์—์„œ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

SpriteKit Physics โ€” Gravity Balls

ํƒญ์œผ๋กœ ๊ณต์„ ๋–จ์–ด๋œจ๋ฆฌ๊ณ , ๋””๋ฐ”์ด์Šค ๊ธฐ์šธ๊ธฐ๋กœ ์ค‘๋ ฅ ๋ฐฉํ–ฅ์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค. SpriteKit์˜ ๋ฌผ๋ฆฌ์—”์ง„ + CoreMotion ํ†ตํ•ฉ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

3D World โ€” Solar System

ํƒœ์–‘๊ณผ 5๊ฐœ ํ–‰์„ฑ์˜ ๊ณต์ „, ๋‹ฌ์˜ ์ข…์† ๊ถค๋„, ์†๋„ ์Šฌ๋ผ์ด๋”๋ฅผ ํ†ตํ•œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜. SceneKit์˜ `SCNAction.rotateBy`์™€ ์ž์‹ ๋…ธ๋“œ ๊ณ„์ธต์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

Particle Effects โ€” Weather

๋ˆˆ/๋น„/๋ฒš๊ฝƒ ํŒŒํ‹ฐํด์„ segmented picker๋กœ ์ „ํ™˜. `CAEmitterLayer`์˜ `birthRate`, `velocity`, `spin` ์†์„ฑ ์กฐ์ ˆ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

Particle Effects โ€” Confetti

๋ฒ„ํŠผ ํŠธ๋ฆฌ๊ฑฐ ์ถ•ํ•˜ ์ดํŽ™ํŠธ, continuous ๋ชจ๋“œ ํ† ๊ธ€. 3D ํ…€๋ธ”๋ง ํšŒ์ „์„ ์œ„ํ•œ `spin` + `spinRange` ํ™œ์šฉ.


์™œ ์„ธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋ฌถ์—ˆ๋Š”๊ฐ€

๊ณตํ†ต์ : ์„ธ ํ”„๋ ˆ์ž„์›Œํฌ ๋ชจ๋‘ ๋ Œ๋”๋ง ๋ฃจํ”„๋ฅผ ๊ฐ€์ง„ ์ž์‹ ๋ทฐ๋ฅผ SwiftUI์— ๋‚ด์žฅํ•˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

Framework SwiftUI ํ†ตํ•ฉ ๋ Œ๋” ๋Œ€์ƒ
SpriteKit SpriteView(scene:) 2D ๋ฌผ๋ฆฌ ๋…ธ๋“œ
SceneKit SceneView(scene:) 3D ๊ธฐํ•˜์ฒด
CAEmitterLayer UIViewRepresentable 2D ํŒŒํ‹ฐํด

์ฐจ์ด์ : ๊ฐ์ž ๋‹ค๋ฅธ ๊ณ„์ธต์˜ ์ถ”์ƒํ™”๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค โ€” ๋ฌผ๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜(SpriteKit), 3D ์”ฌ ๊ทธ๋ž˜ํ”„(SceneKit), ๋‹จ์ˆœ ํŒŒํ‹ฐํด ๋ Œ๋”(CAEmitterLayer).


SpriteKit ํ•ต์‹ฌ API

import SpriteKit

class GravityScene: SKScene {
    override func didMove(to view: SKView) {
        physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
        physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with: UIEvent?) {
        guard let t = touches.first else { return }
        let ball = SKShapeNode(circleOfRadius: 20)
        ball.position = t.location(in: self)
        ball.physicsBody = SKPhysicsBody(circleOfRadius: 20)
        ball.physicsBody?.restitution = 0.6   // ํƒ„์„ฑ
        addChild(ball)
    }
}

์ฃผ์š” ๊ฐœ๋…: SKPhysicsBody (์ถฉ๋Œ/์งˆ๋Ÿ‰), physicsWorld.gravity (์ค‘๋ ฅ ๋ฒกํ„ฐ), SKAction (์„ ์–ธ์  ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œํ€€์Šค).


SceneKit ํ•ต์‹ฌ API

import SceneKit

let scene = SCNScene()
let sphere = SCNSphere(radius: 1.0)
sphere.firstMaterial?.diffuse.contents = UIColor.orange

let node = SCNNode(geometry: sphere)
node.position = SCNVector3(0, 0, -3)
scene.rootNode.addChildNode(node)

// Continuous rotation
let spin = SCNAction.rotateBy(x: 0, y: .pi * 2, z: 0, duration: 4)
node.runAction(SCNAction.repeatForever(spin))

์ฃผ์š” ๊ฐœ๋…: SCNScene (์”ฌ ๊ทธ๋ž˜ํ”„ ๋ฃจํŠธ), SCNNode (๊ณ„์ธต์  ํŠธ๋žœ์Šคํผ), SCNMaterial (์…ฐ์ด๋”ฉ ์†์„ฑ), SCNAction (์• ๋‹ˆ๋ฉ”์ด์…˜).


CAEmitterLayer ํ•ต์‹ฌ API

let emitter = CAEmitterLayer()
emitter.emitterShape = .line
emitter.emitterPosition = CGPoint(x: view.bounds.midX, y: 0)
emitter.emitterSize = CGSize(width: view.bounds.width, height: 1)

let cell = CAEmitterCell()
cell.contents = UIImage(systemName: "snowflake")?.cgImage
cell.birthRate = 10          // per second
cell.lifetime = 6
cell.velocity = 80
cell.velocityRange = 40
cell.yAcceleration = 20
cell.spinRange = .pi

emitter.emitterCells = [cell]
view.layer.addSublayer(emitter)

์ฃผ์š” ์†์„ฑ:


ํ•™์ƒ ํŒ

  1. SwiftUI @State vs Scene ๋‚ด๋ถ€ ์ƒํƒœ: SpriteKit/SceneKit ์”ฌ์€ SwiftUI์˜ relay๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์”ฌ์„ @State ํ”„๋กœํผํ‹ฐ๋กœ ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑํ•ด ์žฌ์‚ฌ์šฉํ•˜์„ธ์š”.
  2. ์„ฑ๋Šฅ: CAEmitterLayer๋Š” GPU ๊ฐ€์†์œผ๋กœ ์ˆ˜์ฒœ ๊ฐœ ํŒŒํ‹ฐํด๋„ ๋ฌด๋‚œํ•˜์ง€๋งŒ, SpriteKit์—์„œ ์ˆ˜๋ฐฑ ๊ฐœ ์ด์ƒ์˜ ๋ฌผ๋ฆฌ body๋Š” CPU ๋ณ‘๋ชฉ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ ํ•œ๊ณ„: SceneKit์˜ Metal ์…ฐ์ด๋” ๋ชจ๋””ํŒŒ์ด์–ด๋Š” ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค๊ธฐ๊ธฐ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  4. ์ขŒํ‘œ๊ณ„: SpriteKit์€ ์ขŒํ•˜๋‹จ ์›์ (UIKit๊ณผ ๋ฐ˜๋Œ€), SceneKit์€ ์šฐ์† ์ขŒํ‘œ๊ณ„ (Y ์œ„, Z ํ™”๋ฉด ์•ž), CAEmitterLayer๋Š” UIKit๊ณผ ๋™์ผํ•œ ์ขŒ์ƒ๋‹จ ์›์ ์ž…๋‹ˆ๋‹ค.