はじめてのYaneSDK.NET番外編3

YaneSDKにはキーボード入力クラスとしてKey1〜4が用意されおり、IsPressはキーが押されている間はtrueを返します。一方、IsPushはキーが押されたタイミングでのみtrueを返し、以降、たとえキーを押しっぱなしにしてもfalseになります。使い分けとしては、IsPressは移動操作のような連続した入力に、IsPushはショット発射などに使うと良さそうです。
ところでシューティングゲーム等では、ショットボタンを押しっぱなしにしておくと連射が掛かるものがあります。この場合はIsPushは使えません。それならIsPressにすれば良いかというと、常に入力状態のため何も考えずに使うと60連射(60fpsなら)になってしまいます。もし、キー入力に対するリピート間隔が指定出来たら便利そうです。

と言うわけで、キーリピートの例です。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using YT = Yanesdk.Timer;
using YD = Yanesdk.Draw;
using YI = Yanesdk.Input;

namespace Sample9
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        YT.FpsTimer fps;
        YD.Win32Window window;
        KeyEx key;
        int counter;

        private void Form1_Load(object sender, EventArgs e)
        {
            window = new YD.Win32Window(pictureBox1.Handle);
            fps = new YT.FpsTimer();
            fps.Fps = 60;
            // KeyExはキーリピートに対応したヘルパークラス
            // Key1に変えると秒間60連射の名人状態になる(^^;
            key = new KeyEx();
            // キーリピートまで16フレーム待つ
            key.Delay = 16;
            // リピート間隔は8フレーム
            key.Interval = 8;

            counter = 0;
        }

        private void OnTick(object sender, EventArgs e)
        {
            key.Update();
            if (key.IsPress(1))
                ++counter;
            else if (key.IsPress(2))
                --counter;

            if (counter < 0)
                counter = 0;

            fps.WaitFrame();
            if (fps.ToBeSkip)
                return;

            window.Screen.Select();

            window.Screen.SetClearColor(255, 255, 255);
            window.Screen.Clear();

            window.Screen.SetColor(0);
            window.Screen.DrawString(counter.ToString(), 100, 100, 12);

            window.Screen.Update();
        }

        // キーリピートに対応したクラス
        public class KeyEx : YI.Key1
        {
            // リピート開始までの時間(フレーム)
            int delay = 0;
            public int Delay
            {
                get { return delay; }
                set { delay = value > 0 ? value : 0; }
            }

            // リピートの間隔(フレーム)
            int interval = 0;
            public int Interval
            {
                get { return interval; }
                set { interval = value > 0 ? value : 0; }
            }

            Dictionary<int, int> keyPressed = new Dictionary<int,int>();

            // Key1.IsPressは仮想関数では無いので上書き
            public new bool IsPress(int nKey)
            {
                bool pressed = base.IsPress(nKey);
                if (pressed)
                {
                    // キーが押されっぱなしか?
                    if (keyPressed.ContainsKey(nKey))
                    {
                        // 取りあえず、入力は無効に
                        pressed = false;
                        ++keyPressed[nKey];
                        // Delay + Interval経過するのを待つ
                        if *1
                    // キーが離された
                    keyPressed.Remove(nKey);

                return pressed;
            }           
        }
    }
}

上記の例では、KeyExがKey1と癒着してしまっているので他のKeyクラスでは使えません。多分、Decoratorパターンでも使ってKeyクラスにキーリピート機能を追加出来る形が良いと思います。手抜きでゴメンなさい。(^^;

*1:keyPressed[nKey] - delay) / interval > 0) { keyPressed[nKey] -= interval; pressed = true; } } else // キーが押された keyPressed[nKey] = 0; } else if (keyPressed.ContainsKey(nKey