Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Unityでキーコンフィグ ref: http://qiita.com/Es_Program/items/fde067254cfc68035173
using MBLDefine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
/// 入力によるイベントを管理する
/// </summary>
public class InputEventManager : SingletonMonoBehaviour<InputEventManager>
{
private Dictionary<Key, EventHandler> onKeyEvents = new Dictionary<Key, EventHandler>();
private Dictionary<Key, EventHandler> onKeyDownEvents = new Dictionary<Key, EventHandler>();
private Dictionary<Key, EventHandler> onKeyUpEvents = new Dictionary<Key, EventHandler>();
private Dictionary<Key, EventHandler> onKeyNotPressedEvents = new Dictionary<Key, EventHandler>();
private Dictionary<Axes, EventHandler> onAxesEvents = new Dictionary<Axes, EventHandler>();
private Dictionary<Axes, EventHandler> onAxesRowEvents = new Dictionary<Axes, EventHandler>();
/// <summary>
/// キー入力イベントの実行を制御する
/// </summary>
public bool Execute { get; set; }
public void Awake()
{
Execute = true;
//キーの種類の数だけイベントを生成する
foreach(Key key in Key.AllKeyData)
{
onKeyEvents.Add(key, (o, a) => { });
onKeyDownEvents.Add(key, (o, a) => { });
onKeyUpEvents.Add(key, (o, a) => { });
onKeyNotPressedEvents.Add(key, (o, a) => { });
}
foreach(Axes axes in Axes.AllAxesData)
{
onAxesEvents.Add(axes, (o, a) => { });
onAxesRowEvents.Add(axes, (o, a) => { });
}
}
public void Update()
{
if(!Execute)
return;
//HACK:EventArgsを継承して様々なデータを受け渡せるように出来る
KeyEventInvoke(InputManager.Instance.GetKey, onKeyEvents, new EventArgs());
KeyEventInvoke(InputManager.Instance.GetKeyDown, onKeyDownEvents, new EventArgs());
KeyEventInvoke(InputManager.Instance.GetKeyUp, onKeyUpEvents, new EventArgs());
KeyEventInvoke((key) => { return !InputManager.Instance.GetKey(key); }, onKeyNotPressedEvents, new EventArgs());
AxesEventInvoke(onAxesEvents, new EventArgs());
AxesEventInvoke(onAxesRowEvents, new EventArgs());
}
/// <summary>
/// キー入力イベントをセットする
/// </summary>
/// <param name="key">キーの種類</param>
/// <param name="eventHandler">実行するイベント</param>
internal void SetKeyEvent(Key key, EventHandler eventHandler)
{
onKeyEvents[key] += eventHandler;
}
/// <summary>
/// キー入力開始時イベントをセットする
/// </summary>
/// <param name="key">キーの種類</param>
/// <param name="eventHandler">実行するイベント</param>
internal void SetKeyDownEvent(Key key, EventHandler eventHandler)
{
onKeyDownEvents[key] += eventHandler;
}
/// <summary>
/// キー入力終了時イベントをセットする
/// </summary>
/// <param name="key">キーの種類</param>
/// <param name="eventHandler">実行するイベント</param>
internal void SetKeyUpEvent(Key key, EventHandler eventHandler)
{
onKeyUpEvents[key] += eventHandler;
}
/// <summary>
/// キーが押されていない場合のイベントをセットする
/// </summary>
/// <param name="key">キーの種類</param>
/// <param name="eventHandler">実行するイベント</param>
internal void SetKeyNotPressedEvent(Key key, EventHandler eventHandler)
{
onKeyNotPressedEvents[key] += eventHandler;
}
/// <summary>
/// 軸入力時イベントをセットする
/// </summary>
/// <param name="axes">軸の種類</param>
/// <param name="eventHandler">実行するイベント</param>
internal void SetAxesEvent(Axes axes, EventHandler eventHandler)
{
onAxesEvents[axes] += eventHandler;
}
/// <summary>
/// 軸入力時イベントをセットする
/// </summary>
/// <param name="axes">軸の種類</param>
/// <param name="eventHandler">実行するイベント</param>
internal void SetAxesRowEvent(Axes axes, EventHandler eventHandler)
{
onAxesRowEvents[axes] += eventHandler;
}
/// <summary>
/// キー入力イベントから指定したイベントを削除する
/// </summary>
/// <param name="key">キーの種類</param>
/// <param name="eventHandler">削除するイベント</param>
internal void RemoveKeyEvent(Key key, EventHandler eventHandler)
{
onKeyEvents[key] -= eventHandler;
}
/// <summary>
/// キー入力時イベントから指定したイベントを削除する
/// </summary>
/// <param name="key">キーの種類</param>
/// <param name="eventHandler">削除するイベント</param>
internal void RemoveKeyDownEvent(Key key, EventHandler eventHandler)
{
onKeyDownEvents[key] -= eventHandler;
}
/// <summary>
/// キー入力終了時イベントから指定したイベントを削除する
/// </summary>
/// <param name="key">キーの種類</param>
/// <param name="eventHandler">削除するイベント</param>
internal void RemoveKeyUpEvent(Key key, EventHandler eventHandler)
{
onKeyUpEvents[key] -= eventHandler;
}
/// <summary>
/// キーが入力されていない場合のイベントから指定したイベントを削除する
/// </summary>
/// <param name="key">キーの種類</param>
/// <param name="eventHandler">削除するイベント</param>
internal void RemoveKeyNotPressedEvent(Key key, EventHandler eventHandler)
{
onKeyNotPressedEvents[key] -= eventHandler;
}
/// <summary>
/// 軸入力時イベントを削除する
/// </summary>
/// <param name="axes">軸の種類</param>
/// <param name="eventHandler">削除するイベント</param>
internal void RemoveAxesEvent(Axes axes, EventHandler eventHandler)
{
onAxesEvents[axes] -= eventHandler;
}
/// <summary>
/// 軸入力時イベントを削除する
/// </summary>
/// <param name="axes">軸の種類</param>
/// <param name="eventHandler">削除するイベント</param>
internal void RemoveAxesRowEvent(Axes axes, EventHandler eventHandler)
{
onAxesRowEvents[axes] -= eventHandler;
}
/// <summary>
/// キーイベントを実行する
/// キーが入力されていない状態の時はイベントを実行しない
/// </summary>
/// <param name="keyEntryDecision">キー入力判定を行う述語</param>
/// <param name="keyEvent">キーごとのイベントを格納するハッシュマップ</param>
/// <param name="args">イベント実行に用いる引数</param>
private void KeyEventInvoke(Func<Key, bool> keyEntryDecision, Dictionary<Key, EventHandler> keyEvent, EventArgs args)
{
foreach(Key key in Key.AllKeyData)
if(keyEntryDecision(key))
if(keyEvent[key] != null)
keyEvent[key](this, args);
}
/// <summary>
/// 軸イベントを実行する
/// </summary>
/// <param name="axesEntryDecision">軸入力値取得を行う述語</param>
/// <param name="axesEvent">軸ごとのイベントを格納するハッシュマップ</param>
/// <param name="args">イベント実行に用いる引数</param>
private void AxesEventInvoke(Dictionary<Axes, EventHandler> axesEvent, EventArgs args)
{
foreach(Axes axes in Axes.AllAxesData)
if(axesEvent[axes] != null)
axesEvent[axes](this, args);
}
}
using MBLDefine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEngine;
/// <summary>
/// 入力を管理する
/// </summary>
internal class InputManager : SingletonMonoBehaviour<InputManager>
{
#region InnerClass
/// <summary>
/// キーコンフィグ設定の変更や保存・ロードを管理する
/// </summary>
internal class KeyConfigSetting
{
private Array keyCodeValues;
private static InputManager inputManager;
private static KeyConfigSetting instance;
public static KeyConfigSetting Instance
{
get
{
if(inputManager == null)
inputManager = InputManager.Instance;
return instance = instance != null ? instance : new KeyConfigSetting();
}
}
private KeyConfigSetting()
{
}
/// <summary>
/// 呼び出されたフレームで押下状態のKeyCodeリストを返す
/// </summary>
/// <returns>押下状態のKeyCodeリスト</returns>
private List<KeyCode> GetCurrentInputKeyCode()
{
List<KeyCode> ret = new List<KeyCode>();
if(keyCodeValues == null)
keyCodeValues = Enum.GetValues(typeof(KeyCode));
foreach(var code in keyCodeValues)
if(Input.GetKey((KeyCode)(int)code))
ret.Add((KeyCode)(int)code);
return ret;
}
/// <summary>
/// コンフィグにキーをセットする
/// </summary>
/// <param name="key">キーを表す識別子</param>
/// <param name="keyCode">割り当てるキーコード</param>
/// <returns>割り当てが正常に終了したかどうか</returns>
public bool SetKey(Key key, List<KeyCode> keyCode)
{
return inputManager.keyConfig.SetKey(key.String, keyCode);
}
/// <summary>
/// コンフィグから値を消去
/// </summary>
/// <param name="key">キーを表す識別子</param>
/// <returns>値の消去が正常に終了したかどうか</returns>
public bool RemoveKey(Key key)
{
return inputManager.keyConfig.RemoveKey(key.String);
}
/// <summary>
/// 押されているキーを名前文字列に対するキーとして設定する
/// </summary>
/// <param name="key">キーに割り付ける名前</param>
/// <returns>キーコードの設定が正常に完了したかどうか</returns>
public bool SetCurrentKey(Key key)
{
//HACK:マウス入力も受け付けるようにするべきなので今後改善
//マウス{0~6}の入力を弾く
var currentInput = GetCurrentInputKeyCode().Where(c => c < KeyCode.Mouse0 || KeyCode.Mouse6 < c).ToList();
if(currentInput == null || currentInput.Count < 1)
return false;
var code = inputManager.keyConfig.GetKeyCode(key.String);
//既に設定されているキーと一部でも同じキーが押されている場合
if(code.Count > currentInput.Count && currentInput.All(k => code.Contains(k)))
return false;
RemoveKey(key);
return SetKey(key, currentInput);
}
/// <summary>
/// デフォルトのキー設定を適用する
/// </summary>
public void SetDefaultKeyConfig()
{
foreach(var key in Key.AllKeyData)
SetKey(key, key.DefaultKeyCode);
}
public List<KeyCode> GetKeyCode(Key keyName)
{
return inputManager.keyConfig.GetKeyCode(keyName.String);
}
public void LoadSetting()
{
InputManager.Instance.keyConfig.LoadConfigFile();
}
public void SaveSetting()
{
InputManager.Instance.keyConfig.SaveConfigFile();
}
}
#endregion InnerClass
/// <summary>
/// 使用するキーコンフィグ
/// </summary>
private KeyConfig keyConfig = new KeyConfig(ExternalFilePath.KEYCONFIG_PATH);
public void Awake()
{
Debug.Log("Load key-config file.");
//最初はデフォルトの設定をコンフィグに格納
KeyConfigSetting.Instance.SetDefaultKeyConfig();
//コンフィグファイルがあれば読み出す
try
{
InputManager.Instance.keyConfig.LoadConfigFile();
}
catch(IOException e)
{
Debug.Log(e.Message);
}
}
/// <summary>
/// 指定したキーが押下状態かどうかを返す
/// </summary>
/// <returns>入力状態</returns>
internal bool GetKey(Key key)
{
return keyConfig.GetKey(key.String);
}
/// <summary>
/// 指定したキーが入力されたかどうかを返す
/// </summary>
/// <returns>入力状態</returns>
internal bool GetKeyDown(Key key)
{
return keyConfig.GetKeyDown(key.String);
}
/// <summary>
/// 指定したキーが離されたかどうかを返す
/// </summary>
/// <returns>入力状態</returns>
internal bool GetKeyUp(Key key)
{
return keyConfig.GetKeyUp(key.String);
}
/// <summary>
/// 軸入力に対する値を返す
/// </summary>
/// <returns>入力値</returns>
internal float GetAxes(Axes axes)
{
return Input.GetAxis(axes.String);
}
/// <summary>
/// 軸入力に対する値を返す
/// </summary>
/// <returns>平滑化フィルターが適用されていない入力値</returns>
internal float GetAxesRaw(Axes axes)
{
return Input.GetAxisRaw(axes.String);
}
}
using LitJson;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEngine;
/// <summary>
/// キーコンフィグ情報を取り扱う
/// </summary>
public class KeyConfig
{
private Dictionary<string, List<KeyCode>> config = new Dictionary<string, List<KeyCode>>();
private readonly string configFilePath;
/// <summary>
/// キーコンフィグを管理するクラスを生成する
/// </summary>
/// <param name="configFilePath">コンフィグファイルのパス</param>
public KeyConfig(string configFilePath)
{
this.configFilePath = configFilePath;
}
/// <summary>
/// 指定したキーの入力状態をチェックする
/// </summary>
/// <param name="keyName">キーを示す名前文字列</param>
/// <param name="predicate">キーが入力されているかを判定する述語</param>
/// <returns>入力状態</returns>
private bool InputKeyCheck(string keyName, Func<KeyCode, bool> predicate)
{
bool ret = false;
foreach(var keyCode in config[keyName])
if(predicate(keyCode))
return true;
return ret;
}
/// <summary>
/// 指定したキーが押下状態かどうかを返す
/// </summary>
/// <param name="keyName">キーを示す名前文字列</param>
/// <returns>入力状態</returns>
public bool GetKey(string keyName)
{
return InputKeyCheck(keyName, Input.GetKey);
}
/// <summary>
/// 指定したキーが入力されたかどうかを返す
/// </summary>
/// <param name="keyName">キーを示す名前文字列</param>
/// <returns>入力状態</returns>
public bool GetKeyDown(string keyName)
{
return InputKeyCheck(keyName, Input.GetKeyDown);
}
/// <summary>
/// 指定したキーが離されたかどうかを返す
/// </summary>
/// <param name="keyName">キーを示す名前文字列</param>
/// <returns>入力状態</returns>
public bool GetKeyUp(string keyName)
{
return InputKeyCheck(keyName, Input.GetKeyUp);
}
/// <summary>
/// 指定されたキーに割り付けられているキーコードを返す
/// </summary>
/// <param name="keyName">キーを示す名前文字列</param>
/// <returns>キーコード</returns>
public List<KeyCode> GetKeyCode(string keyName)
{
if(config.ContainsKey(keyName))
return new List<KeyCode>(config[keyName]);
return new List<KeyCode>();
}
/// <summary>
/// 名前文字列に対するキーコードを設定する
/// </summary>
/// <param name="keyName">キーに割り付ける名前</param>
/// <param name="keyCode">キーコード</param>
/// <returns>キーコードの設定が正常に完了したかどうか</returns>
public bool SetKey(string keyName, List<KeyCode> keyCode)
{
if(string.IsNullOrEmpty(keyName) || keyCode.Count < 1)
return false;
config[keyName] = keyCode;
return true;
}
/// <summary>
/// コンフィグからキーコードを削除する
/// </summary>
/// <param name="keyName">キーに割り付けられている名前</param>
/// <returns></returns>
public bool RemoveKey(string keyName)
{
return config.Remove(keyName);
}
/// <summary>
/// 設定されているキーコンフィグを確認用文字列として受け取る
/// </summary>
/// <returns>キーコンフィグを表す文字列</returns>
public string CheckConfig()
{
StringBuilder sb = new StringBuilder();
foreach(var keyValuePair in config)
{
sb.AppendLine("Key : " + keyValuePair.Key);
foreach(var value in keyValuePair.Value)
sb.AppendLine(" |_ Value : " + value);
}
return sb.ToString();
}
/// <summary>
/// ファイルからキーコンフィグファイルをロードする
/// </summary>
public void LoadConfigFile()
{
//TODO:復号処理
using(TextReader tr = new StreamReader(configFilePath, Encoding.UTF8))
config = JsonMapper.ToObject<Dictionary<string, List<KeyCode>>>(tr);
}
/// <summary>
/// 現在のキーコンフィグをファイルにセーブする
/// </summary>
public void SaveConfigFile()
{
//TODO:暗号化処理
var jsonText = JsonMapper.ToJson(config);
using(TextWriter tw = new StreamWriter(configFilePath, false, Encoding.UTF8))
tw.Write(jsonText);
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;
[assembly: InternalsVisibleTo("UnitTest")]
/// <summary>
/// このゲームで定義する定数などを扱う
/// </summary>
namespace MBLDefine
{
/// <summary>
/// 外部ファイルへの参照に必要なパス群
/// </summary>
internal struct ExternalFilePath
{
internal const string KEYCONFIG_PATH = "keyconf.dat";
}
/// <summary>
/// 入力値の基底クラス
/// </summary>
internal class InputValue
{
public readonly string String;
protected InputValue(string name)
{
String = name;
}
}
/// <summary>
/// 使用するキーを表すクラス
/// </summary>
internal sealed class Key : InputValue
{
public readonly List<KeyCode> DefaultKeyCode;
public readonly static List<Key> AllKeyData = new List<Key>();
private Key(string keyName, List<KeyCode> defaultKeyCode)
: base(keyName)
{
DefaultKeyCode = defaultKeyCode;
AllKeyData.Add(this);
}
public override string ToString()
{
return String;
}
public static readonly Key Action = new Key("Action", new List<KeyCode> { KeyCode.Z });
public static readonly Key Jump = new Key("Jump", new List<KeyCode> { KeyCode.Space });
public static readonly Key Balloon = new Key("Balloon", new List<KeyCode> { KeyCode.X });
public static readonly Key Squat = new Key("Squat", new List<KeyCode> { KeyCode.LeftShift });
public static readonly Key Menu = new Key("Menu", new List<KeyCode> { KeyCode.Escape });
}
/// <summary>
/// 使用する軸入力を表すクラス
/// </summary>
internal sealed class Axes : InputValue
{
public readonly static List<Axes> AllAxesData = new List<Axes>();
private Axes(string axesName)
: base(axesName)
{
AllAxesData.Add(this);
}
public override string ToString()
{
return String;
}
public static Axes Horizontal = new Axes("Horizontal");
public static Axes Vertical = new Axes("Vertical");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment