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

AIプログラムとかUnityゲーム開発について

探索や学習などを活用したAI系ゲームを作りたいと思います。

爆弾追加

対戦RTS

爆弾追加。
自陣深くまで引いておいて、ひきつけて爆弾で敵をせん滅w
爆弾というか地雷だな。

http://27.120.88.154/rts11.gif

対戦開始まで爆弾は見えないようにしておくといいですね。
軍人将棋のノリで( ゚Д゚)
爆弾だらけだどまずいので、設置コストは高めないとだめですが。

どの敵を狙うかという評価

対戦RTS

AIの行動選択のうち、複数の敵がいる場合にどの敵を狙うか?は重要な戦略となります。
基本的には一番近い敵を狙うようにしていますが、その他の評価点として、

  • 味方が狙っていないフリーの敵を狙う
  • 味方が狙っている敵を狙う(数の暴力)
  • HPが減っている敵を狙う(とどめをさす)
  • HPが減ってない敵を狙う(まんべんなく攻撃する)

といった考え方ができます。


対戦させたみた感じでは、フリーの敵を狙うというのが有効みたいでした。
そのほかの戦略がだめなのは、あと一回矢が当たると死ぬ相手に、矢が3本当たるということは、限られた攻撃機会を無駄にしているわけです。
なるべくフリーの敵を失くすということは、無駄な攻撃を失くすという意味合いがありそうです。


下記は、同じ戦力で、左は(一番近い敵を狙う+フリーの敵を狙う)戦略で、右は戦略無し(一番近い敵を狙うのみ)
http://27.120.88.154/rts10.gif

このへんの戦略は、ゲーム作成する上で評価点として調整するところですが、
あえてユーザーにオプションとして開放するのもいいかなと思います。
ただ、フリーの敵を狙うのが最適解なら、みんな設定したほうがいいので、オプションの意味がなくなります。
ケースバイケースのオプションができれば、より望ましいと思います。

サーバーマッチングしてネット対戦する

対戦RTS

サーバーからランダムマッチングできるようになった。

http://27.120.88.154/rts9.gif

Matchingボタンを押すとサーバーからランダムに対戦相手を取得する
Battleボタンで戦闘開始

マッチング後にユニットを増やしているが、これはできないようにした方がいいだろう。
クラクラの場合、マッチング後タイマーがあって、タイマーが来ると自動的に対戦開始になる。
あと、マッチングするたびにゴールドを消費する仕組みになっている。


マッチングは一覧から選ぶやりかたもあるが、それだと、別アカウントでつくった弱い相手を使って、不当に経験値を上げるといった恐れがでてくる
よって、クラクラはランダムマッチングしかないのだと思う。
ソーシャルゲームの農園ゲームなんかでは、別ユーザーの農園を代わりに収穫する機能があったりするが、放置農園を植民地にすることで、
どんどん収穫量を増やすとったことができてしまう問題点があった。
クラクラの場合、別アカウントを使うことで、援軍をつねに確保するといったチートはできてしまう。本来複数アカウントは禁止なんでしょうけど。


MySQLでのランダムレコード取得

SELECT s.* FROM data AS s INNER JOIN(SELECT CEIL(RAND() * (SELECT MAX(`id`) FROM data)) AS `id`) AS `tmp` ON s.id = tmp.id;

参考
qiita.com

MySQL: レコードがすでにあればUpdate。なければInsert

CentOS

マップ配置データをサーバーに保存するにあたり、マップデータがすでにアップロードされていればUpdateし、新規であればinsertする処理を作りたい。


MySQLであればon duplicate key update機能を使う

INSERT INTO data (userid,data,datetime) VALUES(".$db->quote($userid).",".$db->quote($data).",NOW()) ON DUPLICATE KEY UPDATE userid=".$db->quote($userid).",data=".$db->quote($data).",datetime=NOW();"

同じuseridのレコードがあれば、dataとdatetimeのupdateが行われ、新規の場合は、Insertが行われる。

