球体を複数の指定した角度に回転させたい!

マウスで島を回転しクリックしてステージ選択をしていたのですが

ゲーム内でマウスを使うのはここだけだったのでキーボードでステージ選択をさせたいと思いました!

 f:id:ookami_youjyo:20190913114622g:plain

 

まずは試しに手動で座標を取りQuaternionで回転させます

 

public GameObject Mother_star; //回転させる星

public Vector3 point;//ステージの座標

int select_stage = 0; //選択中のステージpublic

float rotation_speed = 3f;//回転スピード


void Update()
{

//回転の命令

Mother_star.transform.rotation = Quaternion.Slerp(Mother_star.transform.rotation, Quaternion.Euler(point[select_stage]), rotation_speed * Time.deltaTime);

 

 if (Input.GetKeyDown(KeyCode.Space))//スペースで次のステージ
 {
  select_stage++;
 }
}

 

 

public Vector3 point;でステージが正面に向く回転座標をUnity側から入力をしていきます

今回は5つ入力します

f:id:ookami_youjyo:20190906101110p:plain

この座標に星を回転さえます

使いのはQuaternionのSlerp

これは少しずつ回転させたいときに便利なやつです

使い方を簡単に説明しますと

 

現在の回転角度 = Quaternion.Slerp(現在の回転角度,向きたい座標,向くまでの時間);

です

 

今回のコードの場合は

現在の回転角度はみんな大好きtransform.rotation

向きたい座標はQuaternion.Euler(point[select_stage])

向くまでの時間はrotation_speed * Time.deltaTime

になります

残りの部分はただスペースを押したらselect_stageの値が増えステージが切り替わるだけのやつです

 

コードの説明は以上です、では実行してみましょう

 

f:id:ookami_youjyo:20190913121642g:plain

 

スペースを押すと自動で動くようになりました

 

続いて座標を自動取得にします
public GameObject star; //回転されたい方向の目印

void rotation()//星の回転位置の保存
{
 for (int i = 1; i < star.Length + 1; i++) //記録したい座標の数だけループ
 {

   //母性の原点と手前方向とクリアスターから中心軸を求める
   Vector3 n = Vector3.Cross(star[i - 1].transform.position, Vector3.back); 

   //母性の中心軸とクリアスターから回転させたい角度を求める
   float th = Vector3.SignedAngle(star[i - 1].transform.position, Vector3.back, n);
   Quaternion rot = Quaternion.AngleAxis(th, n); //回転を保存
   point[i] = rot.eulerAngles; //回転をeulerに変換して格納
 }
}

これを加えます

 

まず正面に来てほしい場所にいる目印となるオブジェクトをstarにいれます

今回はゲームをクリアしたら出る星を目印にしますが空のオブジェクトでも何でもいいです

これを元に回転ルートを計算します

回転ルートの計算を書きます、まず中心軸を求めます

回転させたい母星は原点にいるのでVector3.Crossを使います

Vector3 中心軸 = Vector3.Cross(目印, Vector3.back); 

このようにかけば求まります

 

次に回転角度を求めます

Vector3.SignedAngleをつかいます

float 角度 = Vector3.SignedAngle(目印, Vector3.back, 中心軸);

で求まります

 

求めた角度と中心軸でQuaternion型にし回転を保存します

Quaternion 回転 = Quaternion.AngleAxis(角度, 中心軸);

最後に回転をeulerに変換して格納すれば完了です

以上で完成です、動かしてみましょう

f:id:ookami_youjyo:20190913121426g:plain

 

こんな感じに実行すると自動で座標が求められています

f:id:ookami_youjyo:20190913115850g:plain

 

最後に最初のGIF画像の時と同じくタイトルやステージ移行などを付けた状態です

f:id:ookami_youjyo:20190913121024g:plain

こちらは今回の本題と違うのでソースコードは載せますが解説はしません

おまけ程度のものです

 

以上で終わります、ありがとうございました

 

