🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

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

Q&A

解決済

1回答

3228閲覧

Mathf.Lerpを使った滑らかな移動

sadaxxxx

総合スコア1

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

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

0グッド

0クリップ

投稿2020/12/04 19:08

前提・実現したいこと

まず最初に謝っておきます。
Unityを使い始めたのが2週間前でc#を習ったこともなく、他のプログラミング言語も少し習った程度で、このサイトを使うも初めてなので至らないことも多いと思います。すみません。

Unityでオブジェクトを円運動させて、任意のタイミングで円運動の軌道を滑らかにずらすアニメーションを作っています。

開始から0〜5秒で(0,0,30)を中心に半径8で円運動し、
5〜10秒で中心点が(0,0,30)から(10,0,30)に滑らかに変化しつつ円運動をするようにしたいです。
それ以降の動きは変更予定です。

下記のリンクの他の似たような質問のCarly7766さんの回答を参考にしました
https://teratail.com/questions/158232

発生している問題・エラーメッセージ

製作したプログラムにエラーは出ませんでしたがUnityでアニメーションを実行すると任意のタイミングで滑らかに移動せずに瞬間移動してしまいます。 ### 該当のソースコード ```c# using System.Collections; using System.Collections.Generic; using UnityEngine; public class animation : MonoBehaviour { // Start is called before the first frame update private float speed;//回転速度 private float radius;//回転半径 private float zPosition;//回転する位置(奥行) private float count;//カウントタイマー private float endValue;//軌道を逸れる時の距離 private float duration;//軌道を逸れるのにかかる時間(逸れる速さを変えられる) float startTime;//逸れ始める時刻 float diff;//経過時間 float rate;//経過時間とduration(逸れる時間)の割合(逸れる時間に依存して0~1の間で値変化) float t;//(durationの時間かけてendValueの距離)軌道を逸れるための変数 float x;//座標 float y;//座標 float z;//座標 void Start() { speed = 1.0f;//回転速度 radius = 8.0f;//回転半径 zPosition = 30.0f;//回転する位置(奥行) t = 0;//軌道を逸れるための変数 endValue = 10;//軌道を逸れる距離 duration = 2.5f;//軌道を逸れるのにかかる時間(秒) startTime = Time.timeSinceLevelLoad;//逸れ始める時刻 count = 0.0f;//カウントタイマー } // Update is called once per frame void Update() { count += Time.deltaTime;//秒数のカウント if (5.0f <= count && count < 10.0f)//5秒から10秒の場合 { diff = Time.timeSinceLevelLoad - startTime;//経過時刻=現在時刻-開始時刻 rate = diff / duration;//割合=経過時刻/設定時間(0~1で変化) 経過時刻=設定時間で1になる t = Mathf.Lerp(0, endValue, rate);//rate(0~1)の変化にあわせて0~endValueの間を変化する変数(rateの変化する速さは設定時間に依存する) x = radius * Mathf.Sin(Time.time * speed) + t;//xの値をsin(時間*回転速度)で変化+軌道を逸れる y = radius * Mathf.Cos(Time.time * speed);//yの値をcos(時間*回転速度)で変化 z = zPosition;//zの値(奥行)は初期位置のまま transform.position = new Vector3(x, y, z);//x,y,zの位置を移動 } else if (10.0f <= count && count < 15.0f)//10秒から15秒の場合 { diff = Time.timeSinceLevelLoad - startTime; rate = diff / duration; t = Mathf.Lerp(0, endValue, rate); x = radius * Mathf.Sin(Time.time * speed) - t; y = radius * Mathf.Cos(Time.time * speed); z = zPosition; transform.position = new Vector3(x, y, z); } else if (15.0f <= count && count < 20.0f)//15秒から20秒の場合 { x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed) + 10; z = zPosition; transform.position = new Vector3(x, y, z); } else if (20.0f <= count && count < 25.0f)//20秒から25秒の場合 { x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed) - 10; z = zPosition; transform.position = new Vector3(x, y, z); } else { x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed); z = zPosition; transform.position = new Vector3(x, y, z); } } }

