PG日誌

読者です 読者をやめる 読者になる 読者になる

PG日誌

主にc#の事を書いています

クラリネット用リガチャーKODAMA2のレビュー

石森楽器が発売しているクラリネット用のリガチャー『KODAMA II』を2016年の6月に購入し使用し始めてから10ヵ月程度たったので使い心地のレビューを書きたいと思います。

吹奏環境

当方吹奏環境ですが、以下の通りです。

項目 内容
リード バンドレン ルピック56
マウスピース B40
以前のリガチャ Rovner VERSA V-1R

リガチャーの紹介と画像

画像を見ればなんとなくわかると思いますが、全体は革でできていて、リードを支える面が木(グラナディラ材)でできています。

f:id:Takachan:20170507192242j:plain

f:id:Takachan:20170507192324j:plain

f:id:Takachan:20170507192338j:plain

レビュー

音色

金属製に比べて、割と暗めです。金属製から付け替えると明らかに抑制された音色になります。ただ、リードの留めの材質が木のためか、太めの柔らかい音も持っているので、埋もれたりすることはないと思います。

吹奏感

ロブナーと比べると多少軽いです。ただ、金属製と比べると割と重い感じがします。皮製 と 金属製 の中間よりやや皮よりの抵抗感があります。ただし音の立ち上がりは良いです。小さい音から消えていくような動きの時もスムーズに息が流れます。ただ、すべての指を抑える下の音を出す局面では、パワーが必要なので少し気を使わないといけないかもしれません。

雑感

裏にねじ1本締めなのでセッティングが楽です。結構ぎゅうぎゅうにリードを締められます。強く締めるとレスポンスがよくなりますが少しリードが重くなり、軽く締めるとレスポンスが悪くなりますがリードが少し軽くなります。位置がかなり自由に上下に設定できるのでリードごとに調整もできます。

革製のためか吹くのに少々パワーが必要です。また、良い音を出すためには、息をまとめる必要があるので、月に練習が数回の人にはあまりお勧めできません。コントロールできず音が悪くなってしまうかも。逆に常時吹いていて何かと合わせる機会のある人は皮&木の恩恵をフルに受けられると思います。

まとめ

  • やや暗めの、響きのある音がする
  • 抵抗感が金属製リガチャーに比べて強い
  • 吹きこなすにはパワーが必要、やや慣れる必要あり

もし、気になったらお店に行って試奏してみて下さい。

以上、KODAMA II のレビューでした。

C#のSystem.Threading.Timerクラスの精度を確認する

この話は、C#のSystem.Threading.Timerクラスの定周期処理に限ったことではないのですが、タイマーのインターバールに1msを指定したときの実際の実行間隔の話です。

まず、確認前の前提としてタイマー動作はPC物理的な「ハードウェアタイマー」とそれを制御しているWindowsの「HAL(Hardware Abstraction Layer)」ドライバに関係していると考えています。

で、HALは周期が16ms(ハードによっては10msとかもある)となっていて、その仕組み上に乗っている(と思われる)C#のタイマーの精度は前述の数値に依存するかなと。

従って、タイトルの1msを指定した場合、割り込み周期に同期して1msのタイマーは発生せず、16msでタイマーが発生すると仮定し、これが本当に正しいかを確認します。

なので、上記過程を検証するための、1ミリ秒のタイマー実行要求を100回繰り返すコードを書いてみました。

// 時間計測用のタイマー
private static Stopwatch sw = new Stopwatch();
// 結果の書き出し先
private static StreamWriter log;
// 測定対象のタイマー
private static Timer timer;
// 総実行回数
private static int total;
// 実行回数
private static int cnt;
// スレッド待機用のハンドル
private static AutoResetEvent thHandle = new AutoResetEvent(false);

