SwiftUIで作るドラえもん【顔編】

# はじめに
日曜日で暇なので， SwiftUIを使ってドラえもんを作ってみました．

この記事で完成するドラえもんは以下の画像です．
口を開けているドラえもんは難しそうなので断念しました．
かなり本物に近くないですか？笑

<img width="366" alt="DoraFace" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/9c8307fc-a572-5209-82f8-72edbf65b9f9.png">

さぁ作って行きましょう．


# 土台づくり
まず，以下の画像のような土台となる青の円とその中にある円から作って行きましょう．
ドラえもんって意識してませんでしたが，地味に楕円なんだと感じました．
確かによくよく見たら楕円なんですよね．

土台の色のみ，Asset Catalogで色を管理しています．
(鼻も管理した方が良さそう...)

<img width="372" alt="土台" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/d21dd0ae-1257-7b9a-d3c8-59635b8c2066.png">


以下コードです．

```swift:ContentView.swift

struct base: View {
    var body: some View {
        ZStack {
            // 土台
            Ellipse()
            .overlay(
              Ellipse()
             .stroke(Color.black,lineWidth: 2)
            )
            .frame(width: 300, height: 290)
            .foregroundColor(Color("DoraColor"))
            
            // 顔
            Ellipse()
                .frame(width: 270 , height: 250)
                .foregroundColor(Color.white)
                .overlay(
                  Ellipse()
                 .stroke(Color.black,lineWidth: 2)
                )
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 100 } )
        }
    }
}

```

# 目
次に目です．


<img width="374" alt="eye" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/3bee7534-5142-5e76-0ce0-ecfc144cc6cf.png"><img width="374" alt="eye" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/74f0dfd5-0507-6112-1bc5-c072e81132dc.png">


```swift:ContentView.swift
struct eyes: View {
    var body: some View {
        HStack(spacing:0) {
            // 左目
            ZStack {
                Ellipse()
                    .frame(width: 60, height: 80)
                    .foregroundColor(Color.white)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                ZStack {
                    Ellipse()
                        .frame(width: 20, height: 30)
                        .foregroundColor(Color.black)
                    
                    Ellipse()
                        .frame(width:5, height: 10)
                        .foregroundColor(Color.white)
                }
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -5 })
                
            }
            
            ZStack {
                // 右目
                Ellipse()
                    .frame(width: 60, height: 80)
                    .foregroundColor(Color.white)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                
                ZStack {
                    Ellipse()
                        .frame(width: 20, height: 30)
                        .foregroundColor(Color.black)
                    
                    Ellipse()
                        .frame(width:5, height: 10)
                        .foregroundColor(Color.white)
                }
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 25 } )
            }
        }
    }
}
```

# 鼻
続いては鼻ですね．

<img width="374" alt="nose" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/d378e89a-1449-8aec-388c-7b5e21784839.png"><img width="374" alt="nose" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/84bba946-d75f-c3cf-4ce2-6f5efe1dfe33.png">



```swift:ContentView.swift
struct nose: View {
    var body: some View {
        Group {
            // 鼻
            ZStack{
                Circle()
                    .frame(width: 50, height: 50)
                    .foregroundColor(Color.red)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                Circle()
                    .frame(width: 20, height: 10)
                    .foregroundColor(Color.white)
                    .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 20})
                    .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 15})
            }
            .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 60 } )

            // 人中?
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 110, height: 2)
                .rotationEffect(Angle(degrees: 90))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -45 } )
        }
    }
}
```


# 髭

ここまでくるとそれっぽくなってきました．

<img width="374" alt="CatBeard" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/5167ecac-d87a-4fff-4297-f10a4ef4649b.png"><img width="374" alt="CatBeard" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/98eab1ec-ecf9-d1cc-48b9-bb7f36ed495d.png">

```swift:ContentView.swift
struct CatBeard: View {
    var body: some View {
        Group {
            // 左髭
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )
            
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 0))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -20 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )
            
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: -15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -50 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )
            
            // 右髭
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: -15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )
            
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 0))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -20 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )
            
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -50 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )
        }
    }
}

```


# 口

最後に口です．

<img width="374" alt="mouth" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/2c0911b8-922e-8178-cce9-cddbf1956dee.png"><img width="374" alt="mouth" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/3de5a995-4461-6e7a-203a-abcc7d6784ad.png">



