過去雑記

旧鯖時代の雑記です。新しいの。リンク切れに注意。


2007: 12345678910
2006: 123456789101112
2005: 123456789101112
2004: 456789101112

過去雑記

2006/12/4(月)

散財00:35:18

姉妹の方程式#3かってきました。またまた風邪がぶり返してきたっぽいです。体調管理はしっかりと。

コメントはありません。

OrcasのCLRは2.0らしい21:41:30

情報元。ということはOrcasの(個人的な)魅力はC#3.0とWPFデザイナですか。だとするとわざわざ乗り換える必要もないかなぁ。.Net 1.1→2.0のときはジェネリックサポートで飛びついたわけですが、現状C#3.0にそこまで魅力感じていませんし。しかしC++でSDKなら開発環境をバージョンアップしなくてもコードかけますけど、C#は開発環境ごとにバージョンが決まってるのが。。。うまい商売してますね。

コメントはありません。

2006/12/10(日)

Vistaのアイコンは256x25603:20:05

情報元。シェルで使用される大きいアイコンは256x256らしいです。こいつはPNGらしいですが、MSDNに見つからないので詳細は不明。そしてオプション扱いにされるXPの48x48サイズアイコン。今後は256x256,32x32,16x16おけばいいのですかね。48x48なんて使ってる人見たことないですし。まぁアイコンなんて書かないのですけど。

コメントはありません。

