キー入力で何かしよう

Modを作ろう

キーが押されたら何かしてみます。色々注意するべき点がありますのでまとめました。

キーコードを調べる

キーを指定するためのキーコードが必要です。直接キーコードを指定することもできますし、MCMであらかじめ設定を作っておくのもいいでしょう。

ゲームに割り当てられているキーを使いたい場合があります。例えばアクティベートボタンやスニークボタンなどです。これらはプレイ環境でかわるので、決め打ちで指定できません。

割り当てられている機能のキーコードはInput.GetMappedKey関数で取得できます。

キーコードを調べる (papyrus)

Int Function GetSneakKey()
    ; まず自動モードで取得してみる
    Int iKeyCode = Input.GetMappedKey("Sneak", 0xFF)

    if iKeyCode != -1
        return iKeyCode
    endif

    ; ダメだったらゲームパッドモードで
    iKeyCode = Input.GetMappedKey("Sneak", 0x02)

    if iKeyCode != -1
        return iKeyCode
    endif

    ; ダメだったらキーボードモードで
    iKeyCode = Input.GetMappedKey("Sneak", 0x00)

    if iKeyCode != -1
        return iKeyCode
    endif

    ; それでもダメだったらゲームパッドの下ボタンを使う
    return 267
EndFunction

このGetMappedKey関数はバカなので、一発では取れないことがあります。

特に、controlmap.txtでキーの組み合わせを設定している場合、この関数では取得できません。この関数は整数を1つだけ返すので、2つのキーコードの組み合わせは返せないからです。

キーが押されたら何かする

キーの入力を判定するのに使うのはOnKeyDown関数OnKeyUp関数です。とりあえず、Wキーが押されたら何かしてみます。Wのキーコードは17です。

キーが押されたら何かする (papyrus)

Scriptname MyQuest Extends Quest

Event OnInit()
    RegisterForKey(17)
EndEvent

Event OnKeyDown(Int aiKeyCode)
    Debug.Notification("Wキーが押されました")
EndEvent

これで動きます。使いたいキーをRegisterForKey関数で登録するのがポイントです。

注意するべき点は、キーを押すと何度でもOnKeyDownイベントが発生するので、必要に応じて入力を無効にしたり無視したりすることです。無効にするにはUnregisterForKey関数で登録を解除します。一時的に無視するにはフラグを立てるなどして対応します。

メニューを開いているときは何もしない

キャラクターを動かしているときだけ入力を受け付け、メニューが開いているときは無視するにはUtility.IsInMenuMode関数を使えば判定できます。

メニューモードならキー入力を無視する (papyrus)

Event OnKeyDown(Int aiKeyCode)
    if Utility.IsInMenuMode()
        Debug.Notification("キーが押されましたが、メニューを開いている最中なので無視します")
        return
    endif

    Debug.Notification("キーが押されました")
EndEvent

キーが押されたらコンテナを開き、コンテナを閉じたら処理の続きをする場合、IsInMenuMode関数を使い、メニューモードにいる間は待ち続けるループを作ります。

メニューモードが終わるのを待つ (papyrus)

Event OnKeyDown(Int aiKeyCode)
    Debug.Notification("いまからインベントリを開きます")
    Game.GetPlayer().OpenInventory()

    while Utility.IsInMenuMode()
        Utility.Wait(0.1)
    endwhile

    Debug.Notification("インベントリが閉じられました")
EndEvent

Wait関数は指定された時間が経過するまで待つという関数です。実は、メニューモードにいる間は時間が進まないので、メニューを閉じるまで永遠に待ち続けます。バニラならWait関数だけでもいいのですが、Skyrim Soulsを入れている環境では、メニューを開いている間も時間が進みます。よってWait関数ではダメで、IsInMenuMode関数を使う必要があります。

長押しを判定する

キーが一定時間押される、いわゆる長押しを判定するには、RegisterForSingleUpdate関数を使います。一定時間後にOnUpdateイベントを発生させて長押しを検出します。

長押しの判定 (papyrus)

Bool IsUpdateRegistered

Event OnKeyDown(Int aiKeyCode)
    RegisterForSingleUpdate(1.0) ; 1秒後にOnUpdateイベントを予約
    IsUpdateRegistered = true ; 予約したということを覚えておく
EndEvent

Event OnUpdate()
    IsUpdateRegistered = false ; 時間がきたのでもう覚えてなくていい
    Debug.Notification("キーが長押しされました")
EndEvent

Event OnKeyUp(Int aiKeyCode, Float afHoldTime)
    if IsUpdateRegistered ; まだ予約している最中なら
        IsUpdateRegistered = false ; 予約したことを忘れる
        UnregisterForUpdate() ; OnUpdateイベントの予約を取り消す
    endif
EndEvent

注意すべき点が多くあり、時間到達前にキーが離されたときと、時間到達後からキーが離されたときのために、それぞれ処理が必要です。

タイトルとURLをコピーしました