試したこと

軌道を逸れる速さが速すぎるのかと思い1.5秒から2.5秒にしましたが瞬間移動してるようです

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

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

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

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

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

ozwk

2020/12/04 22:55

diffの値を確認してみましょう
sadaxxxx

2020/12/05 04:03 編集

ご指摘ありがとうございます! Time.timeSinceLevelLoad がこれを書いたタイミングからの時間でdiffを開始時刻と現在時刻の差にしたければ、 diff = Time.time - startTime; にするべきとういうことですね!
sadaxxxx

2020/12/05 04:04 編集

すみません試してみましたが違うみたいですね… Time.timeSinceLevelLoadが既に経過時間の役割をしてる気がしてきたので startTimeを消してdiff=Time.timeSinceLevelLoad; でやってみます
sadaxxxx

2020/12/05 03:25

すみません… どうやっても瞬間移動になってしまいました…
sadaxxxx

2020/12/12 06:18

以下のように書き直したら動作しました。 using System.Collections; using System.Collections.Generic; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { // Start is called before the first frame update private float speed;//回転速度 private float radius;//回転半径 private float zPosition;//回転する位置(奥行) private float count;//開始からの時刻 private float endValue;//軌道を逸れる時の距離 private float duration;//軌道を逸れるのにかかる時間(逸れる速さを変えられる) float startTime;//開始時刻(ズレ防止) float diff;//経過時間 float rate;//経過時間とduration(逸れる時間)の割合(逸れる時間に依存して0~1の間で値変化) float t;//(durationの時間かけてendValueの距離)軌道を逸れるための変数 float x;//座標 float y;//座標 float z;//座標 void Start() { speed = 1.0f;//回転速度 radius = 8.0f;//回転半径 zPosition = 30.0f;//回転する位置(奥行) t = 0;//軌道を逸れるための変数 endValue = 10.0f;//軌道を逸れる距離 duration = 0.2f;//軌道を逸れるのにかかる時間(秒) startTime = Time.timeSinceLevelLoad;//開始時刻 } // Update is called once per frame void Update() { count = Time.timeSinceLevelLoad; if (count >= 5.0f && count < 10.0f)//5秒から10秒の場合 { diff = Time.timeSinceLevelLoad - startTime - 5.0f;//経過時刻=現在時刻-開始時刻 rate = diff / duration;//割合=経過時刻/設定時間(0~1で変化) 経過時刻=設定時間で1になる t = Mathf.Lerp(0, endValue, rate);//rate(0~1)の変化にあわせて0~endValueの間を変化する変数(rateの変化する速さは設定時間に依存する) x = radius * Mathf.Sin(Time.time * speed) + t;//xの値をsin(時間*回転速度)で変化+軌道を逸れる y = radius * Mathf.Cos(Time.time * speed);//yの値をcos(時間*回転速度)で変化 z = zPosition;//zの値(奥行)は初期位置のまま transform.position = new Vector3(x, y, z);//x,y,zの位置を移動 } else if (count >= 10.0f && count < 15.0f)//10秒から15秒の場合 { diff = Time.timeSinceLevelLoad - startTime - 10.0f; rate = diff / duration; t = Mathf.Lerp(0, endValue, rate); x = radius * Mathf.Sin(Time.time * speed) - t; y = radius * Mathf.Cos(Time.time * speed); z = zPosition; transform.position = new Vector3(x, y, z); } else if (count >= 15.0f && count < 20.0f)//15秒から20秒の場合 { diff = Time.timeSinceLevelLoad - startTime - 15; rate = diff / duration; t = Mathf.Lerp(0, endValue, rate); x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed) + t; z = zPosition; transform.position = new Vector3(x, y, z); } else if (count >= 20.0f && count < 25.0f)//20秒から25秒の場合 { diff = Time.timeSinceLevelLoad - startTime - 20.0f; rate = diff / duration; t = Mathf.Lerp(0, endValue, rate); x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed) - t; z = zPosition; transform.position = new Vector3(x, y, z); } else { x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed); z = zPosition; transform.position = new Vector3(x, y, z); } } }
guest

回答1

0

ベストアンサー

動きを「回転中心点の平行移動」と「回転中心点周りの円運動」に分解して考えるのはどうでしょう。
下記のようなコードにしてみたところ...

C#

1using UnityEngine; 2 3public class animation : MonoBehaviour 4{ 5 float speed;//回転速度 6 float radius;//回転半径 7 float zPosition;//回転する位置(奥行) 8 float count;//カウントタイマー 9 float endValue;//軌道を逸れる時の距離 10 11 // Start is called before the first frame update 12 void Start() 13 { 14 speed = 8.0f;//回転速度 15 radius = 4.0f;//回転半径 16 zPosition = 30.0f;//回転する位置(奥行) 17 endValue = 10;//軌道を逸れる距離 18 count = 0.0f;//カウントタイマー 19 } 20 21 // Update is called once per frame 22 void Update() 23 { 24 count += Time.deltaTime;//秒数のカウント 25 26 Vector3 from; 27 Vector3 to; 28 float rate; 29 30 if (count < 5.0f)//0秒から5秒の場合 31 { 32 // 5秒までは回転中心の位置は(0, 0, 0)とする 33 from = Vector3.zero; 34 to = Vector3.zero; 35 rate = 0.0f; 36 } 37 else if (count < 10.0f)//5秒から10秒の場合 38 { 39 // (0, 0, 0)の位置を起点とし... 40 from = Vector3.zero; 41 42 // (endValue, 0, 0)の位置を終点とし... 43 to = new Vector3(endValue, 0.0f, 0.0f); 44 45 // 5秒を0、10秒を1としたときの現在の時刻の割合を求めておく 46 rate = Mathf.InverseLerp(5.0f, 10.0f, count); 47 } 48 else if (count < 15.0f)//10秒から15秒の場合 49 { 50 from = new Vector3(endValue, 0.0f, 0.0f); 51 to = new Vector3(-endValue, 0.0f, 0.0f); 52 rate = Mathf.InverseLerp(10.0f, 15.0f, count); 53 } 54 else if (count < 20.0f)//15秒から20秒の場合 55 { 56 from = new Vector3(-endValue, 0.0f, 0.0f); 57 to = new Vector3(0.0f, 10.0f, 0.0f); 58 rate = Mathf.InverseLerp(15.0f, 20.0f, count); 59 } 60 else if (count < 25.0f)//20秒から25秒の場合 61 { 62 from = new Vector3(0.0f, 10.0f, 0.0f); 63 to = new Vector3(0.0f, -10.0f, 0.0f); 64 rate = Mathf.InverseLerp(20.0f, 25.0f, count); 65 } 66 else 67 { 68 from = new Vector3(0.0f, -10.0f, 0.0f); 69 to = Vector3.zero; 70 rate = Mathf.InverseLerp(25.0f, 30.0f, count); 71 } 72 73 // 回転運動成分は回転中心に対する相対位置として表現し... 74 Vector3 offset = new Vector3( 75 radius * Mathf.Sin(Time.time * speed), //xの値をsin(時間*回転速度)で変化 76 radius * Mathf.Cos(Time.time * speed), //yの値をcos(時間*回転速度)で変化 77 zPosition); //zの値(奥行)は初期位置のまま 78 79 // 先のif分岐で決定したfrom、to、rateをもとに回転中心の位置を決め... 80 Vector3 center = Vector3.Lerp(from, to, rate); 81 82 // オブジェクトの最終的な位置はcenterとoffsetの和とする 83 transform.position = center + offset;//x,y,zの位置を移動 84 } 85}

下図のような動きになりました。なお、回転中心が動いていることをわかりやすくするため、ご質問者さんのコードよりもspeedを大きく、radiusを小さくしています。

図

投稿2020/12/05 22:40

Bongo

総合スコア10811

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

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

sadaxxxx

2020/12/07 02:06

ご回答ありがとうございます。 offsetやIverslerpなのど知らなかったのでとてもありがたいご回答なのですが、あとで動きを調整できるように speed;//回転速度 radius;//回転半径 zPosition//回転する位置(奥行) endValue //軌道を逸れる距離 duration //軌道を逸れるのにかかる時間(速度を変えられるもの) startTime //逸れ始める時刻 の変数を残しておきたいです。 でもoffsetで円運動を表して、中心点を相対的な位置で表すという手法で新しくできそうな気がしています。 本当にありがとうございます。
sadaxxxx

2020/12/07 10:20

Time.timeSinceLevelLoadの理解が間違っていました。Bongoさんありがとうございます。 以下のように書き直したら動作しました。 using System.Collections; using System.Collections.Generic; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { // Start is called before the first frame update private float speed;//回転速度 private float radius;//回転半径 private float zPosition;//回転する位置(奥行) private float count;//開始からの時刻 private float endValue;//軌道を逸れる時の距離 private float duration;//軌道を逸れるのにかかる時間(逸れる速さを変えられる) float startTime;//開始時刻(ズレ防止) float diff;//経過時間 float rate;//経過時間とduration(逸れる時間)の割合(逸れる時間に依存して0~1の間で値変化) float t;//(durationの時間かけてendValueの距離)軌道を逸れるための変数 float x;//座標 float y;//座標 float z;//座標 void Start() { speed = 1.0f;//回転速度 radius = 8.0f;//回転半径 zPosition = 30.0f;//回転する位置(奥行) t = 0;//軌道を逸れるための変数 endValue = 10.0f;//軌道を逸れる距離 duration = 0.2f;//軌道を逸れるのにかかる時間(秒) startTime = Time.timeSinceLevelLoad;//開始時刻 } // Update is called once per frame void Update() { count = Time.timeSinceLevelLoad; if (count >= 5.0f && count < 10.0f)//5秒から10秒の場合 { diff = Time.timeSinceLevelLoad - startTime - 5.0f;//経過時刻=現在時刻-開始時刻 rate = diff / duration;//割合=経過時刻/設定時間(0~1で変化) 経過時刻=設定時間で1になる t = Mathf.Lerp(0, endValue, rate);//rate(0~1)の変化にあわせて0~endValueの間を変化する変数(rateの変化する速さは設定時間に依存する) x = radius * Mathf.Sin(Time.time * speed) + t;//xの値をsin(時間*回転速度)で変化+軌道を逸れる y = radius * Mathf.Cos(Time.time * speed);//yの値をcos(時間*回転速度)で変化 z = zPosition;//zの値(奥行)は初期位置のまま transform.position = new Vector3(x, y, z);//x,y,zの位置を移動 } else if (count >= 10.0f && count < 15.0f)//10秒から15秒の場合 { diff = Time.timeSinceLevelLoad - startTime - 10.0f; rate = diff / duration; t = Mathf.Lerp(0, endValue, rate); x = radius * Mathf.Sin(Time.time * speed) - t; y = radius * Mathf.Cos(Time.time * speed); z = zPosition; transform.position = new Vector3(x, y, z); } else if (count >= 15.0f && count < 20.0f)//15秒から20秒の場合 { diff = Time.timeSinceLevelLoad - startTime - 15; rate = diff / duration; t = Mathf.Lerp(0, endValue, rate); x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed) + t; z = zPosition; transform.position = new Vector3(x, y, z); } else if (count >= 20.0f && count < 25.0f)//20秒から25秒の場合 { diff = Time.timeSinceLevelLoad - startTime - 20.0f; rate = diff / duration; t = Mathf.Lerp(0, endValue, rate); x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed) - t; z = zPosition; transform.position = new Vector3(x, y, z); } else { x = radius * Mathf.Sin(Time.time * speed); y = radius * Mathf.Cos(Time.time * speed); z = zPosition; transform.position = new Vector3(x, y, z); } } }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問