講義メモ

テキスト編:「アレンジ演習:p.291 clock01.cs」から
ゲーム開発演習:背景画面のスクロール、アイテムの同時スクロール、左右移動 など

アレンジ演習:p.291 clock01.cs

・ストップウォッチにしよう
・実行すると「00:00:00」を表示してカウントを開始するようにしよう
・そのために、現在時刻ではなく、時刻を表す1000万分の1秒刻みのカウンタをDateTime構造体のTicksプロパティ(long型)で得て用いる
・起動時に現在時刻を持つオブジェクトを得たらTicksを確保しておき、最新のTicksとの差を算出する
・この差を1000万倍すると秒になるので、3600で割って時間を、60で割った結果の60の剰余で分を、60の剰余で秒を得ると良い

作成例

//アレンジ演習:p.291 clock01.cs
using System;
class clock01 {
    public static void Main() {
        int oldsecond = 0; //秒を比較用に保持する変数
        Console.CursorVisible = false; //カーソルを非表示に
        Console.Title = "時計"; //コンソールタイトル設定
        Console.SetWindowSize(12, 3); //コンソールの大きさ設定
        Console.BackgroundColor = ConsoleColor.Yellow; //背景色
        Console.ForegroundColor = ConsoleColor.Black; //文字色
        Console.Clear(); //変更を反映
        DateTime st = DateTime.Now; //【追加】開始時の日付時刻オブジェクト
        DateTime mt; //日付時刻オブジェクト用
        while (true) { //無限ループ
            mt = DateTime.Now; //現在日付時刻を得る
            int lap = (int)((mt.Ticks - st.Ticks) / 10000000); //【追加】経過秒数を得る
            int Hour = lap / 3600; //【追加】時間を得る
            int Minute = lap / 60 % 60; //【追加】分を得る
            int Second = lap % 60; //【追加】秒を得る
            if (Second == oldsecond) { //【変更】秒が変わっていない?
                continue; //後続処理をスキップして次へ
            } else { //秒が変わっている?
                oldsecond = Second; //【変更】新しい秒を取っておく
            }
            Console.SetCursorPosition(2, 1); //カーソルを前へ移動
            Console.Write("{0:00}:{1:00}:{2:00}",
                Hour, Minute, Second); //【変更】時分秒を各2桁で表示
            if (Console.KeyAvailable) { //何かキーが押された?}
                break; //繰返しを抜ける
            }
        }
    }
}

アレンジ演習:p.291 clock01.cs・続き

・ミリ秒までのストップウォッチにしよう
・実行すると「00:00:00.000」を表示してカウントを開始するようにしよう(表示幅を4文字分増やす)
・最新のTicksとの差を1万倍するとミリ秒になるので、3600000で割って時間を、60000で割った結果の60の剰余で分を、
 1000で割った結果の60の剰余で秒を、1000の剰余でミリ秒を得ると良い

作成例

//アレンジ演習:p.291 clock01.cs
using System;
class clock01 {
    public static void Main() {
        int oldmsecond = 0; //【変更】ミリ秒を比較用に保持する変数
        Console.CursorVisible = false; //カーソルを非表示に
        Console.Title = "時計"; //コンソールタイトル設定
        Console.SetWindowSize(16, 3); //【変更】コンソールの大きさ設定
        Console.BackgroundColor = ConsoleColor.Yellow; //背景色
        Console.ForegroundColor = ConsoleColor.Black; //文字色
        Console.Clear(); //変更を反映
        DateTime st = DateTime.Now; //開始時の日付時刻オブジェクト
        DateTime mt; //日付時刻オブジェクト用
        while (true) { //無限ループ
            mt = DateTime.Now; //現在日付時刻を得る
            int lap = (int)((mt.Ticks - st.Ticks) / 10000); //【変更】経過秒数を得る
            int Hour = lap / 3600000; //【変更】時間を得る
            int Minute = lap / 60000 % 60; //【変更】分を得る
            int Second = lap / 1000 % 60; //【変更】秒を得る
            int MSecond = lap % 1000; //【追加】ミリ秒を得る
            if (MSecond == oldmsecond) { //【変更】ミリ秒が変わっていない?
                continue; //後続処理をスキップして次へ
            } else { //秒が変わっている?
                oldmsecond = MSecond; //【変更】新しいミリ秒を取っておく
            }
            Console.SetCursorPosition(2, 1); //カーソルを前へ移動
            Console.Write("{0:00}:{1:00}:{2:00}.{3:000}",
                Hour, Minute, Second, MSecond); //【変更】時分秒を各2桁で表示
            if (Console.KeyAvailable) { //何かキーが押された?}
                break; //繰返しを抜ける
            }
        }
    }
}

