チワ裏

趣味の備忘録です

Unityで3Dモデルを動かして剣で敵をぶっ飛ばす実装メモ

3Dモデルをちゃんと動かすゲームを作ってみたくなったので試しに作ってみました。

実装手順

まずは使用したアセット(無料のやつです)

キャラクター Strong Knight (つよそう)
いい感じの騎士?のアセット
https://assetstore.unity.com/packages/3d/characters/humanoids/strong-knight-83586

スクリプト Free Footsteps System
モデルの動きやアニメーションを思い通りに実装できるアセット
https://assetstore.unity.com/packages/tools/audio/free-footsteps-system-47967

アニメーションやエフェクトは適当にどうぞ

ヒエラルキーの構成

f:id:tiwaluna:20170919220127p:plain

・top_down_camera_pivot
Standert AssetのMultipurposeCameraRigみたいなやつっぽい。
Targetにtop_down_controllerを設定する。
f:id:tiwaluna:20170919220548p:plain

・top_down_controller
このオブジェクトの子にキャラクターの3Dモデル(kinghtprefab)を配置する。
f:id:tiwaluna:20170919220553p:plain

上記はFree Footsteps Systemのデモシーンのオブジェクトに既に設定されているので流用して改造できます。

アニメーションの実装

最終的なアニメーション図 f:id:tiwaluna:20170919221336p:plain

Free Footsteps Systemのスクリプトを改造していきます。
アセットに付いている、TopDownController.csでモデルの制御ができます。
これをアタッチすると、移動キーに合わせたオブジェクトの移動と回転が実装されます。すげぇ

次に任意のアニメーションを再生できるようにします。
TopDownController.csのコードでは歩行時にAnimatorのパラメーターのmoveをtrueにすることでアニメーションを遷移させています。
このスクリプトを以下のように改造して対応するアニメーションを増やします。


void UpdateAnimator() {
  …
  <既存のコード>
  …
  //移動キーのいずれかが押されていればtrue、押されてないならfalse
  isMoving = Input.GetButton(“Horizontal”) || Input.GetButton(“Vertical”);  

   //tureかfalseが設定される
  thisAnimator.SetBool(“move”, isMoving); //tureかfalseが設定される
}

これを応用すれば、
isRunning = isMoving && Input.GetKey(KeyCode.LeftShift);
isAttack = Input.GetKey(KeyCode.Z);

thisAnimator.SetBool(“run”, isMoving);
thisAnimator.SetBool(“attack”, isRunning);

みたいな感じでダッシュ、攻撃のアニメーションフラグを設定できます。 AnimationControllerにちゃんとパラメーターを用意するのも忘れないようにしましょう。


剣で敵を吹き飛ばせるようにする

キャラクターのモデルをこんな感じで改造してみました。

f:id:tiwaluna:20170919222829p:plain

変更した点は元モデルでは剣のモデル(dagger)を腰につけているんですが、daggerをR_elbowの子の位置に設定します。
僕の使ったアニメーションではこれで剣を振るう動きが作れました。
また、不要なパーツは非表示か削除しておきます。

daggerのメッシュに敵が当たったときに攻撃判定としたいので、daggerにMesh Colliderをアタッチします。
また、Mesh ColliderはOnTriggerEnterを使って接触の判定をしたいので、isTriggerを設定します。
そして敵を吹き飛ばすスクリプトを作ってアタッチします。

ブログ用 当たったオブジェクトを吹き飛ばすUnityスクリプト

解説

OnTriggerEnterで大体の処理を行ってます。

  • 敵の判定
    今回は敵にenemyタグをつけて判定するので、 if (other.gameObject.tag == “enemy”)で判定。

  • 攻撃アニメーションの判定
    if( (animatorStateInfo.IsName(“attack”) || animatorStateInfo.IsName(“jump attack”) )
    で攻撃アニメーションが再生されているかどうかを攻撃アニメーションの名前で判定します。

    • また、AnimatorStateInfoの情報は取得する前に
      rootAnimator.Update(0);
      で更新しないと最新のAnimatorの情報を取得できないので注意。
  • 攻撃判定
    0.2f < animatorStateInfo.normalizedTime && animatorStateInfo.normalizedTime < 0.8f
    animatorStateInfo.normalizedTimeで再生中のアニメーションの進捗を取得できます。
    0%(再生開始) ~ 100%(再生終了)
    今回は20%~80%の間で、剣を振っている最中のみ攻撃判定を出すようにします。

  • 吹っ飛ばす!
    rigit.AddForce(transform.root.forward * 25, ForceMode.Impulse);
    敵にRigitBodyがある前提ですが、こいつで吹き飛ばします。ForceMode.Impulseでは相手の質量(Mass)の影響を受けて、瞬間的に力を加えます。適切な値を設定します。

  • その他
    effectの部分は適当にすきなものをどうぞ。
    effectはプレハブを剣と敵の中間の位置に生成されます。


以上で実装は終わりです。正直ただのアセット紹介なんだよなぁ・・・。
説明が抜けていたらすみません。

完全にブログ放置してたからこれからは徐々に記事を書いていきたいなぁ…

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 追記
    ブログを放置していたのでコードを改善したのに記事を更新してなかった、反省。

    はじめ

    ブログの目的

    趣味のプログラミングでやったことを忘れないようにメモしていきたい。

    ついでに文章を書く練習もする。