[๐งฉ Creative Coding] ์ปฌ๋ฌํํ ๋ฌผ๊ฒฐ ์จ์ด๋ธ ๋ง๋ค๊ธฐ(feat. Interactive Developer)
์๋ ํ์ธ์ Foma ๐ป ์ ๋๋ค!
์ค๋์ ์ ๋ฒ์ ์ค์ ๋งค๋ฌ๋ ค ํ๋ค๋ฆฌ๋ ์์ ๋ง๋ค๊ธฐ ์ ์ด์ด์ ์ธํฐ๋ํฐ๋ธ ๋๋ฒจ๋กํผ๋์ ํํ ๋ฆฌ์ผ ์์ง์ด๋ ์จ์ด๋ธ๋ฅผ
Swift๋ก ๊ตฌํํ ๊ฒ์ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํฉ๋๋ค!
๋ฐ๋ก ์์ํ ๊ฒ์~
์๋๋ ์ธํฐ๋ํฐ๋ธ ๋๋ฒจ๋กํผ ๊น์ข ๋ฏผ๋์ ํํ ๋ฆฌ์ผ ์์์ ๋๋ค.
Preview
1. S์ ๊ณก์ ๊ทธ๋ฆฌ๊ธฐ
S์ ๊ณก์ ์ ๊ทธ๋ฆฌ๊ธฐ ์ํด์ ์์๊ณผ ๋์ ์ ํด์ฃผ๊ณ ์ฌ์ด์ ๋ ์ ์ด ํ์ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ฌ์ด์ ์ ์ ์๋ก ๋น๊ธฐ๊ฑฐ๋ ์๋๋ก ๋น๊ฒจ์ฃผ๋ฉด ์๋์ ๊ฐ์ S์ ๊ณก์ ์ด ๊ทธ๋ ค์ง๋๋ค.
2. ์์ง์ด๋ ์จ์ด๋ธ ๋ง๋ค๊ธฐ
์ฐ๊ฒฐ๋ ์ ์ ์ฌ์ด ๋ ์ ์ ์ ์๋๋ก ์ด๋์ํค๋ฉด ์จ์ด๋ธ๊ฐ ์์ง์ด๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ฒ ์ฃ ?
3. ์ฌ๋ฌ ์จ์ด๋ธ ๋ง๋ค๊ธฐ
์ฐ์ ์์๊ณผ ๋์ ์๋์ ๊ฐ์ด ๋ ์ ์ผ๋ก ์ ํด์ค๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทธ ์ฌ์ด์ ์๋ ์ 4๊ฐ๋ฅผ 1,2,3,4๋ผ๊ณ ๋ถ๋ฅด๊ฒ ์ต๋๋ค.
์ฌ์ด์ ์ ๋ ๊ฐ๋ฅผ ์์๋ก ๊ณจ๋ผ ๊ณก์ ์ ๋ง๋ค์ด ์ค๋๋ค.
1๊ณผ 3์ผ๋ก ๊ณจ๋์ ๊ฒฝ์ฐ
2์ 4๋ก ๊ณจ๋์ ๊ฒฝ์ฐ
1๊ณผ 4๋ก ๊ณจ๋์ ๊ฒฝ์ฐ
์ฝ๋ ๊ตฌํ
Line
์ ์ ์ ์ ๊ทธ๋ฆด CAShapeLayer์ ์ฌ์ด ๋ ๊ฐ์ ์ p1,p2์ ์จ์ด๋ธ๋ฅผ ์ฑ์ธ ์์ ํ๋กํผํฐ๋ก ๊ฐ์ง๊ณ ์์ต๋๋ค.
import UIKit
struct Line {
let layer:CAShapeLayer
let p1:Int
let p2:Int
var color:UIColor
}
Point
์ ์ ํ์ฌ ์์น์ธ x์ y
์ ์ด ์ ์๋๋ก ์ด๋ํ๋๋ฐ ํ๊ณ๋ฅผ ์ ํด์ค max์ min
์๋ก ๊ฐ์ง ์๋๋ก ๊ฐ์ง๋ฅผ ์ ํด์ค addY๋ฅผ ํ๋กํผํฐ๋ก ๊ฐ์ง๊ณ ์์ต๋๋ค.
import UIKit
struct Point {
var x:CGFloat
var y:CGFloat
var max:CGFloat
var min:CGFloat
var addY:CGFloat
var center:CGPoint {
return CGPoint(x: x, y: y)
}
}
WaveView
WaveView์ ํ์ํ ํ๋กํผํฐ๋ ์๋์ ๊ฐ์ต๋๋ค.
class WaveView: UIView {
private var timer : Timer?
private var points:[Point] = []
private var lines:[Line] = []
private lazy var centerY:CGFloat = frame.height/2
private var lineCount:Int = 3
private var dotCount:Int = 4
private let colors:[UIColor] = [.systemPink,.systemBlue,.systemCyan,.systemMint,.systemTeal]
configure
ํ์ด๋จธ๋ฅผ ์ค์ ํด์ค๋๋ค.
private func configure() {
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerCallback), userInfo: nil, repeats: true)
putDots()
appendLines()
}
๊ทธ๋ฆฌ๊ณ ํ์ด๋จธ๊ฐ ํธ์ถ๋ ๋๋ง๋ค ๊ณก์ ๋ค์ ๋ ์ฌ์ด์ ์ ์ ์์น์ ๋ง๊ฒ ์ ๋ฐ์ดํธ ๋ฉ๋๋ค.
@objc func timerCallback() {
updateLineCuve()
}
private func updateLineCuve() {
for i in 0..<points.count {
points[i].y += points[i].addY
if points[i].y > centerY + points[i].max || points[i].y < centerY + points[i].min {
points[i].addY = -(points[i].addY)
}
}
for i in 0..<lineCount {
addCurve(line:lines[i],p1:lines[i].p1,p2:lines[i].p2)
}
}
putDots
์ ์ ๋ทฐ์ ๊ฐ๋ก๋ฅผ ์ ๊ฐฏ์+1๋งํผ์ผ๋ก ๋๋ x๊ฐ์ ์ ํ๊ณ ์ต๋์ ์ต์,์๋ก ๊ฐ์ง ์๋๋ก ๊ฐ์ง๋ฅผ ์ ํด์ ๋ฃ์ด์ค๋๋ค.
private func putDots() {
let w:CGFloat = self.bounds.width/CGFloat(dotCount+1)
for i in 1...dotCount {
let x:CGFloat = w*CGFloat(i)
let max:CGFloat = CGFloat.random(in: centerY/2...centerY)
let min:CGFloat = CGFloat.random(in: (-centerY)...(-centerY/2))
let addY:CGFloat = CGFloat(i%2) == 0 ? -1:1
points.append(Point(x: x, y: centerY, max: max, min: min, addY: addY))
}
}
appendLines
์ ์ ์ฌ์ด์ ๋ ์ ๊ณผ ์์ ๋๋คํ๊ฒ ์ ํด์ ์ํ๋ ๊ฐฏ์๋งํผ ๋ฃ์ด์ค๋๋ค.
private func appendLines() {
for _ in 0..<lineCount {
lines.append(Line(layer:CAShapeLayer(),p1:(0..<dotCount).randomElement()!, p2:(0..<dotCount).randomElement()!, color: (colors.randomElement()!)))
}
}
addCurve
์๋์ ๊ฐ์ด ๊ณก์ ์ p1,p2์ ๋ง๊ฒ ์ฐ๊ฒฐํด์ฃผ๊ณ ๊ทธ ์์ ์ฑ์ธ ์์ ์ ํด์ค๋๋ค.
private func addCurve(line:Line,p1:Int,p2:Int) {
line.layer.removeFromSuperlayer()
let height:CGFloat = self.frame.height
let width:CGFloat = self.frame.width
let linePath = UIBezierPath()
linePath.move(to:CGPoint(x: 0, y:height))
linePath.addLine(to:CGPoint(x: 0, y:height/2))
linePath.addCurve(to:CGPoint(x: width, y:height/2), controlPoint1:points[p1].center, controlPoint2:points[p2].center)
linePath.addLine(to: CGPoint(x: width, y: height))
line.layer.path = linePath.cgPath
line.layer.fillColor = line.color.withAlphaComponent(0.4).cgColor
layer.addSublayer(line.layer)
}
WaveViewController
์ปจํธ๋กค๋ฌ์์ ๋ทฐ๋ฅผ ์์ฑํ์ฌ ํ์ธํฉ๋๋ค.
class WaveViewController: UIViewController {
var waveView:WaveView!
override func viewDidLoad() {
super.viewDidLoad()
configure()
}
private func configure() {
self.view.backgroundColor = UIColor(displayP3Red: 55/255, green: 55/255, blue: 55/255, alpha: 1)
waveView = WaveView(frame:CGRect(x:self.view.center.x-150, y: self.view.center.y-130, width: 300, height: 260))
self.view.addSubview(waveView)
}
์๋์ฒ๋ผ ์ฌ๋ฌ ๊ฐ์ ๊ณก์ ์ด ์จ์ด๋ธ์ฒ๋ผ ๋ณด์ด๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
Source Code
์ ์ฒด ์์ค ์ฝ๋๋ ์๋ ๊นํ์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
(๋ง์ ๋์ จ๋ค๋ฉด ์คํ ํ๋ฒ์ฉ๋ง ๋๋ฌ์ฃผ์ธ์ ใ )