なお、重複チェックの対象であるuseridは、UNIQUEインデックス(かPRIMARY KEY)を指定しておく必要がある。
要するに、同じuseridのレコードは一つしかないという状態になっている。

同様な処理をするのに、以前は、まずselectしてデータがなければInsert。あればUpdateみたいなことをやっていたが、SQL発行が一回で済んで楽。


参考
qiita.com

ユニークIDの保存

サーバーに配置データを保存するにあたり、ユーザーを区別するためにユニークIDを発行しなければならない。
また、ユニークIDはローカルに保存しておいて、アプリを起動するたびに同じIDが読み込まれるようにする必要がある。



データをセーブするには、以前の記事に書いたSaveData.csを使う。

yasu9780.hatenablog.com



セーブデータは以下のような構造とする。

    class Player
    {
        public string uuid;
        public int mode;
        public Vector3[] pos;
        public int[] type;
        public Player()
        {
            uuid = "";
            mode = 0;
            pos = new Vector3[100*3];
            type = new int[100 * 3];
            for (int i = 0; i < 100 * 3; i++) type[i] = -1;
        }
    }
    Player player;

ユニークIDはuuidに保存されている。


起動時に、以下のような処理を入れる

   void Start () {

        player = SaveData.GetClass<Player>("p1", new Player());
        if(player.uuid=="")
        {
            System.Guid guid = System.Guid.NewGuid();
            player.uuid = guid.ToString();

            SaveData.SetClass<Player>("p1", player);
            SaveData.Save();
        }
        Debug.Log("uuid=" + player.uuid);

p1というキーで保存されているデータを読み込む。
初回はデータが無いので、new Player()の結果が返ってくる。
コンストラクターがuuidに""に代入しているので、初回はuuidが空として、uuid発行処理が走る。UUIDを発行したので、p1をキーとしてplayerをセーブする。

一度アプリを終了させ、次回の起動では、SaveData.GetClassの読み込みでuuidが入っているので、uuid発行処理は今度は走らない。

これで、初回時はuuid発行。以後は同じuuidが起動時にセットされるという処理ができた。

キャラ配置をVPSサーバーに保存・読み込み成功

対戦RTS

キャラを配置して、Saveボタンを押すと、キャラ配置データをCSVにして、HTTPのGETでVPSサーバーのCGIに転送
LOADボタンを押すと、VPSサーバーのCGIからデータを取得して、キャラ配置を再現。
f:id:yasu9780:20170324194944p:plain


phpMyAdminで確認すると、MySQLに保存したCSVデータが入っているレコードができている。

f:id:yasu9780:20170324194950p:plain

テスト用で、useridは1になっているが、スマホ上のユニークIDをユーザーIDとして実行すれば、
ユニークIDごとに配置データをVPS上に保存できる。

後は、別のスマホから保存した配置データをLOADできるようにすれば、違うユーザー同士で対戦が可能になる。



回転向きは固定なので保存する必要なし。本来はY座標も固定なんですが、いちおう保存します。typeはキャラ種別。

        if(no == 2 && !battle) // save
        {
            string temp = "";
            for (int i = 0; i < 100; i++)
            {
                if (ch[i] == null) continue;
                temp += chcc[i].type + ",";
                temp += ch[i].transform.position.x.ToString("0.0") + ",";
                temp += ch[i].transform.position.y.ToString("0.0") + ",";
                temp += ch[i].transform.position.z.ToString("0.0") + "@";
            }

            StartCoroutine(HttpGet("http://VPSURL/?u=1&d="+temp,0));
        }

アーチャーの矢を追加

対戦RTS

無料の弓と矢のアセットがあったので、矢だけ流用。
ちゃんと矢にするとリアル感が増しますね。
ちなみにこの矢は自動追尾です。打ち出せば必ず当たる必中の矢。

http://27.120.88.154/rts8.gif