チワ裏

趣味の備忘録です

Unityでカレンダー作ったメモ

2017/4/28 記事内容をめちゃくちゃ修正

Unityでこんな感じのカレンダーを作りました。
(WPFでやれとは言わない)
作ってみて、C#のDateTimeについて知らないことが思ったより沢山あったのでそれのメモ。
あと、UniRxを久しぶりにちょろっと使ってみて、結構忘れてたのでメモ。

作り方

まず、カレンダーの日付のマスをHierarchyのCreate->UI->Buttonで作ります。
7×6行で42個あれば十分です。

あとはこれらのButtonの親に空オブジェクトを設定しておきます。
また、カレンダーの月を変えるためのNext、Prevボタンも適当な場所に配置しておきます。
f:id:tiwaluna:20170217211911p:plain
Hierarchyはこんな感じになります。
Calendar、Row0~5が空オブジェクトになります。それぞれのRowオブジェクトの子にButtonオブジェクトが7つ入ります。この親子関係を利用して、Calendarにスクリプトを設定します。

2017/4/28 修正
Hierarchyの親子関係を複雑にすると後でいじくったりする際に面倒なことになります。
42個のButtonをまとめる親オブジェクトを一つ用意するだけでOKです。
Hierarchyはこんな感じになります(修正後)
f:id:tiwaluna:20170428191533p:plain

カレンダーの管理スクリプト

Calendarオブジェクトにアタッチします。
UIとは別の場所に空のオブジェクトを作成して、それにAdd Componentします。
日付を表示するButtonはスクリプトから読み込むため、Buttonの親オブジェクトを指定しておきます。
f:id:tiwaluna:20170428191725p:plain

解説
  • 初期設定

まず、Unity上でnextButtonとprevButtonに先ほど作ったNext、PrevのButtonオブジェクトを指定しておきます。

  • InitCalendarComponent
     InitCalendarComponentメソッドで各ButtonにCalendarButtonをアタッチします。ついでにオブジェクトとコンポーネントを保存しておきます。
     各Buttonの取得はGetChildを使って取得します。このスクリプトがアタッチしている空オブジェクトがrootオブジェクトなので、先ほどのHierarchyの構造を活用して取得します。
     何番目のRowオブジェクトのColumnであるかでそのButtonが何行目の何列目かわかります。このカレンダーは1行あたり7列で固定されているので、7×行数 + 列数で左上のButtonから数えて何番目なのかが分かります。これを利用してobjDays配列およびDays配列に保存しておきます。

     
     先ほども書いたとおり、↑の実装だとオブジェクト構造を変更することができなくなるので、ソースコードにあるように単純に連番で番号をつけます。

  • SetCalendar
     SetCalendarメソッドで各CalendarButtonオブジェクトに対応した日付を指定していきます。 
     first変数はSystem.DateTime型で、今月の1日目の日付を表します。DateTimeは(年, 月, 日)をint型で指定して作れるのでcurrentの年月を指定して、日にちに1を入れます。
     また、先月、来月の取得はcurrent.AddMonths()を使います。current.AddMonths(1)で来月、current.AddMonths(-1)で先月を取得します。
     このカレンダーでは空いたマスに先月、今月の日にちを表示したいので、そのための変数を用意します。来月の分は1から数えますが、先月の場合はまず、DateTime.DaysInMonthメソッドで先月の日数を取得します。その日数から空いたマスの日数分を減らします。空いたマスは今月の一日の曜日から計算します。曜日の取得はfirst.DayOfWeekから取得します。DayOfWeekは列挙型なのでint型にキャストします。DateTimeの曜日は日曜~土曜の間で(0~6)となっているので、先月の日数 - 今月の1日の曜日 + 1で空いたマスを計算できます。
     あとは条件に合ったマスに日時を指定していきます。

  • UniRx部分について
     まず、自分が深い理解ができてないので、非常にざっくりとした説明しかできないので申し訳ないですorz。
     nextButton.onClick.AsObservable()という部分でNextボタンが押されたかどうかを常に監視します。もし押された場合、Subscribe内の処理が行われます。Prevボタンも同様です。
    完璧に使い方を忘れていたので参考のリンク
    【OnClickAsObservable】UniRxでボタンのクリック回数をテキストに表示する【SubscribeToText】 - Qiita

  • 日付マスのスクリプト

    各Buttonにアタッチします。(数が多いのでCalendarManagerから動的にアタッチする。)

    解説


  •  UniRxで値の変動を監視します。各マスの設定された日付はDateValueに保存されていて、CalendarManagerから変更されます。UniRxのObserveEveryValueChangedを使ってDateValueの値の変動を取得します。ここではDateValueの値が変更された場合、.Subscribe内の処理が行われます。
    【UniRx】ObserveEveryValueChangedでフレーム間での値の変動を監視する - Qiita
     値が変動したらテキストの値を変えて、土日などは色を変えたいので、DateValueの値を使って色の判定をGetColorDayOfWeekメソッドでします。


  • 以上のスクリプトを踏まえて、他にも年や月を表示する処理を作れば冒頭のgifみたいなカレンダーができます。(たぶん)
     わざわざUnityで作らなくても良かった気もしますが、一応、Unityのオブジェクトとしてカレンダーを作ったのでここから更にカレンダーを他のUnityのアプリに組み込み易いかもです(こなみ)。
    あと傾けたりとか。
    f:id:tiwaluna:20170217234902p:plain

    おわり

    とりあえず実質的な初めてのブログ記事。
    正直誰に向けて書いてんだか良く分からない感じになってしまいました。(必要なUnityの前提知識が多い)
    あと、普段は感覚的になんとなくの理解でプログラミングしているので(UniRx関係とか)、ブログ記事で文章にしてみて、人に説明するのが難しいというか説明できないのをすごく実感したので精進したいと思います。
    こんな記事で書くのに3時間かかってしまったのでこれからは無駄な説明は省いていかないときつそう。

    2017/4/28 追記
    ブログを放置していたのでコードを改善したのに記事を更新してなかった、反省。