p.294 練習問題 ヒント

・プロパティによる制限なので、エラー表示は含まなくて良い
・偶数は正の整数なので、構造体に含まれるメンバの型はuintにすると良い
・偶数しか保持できないようにするには、データメンバへの直接アクセスを禁止するしかない
・よって、データメンバはprivateとしよう
・そして、このデータメンバを扱うプロパティはpublicとする
・プロパティのsetにおいて、valueをチェックし、偶数であれば代入する
・プロパティのgetは通常通り

作成例

//p.294 練習問題
using System;
struct MyStruct { //構造体定義
    private uint x; //構造体のデータメンバ
    public uint X { //プロパティ
        get { return x; }
        set { if (value % 2 == 0) { x = value; } }
    }
}
class struct01 {
    public static void Main() {
        MyStruct ms = new MyStruct(); //newが必要
        ms.X = 10; //構造体のプロパティで代入
        Console.WriteLine(ms.X); //構造体のプロパティを呼ぶ
        ms.X = 11; //構造体のプロパティで代入(できない)
        Console.WriteLine(ms.X); //構造体のプロパティを呼ぶ
    }
}

第12章 デリゲートとイベント

p.295 デリゲートとは

・メソッドへの参照を保持しておいて、これを用いてメソッドを呼び出せる仕掛け
・C/C++における「関数へのポインタ」の考え方を洗練したもの
・C#公式リファレンスでは「代理人」と和訳されていることがあるが、ニュアンスが異なる
・主に、イベントなどで用いる
・利用には宣言と生成が必要で、宣言はクラスの外で行う
・宣言書式: delegate メソッドの戻り値型 デリゲート名(メソッドの引数リスト);
・この書式でわかる通り、デリゲートで用いたいメソッドと、戻り値型、引数リストが一致している必要がある
・例: delegate bool md(int w); //このデリゲートで「bool foo(int x){…}」などが扱える
・デリゲートの生成において、扱うメソッド名を指定する
・生成書式: デリゲート名 参照変数 = new デリゲート名(メソッド名);
・例: md work = new md(foo); //fooメソッドを呼び出せるデリゲートを生成しworkとする
・デリゲート経由でメソッドを呼び出すには、参照変数をメソッドの別名にように扱える
・例: bool ans = work(12); // bool ans = foo(12);と同じ動作になる

p.297 delegate01.cs

//p.297 delegate01.cs
using System;
delegate void MyDelegate(); //デリゲートの宣言(戻り値無、引数無))
class delegate01 {
    public static void show() { //静的メソッド(Mainから呼出可)
        Console.WriteLine("呼ばれました");
    }
    public static void Main() {
        //直接showメソッドを呼び出す
        show();
        //デリゲートの作成
        MyDelegate md = new MyDelegate(show);
        //デリゲートを通してshowメソッドを実行
        md();
    }
}

p.298(別のクラスにあるインスタンスメソッドをデリゲート経由で呼び出す)

・別のクラスにあるインスタンスメソッドをデリゲート経由で呼び出すことができる
・そのクラスのインスタンスを生成して用いると良い
・生成書式: デリゲート名 参照変数 = new デリゲート名(インスタンス名.メソッド名);

作成例

//p.298 delegate02.cs
using System;
delegate void MyDelegate(); //デリゲートの宣言(戻り値無、引数無))
class MyClass {
    public void show() { //インスタンスメソッド
        Console.WriteLine("呼ばれました");
    }
}
class delegate02 {
    public static void Main() {
        MyClass mc = new MyClass(); //インスタンスを生成
        mc.show(); //インスタンスで直接呼出す
        MyDelegate m = new MyDelegate(mc.show); //デリゲートを生成
        m(); //デリゲート経由で呼出す(インスタンス名は不要)
    }
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です