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

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

ただいまの
回答率

90.51%

  • Unity

    3996questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • Unity3D

    1290questions

    Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

方向キーの入力を一度だけ取りたい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 882

jum6948

score 13

前提・実現したいこと

タイトル画面にて、以下のような感じの選択肢があるのですが

▶ ゲームスタート
_ランキング
_コンフィグ

コントローラーの左スティックを倒した時にカーソルを一段だけ下げたい。
また、カーソルが一番上に有る時にスティックを上に倒すと一番下(この場合コンフィグ)、カーソルが一番下に有る時にスティックを上に倒すと一番上(この場合ゲームスタート)にカーソルが行くようにしたいです。
(現在使用中のコントローラーはXbox360のものを使用中)
動的に動かしているのを見せたいので【iTween】を使用しています。

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

カーソルが、下に行き過ぎたり、上に行き過ぎたり、画面外に出たり、Updateで入力を受け付けているので、かなりのスピードでカーソルが動く。

該当のソースコード

public class GameDirectorTitle : MonoBehaviour {

    [Header("ゲームモードを選ぶ")]
    public GameObject SelectIcon;
    public int SelectIconPosition;

    // Use this for initialization
    void Start () {
        SelectIconPosition = 0;
    }

    // Update is called once per frame
    void Update() {
        StartCoroutine(SelectIconMove());
    }

    IEnumerator SelectIconMove()
    {
        //カーソルがゲームスタートの時
        if (SelectIconPosition == 0)
        {
            //十字キーを上
            if (Input.GetAxisRaw("Vertical") == 1)
            {
                //カーソル移動
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -160f, "time", 0.25f));
                //【Config】
                SelectIconPosition = 2;
                Debug.Log("0,+1");
                yield return new WaitForSeconds(0.25f);
            }
            //十字キーを下
            else if (Input.GetAxisRaw("Vertical") == -1)
            {
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -80f, "time", 0f));
                //【ランキング】
                SelectIconPosition = 1;
                Debug.Log("0,-1");
                yield return new WaitForSeconds(0.25f);
            }
            //決定ボタンを押す
            else if (Input.GetButtonDown("AtackX"))
            {
                SceneManager.LoadScene("new-stage1");
            }
        }
        //カーソルがランキングの時
        else if (SelectIconPosition == 1)
        {
            //十字キーを上
            if (Input.GetAxisRaw("Vertical") == 1)
            {
                //カーソル移動
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 80f, "time", 0.01f));
                //【ゲームスタート】
                SelectIconPosition = 0;
                Debug.Log("1,+1");
                yield return new WaitForSeconds(0.25f);
            }
            //十字キーを下
            else if (Input.GetAxisRaw("Vertical") == -1)
            {
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -80f, "time", 0f));
                //【Config】
                SelectIconPosition = 2;
                Debug.Log("1,-1");
                yield return new WaitForSeconds(0.25f);
            }
            //決定ボタンを押す
            else if (Input.GetButtonDown("AtackX"))
            {

            }
        }
        //カーソルがConfigの時
        else if (SelectIconPosition == 2)
        {
            //十字キーを上
            if (Input.GetAxisRaw("Vertical") == 1)
            {
                //カーソル移動
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 80f, "time", 0.01f));
                //【ランキング】
                SelectIconPosition = 1;
                Debug.Log("2,+1");
                yield return new WaitForSeconds(0.25f);
            }
            //十字キーを下
            else if (Input.GetAxisRaw("Vertical") == -1)
            {
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 160f, "time", 0f));
                //【ゲームスタート】
                SelectIconPosition = 0;
                Debug.Log("2,-1");
                yield return new WaitForSeconds(0.25f);
            }
            //決定ボタンを押す
            else if (Input.GetButtonDown("AtackX"))
            {

            }

        }
    }

}

試したこと

コンフィグ画面、ランキング画面はまだ作っておりません。
【SelectIconPosition】は選んでいるカーソルの位置で、
ゲームスタート【0】
ランキング__【1】
コンフィグ__【2】
で0の時に上を押せば、カーソルが一番下に行くという考えで作ったのですが、カーソルが画面外に出ていってしまいました。
また、一回の動作ごとにコルーチンで休みを挟めばいいかと思って移動ごとに【0.25f】一時停止するようにしてみましたが、コレもダメ。
【void PositionUp】というクラスを別に作って、みましたが、根本がUpdateから取っているのでその関数が連続で実行されてしまって、これもダメ。ダレカタスケテッ!

