炭次郎の模様を壁紙にしたいゾ!

公開:2021/01/23
更新:2021/01/26
7 min読了の目安(約6600字TECH技術記事

はじめに

炭次郎の模様(市松模様)をプログラミングで表現していく。普段はこういうものを描くときはProcessingを使っているが、今回はスクリーンショットが楽に取れる,CALayerの勉強ができるという観点からSwiftを使う。ちなみに鬼滅の刃は5話くらいでみるのやめた。(話難しくないか??)

対象を観察する

描きたいものはこんな感じ。正方形が敷き詰められていること、緑と黒には規則性がありそうなことがわかる。正方形を敷き詰めるにはfor文を二重に使えば良さそうだ。では規則性について考えてみる。

横と縦にiとjを当てはめ、正方形にそれぞれ数字を割り振る。すると、緑で塗られる場所と黒で塗られる場所の規則性が見つかりそうだ。

i j
0 0
0 2
0 4
1 1
1 3
2 0
2 2
2 4

i j
0 1
0 3
0 4
1 0
1 2
1 4
2 1
2 3

緑はiとjの偶奇が一致しており、黒はそうでないとわかる。

考えたことをコーディングする

今回は画面の持つcanvasLayerにレイヤーを加える関数を作成し、それを起動時に実行することで絵を描いたということにする。

正方形を描く用意をする

正方形を画面に敷き詰めたいので、一辺の長さは画面の大きさに依存します。(横にも縦にも完全に敷き詰めることはほとんど不可能なので横いっぱいに敷き詰めることを想定しています。)
画面の横幅を3等分する長さは以下のようにして求め、sideOfSquereとして定義します。

let sideOfSquere = view.bounds.width/3

CALayerのframeを設定する

CALayerをインスタンス化し、frameを設定します。

let layer = CALayer()
layer.frame = CGRect(x: 0, y: 0, width: sideOfSquere, height: sideOfSquere)

背景色を設定する

.cgColorをつけるの忘れがち。ちなみにこの色は色検索というアプリで探した。

let layer = CALayer()
layer.frame = CGRect(x: 0, y: 0, width: sideOfSquere, height: sideOfSquere)
layer.backgroundColor = UIColor(red: 36/255, green: 110/255, blue: 72/255, alpha: 1).cgColor

これで画面の横幅を3等分する正方形を描く準備ができた。

関数を定義する

以下の関数は起動時に実行される。

func tanjiro() {
        
}

正方形を描いてみる

定義した関数の中に先ほど準備した正方形を入れて描いてみる。元々あるcanvasLayerに加える処理が必要。これも忘れがち。

func tanjiro() {
    let layer = CALayer()
    layer.frame = CGRect(x: 0, y: 0, width: sideOfSquere, height: sideOfSquere)
    layer.backgroundColor = UIColor(red: 36/255, green: 110/255, blue: 72/255, alpha: 1).cgColor
    canvasLayer.addSublayer(layer)
}

実行するとこんな感じになるはず。あとはここまでやってきたことを少し変えたり繰り返すだけだ。

一列描いてみる

ここでポイントとなるのが、正方形が描かれ始める座標だ。真ん中からではなく左上に座標があることに留意する。

func tanjiro() {
        let sideOfSquere = view.bounds.width/3
        for i in 0 ..< 3 {
            let layer = CALayer()
            layer.frame = CGRect(x: CGFloat(i) * sideOfSquere, y: 0, width: sideOfSquere, height: sideOfSquere)
            layer.backgroundColor = UIColor(red: 36/255, green: 110/255, blue: 72/255, alpha: 1).cgColor
            canvasLayer.addSublayer(layer)
        }
}

for文が出てきていよいよプログラミングっぽくなってきた。

背景色を変える条件を追加する

iが奇数のとき背景色が黒になるように条件を追加してみる。この条件はあとで一般化されてしまうのだが、小さい事例で考えることはとても大事だと思う。

func tanjiro() {
        let sideOfSquere = view.bounds.width/3
        for i in 0 ..< 3 {
            let layer = CALayer()
            layer.frame = CGRect(x: CGFloat(i) * sideOfSquere, y: 0, width: sideOfSquere, height: sideOfSquere)
            if i.isMultiple(of: 2) {
                    layer.backgroundColor = UIColor(red: 36/255, green: 110/255, blue: 72/255, alpha: 1).cgColor
            } else {
                layer.backgroundColor = UIColor.black.cgColor
            }
            canvasLayer.addSublayer(layer)
        }
}

横に並べたものを縦に並べる

for文を2重にし、縦にも並べる。考え方は横一列に並べた時と同じだ。

func tanjiro() {
        let sideOfSquere = view.bounds.width/3
        for j in 0 ..< 3 {
            for i in 0 ..< 3 {
                let layer = CALayer()
                layer.frame = CGRect(x: CGFloat(i) * sideOfSquere, y: CGFloat(j) * sideOfSquere, width: sideOfSquere, height: sideOfSquere)
                if i.isMultiple(of: 2) {
                    layer.backgroundColor = UIColor(red: 36/255, green: 110/255, blue: 72/255, alpha: 1).cgColor
                } else {
                    layer.backgroundColor = UIColor.black.cgColor
                }
                canvasLayer.addSublayer(layer)
            }
        }
}

これを実行すると上の写真のようになる。この問題点としては画面が正方形ではないので1回目のfor文と2回目のfor文で上限は変えないといけないということと、背景色を縦の変数も含めて考えなければならないということだ。

1回目のfor文の上限を変更する

縦の長さは横の長さの2倍以上であることはなさそうなので、1回目のfor文の上限は6で良さそう。

背景色の条件を追加する

ここでいよいよ最初に考えたものが役に立つ。2変数i,jの偶奇が一致するということをプログラムで表現すると、
「二つとも2で割り切れる、あるいは二つとも2で割り切れない」ということなので

if (!i.isMultiple(of: 2) && j.isMultiple(of: 2)  || (i.isMultiple(of: 2) && !j.isMultiple(of: 2)))

となる。
これを関数に入れると...

func tanjiro() {
        let sideOfSquere = view.bounds.width/3
        
        for j in 0 ..< 6 {
            for i in 0 ..< 3 {
                let layer = CALayer()
                layer.frame = CGRect(x: CGFloat(i) * sideOfSquere, y: CGFloat(j) * sideOfSquere, width: sideOfSquere, height: sideOfSquere)
                if (!i.isMultiple(of: 2) && j.isMultiple(of: 2)  || (i.isMultiple(of: 2) && !j.isMultiple(of: 2))){
                    layer.backgroundColor = UIColor(red: 36/255, green: 110/255, blue: 72/255, alpha: 1).cgColor
                } else {
                    layer.backgroundColor = UIColor.black.cgColor
                }
                canvasLayer.addSublayer(layer)
            }
        }
}

となる。

いい感じ!

一般化する

上のままだとややデカい気がするので、大きさを変更できるようにする。正確には、横に敷き詰める正方形の数を決められるようにする。

引数を用意する

func tanjiro(numberOfSquereIs number: Int)

3だったところをnubmerに置き換える

func tanjiro(numberOfSquereIs number: Int) {
        let sideOfSquere = view.bounds.width/CGFloat(number)
        for j in 0 ..< number*2 {
            for i in 0 ..< number {
                let layer = CALayer()
                layer.frame = CGRect(x: CGFloat(i) * sideOfSquere, y: CGFloat(j) * sideOfSquere, width: sideOfSquere, height: sideOfSquere)
                if (!i.isMultiple(of: 2) && j.isMultiple(of: 2)  || (i.isMultiple(of: 2) && !j.isMultiple(of: 2))){
                    layer.backgroundColor = UIColor(red: 36/255, green: 110/255, blue: 72/255, alpha: 1).cgColor
                } else {
                    layer.backgroundColor = UIColor.black.cgColor
                }
                canvasLayer.addSublayer(layer)
            }
        }
}

これで一応完成。実行するときは

override func viewDidLoad() {
        print("viewDidLoad")
        super.viewDidLoad()
        tanjiro(numberOfSquereIs: 5)
}

のようにすることで


のような炭次郎の壁紙を作ることができる。