継承したクラスで基底クラスのインタフェースを実装すると基底クラスのインタフェースが実行できなくなる(長10:48:26

Wikiと同時更新〜。このコード問題なくコンパイル通るんですけど、BaseにあるMethodが呼び出せないんですよね。仕様といえば仕様なんでしょうけどいいのかなぁ。

using System;
 
interface IInterface {
    void Method();
}
 
class Base : IInterface {
    void IInterface.Method() {
        Console.WriteLine( "Base" );
    }

    public void Call() {
        // これはコンパイルエラー
        //this.Method();
        ((IInterface)this).Method();
    }
}

class Derivation : Base, IInterface {
    public void Method() {
        Console.WriteLine( "Derivation" );
    }
}

static class Program {
    static void Main() {
        Base b = new Derivation();

        b.Call();
    }
}

//出力
//Derivation

コメントはありません。

2006/12/11(月)

散財23:22:39

おとぎ銃士 赤ずきん#1。アンソロのほうは悩みましたが特に知っている人が書いていなかったので見送り。

コメントはありません。

2006/12/12(火)

MP3プレイヤー購入23:25:21

MP3プレイヤー買いました。サンヨーのスティック型1Gです。型番は検索して自分のサイトが引っかかるといやなので書きません。ええ。お値段は10k弱也。価格ドットコムの最安値以下です。クリスマス商戦万歳。

今使ってるの3年くらい使ってると思って雑記を読み返してみると2年目でした。17k+SDカードが2年だと割に合わないかなぁ。SDカードは再利用できますけど。まぁ接続のケーブルを紛失したりして不満が多かったのでいいのですけど。で、過去2機種全部ケーブル紛失してるんですよね。さて今回は。。。そんなことを気にするならサードパーティの接続ケーブルが売られてるiPodとか買えって話ですか。

とりあえず軽く使ってみた感想は、特殊なアプリなしで転送できるのは便利。再生リストを作るには専用ソフトを入れないと駄目っぽいですが、1Gごときで再生リストを作る価値があるかは微妙なところ。ランダム再生は現在位置からランダムに次曲に行くパターンの模様。プレイリストを生成しないので戻ることができません。前の機種が再生リストを生成→1巡すると再生成→しかしこのリストを保存しないので電源を切ると常に同じ再生リストという謎仕様だったので妥協できる点。液晶表示がID3TAGと再生時間が排他なのは不満。まぁこんな感じですか。

コメントはありません。

2006/12/17(日)

ゲームにおけるリソース管理の考察11:27:20

ちょっと前ゲームを作った際テクスチャの管理で悩んだのでそのときの考察のまとめ。ぐだぐだと書いていたら一月かかってしまいました。クラスがテクスチャを持つ手法とテクスチャのコレクションを作ってクラスのインスタンスと結びつける方法が考えられますが、後者は速い実装方法が思いつかないので今回は前者で。

まず、何も考えずに素直に実装するとこんな感じになります。

class HogeObject : IDisposable {
    private Texture m_texture = new Texture(...);
    public Texture Texture { get { return this.m_texture; } }
}

しかしこのコードだとインスタンス毎に同じテクスチャを持って激しく無駄なわけです。背景のような1インスタンスしか作らないのならともかく、大量のインスタンスを作る場合同じテクスチャが大量に作られて無駄です。

ということで今回使ったのは次の方法。

class HogeObject {
    private static Texture m_texture = new Texture(...);
    public Texture Texture { get { return m_texture; } }
}

この方法だといくらインスタンスを作ってもテクスチャは同じものを使用するのでメモリを節約できます。余談ですがこのようにstaticコンストラクタを使用する場合あらかじめ何らかの方法でstaticコンストラクタを起動させておかないとゲーム中にstaticコンストラクタが起動してラグが出る恐れがあります。この方法の欠点としては、いうまでもなく開放ができません。今回はそんな大作でもないのでこれで済ませましたが、大量のテクスチャを必要とする場合この手法は使えません。

案1.Load, Freeメソッド

class HogeObject {
    private static Texture m_texture = null;

    public static void Load() {
        m_texture ?? m_texture = new Texture(...);
    }

    public static void Free() {
        if(m_texture != null)
            m_texture.Dispose();
        m_texture = null;
    }
}

ゲームの区切りごとにLoad, Freeを挿入すれば開放できない問題は解決できますが、Loadを忘れたりFreeを忘れたりすると問題が発生します。Loadは例外がくるのでわかるでしょうが、Freeは特に目に見た問題が発生しない分やっかいです。ただし、これはリフレクションでメソッドをまとめて呼び出すという手法をとれば解決できます。またこの手法は明示的にロードを行うため、ゲーム中に意図しないstaticコンストラクタによるラグを防ぐというメリットもあります。

static void Run() {
    Type[] types = new Type[] { typeof(HogeObject), ... };
    foreach(Type type in types) {
        MethodInfo mi = type.GetMethod("Load", new Type[] { });
	if(mi == null) {
            // メソッドが見つからない
        }
	mi.Invoke(null, new object[] { });
    }

    // ゲーム開始

    // Freeはロードと同じなので省略
}

案2.参照カウンタ

class HogeObject : IDisposable {
    private static int m_textureCount = 0;
    private static Texture m_texture = null;
    private bool m_isDisposed;

    public HogeObject() {
        if((m_textureCount++ == 0) || (m_texture == null))
            m_texture = new Texture(...);
        this.m_isDisposed = false;
    }

    ‾HogeObject() {
        lock(this) {
            this.Dispose(false);
        }
    }

    public void Dispose() {
        this.Dispose(true);
    }

    private void Dispose(bool disposing) {
        if(!this.m_isDisposed) {
            if(--m_textureCount == 0)) {
                if(disposing) {
                    if(m_texture != null)
                        m_texture.Dispose();
                    m_texture = null;
                }
            }
            if(disposing) {
                this.m_isDisposed = true;
                GC.SuppressFinalize(this);
            }
        }
    }
}

newする際にテクスチャが作成されていないとテクスチャを作成します。解放はList<IDisposable>にでも突っ込んで必要なタイミングでまとめて処理すればいいでしょう。

案3.staticコンストラクタ+アプリケーションドメイン

新しくアプリケーションドメインを作りループをアプリケーションドメイン内で行います。このメリットはループを抜けた際にアプリケーションドメインをアンロードすることによってループで使用していたメモリをすべて解放することができます。しかしながらアプリケーションドメイン間の通信はコストが高いのでこれをいかに回避するかが鍵となるでしょう。実際やってみたことがないので実用に耐えうるかはわかりません。

案2が一番実用っぽいのですが、これstaticメソッドを使っているのでクラスにメソッドの実装を強要できないのですね。インスタンスメソッドならインタフェースでも定義してそれを実装させればよいのですが、それができません。この問題は例えばLoad()メソッドがLoad(Device)のように引数が変わったりした場合、つまり仕様変更があった場合コンパイル時に検出できません。私はプロトタイプを作っては壊して作り直して、という組み方をするので結構痛い問題です。

コメントはありません。

2006/12/19(火)

気がつけば年の瀬21:51:51

気がつけば今年ももう残り2週間。年末進行真っ只中です。そんなわけでこのエントリも雑多に。(関係ない)