internal static void Main(string[] args)
{
    using (log = new StreamWriter(@"d:\log.csv"))
    {
        // 繰り返し計測用のループ
        //for (int j = 0; j < 1; j++)
        //{
        //    for (int i = 1; i <= 1; i++)
        //    {
                timer = new Timer(threading_timer_callback, 1, 0, 1); // 1msを指定

                thHandle.WaitOne();
        //    }
        //}
    }

    Console.WriteLine("Finish");
    Console.ReadLine();
}

private static void threading_timer_callback(object state)
{
    int i = (int)state;

    if (cnt > 100)
    {
        cnt = 0;
        timer.Change(Timeout.Infinite, 0);
        timer.Dispose();
        thHandle.Set();
    }

    sw.Stop();

    // 前回終了時からの経過時間
    log.WriteLine(total + ", " + cnt + ", " + i + ", " + sw.Elapsed.TotalMilliseconds);
    log.Flush();

    total++;
    cnt++;

    sw.Reset();
    sw.Start();
}

実行結果ですが、概ね16msで実行されて、たまに14msで実行されます。

f:id:Takachan:20170330002220p:plain

で、もう少し発展させて、じゃあ16ミリ秒以上を指定したらどうなるんだという問題です。

32msを指定しました。

f:id:Takachan:20170330003243p:plain

まぁ、こんな感じに、めちゃくちゃになります。

何回に1回かはジャストで発生しますが、大体、次の割り込み周期に回されて32+16ms近辺で発生します。

31msを指定した場合こんな感じになります。

f:id:Takachan:20170330003929p:plain

今度はかなり希望に近い結果が出ました。

というわけでこの記事を書いているPCのタイマーの精度は16msだったという事が分かったので、確認結果をまとめると

  • 1ms周期のタイマーは発生しない
    • 16ms以下、10ms以下のタイマーは(HAL的に?)無理(と思われる)
  • 発生周期は割り込み周期の倍数で発生する(可能性が高い)
  • 次回割り込みに回されると+割り込み周期の誤差が発生する
    • 今回の場合16ミリ秒(程度)、後で実行される可能性がある
  • .NET COREでほかのOSの場合、結果が全然異なると思われる

.NETのコード読んでないので推測だらけになってしまいましたが(いや、軽く読んだのですが)、少なくとも検証した環境で.NETを使った場合、公明正大かつ精度高いタイマー動作を期待してプログラムを書いてはいけないという事が分かりました。

真・C# と WPF でインベーダー風ゲームを作る

3日前に『C# と WPF でインベーダー風ゲームを作る』を言って、雰囲気だけ似ているオリジナルのイカのシューティングの記事を書きましたが、「インベーダー」を名乗ってあの出来栄えはさすがに我田引水が過ぎるかなと思い反省したので、本物の「インベーダー」のクローンをまじめに作成しすることにしました。

takachan.hatenablog.com

画面構成

f:id:Takachan:20170320003414p:plain:h350

敵機、自機、弾などはすべてImageクラスになっています。 ImageクラスをCanvas上に配置しTimerを1秒間に60回更新して60fpsの疑似動作を行っています。

作成環境

今回制作に使うツールは以下の通りです。

  • VisualStudio2017Community
    • .NET Framework4.6.2をターゲットにしています
  • Paint.net
    • 敵画像の作成に使用します

出来上がったゲームの画面

今回は、本家のインベーダーゲームにかなり寄せています。

f:id:Takachan:20170320003900p:plain:h350

f:id:Takachan:20170320003905p:plain:h350

制作過程

イカゲームの時と流れはほとんど同じですがこんな流れで作業しました。

  • 1日目
    • イカゲームから必要な部分を残して全部削除
    • 自機の表示、左右キーでの移動
    • 自機の弾の発射、取り除き
  • 2日目
    • インベーダーの配置
    • インベーダーの攻撃処理とあたり判定の追加
  • 3日目
    • 防御ブロックの配置と自機の弾とのあたり判定
    • 敵UFOの出現処理
    • ゲームオーバー/ゲームクリア画面表示の作成

ブロックの配置ですが、これを実装するとゲームのデバッグが大変めんどくさくなるります。なのでなるべく後回し & 実装しても非表示にするなどが必要でした。

