スマホアプリで一人回しがしたい(ついでにSwiftUIお勉強)その2
導入 スマホで一人回しがしたい
どうも、湊です。
ただこの一人回し、自宅などカードを広げることが許されるスペースでしかできません(当然)。
どこでもやりたくない...?
スマホでやりたくない...?
と思ったのでアプリを作ることにしました。
趣味のツール作成と仕事の勉強(SwiftUI)ができて一石二鳥です。
前回まで
前回↓はキャラクターを配置するViewをSwiftUIで作りました。
スマホアプリで一人回しがしたい(ついでにSwiftUIお勉強)① - minato_blog
今回は盤面全体を作っていくことにします。
画面イメージ(ざっくり)
スマホの画面に収める必要があるため、実際の盤面からは少々レイアウトを変える必要がありそうです。
こんな感じです。
ピンク色のマスがAFで青色はDFです。
山札や置き場は、ぱっと見でわかればいいのが枚数だけなのでまずはそれだけ表示することにします。
(山札などの中身が見れる画面は別で作ります)
AF, DF
前回作ったフィールド一つあたりのViewを6つ並べるだけでよさそうです。
これはVStackとHStackを用いることで簡単に実現できます。(Viewの表示用データを格納するstructも一緒に記載しておきます)
struct Fields { var leftAF = Field() var centerAF = Field() var rightAF = Field() var leftDF = Field() var centerDF = Field() var rightDF = Field() } struct FieldsView: View { var fields: Fields var body: some View { GeometryReader { geometry in let fieldWidth = min(geometry.size.width, geometry.size.height) / 3.2 VStack { HStack { FieldView(field: fields.leftAF) .frame(width: fieldWidth, height: fieldWidth) FieldView(field: fields.centerAF) .frame(width: fieldWidth, height: fieldWidth) FieldView(field: fields.rightAF) .frame(width: fieldWidth, height: fieldWidth) } HStack { FieldView(field: fields.leftDF) .frame(width: fieldWidth, height: fieldWidth) FieldView(field: fields.centerDF) .frame(width: fieldWidth, height: fieldWidth) FieldView(field: fields.rightDF) .frame(width: fieldWidth, height: fieldWidth) } } .frame(width: geometry.size.width) } } }
これをPreviewで見てみるとこんな感じになります。
山札・ゴミ箱・その他置き場の情報
とりあえずその領域の名前とカード枚数だけわかればよさそうなので、Textで配置しました。
コード。ここを押して展開。
struct DomainInfoView: View { var onePlayerDomain: PlayerDomain var otherPlayerDomain: PlayerDomain init(one oneDomain: PlayerDomain, other otherDomain: PlayerDomain) { self.onePlayerDomain = oneDomain self.otherPlayerDomain = otherDomain } var body: some View { GeometryReader { geometry in VStack { HStack { Spacer() HStack { VStack { HStack { VStack { Text("山札") Text("\(otherPlayerDomain.deck.cards.count)枚") } .padding(.leading, /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/) VStack { Text("ゴミ箱") Text("\(otherPlayerDomain.trashBox.cards.count)枚") } Spacer() } .font(.system(size: 12)) HStack { ForEach(otherPlayerDomain.somePlaces, id: \.name) { place in VStack { Text(place.name) Text("\(place.cards.count)枚") } } } .font(.system(size: 10)) .padding(.bottom, 8) } } .frame(width: geometry.size.width * 0.45) .overlay( Rectangle() .frame(width: geometry.size.width * 0.45, height: 1), alignment: .bottom ) .overlay( Rectangle() .frame(width: 1), alignment: .leading ) .overlay( Rectangle() .frame(width: 1), alignment: .trailing ) Spacer() HStack { VStack { HStack { Spacer() VStack { Text("山札") Text("\(onePlayerDomain.deck.cards.count)枚") } VStack { Text("ゴミ箱") Text("\(onePlayerDomain.trashBox.cards.count)枚") } .padding(.trailing, /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/) } .font(.system(size: 12)) .padding(.top, 8) HStack { ForEach(onePlayerDomain.somePlaces, id: \.name) { place in VStack { Text(place.name) Text("\(place.cards.count)枚") } } } .font(.system(size: 10)) } } .frame(width: geometry.size.width * 0.45) .overlay( Rectangle() .frame(width: geometry.size.width * 0.45, height: 1), alignment: .top ) .overlay( Rectangle() .frame(width: 1), alignment: .leading ) .overlay( Rectangle() .frame(width: 1), alignment: .trailing ) Spacer() } .frame(width: geometry.size.width, height: geometry.size.height) } } } }
やってることは単純なのですが、枠をつけるためのコードで行数が嵩んでしまいました。。
表示はこんな感じになります。
手札
カード情報から画像を取得して、HStackとForEachで並べます。
struct Hand { var cards: [Card]() } struct HandView: View { var hand: Hand var body: some View { HStack { ForEach(hand.cards.indices) { index in Image(hand.cards[index].imageName) .resizable() .scaledToFit() } } } }
盤面全体
それではここまでで作ってきたViewで画面を組み立てましょう
コードは上の図の通り並べるだけです。
struct BoardView: View { var board: Board var body: some View { GeometryReader { geometry in VStack { HandView(hand: board.otherDomain.hand) .frame(width: geometry.size.width, height: geometry.size.width / 8) FieldsView(fields: board.otherDomain.fields) .rotationEffect(Angle(degrees: 180)) DomainInfoView(one: board.oneDomain, other: board.otherDomain) .frame(width: geometry.size.width, height: geometry.size.width / 6, alignment: .center) FieldsView(fields: board.oneDomain.fields) HandView(hand: board.oneDomain.hand) .frame(width: geometry.size.width, height: geometry.size.width / 8) } } } }
すごい簡単ですね。ここまででこんな感じの表示になります。
まだちょっと味気ないですが、必要なものは表示できたのではないでしょうか。
その2はここまで。
その3の記事では実際に表示しているこれらのカードを操作する部分をつくっていきます。
各種カード画像はLycee公式サイトから拝借しました。
LYCEE OVERTURE TRADING CARD GAME || リセ オーバーチュア トレーディングカードゲーム
*1:一人回し:一人で2つのデッキを使って練習すること