3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Unity(C#)】キーボードの同時入力を禁止する

Last updated at Posted at 2019-03-23

##UnityのInput(キーボード入力)は同時入力できてしまう
Input.GetKeyDownを例に話を進めていきます。
こちらの記事にもありますように、
指定したキーを押した瞬間、1フレームだけ呼び出されてtrueを返します。

もし同時に押したらどうなるのか検証してみました。

void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            print("A");
        }
        if (Input.GetKeyDown(KeyCode.S))
        {
            print("S");
        }
    }

Key同時押し.png

このように両方が同じように増えました。
キー入力は人間の手で行っているので
厳密に同時(同一フレーム上)に増えているかどうかは読み取れませんが、
前回の記事で発生したバグは
同一フレーム上でキー入力を受け取ってしまったことが原因かと思われます。

Bag.png

矢印キーの入力が同時に行われてしまったことでこのようなバグが発生しています。
※正しい挙動は前回の記事を参照ください

##同時(同一フレーム)入力できるのはヤバい
ヤバいです。
例えば、自動販売機。
ふざけてボタンを同時押ししたことがあるかと思います。(ない?)

あれがもし奇跡的なタイミングで両方のボタンをぴったり同時に押した場合、
反応してしまう仕組みだったとしたらどうでしょうか。
一本タダで手に入ってしまいます。それくらいヤバいです。

とてもわかり易い例えは置いといて、
同時押しを想定していないのであれば、バグの温床になりかねません。

なので、キーボードは片方づつ押せるようになっていてほしいものです。

##namespaceを使ってみた
namespaceはコンポーネントをいっぱい登録して簡単にどこでも呼び出しやすくしました
みたいな理解をしています。(合ってますか?)

Unityのスクリプトリファレンスには
大規模な開発にもってこいです みたいなことが書いてありました。
(それ以外に使う理由ってありますか?よく使う方見てたらコメントください)

現時点であまり縁がないですが使ってみようと思います。

using UnityEngine;

namespace InputKey{
    /// <summary>
    /// 同時入力を禁止する
    /// </summary>
    public static class MyInput 
    {
        static bool isCheck_Input;

       public static bool MyInputKeyDown(KeyCode key)
        {
            if(Input.anyKeyDown == false) isCheck_Input = false;
         
            if (isCheck_Input==false)
            {
                if (Input.GetKeyDown(key))
                {
                    isCheck_Input = true;
                    return true;
                }
            }
            return false;
        }
    }
}

このスクリプトは何にもAdd Componentしなくていいやつっぽい(staticなので)です。

次は使う側です。using InputKeyを名前空間に追加します。

using UnityEngine;
using InputKey;

public class Test : MonoBehaviour
{
    void Update()
    {
        if (MyInput.MyInputKeyDown(KeyCode.A))
        {
            print("A");
        }

        if (MyInput.MyInputKeyDown(KeyCode.S))
        {
            print("S");
        }
    }
}

これで同時入力(同一フレーム入力)できなくなってました:ok_hand:

void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            print("A");
        }
        else if (Input.GetKeyDown(KeyCode.S))
        {
            print("S");
        }
    }

else if使えば同一フレームを回避できるらしいです!
ただ、1フレームずれただけだと見た目ではあまり変化ないです。

##もっと厳格な同時押し禁止
MyInputKeyDownにしろ、else ifにしろ、
同時入力が避けられるのは1フレームのみです。

キーを押し込んでいる間は他のキーを押せない状態こそ
真の同時押し禁止といえるでしょう。

 //真の同時押し不可
        public static bool MyInputKey(KeyCode key)
        {
            if(Input.anyKey == false) isCheck_Input = false;
         
            if (isCheck_Input==false)
            {
                if (Input.GetKey(key))
                {
                    isCheck_Input = true;
                    return true;
                }
            }
            return false;
        }

これで
押しっぱなしでも一回しか反応しない、かつキーを押し込んでいる間は他のキーを押せない状態になりました。

これが真の同時押し禁止だーーー!


2019/03/28 追記

namespaceを使う理由を教えてもらいました!
プロジェクトを外部に公開したり、配布したりする際にも使えるそうです。

例えば、
importしたscriptに記述されたクラス名が自分のプロジェクト内のscriptに記述されたクラス名と一致した場合、
エラーとなってしまいます。
そういった汎用的なクラス名の衝突を避ける目的で利用されるそうです!

アセットなどによくnamespaceが使われている理由もそのためらしいです。


2019/10/07 追記 

これほんとに同時入力禁止なのか?って思ったのでもっかい調べてみました。
というかそもそも、同時に別のキー入力の受付ってできるのか?と思って調べてみました。

通常のInputだと 同時に別のキー入力できてました。
SameTimeInput.PNG

で、この記事のMyInputとかいうダサい名前のクラス使ったらできなくなってました。
やるじゃん過去の俺。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?