成果物

成果物はGitHubにアップしました。 前回と同じリポジトリですが、ブランチを切ってそちらで作業しています。

github.com

作った感想

イカのゲームからこのゲームを作っている最中に気が付いたことですが

  • インベーダーの画像はクオリティとか説得力が高い
    • 流石に商業リリースしたゲームのリソースは違います
  • 意外と処理が膨らむ
    • 弾が爆発したら画像を差し替えてN秒後に消すとか結構コードが必要です
  • ImageクラスはSpriteと同じように扱える
    • Cocos2d-xのSpriteとまぁまぁにてる操作が可能
  • 段々問題領域に対して理解が深まって前半と後半でコードスタイルがぶれている

今回ゲームライブラリを一切使用しないピュアC#のみで開発しましたが、Unityなどのゲームツールを使用すればライブラリなどもありますし、苦労は少ないと思います。無料で使用できますしね。

特にゲームライブラリだと

  • 特にN秒経過したら画面から除去する
  • ImageをアニメーションしているようにN秒ごとに切り替える
  • 衝突判定

は普通にクラスなり関数を呼べば良いケースが多いと思いますので、わざわざ自分で開発する必要ないですね。

今回は規模が前のより倍になったため、途中からコードが崩壊しかけてるのが実感できました。要素が多くなると変数が増加するのでそれらの整合性の管理や処理の順序、コード自体のボリュームで開発効率が少し落ちていました。少し構造は気にしながらコードを書いた方がよさそうです。

今回も完成が途中で危ぶまれましたがなんとか勢いだけで作りきることができました。

やっぱり短期間に勢いでガーっと作るのがよさそうです。

C# と WPF でインベーダー風ゲームを作る

VisualStudio2017が出たということで記念するわけではないですが、C#とWPFのみでインベーダー風ゲームを作ってみたいと思います。

すいません、嘘つきました。インベーダーを意識した気がするオリジナルなシューティングゲームです。リスペクトしたということでインベーダー風と言っています。

制作時間は3日に分けて3時間~4時間くらいで作成しました。

ゲームのルールと操作方法

  • スペースキーを押すと自機が弾を発射
    • 自機が撃てる弾は1画面に3発まで
  • 左右キーで自機の移動
  • 画面上部に侵略者(イカ)を生むUFOがいる
    • UFOは一定間隔でイカを生成する
  • イカは弾を出しながら手前に移動してくる

画面構成

今回、特にゲームエンジンを使わないのでWPFのWindowクラスの上にCanvasを張り付けてImageを動かしながらゲームを表現します。

f:id:Takachan:20170317012039p:plain:h350

作成環境

今回制作に使うツールは以下の通りです。

  • VisualStudio2017Community
    • .NET Framework4.6.2をターゲットにしています
  • Paint.net
    • 敵画像の作成に使用します

出来上がったゲームの画面

f:id:Takachan:20170317012256p:plain:h330

f:id:Takachan:20170317012301p:plain:h330

f:id:Takachan:20170317012305p:plain:h330

気が付いたこと

WPFはゲーム向けのライブラリとか一切ないので、60fpsをタイマークラスのElapsedイベントハンドラを1秒間に60回呼び出すことで対応しました。

またキー入力は、キーを押しっぱなしにすると、不連続に「テ、、、テテテテテ」と入力が走るので、キー入力処理の識別を自前で書く必要があります。

弾のあたり判定も無いので以下の通り自作しています。

public class GameUtil
{
    /// <summary>
    /// 指定した2つのオブジェクトが衝突しているか確認します。
    /// </summary>
    public static bool IsCollision(FrameworkElement a, FrameworkElement b)
    {
        double x_abs = 
          Math.Abs((Canvas.GetTop(a) + a.Width / 2)
                - (Canvas.GetTop(b) + a.Width / 2));
        double y_abs = 
            Math.Abs((Canvas.GetLeft(a) + a.Height / 2)
                - (Canvas.GetLeft(b) + a.Height / 2));

        double aw = a.Width / 2 + b.Width / 2;
        double ah = a.Height / 2 + b.Height / 2;

        return x_abs < aw && y_abs < ah;
    }
}

