前回、AvatarControllerをやりながら、このダイアログ

 

 

【拡大図】

 

について全く説明しなかったことに気が付きました!(ゴメンナサイ!)以下に概要を説明します。

 

(1)このダイアログがModal Dialogで、Worldクラスインスタンスを親(thisで呼ぶ)として呼んでいます。

 

(2)しかし、このダイアログは「3秒の命」しかなく、(何もしなくても)3秒経つと自動的に閉じられます

 

(3)↑ご覧のように多くのコントロールがありますが、「選択する動作は一つだけ」(動作はカラープッシュボタンを押すことにより実行しますが、ボタンは一つしか押せません)ので、その「3秒の命」の中で、ひとつだけ選択します。(カラープッシュボタンを押すとダイアログが閉じられます。)敢えて何もしない場合には最下段の「パス」ボタンを押してください。

 

(4)具体的に言うと、「遭遇したCellへの対応」では「親交」を結んだり、「威嚇」、「闘争」や「逃走」したりできます。又、食べ物があれば「食べる(への対応)」ことができ、野原があれば「移動(対応)」することができます。

 

(5)しかし、「ボタンを押しても、できないことがあるということを判断するには3秒間では難しい」だろうということで、「できないことはできない(グループボックスの.Enabledプロパティがfalse」ようにしていますので()、「押せるボタンが、今出来ること」になります。(さすがにそれはボタン状態からわかるでしょうと...)

:↑のイメージでいえば「遭遇したCellへの対応」と「食物への対応」がDisable状態です。

 

(6)また、、「遭遇したCellへの対応」では「異種族間婚姻が許可されているか」「自分と相手の種族、愛着性、敵対性」の数値が表示されるので、「親交を結ぶか、威嚇するか、即戦うか、逃げるか」を判断する素地になるでしょう。

 

(7)「食物への対応」動作も対象が複数ある場合は選択ができることも考えたのですが、余りに面倒にすると「特に反応が劣る高齢者」にはキツイのでPC判断と同じ対処にしました。

 

(8)「移動対応」も移動できる方向だけボタンを押せるよう、特に反応が劣る高齢者に対して「親切設計」にしています。

 

このように、従来のC++版のように単に「世界とCellの行く末を神の視座で眺める」というゲームから、「ユーザー自身がアバターを使って世界に入ってプレイする」というのが今回のC#版の売りなんですが、実際にプレイして思ったことは、

 

このゲームで、俺は主役にはなれない!

 

という

 

厳しい現実

 

でした。

 

Cell数を絞ってプレイする場合でも、採り得る戦略は「ひたすら食べ物を追っかけて、他のセルから逃れる」か、「なるべく戦わないで親交を深めるか」しかなく、「威勢よく他のセルを切り結ぶ」なんてことは考えない方がよい(直ぐに死ぬ)という現実です。

 

これがCellの数を多くすると

 

直ぐに大衆に飲み込まれてしまう...

 

という「しがない一個人の悲しい人生」を

 

嫌っていう程、味あわされます

 

正に「人生ゲーム」。期待した効果とは異なりましたが、それはそれで

 

大成功!!!

 

ps. 今回のプログラミングで初めて遭遇したエラーについて備忘として書いておきます。

 

最初AvatarControllerクラスからWorldクラスのフィールドやメソッドを使おうと思い、Worldクラス中の「Class in Class」にしようかと考えて進めたのですが、それでコンパイルすると、

 

CS0038: 入れ子になっている型 'Cell_World.World.AbatarController' を経由して、外の型 'Cell_World.World' の静的でないメンバーにアクセスすることはできません

というエラーが生じます。これはクラスインスタンスがスタックエリアに作られるために「アドレスが実際の実行まで確定できない」ことから来る問題()と考えました。

:言語設計により、相対距離でアクセスできる場合もあるようですが...一方、クラスの静的メンバーであれば、アドレスが確定しているためにアクセスが可能です。

【ご参考】

 

念のためにChat-GPTに確認すると矢張り、

 

C#でこのエラー(CS0038)が発生するのは、インナークラス(入れ子の型)から、外側のクラスの「静的ではない(non-static)メンバー」に直接アクセスしようとしたためです。C#の入れ子クラスは、Javaのインナークラスとは異なり、自動的に外側のクラスのインスタンス(this)への参照を持ちません。

(例)
csharpnamespace Cell_World
{
    public class World
    {
        public int worldSize = 100; // 静的ではないメンバー(インスタンス変数)

        public class AbatarController // 入れ子になっている型
        {
            public void Move()
            {
                // エラーCS0038:外側の非静的メンバーに直接アクセスできない
                int size = worldSize; 
            }
        }
    }
}

 

ということで、「Class in Class」は役に立たないので止め、コンストラクターの引数でWorldインスタンスを参照渡し(C++であれば「ポインター渡し」ですね)することにしました。ちょっとどんくさいですが...ご参考まで。