質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

2514閲覧

velocityでの次の到達地点

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2018/06/17 04:06

編集2018/06/22 11:15

前提・実現したいこと

transform系での移動は、Mathf.Clampを使えば移動制限できるみたいですが、
velocityでの移動はどのように制御すれば移動制限できるのでしょうか?
ご教示お願いします。

該当のソースコード

C#

1 void FixedUpdate(){ 2 rb.velocity = this.transform.right * speed; 3 }

試したこと

transform系での移動は、こちらのサイトのように、
Mathf.Clampを使えば移動制限できることがわかりました。

C#

1 // 移動量を加える 2 pos += direction * spaceship.speed * Time.deltaTime; 3 4 // プレイヤーの位置が画面内に収まるように制限をかける 5 pos.x = Mathf.Clamp (pos.x, min.x, max.x); 6 pos.y = Mathf.Clamp (pos.y, min.y, max.y);

velocityの場合でも、Mathf.Clampを使って移動制限できるのでしょうか?
可能であれば、Mathf.Clampを使った移動制限を知りたいですが、
不可能であれば、velocityでの次の到達点が指定範囲内ならば、
移動するといった制御にしたいです。

C#

1 void FixedUpdate(){ 2 if(velocityでの次の到達点<max.x){ 3 rb.velocity = this.transform.right * speed; 4 } 5 }

妥協案として、「移動前に制限」ではなく、「移動後に調整して制限」を考えてみたのですが、
下記のコードでも、移動制限されませんでした。
下記コードが意図通りにいかない理由もわかりませんが、できればこのようなコードではなく、
「移動前に制限」させたいです。

C#

1 void FixedUpdate(){ 2 rb.velocity = this.transform.right * speed; 3 if(this.transform.position.x > max.x){ 4 Vector3 limit = new Vector3(max.x, this.transform.position.y, this.transform.position.z); 5 this.transform.position = limit; 6 } 7 }

追記。

C#

