11
6

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でキーボード入力をイベント駆動ライクに扱ってみる

Last updated at Posted at 2017-04-18

※2017/10/26 修正: @kajimura さんのコメントをもとにイベントリスナ側のコードを修正しました、ご指摘ありがとうございました!

サンプルについて(2017/11/3追記)

この記事にて作ったScriptを、サンプル的なそれと一緒にGitHubに上げてみました

前置き

イベント駆動なプログラミングに浸かってると、Unityでもキー入力等をイベント駆動ぽく処理とかしてみたくなってくることもあります。1

ですが、Unityでは各種のキー入力をイベント駆動的に処理する仕組みが、Unity側で用意されていない...ように見受けられます。2

そこで、Unityの諸々を利用して、キー入力をイベント駆動ぽく処理する試みをしてみます。

以下、Unity 5.6f3で実装しました。

参考文献とか

以下のWebページを参考にしました。
SendMessageに変わる新しいメッセージシステム、ExecuteEvents.Execute - テラシュールブログ
Unity - スクリプトリファレンス: EventSystems.ExecuteEvents.Execute

実装する

インタフェース構築

通知用のInterfaceを組み立てます。
キーの押下と押上のときに、UnityEngine.EvemtSystems.ExecuteEvents.Execute<>()でイベントを発行する想定で組んでみます。

KeyInputEvent.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using UnityEngine.EventSystems;

/// <summary>
/// キー押下時イベントのInterface
/// </summary>
public interface IKeyDownEvent : IEventSystemHandler {
	void OnKeyDown(List<KeyCode> downKeyList);
}
/// <summary>
/// キー押上時イベントのInterface
/// </summary>
public interface IKeyUpEvent : IEventSystemHandler {
	void OnKeyUp(List<KeyCode> upKeyList);
}

UnityEngine.EvemtSystems.ExecuteEvents.Execute<>()がイベントを発火できるように、IEventSystemHandlerを継承するのがミソです。

発行役の構築

イベントの発行役を実装します。
ComponentとしてGameObjectにAttachする想定です。

仕組みは、

  1. 毎フレーム、Keycode列挙型で登録されているキー全部に押下と押上の瞬間をチェック
  2. 1つでもチェックに引っ掛かったら、イベントをUnityEngine.EvemtSystems.ExecuteEvents.Execute<>()経由でイベント発行

といった感じに。

KeyEventDispatcher.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using System;
using UnityEngine.EventSystems;

/// <summary>
/// 各種のキー入力イベントの発行役
/// </summary>
public class KeyEventDispatcher : MonoBehaviour {
	
	/// <summary>
	/// 処理負荷軽減のため、KeyCodeの全ての値を保持する配列
	/// </summary>
	static Array KeyCodeList;

	// Use this for initialization
	void Start () {
		//全てのKeyCode列挙型の値を控える
		KeyCodeList = Enum.GetValues(typeof(KeyCode));
	}
	
	// Update is called once per frame
	void Update () {
		var tmpUpList = new List<KeyCode>();
		foreach (KeyCode code in KeyCodeList) {//押上キーがあるかチェック
			if (Input.GetKeyUp(code)) {
				tmpUpList.Add(code);
			}
		}
		if (tmpUpList.Count != 0) {//1つでも押上キーがあれば
			ExecuteEvents.Execute<IKeyUpEvent>(this.gameObject,
				null,
				(handler, eventData) => handler.OnKeyUp(tmpUpList) //押上キー全てを込めてリスナを叩く
			);
		}
		var tmpDownList = new List<KeyCode>();
		foreach (KeyCode code in KeyCodeList) {//押下キーがあるかチェック
			if (Input.GetKeyDown(code)) {
				tmpDownList.Add(code);
			}
		}
		if (tmpDownList.Count != 0) {//1つでも押下キーがあれば
			ExecuteEvents.Execute<IKeyDownEvent>(this.gameObject,
				null,
				(handler, eventData) => handler.OnKeyDown(tmpDownList) //押下キー全てを込めてリスナを叩く
			);
		}
	}
}

この例では、発行役と同じGameObjectにAttachされているComponentに対して、イベントを発行しています。

リスナ側実装

イベントを受け取るComponentを作ります。

先の作業で作ったInterfaceを実装し、通知役と同じGameObjectにAttachします。
すると、そのComponentはキー入力イベントを受け取ることができるようになります。

以下は、イベント発行の際に送られてきたKeyCodeをそのままデバッグコンソールに出力するだけの実装です。

KeyEventListener.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KeyEventListener : MonoBehaviour, IKeyUpEvent, IKeyDownEvent {

	// Use this for initialization
	void Start () {
		
	}

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

	public void OnKeyUp(List<KeyCode> upKeyList) {
		foreach (KeyCode code in upKeyList) {
			Debug.Log("Key up:" + code.ToString());
		}
	}

	public void OnKeyDown(List<KeyCode> downKeyList) {
		foreach (KeyCode code in downKeyList) {
			Debug.Log("Key down:" + code.ToString());
		}
	}
}

どのキーを受け付けるか、などは全てリスナでよしなに処理し、発行役はどんなキーでもイベントを発行するような実装です。

#あとがき

PCで遊ぶ音楽ゲームとか、タイピングゲームとかに活用できそうかな...と考えています。

  1. あくまで私の場合

  2. 見落としているだけかもしれませんが...

11
6
2

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
11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?