補足情報(言語/FW/ツール等のバージョンなど)

【環境】 
Unity5.6.1f1 personal 
win10 
MicrosoftVisualStudio
上記が作成環境になっております。

【おまけのおたすけ】
いつも私の質問に答えていただいている皆様、本当にありがとうございます。

根本的に、本を2冊ほどしか読んでいないので、知ってる知識が少なすぎる問題なんだとは思います。
ただ、友達がオススメしてくれる本が、字ばっかりでまったく理解が出来ません。自分は、図解がないとイメージがわかず、理解が出来ない、のだと分析します。

てめぇのクソ質問に答えるのがうんざりだと言う方、もし宜しければ、わかりやすいオススメの本とかあれば教えてください。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

    // Update is called once per frame
    void Update() {
        StartCoroutine(SelectIconMove());
    }

上記を書いてしまっているので、毎フレーム、コルーチンを開始していることになります。
そのため、yield return new WaitForSeconds(0.25f);としても、Update()で別のコルーチンが開始されてしまうので、意味の無い状態になります。

解決策としては、以下のいずれかをとればよいです。

・コルーチンが終了するまで、新たなコルーチンを開始させない

    // コルーチンが実行中かどうか
    bool nowExecCoroutine_ = false;

    // …(中略)

    // Update is called once per frame
    void Update()
    {
        if (!nowExecCoroutine_)
        {
            nowExecCoroutine_ = true;
            StartCoroutine(SelectIconMove());
        }
    }

    IEnumerator SelectIconMove()
    {
        // …(中略)

        nowExecCoroutine_ = false;
    }

・コルーチンではなく関数で定義、Update()上で最後の操作から何秒経過したかを取得・計算し、0.25秒以上経過していればその関数を実行する

    // 最後に十字キーが押された時間
    float lastTimeArrowKeyDown_ = 0f;

    // …(中略)

        // Update is called once per frame
    void Update()
    {
        if (Time.time - lastTimeArrowKeyDown_ > 0.25f)
        {
            SelectIconMove();
        }
    }

    void SelectIconMove()
    {
        //カーソルがゲームスタートの時
        if (SelectIconPosition == 0)
        {
            //十字キーを上
            if (Input.GetAxisRaw("Vertical") == 1)
            {
                //カーソル移動
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -160f, "time", 0.25f));
                //【Config】
                SelectIconPosition = 2;
                Debug.Log("0,+1");
                lastTimeArrowKeyDown_ = Time.time;
            }
            //十字キーを下
            else if (Input.GetAxisRaw("Vertical") == -1)
            {
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -80f, "time", 0f));
                //【ランキング】
                SelectIconPosition = 1;
                Debug.Log("0,-1");
                lastTimeArrowKeyDown_ = Time.time;
            }
            //決定ボタンを押す
            else if (Input.GetButtonDown("AtackX"))
            {
                SceneManager.LoadScene("new-stage1");
            }
        }
        //カーソルがランキングの時
        else if (SelectIconPosition == 1)
        {
            //十字キーを上
            if (Input.GetAxisRaw("Vertical") == 1)
            {
                //カーソル移動
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 80f, "time", 0.01f));
                //【ゲームスタート】
                SelectIconPosition = 0;
                Debug.Log("1,+1");
                lastTimeArrowKeyDown_ = Time.time;
            }
            //十字キーを下
            else if (Input.GetAxisRaw("Vertical") == -1)
            {
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -80f, "time", 0f));
                //【Config】
                SelectIconPosition = 2;
                Debug.Log("1,-1");
                lastTimeArrowKeyDown_ = Time.time;
            }
            //決定ボタンを押す
            else if (Input.GetButtonDown("AtackX"))
            {

            }
        }
        //カーソルがConfigの時
        else if (SelectIconPosition == 2)
        {
            //十字キーを上
            if (Input.GetAxisRaw("Vertical") == 1)
            {
                //カーソル移動
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 80f, "time", 0.01f));
                //【ランキング】
                SelectIconPosition = 1;
                Debug.Log("2,+1");
                lastTimeArrowKeyDown_ = Time.time;
            }
            //十字キーを下
            else if (Input.GetAxisRaw("Vertical") == -1)
            {
                iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 160f, "time", 0f));
                //【ゲームスタート】
                SelectIconPosition = 0;
                Debug.Log("2,-1");
                lastTimeArrowKeyDown_ = Time.time;
            }
            //決定ボタンを押す
            else if (Input.GetButtonDown("AtackX"))
            {

            }

        }
    }