```swift:ContentView.swift
struct Mouth: View {
    var body: some View {
        Circle()
            .trim(from: 0.05, to: 0.45)
            .stroke(Color.black,lineWidth: 3)
            .frame(width: 200, height: 200)
    }
}
```

# 完成
無理やりですがなんとか完成しました．
<img width="374" alt="DoraFace" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595030/1e480d7d-b83c-ae72-7a36-fed03ae6af5a.png">

<details><summary>全文</summary><div>

```swift:ContentView.swift

import SwiftUI

struct base: View {
    var body: some View {
        ZStack {
            // 土台
            Ellipse()
            .overlay(
              Ellipse()
             .stroke(Color.black,lineWidth: 2)
            )
            .frame(width: 300, height: 290)
            .foregroundColor(Color("DoraColor"))
            
            // 顔
            Ellipse()
                .frame(width: 270 , height: 250)
                .foregroundColor(Color.white)
                .overlay(
                  Ellipse()
                 .stroke(Color.black,lineWidth: 2)
                )
                .alignmentGuide(.leading, computeValue: { _ in 10 } )
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 100 } )
        }
    }
}

struct eyes: View {
    var body: some View {
        HStack(spacing:0) {
            // 左目
            ZStack {
                Ellipse()
                    .frame(width: 60, height: 80)
                    .foregroundColor(Color.white)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                ZStack {
                    Ellipse()
                        .frame(width: 20, height: 30)
                        .foregroundColor(Color.black)
                    
                    Ellipse()
                        .frame(width:5, height: 10)
                        .foregroundColor(Color.white)
                }
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -5 })
                
            }
            
            ZStack {
                // 右目
                Ellipse()
                    .frame(width: 60, height: 80)
                    .foregroundColor(Color.white)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                
                ZStack {
                    Ellipse()
                        .frame(width: 20, height: 30)
                        .foregroundColor(Color.black)
                    
                    Ellipse()
                        .frame(width:5, height: 10)
                        .foregroundColor(Color.white)
                }
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 25 } )
            }
        }
    }
}

struct nose: View {
    var body: some View {
        Group {
            // 鼻
            ZStack{
                Circle()
                    .frame(width: 50, height: 50)
                    .foregroundColor(Color.red)
                    .overlay(
                      Ellipse()
                     .stroke(Color.black,lineWidth: 2)
                    )
                Circle()
                    .frame(width: 20, height: 10)
                    .foregroundColor(Color.white)
                    .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 20})
                    .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 15})
            }
            .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 60 } )
            // 人中?
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 110, height: 2)
                .rotationEffect(Angle(degrees: 90))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -45 } )
        }
    }
}

struct CatBeard: View {
    var body: some View {
        Group {
            // 左髭
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )
            
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 0))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -20 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )
            
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: -15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -50 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 120 } )
            
            // 右髭
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: -15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 10 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )
            
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 0))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -20 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )
            
            Rectangle()
                .foregroundColor(Color.black)
                .frame(width: 70, height: 2)
                .rotationEffect(Angle(degrees: 15))
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in -50 } )
                .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in -50 } )
        }
    }
}

struct Mouth: View {
    var body: some View {
        Circle()
            .trim(from: 0.05, to: 0.45)
            .stroke(Color.black,lineWidth: 3)
            .frame(width: 200, height: 200)
    }
}

struct DoraFace: View {
    var body: some View {
        ZStack{
            // 土台
            base()
            // 目
            eyes()
                .alignmentGuide(VerticalAlignment.center, computeValue: { _ in 130})
            // 鼻
            nose()
            //　髭
            CatBeard()
            //　口
            Mouth()
        }
    }
}

struct ContentView: View {
    var body: some View {
        VStack{
            Text("ドラえもん")
                .font(.largeTitle)
            DoraFace()
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```

</div></details>

# 終わりに
あまり綺麗ではありませんが，なんとか完成させることができました．
次の暇な日曜日にでも綺麗なコードに修正していこうと思います．

ちなみに，今回のタイトルに，【顔編】とありますが，【体編】を作る予定はありません．笑

SwiftUI初心者なのでもっと良い書き方があればご教示ください．

GitHub URL: https://github.com/tukuyo/Doraemon_SwiftUI