MP3プレイヤーコネクタは汎用USB MinBピンでした。とりあえず予備確保。しかし起動時と同時に再生できないのは地味に不満。またPCに接続すると再生情報が消去されるのもどうかと。ファイルを変更したのならわかりますが、充電のためにPCにつないだ際にも消えるのはおかしい気が。

世間様からかなり遅れていますがSystem.Drawing.SystemFontsとか発見。.net 2.0でこんなクラスが追加されていたんですね。.net 1.1だとメニューのフォントしか取得する方法がなかったわけですが、これでユーザー設定のフォントを取得できます。あわせてControl.DefaultFontもGetStockObject()のものではなく、ユーザ設定のものが使用されるように。しかし互換性のためとはいえSystem.Windows.Forms.SystemInformation.MenuFontが残っているのには違和感が。

VS2005のサービスパックが公開されたわけですが、これインストールすると結構な量のバックアップを作成して無駄なわけです。近年の大容量化でデスクトップはいいのですが、ノートだと結構な負担。まぁ統合できるっぽいですけど。

コメントはありません。

2006/12/24(日)

VS2005 SP1がMSアップグレードに無い件について23:54:20

VS 2005のインストーラはサービスパックの有無を調べるためにMSアップグレードに飛ばすわけですが、ここに無いんですよね。VS 2005SP1。いいのかなぁ。

コメントはありません。

2006/12/30(土)

ゲームにおけるリソース管理の考察(2)02:38:39

以前書いたリソース管理の考察で、参照カウンタ方式が一番スマートだと思うものの実装コストが高いとか考えていたのですが、ジェネリックな管理クラスを作ると解決できますな。

sealed class SingletonResource<T> : IDisposable where T : class, IDisposable, new() {
    const int DefaultListValue = 1024;
    private static Dictionary<Type, Resource> s_dictionary;

    sealed class Resource {
        private int m_count;
        private IDisposable m_object;
        public Resource(IDisposable obj) {
            this.m_count = 1;
            this.m_object = obj;
        }

        public int Count { get { return this.m_count; } }
        public int Add() { return ++this.m_count; }
        public int Remove() { return --this.m_count; }

        public IDisposable Value { get { return this.m_object; } }
    }

    static SingletonResource() {
        s_dictionary = new Dictionary<Type, Resource>(DefaultListValue);
    }

    private bool m_disposed = false;
    private Resource m_resource;
    public SingletonResource() {
        lock(s_dictionary) {
            if(s_dictionary.TryGetValue(typeof(T), out this.m_resource)) {
                this.m_resource.Add();
            } else {
                s_dictionary[typeof(T)] = this.m_resource = new Resource(new T());
            }
        }
    }

    ‾SingletonResource() {
        this.Dispose(false);
    }

    public void Dispose() {
        this.Dispose(true);
        this.m_disposed = true;
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing) {
        lock(this) {
            lock(s_dictionary) {
                if(!this.m_disposed && (this.m_resource.Remove() == 0)) {
                    if(disposing)
                        this.m_resource.Value.Dispose();
                    s_dictionary.Remove(typeof(T));
                }
                this.m_resource = null;
            }
        }
    }

    public bool Disposed { get { return this.m_disposed; } }
    public T Value { get { return this.m_resource.Value as T; } }
}

参照カウンタを備えたリソース管理クラスです。ジェネリックパラメータのTypeを取得して存在しなければインスタンスを作成して格納しています。

class Hoge {
    class HogeResource : IDisposable {
        public void Dispose() {}
    }

    SingletonResource<HogeResource> m_resource;
}

使い方はこんな感じで。専用のリソースクラスを作って放り込みます。問題はSingletonResource<T>.Dispoe()を呼び出す権限をどこにおくかということでしょうか。HogeResourceの上のHogeクラスでIDisposebleを実装してHoge.Dispose()で開放させるというのが理想的な気がしますが、何か冗長な気もします。

コメントはありません。

2006/12/31(日)

それではよいお年を00:17:00

2007/1/1で雑記をPHP5に移行しようと思ってたのですが、まったくモチベーションがあがらずに頓挫。まぁ気長にやっていきます。ていうかもう人様のものでいいかなぁ。静的にRDF更新するタイプなら今と同じことはできますし。。。

コメントはありません。

goto Top

Copyright(C)方位記号