teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

アニメーション設定例を追記

2020/05/05 01:30

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -29,4 +29,103 @@
29
29
  }
30
30
  }
31
31
  }
32
- ```
32
+ ```
33
+
34
+ **追記**
35
+
36
+ ご質問内容から想像した動きを元にアニメーションを構成してみました。
37
+ コンポーネントのアタッチ状況は下図のようになっています。
38
+
39
+ ![図1](e34a5a7ad665a0114b367444c78c7c91.gif)
40
+
41
+ AnimatorのApply Root Motionはオフ前提としましたので、Animatorを持つオブジェクト全体を空のオブジェクトに入れて、ボール全体の位置を動かすには親オブジェクトの方を動かすことにしました。
42
+ コライダーはHoverアニメーションの上下動範囲をカバーするように縦長にして、アニメーションと一緒に動くようにはしませんでした。上下動するボール本体に球形コライダーを付ける案も試してみたものの、マウスポインタの位置によっては上下動のためにポインタが当たったり外れたりしてアニメーションがせわしなく切り替わり、若干見苦しく感じたため却下しました。
43
+
44
+ アニメーションは、マウスポインタを当てると浮遊して存在をアピールし、クリックすると開くというアイテムボックス的なものをイメージしました。
45
+ ステート遷移の概要は...
46
+
47
+ - Idle、IdleToHover、Hover、Openの4つのステートを持つ。
48
+ - Idleは何もアニメーションしない。Loop Timeオン。
49
+ - IdleToHoverは地上から空中へ浮き上がるモーション。Loop Timeオフ。
50
+ - Hoverは空中をふわふわ上下するモーション。Loop Timeオン。
51
+ - Openはフタを開くモーションで、アニメーション終了後はフタが開かれた状態のまま維持される。Loop Timeオフ。
52
+ - 初期状態はIdleで、マウスポインタを当てるとIdleToHoverへ、引き続きHoverへ移行する。
53
+ - IdleToHoverまたはHover状態でマウスポインタが外れるとIdle状態へ遷移する。
54
+ - マウスクリックがあった場合、どのステートからでもOpenへ遷移させる。ただし自分自身への遷移は無効化しておき、OpenからOpenへの遷移は起こらないようにする。
55
+ - Openは遷移先を持たず、いったんOpen状態になるとそのまま元に戻らない。
56
+
57
+ となります。プロパティとしては...
58
+
59
+ - マウスポインタが当たっているかどうかはBoolプロパティの「Hover」で表現し、trueなら当たっていてfalseなら当たっていない。
60
+ - マウスクリックはTriggerプロパティの「Open」で表現し、コライダー上でクリックした時に起動される。
61
+
62
+ の2つを用意しました。
63
+ ご質問者さんが「Idle」と「Hover」の2種類のプロパティを使っている理由がよく分からなかったのですが、おそらくこれら2つは排他的だろうと想像し、Boolプロパティ一つでまかなうことにしました。
64
+ 「Open」については、Boolプロパティのような二者択一の2つの状態というよりも、ボールを開くアクションの引き金としての意味合いが強いように感じましたのでTriggerとしました。
65
+ これだとまずいようでしたらコメントいただけましたらさらに遷移条件を検討してみようと思います。
66
+
67
+ 各ステートは下記のように矢印を繋いでいます。
68
+
69
+ - IdleからIdleToHoverへの遷移条件は「Hoverがtrue」。Exit Timeなし。Interruption SourceはNext State。
70
+ - IdleToHoverからIdleへの遷移条件は「Hoverがfalse」。Exit Timeなし。Interruption SourceはNext State。
71
+ - IdleToHoverからHoverへの遷移条件はない。Exit Timeあり。Interruption Sourceはどちらでもいいが、さしあたりNext State。
72
+ - HoverからIdleへの遷移条件は「Hoverがfalse」。Exit Timeなし。Interruption SourceはNext State。
73
+ - Any StateからOpenへの遷移条件は「Openトリガーが発火」。Interruption Sourceなし。Can Transition To Selfオフ。
74
+
75
+ 最初の図で親オブジェクト側にアタッチしている`BallController`がマウスポインタの当たり判定を検知し、Animatorの状態を制御しています。
76
+
77
+ ```C#
78
+ using UnityEngine;
79
+
80
+ public class BallController : MonoBehaviour
81
+ {
82
+ private static bool needsRaycast = true;
83
+ private static Collider raycastResult;
84
+ private static readonly int HoverState = Animator.StringToHash("Hover");
85
+ private static readonly int OpenState = Animator.StringToHash("Open");
86
+ private Animator animator;
87
+ private new Collider collider;
88
+ private Camera mainCamera;
89
+
90
+ private void Start()
91
+ {
92
+ this.animator = this.GetComponentInChildren<Animator>();
93
+ this.collider = this.GetComponentInChildren<Collider>();
94
+ this.mainCamera = Camera.main;
95
+ }
96
+
97
+ private void Update()
98
+ {
99
+ if (needsRaycast)
100
+ {
101
+ // 今回想定したケースでは、複数のボールがあったとしてもレイキャストは1フレームあたり
102
+ // 少なくとも1回やれば十分なはずなので、最初にUpdateを処理することになったボールが
103
+ // 代表してレイキャストを行い、結果をstaticフィールドに保存しておく
104
+ var mouseRay = this.mainCamera.ScreenPointToRay(Input.mousePosition);
105
+ raycastResult = Physics.Raycast(mouseRay, out var hitInfo) ? hitInfo.collider : null;
106
+ needsRaycast = false;
107
+ }
108
+
109
+ // 自分が担当しているコライダーと、先の当たり判定で見つかったコライダーが一致すれば
110
+ // それはこのボールにマウスポインタが当たっていることを意味する
111
+ var hover = this.collider == raycastResult;
112
+ this.animator.SetBool(HoverState, hover);
113
+
114
+ // 自分の上にマウスポインタが当たっており、かつマウスボタンがクリックされたのであれば
115
+ // このボールがクリックされたと判断できるので、Openトリガーを起動する
116
+ if (hover && Input.GetMouseButtonDown(0))
117
+ {
118
+ this.animator.SetTrigger(OpenState);
119
+ }
120
+ }
121
+
122
+ private void LateUpdate()
123
+ {
124
+ needsRaycast = true;
125
+ }
126
+ }
127
+ ```
128
+
129
+ 実行時のステート遷移は下図のような様子でした。
130
+
131
+ ![図2](5bf6099a3993adf2f94ba29db91e1562.gif)

2

条件分岐が誤っていたため訂正

2020/05/05 01:29

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -8,7 +8,7 @@
8
8
  ray = Camera.main.ScreenPointToRay(Input.mousePosition);
9
9
 
10
10
  var hover = Physics.Raycast(ray, out hit);
11
- if (hover && (hit.transform.name != gameObject.name))
11
+ if (hover && (hit.transform.name == gameObject.name))
12
12
  {
13
13
  hover = false;
14
14
  }

1

条件式が逆だったため修正

2020/04/21 22:21

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -8,7 +8,7 @@
8
8
  ray = Camera.main.ScreenPointToRay(Input.mousePosition);
9
9
 
10
10
  var hover = Physics.Raycast(ray, out hit);
11
- if (hover && (hit.transform.name == gameObject.name))
11
+ if (hover && (hit.transform.name != gameObject.name))
12
12
  {
13
13
  hover = false;
14
14
  }