・コルーチン上でループさせる。コルーチン自体はStart()で一度だけ実行する

    // Use this for initialization
    void Start()
    {
        SelectIconPosition = 0;
        StartCoroutine(SelectIconMove());
    }

    IEnumerator SelectIconMove()
    {
        bool breakFlag = false;
        do
        {
            //カーソルがゲームスタートの時
            if (SelectIconPosition == 0)
            {
                //十字キーを上
                if (Input.GetAxisRaw("Vertical") == 1)
                {
                    //カーソル移動
                    iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -160f, "time", 0.25f));
                    //【Config】
                    SelectIconPosition = 2;
                    Debug.Log("0,+1");
                    yield return new WaitForSeconds(0.25f);
                }
                //十字キーを下
                else if (Input.GetAxisRaw("Vertical") == -1)
                {
                    iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -80f, "time", 0f));
                    //【ランキング】
                    SelectIconPosition = 1;
                    Debug.Log("0,-1");
                    yield return new WaitForSeconds(0.25f);
                }
                //決定ボタンを押す
                else if (Input.GetButtonDown("AtackX"))
                {
                    SceneManager.LoadScene("new-stage1");
                    breakFlag = true;
                }
            }
            //カーソルがランキングの時
            else if (SelectIconPosition == 1)
            {
                //十字キーを上
                if (Input.GetAxisRaw("Vertical") == 1)
                {
                    //カーソル移動
                    iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 80f, "time", 0.01f));
                    //【ゲームスタート】
                    SelectIconPosition = 0;
                    Debug.Log("1,+1");
                    yield return new WaitForSeconds(0.25f);
                }
                //十字キーを下
                else if (Input.GetAxisRaw("Vertical") == -1)
                {
                    iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", -80f, "time", 0f));
                    //【Config】
                    SelectIconPosition = 2;
                    Debug.Log("1,-1");
                    yield return new WaitForSeconds(0.25f);
                }
                //決定ボタンを押す
                else if (Input.GetButtonDown("AtackX"))
                {
                    breakFlag = true;
                }
            }
            //カーソルがConfigの時
            else if (SelectIconPosition == 2)
            {
                //十字キーを上
                if (Input.GetAxisRaw("Vertical") == 1)
                {
                    //カーソル移動
                    iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 80f, "time", 0.01f));
                    //【ランキング】
                    SelectIconPosition = 1;
                    Debug.Log("2,+1");
                    yield return new WaitForSeconds(0.25f);
                }
                //十字キーを下
                else if (Input.GetAxisRaw("Vertical") == -1)
                {
                    iTween.MoveBy(SelectIcon.gameObject, iTween.Hash("y", 160f, "time", 0f));
                    //【ゲームスタート】
                    SelectIconPosition = 0;
                    Debug.Log("2,-1");
                    yield return new WaitForSeconds(0.25f);
                }
                //決定ボタンを押す
                else if (Input.GetButtonDown("AtackX"))
                {
                    breakFlag = true;
                }

            }

            yield return null;  //これがないと固まる
        } while (!breakFlag);
    }

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/22 12:06

    いろんなやり方があるんですね。
    【高評価】じゃなく、【超評価】のボタンが欲しいすばらしい回答ありがとうございます。+100にしたい位勉強になる回答です。アプローチの方法を複数書いてもらえて本当に感謝です!

    勉強のために全部動作テストしましたが、全部同じ動きしました。凄い!
    「一回だけ実行」をnull(このnullすら理解しきれてない)しか知らなかったので、書く方法がわからなかったので、こういう新しいやり方を教えてもらえるので、回答者さんもteratailも本当に最高です。ありがとうございます。

    今回は、ネットでUpdate使わない方がいいと見たことが有るので、コルーチンでループさせる方法を使うことにしました。「do while」という自分がまだ、使ったことがない技があるので、これは要勉強ですね。これは他でも使えそうですね。本当にありがとうございました!

    キャンセル

  • 2017/10/22 12:41 編集

    解決できてよかったです。

    補足ですが、「yield return null;」は、「処理を中断して、1フレーム分待機する」という意味です。
    Unityは基本的にシングルスレッドで動作するため「yield return ~;」で処理を中断しないと、他の処理ができず、Unity全体が固まってしまいます。
    待機時間が1フレーム分長くなってしまっている可能性がありますが、自分はそこまで気にならなかったのと、正確に時間を測る必要性は無いと判断したため、この点は特に考慮してないです。

    キャンセル

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

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Unity

    3996questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • Unity3D

    1290questions

    Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。