void Start()
{
date = PlayerPrefs.GetInt("cleardata", 0); //クリア状況の確認
rotation();//最初に星の回転位置の保存を実行する
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////プレイヤーの操作///////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////


int select_stage = 0; //選択中のステージ
public GameObject Mother_star; //回転させる星
public float rotation_speed = 5f; //回転スピード
int date; //クリア状況保存
int rock = 0;

void Update()
{
if (rock == 0) //操作できなくするためのロック
{
//回転命令
Mother_star.transform.rotation = Quaternion.Slerp(Mother_star.transform.rotation, Quaternion.Euler(point[select_stage]), rotation_speed * Time.deltaTime);

if (Input.GetKeyDown(KeyCode.RightArrow))//次のステージ
{
select_stage++; //選択中ステージを変える
if (date == 10) //全部クリア時の処理
{
if (select_stage > date) //ステージ10より先のステージを選ぼうとした時ステージ1に戻す
{
select_stage = 1;
}
}
else  //攻略中の処理
{
if (select_stage > date + 1) //クリア済み + 未クリアより先のステージを選ぼうとした時ステージ1に戻す
{
select_stage = 1;
}
}
text();
}
if (Input.GetKeyDown(KeyCode.LeftArrow))//前のステージ
{
select_stage--; //選択中ステージを変える
if (date == 10)//全部クリア時の処理
{
if (select_stage < 1) //ステージ1より前のステージを選ぼうとしたらステージ10へ
{
select_stage = date;
}
}
else //攻略中の処理
{
if (select_stage < 1) //ステージ1より前のステージを選ぼうとしたら未クリアステージへ
{
select_stage = date + 1;//クリア済み + 未クリア
}
}
text();
}
if (select_stage != 0) //ステージ選択時の処理
{
if (Input.GetKeyDown(KeyCode.Z)) //Zを押したらゲームスタート
{
Game_Start();
rock++; //操作できなくする
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////星の回転位置の保存////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///
public Vector3 point; //星の座標
public GameObject star; //回転されたい方向の目印

void rotation()//星の回転位置の保存
{
for (int i = 1; i < star.Length + 1; i++) //記録したい座標の数だけループ
{
Vector3 n = Vector3.Cross(star[i - 1].transform.position, Vector3.back); //母性の原点と手前方向とクリアスターから中心軸を求める
float th = Vector3.SignedAngle(star[i - 1].transform.position, Vector3.back, n); //母性の中心軸とクリアスターから回転させたい角度を求める
Quaternion rot = Quaternion.AngleAxis(th, n); //回転を角度を回転に保存
point[i] = rot.eulerAngles; //回転をeulerに変換して格納
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////ステージタイトル/////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[SerializeField] private TextMeshProUGUI Title_Text;
float alfa = 0; //フェードスピード//白いパネルの透明度
public float fadeSpeed = 0.01f;

void text()
{
SE.play(0); //SEを鳴らす
alfa = 0; //Txet透明度リセット
StartCoroutine(fadeout()); //フェードアウトをするコルーチンを実行

//表示テキスト内容の変更
switch (select_stage)
{
case 1:
Title_Text.text = "STAGE1\nBeginning island";
break;
case 2:
Title_Text.text = "STAGE2\nSmall hill";
break;
case 3:
Title_Text.text = "STAGE3\nPoison river";
break;
case 4:
Title_Text.text = "STAGE4\nTriangular flight";
break;
case 5:
Title_Text.text = "STAGE5\nUp Up Down";
break;
case 6:
Title_Text.text = "STAGE6\nBackyard";
break;
case 7:
Title_Text.text = "STAGE7\nMushroom fly";
break;
case 8:
Title_Text.text = "STAGE8\nRiding the fluff";
break;
case 9:
Title_Text.text = "STAGE9\nBall riding";
break;
case 10:
Title_Text.text = "STAGE10\nIsland of the end";
break;
}
}

IEnumerator fadeout() //フェードアウトコルーチン
{
while (StartFadeOuttext()) //StartFadeOutからfalseが返ってくるまで実行
{
yield return null; //ループを1フレームの間止める
}
}
bool StartFadeOuttext() //⑥コルーチンに呼び出される
{
Title_Text.color = new Color(255, 255, 255, alfa += fadeSpeed); //透明度下げ反映
if (alfa >= 1) //完全に不透明になったらループを抜ける
{
return false; //コルーチンのループを止める
}
return true; //コルーチンのループに戻る
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////ステージスタート////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Game_Start_FadeSpeed = 0.01f, alfa1 = 0, Camera_Speed = 0.065f; //フェードスピード//白いパネルの透明度//カメラの前進スピード
public Image fadeImage; //白いパネル
public GameObject kamera; //カメラオブジェクト//星オブジェクト
public Transform target;//追いかける対象-オブジェクトをインスペクタから登録できるように
private Vector3 vec;


public void Game_Start()
{
SE.play(1);
StartCoroutine(fadeout1()); //フェードアウトをするコルーチンを実行
}
IEnumerator fadeout1() //フェードアウトコルーチン
{
while (StartFadeOut()) //StartFadeOutからfalseが返ってくるまで実行
{
yield return null; //ループを1フレームの間止める
}
}
bool StartFadeOut() //コルーチンに呼び出される
{
//targetの方に少しずつ向きが変わる
kamera.transform.rotation = Quaternion.Slerp(kamera.transform.rotation, Quaternion.LookRotation(target[select_stage - 1].position - kamera.transform.position), 0.05f);
//targetに向かって進む
kamera.transform.position += kamera.transform.forward * Camera_Speed;
fadeImage.enabled = true; //透明な白いパネルを表示
fadeImage.color = new Color(255, 255, 255, alfa1 += Game_Start_FadeSpeed); //透明度下げ反映
if (alfa1 >= 1) //完全に不透明になったらループを抜ける
{
//シーン切り替え

switch (select_stage)
{
case 1:
SceneManager.LoadScene("stage1");
break;
case 2:
SceneManager.LoadScene("stage2");
break;
case 3:
SceneManager.LoadScene("stage3");
break;
case 4:
SceneManager.LoadScene("stage4");
break;
case 5:
SceneManager.LoadScene("stage5");
break;
case 6:
SceneManager.LoadScene("stage6");
break;
case 7:
SceneManager.LoadScene("stage7");
break;
case 8:
SceneManager.LoadScene("stage8");
break;
case 9:
SceneManager.LoadScene("stage9");
break;
case 10:
SceneManager.LoadScene("stage10");
break;
}
return false; //コルーチンのループを止める
}
return true; //コルーチンのループに戻る
}