1 void Update () { 2 Vector3 viewport = Camera.main.WorldToViewportPoint(this.transform.position); 3 Vector3 viewmin = new Vector3(0.0f, 0.0f,viewport.z); 4 Vector3 viewmax = new Vector3(1.0f, 1.0f,viewport.z); 5 min = Camera.main.ViewportToWorldPoint(viewmin); 6 max = Camera.main.ViewportToWorldPoint(viewmax); 7 8 } 9 10 void FixedUpdate(){ 11 12 Vector3 pos = this.transform.position + (this.transform.right * speed); 13 pos.x = Mathf.Clamp(pos.x, min.x, max.x); 14 15 rb.velocity = pos - this.transform.position;

### 追記②

float speed = 2.0f; Vector3 min; Vector3 max; void Update () { Vector3 viewport = Camera.main.WorldToViewportPoint(this.transform.position); Vector3 viewmin = new Vector3(0.0f, 0.0f,viewport.z); Vector3 viewmax = new Vector3(1.0f, 1.0f,viewport.z); min = Camera.main.ViewportToWorldPoint(viewmin); max = Camera.main.ViewportToWorldPoint(viewmax); Debug.Log(max); } void FixedUpdate(){ Vector3 pos = this.transform.position + this.transform.TransformDirection(this.transform.right * speed); pos.x = Mathf.Clamp(pos.x, min.x, max.x); rb.velocity = transform.InverseTransformDirection(pos - this.transform.position); }

### 追記③

C#

1 Vector3 max; 2 3 void Start () { 4 //空のゲームオブジェクトの位置に設定。 5 max = go.transform.position; 6 } 7 8 void FixedUpdate(){ 9 10 Vector3 pos = this.transform.position + this.transform.TransformDirection(this.transform.right * speed); 11 pos.x = Mathf.Clamp(pos.x, min.x, max.x); 12 13 rb.velocity = transform.InverseTransformDirection(pos - this.transform.position); 14 }

イメージ説明

イメージ説明

### 追記④

イメージ説明

C#

1 Vector3 min; 2 Vector3 max; 3 4 void Start () { 5 } 6 7 8 void Update () { 9 Vector3 viewport = Camera.main.WorldToViewportPoint(this.transform.position); 10 Vector3 viewmin = new Vector3(0.0f, 0.0f,viewport.z); 11 Vector3 viewmax = new Vector3(1.0f, 1.0f,viewport.z); 12 min = Camera.main.ViewportToWorldPoint(viewmin); 13 max = Camera.main.ViewportToWorldPoint(viewmax); 14 } 15 16 17 void FixedUpdate(){ 18 19 Vector3 pos = this.transform.position + this.transform.TransformDirection(this.transform.right * speed); 20 pos.x = Mathf.Clamp(pos.x, min.x, max.x); 21 pos.z = Mathf.Clamp(pos.z, min.z, max.z); 22 23 rb.velocity = transform.InverseTransformDirection(pos - this.transform.position);

### 追記⑤

C#

1 void Update () { 2 Vector3 viewport = Camera.main.WorldToViewportPoint(this.transform.position); 3 Vector3 viewmin = new Vector3(0.0f, 0.0f,viewport.z); 4 Vector3 viewmax = new Vector3(1.0f, 1.0f,viewport.z); 5 min = Camera.main.ViewportToWorldPoint(viewmin); 6 max = Camera.main.ViewportToWorldPoint(viewmax); 7 } 8 9 10 void FixedUpdate(){ 11 12 Vector3 baseVelocity = this.transform.right * speed; 13 Vector3 pos = this.transform.position + this.transform.TransformDirection(baseVelocity); 14 pos.x = Mathf.Clamp(pos.x, min.x, max.x); 15 16 Vector3 vel = transform.InverseTransformDirection(pos - this.transform.position); 17 vel.z = vel.z * vel.x /baseVelocity.x; 18 rb.velocity = vel; 19 }

下の画像の位置で停止しました。ちょっと画面外に出てしまっています。
※移動時はy方向に動きません。
イメージ説明

### 追記⑥

追記⑤の画像の停止位置とほぼ変わらない状態でした。

C#

1 void FixedUpdate(){ 2 3 Vector3 viewport = Camera.main.WorldToViewportPoint(this.transform.position); 4 Vector3 viewmin = new Vector3(0.0f, 0.0f,viewport.z); 5 Vector3 viewmax = new Vector3(1.0f, 1.0f,viewport.z); 6 min = Camera.main.ViewportToWorldPoint(viewmin); 7 max = Camera.main.ViewportToWorldPoint(viewmax); 8 9 Vector3 baseVelocity = this.transform.right * speed; 10 Vector3 pos = this.transform.position + this.transform.TransformDirection(baseVelocity); 11 pos.x = Mathf.Clamp(pos.x, min.x, max.x); 12 13 Vector3 vel = transform.InverseTransformDirection(pos - this.transform.position); 14 vel.z = vel.z * vel.x /baseVelocity.x; 15 rb.velocity = vel; 16 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

「速度」とは「時間あたりの移動量」です。
なので「現在地+velocity」が次の移動地点です。

よってMathf.Clampを使う場合もTransform系の移動と同じように出来ます。

C#

1 // 入力後の移動量を求める 2 pos = this.transform.position + this.transform.right * speed; 3 4 // プレイヤーの位置が画面内に収まるように制限をかける 5 pos.x = Mathf.Clamp (pos.x, min.x, max.x); 6 pos.y = Mathf.Clamp (pos.y, min.y, max.y); 7 8 // 速度に反映 9 rb.velocity = pos - this.transform.position;

妥協案のコードが上手くいかないのは、
「そのフレームでの位置」は決定されていても、「速度」がthis.transform.right * speedのままキープされているので、次のフレームでは移動が再開されるからだと思います。
例えるならエンジンがかかりっぱなしの車をある一点に置いても、次の瞬間には走り出して行ってしまうようなものです。
下記のようにすれば上手くいくのではないかと思います。

C#

1void FixedUpdate(){ 2 if(this.transform.position.x > max.x){ 3 Vector3 limit = new Vector3(max.x, this.transform.position.y, this.transform.position.z); 4 this.transform.position = limit; 5 rb.velocity = Vector3.zero; 6 } else { 7 rb.velocity = this.transform.right * speed; 8 } 9 }

投稿2018/06/17 06:04

sakura_hana

総合スコア11427

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/06/17 08:07

ご回答ありがとうございます。 ご回答者様の2つのコードを試してみたのですが、どちらのコードも移動が停止しなくてわからなかったのですが、動かすゲームオブジェクトの三軸がワールド空間の三軸と同じ向きでないことが原因であることがわかりました。 ゲームオブジェクトの三軸をワールドの三軸と同じ向きにすると、2つのコードそれぞれで意図通り停止することが確認できましたが、ゲームオブジェクトの三軸の向きがワールドの三軸と合わない場合は、どのようにコードを書けばよいか教えていただけませんか?
sakura_hana

2018/06/17 08:16

具体的にどうずれてて、何がしたいのかによりますが、 「ゲームオブジェクトのXY」と解釈して制限の入力値側を調整するか(本来Yに入る値をXに入れるとか)、 調整の計算式を変更する(pos.x = Mathf.Clamp (pos.x, min.y, max.y);みたいな)か、 this.transform.positionの代わりにthis.transform.localPositionを使うとかですかね?
退会済みユーザー

退会済みユーザー

2018/06/17 09:23 編集

ご回答ありがとうございます。説明不足ですみません、追記しました。 目的は画面外に行かせないようにしたいのですが、ViewportToWorldPointがワールドでなく、オブジェクトのローカルな座標で取得できれば実現できるように思えるのですが、そういった方法はありませんか? (ローカルな座標で取得できて、ローカルな位置移動すれば実現できるという前提が合っていればのお話ですが。) もしくは何か方法があればご教示いただけませんか?
sakura_hana

2018/06/18 02:02

Vector3 pos = this.transform.position + transform.TransformDirection(this.transform.right * speed); pos.x = Mathf.Clamp(pos.x, min.x, max.x); rb.velocity = transform.InverseTransformDirection(pos - this.transform.position); これだとどうでしょうか。 TransformDirection:ローカル軸からワールド軸へ方向を変換 InverseTransformDirection:ワールド軸からローカル軸へ方向を変換
退会済みユーザー

退会済みユーザー

2018/06/18 15:26 編集

ご回答ありがとうございます。追記しました。 検証してみたのですが、移動が画面外まで続いてしまいました。 メインカメラが動き回ることにも対応させる為、Updateでminやmaxをとっているんですが、 ゲームを実行してメインカメラを固定させていても、Update内でDebug.Log(max)したら、 値が変わり続けていました。 このmaxが変動するのがおかしい為に、移動制限ができていないということでしょうか?
sakura_hana

2018/06/19 01:14

>このmaxが変動するのがおかしい為に、移動制限ができていないということでしょうか? そうなります。 試しにviewport.zの部分を固定値にするとどうなるかとか(恐らく変わらないように思いますが)、 いっそmaxをViewportToWorldPointから取得しない完全固定値にするとどうなるか確認してみてください。
退会済みユーザー

退会済みユーザー

2018/06/19 11:34

ご回答ありがとうございます。 追記③を追記しました。 maxを空のゲームオブジェクトの位置の固定値に設定したのですが、 空のゲームオブジェクトを通り過ぎても、少し軌道を変えて移動を続けました。
sakura_hana

2018/06/20 01:53

制限しているのはXだけなので、YとZ方向に移動し続けるのは当然ですね。 (this.transform.rightのY値が0なので結果的にY軸の移動はしていませんが、制限無し状態ではある)
退会済みユーザー

退会済みユーザー

2018/06/20 15:36

ご回答ありがとうございます。 空のゲームオブジェクトの検証では、Z方向も制限することで停止することが確認できました。 すみません、画面外の制限が説明不足でしたので、追記④を追記しました。 画面外の制限の場合、右方向に進むたびにZの値も変わるので、 posのZ値は更新を続けるviewport.zのminとmaxで制限すべきなのかと思って試してみたのですが、意図しない動きになってしまいました。 どのようにすれば画面外制限が実現できますか? 何度もすみません。
sakura_hana

2018/06/21 01:13

なるほど、実際にZ方向にも動くんですね。 ViewportToWorldPointは「Z地点に存在する平面」を基準としてワールド座標を取得します。 なのでZ値の制限は出来ません。(Z値を基準として範囲を決定しているので、そのZ値が動いたら基準となる範囲も変わる) とは言えX値が制限に達した時にZ値も移動不可となる訳ですから、ここは比例関係になります。 Vector3 baseVelocity = this.transform.right * speed; //ベースとなる速度 Vector3 pos = this.transform.position + this.transform.TransformDirection(baseVelocity); pos.x = Mathf.Clamp(pos.x, min.x, max.x); //一旦速度を算出 Vector3 vel = transform.InverseTransformDirection(pos - this.transform.position); vel.z = vel.z * pos.x / baseVelocity.x; rb.velocity = vel; 元の速度X値とClamp後のX値の割合を算出。元の速度Z値にその割合を反映させています。 精査出来ていませんので適宜綺麗にしてもらえればと思います。(Y値も動くなら上手いこと調整は必要かと) ただし、カメラから離れれば離れる程見えていると判定される範囲は広がりますので、カメラ位置固定の場合は画面端で微妙に動き続けると思います。 Z値の範囲を定数で定めてしまうか、カメラがターゲットを(Z方向だけでも)追いかけるようにする必要があるかと思います。
退会済みユーザー

退会済みユーザー

2018/06/21 15:16

ご回答ありがとうございます。 なるほど、比例関係で表せるのですね。 しかし、「vel.z = vel.z * pos.x / baseVelocity.x;」で実行した所、よくわからない移動を続けたので(画面外に出てからカメラに近づいて一旦停止後、またカメラから離れる方向に動き続ける) 試しに「vel.z = vel.z * vel.x /baseVelocity.x;」と書いた所、割とそれっぽい動きをしたのですが、 停止位置が画面外よりややオーバーしてしまいました(追記⑤の画像です)。 このコードの修正が合っているかどうかも自信がないのですが、画面外にけっこう出てしまうのは、これ以上修正の効かない誤差なのでしょうか?
sakura_hana

2018/06/22 01:41

計算式はご指摘の通りです(こちらが間違えてました)。 「正常に動作はしているが誤差っぽい」という結果なので、 現在Updateに入っている計算式を全部FixedUpdateに入れるとどうでしょうか。 (50fps以上出ているならあまり変わらないとは思いますが)
退会済みユーザー

退会済みユーザー

2018/06/22 11:29

ご回答ありがとうございます。 Update内の処理もFixedUpdateにまとめてみたのですが、結果はあまり変わらなかったです。 ただ、maxのviewportを0.8f辺りに設定することで画面境界付近で停止してくれました。 無理矢理な対処法にはなってしまいますが、これよりもキレイなコードで修正できる方法ってないですよね?
sakura_hana

2018/06/25 06:43

私もZ値が動くケースはやったことが無いので、近似値が出せたならそれで収めた方がいいかもしれないです。 綺麗にまとめられずすみません。
退会済みユーザー

退会済みユーザー

2018/06/25 15:35 編集

ご回答ありがとうございます。 いえいえ、とんでもないです。 ご教示くださり、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問