制作過程

以下のような順番で作成しました。

  • 1日目
    • 背景が黒い画面の作成
    • 自機の表示、左右キーでの移動
    • 自機の弾の発射、取り除き
  • 2日目
    • 防御ブロックの配置と自機の弾とのあたり判定
    • 敵UFOの表示と左右移動
  • 3日目
    • UFOのイカ生成処理
    • イカの移動、弾の発射
    • イカの弾と自機のあたり判定
    • ゲームオーバー/ゲームクリア画面表示の作成

それぞれ1日1時間ちょいずつ作業しています。

成果物

作ったものをGitHubへアップしました。

github.com

作った感想

気がついたことや残件、作った感想です

  • 絵がしょぼい
  • 効果音が無い
  • あたり判定の範囲が左にずれている
  • インベーダークローンを作ってたつもりなのにいつの間にか全然違うものができていた
    • 完全なクローンも時間をかければ出来そうな感はありましたが、丁寧作業すると結構時間がかかりそうな事に気が付きました

プログラムの内容はImageクラスをCanvasクラス上で1フレームごとに移動したりするだけなので特に難しいことはありませんでした。

  • 自機や敵の移動は、移動をする前に除去判定をしないといけない
  • 弾が当たったらループを中断して処理を打ち切らないとヤバイことになる
  • ImageはCanvasに追加してからCanvas.SetXXXした方がいい
  • ループ変数のインデックスのiとかjとかdfiを間違えて使わない
  • ループはforeach使わない、forで逆順で回す
    • リストから削除する事が多かったので逆順です

が大変だったかもしれません。

2日目くらいに、「なんでこんなもの作ってるんだろう」という気がしてやめようかと思いましが、自分に鞭をうって強引に進めました。多分4日目に突入したら完成しなかったと思います。

細かいことは気にせずにガーっと勢いでやるのが大切だと思いました。

後半戦

すいません、ちょっとこのままインベーダーを名乗るのはリスペクトが足りないと思ったので後編を書きました。

takachan.hatenablog.com

Exlipse 4.4 LunaでのSVN 1.9のリポジトリに接続する

f:id:Takachan:20170115150341j:plain

こんな事してる人もうこの世に存在しないのかな?それとも使ってる環境のせいなのか・・・

環境

  • Eclipse4.4 Luna (Pleiades Full版)
  • Subversive 4.0 (これ以下ならマーケットからアプデしてください)

この環境でHTTPでホストされていないファイルベースのSVN1.9で作成したリポジトリへ接続しようとすると接続エラーになる問題の対処方法です。

SVNKitが1.8.5とか1.8.7だと接続できないので

以下手順で、SVNKit(SVN Connecter)を最新バージョン(1.9対応版)に更新します。

ヘルプ > 新規ソフトウェアのインストール

から以下URLを入力して

http://community.polarion.com/projects/subversive/download/eclipse/6.0/update-site/?dir=features

で表示される内容から以下を選択します。

  • JavaHL 1.8.15 Win32
  • JavaHL 1.9.3 Win32
  • 他にもあれば全部チェック入れておく

途中で代替案が提案されたらそれらも全部入れれば、インストール完了後に再起動すると

“Connector Discovery"ウインドウが表示されてSVN Kitが選択できるようになります。

そこからまた、全部チェック入れてクライアントを更新しましょう。

更新したら

設定 > チーム > SVN > SVNクライアント[Tab]

から

SVNクライアント = Native JavaHL 1.8.15 rxxxxxx (SVN 1.8.15)

を選択すれば1.9を含む過去バージョンのリポジトリに接続できるようになります。

乱暴すぎて、選択項目が正しいか不明ですが上記URLが分かれば大丈夫だと思います。