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

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

次はトランプゲームを作る予定

今週は色々と忙しいのですが、終末はトランプゲームでも作ってみようと思います。
大富豪かセブンブリッジあたり。
セブンブリッジは麻雀と似てますが、大富豪の方が作りやすいかな?


トランプゲームの場合、CPU側が人間の手札を覗けばいくらでも強くできます。
それではプレイヤーが面白く無いので、
見ないように作ればいいんですが、それだと弱くなりますw
CPUがズルをしているかどうかは傍目には分からないので、
どっちで行くかは作る人の趣味の問題かと思います。
ズルせずに強い思考エンジンを作るぜ!と思えばそっちの路線で行くべきでしょう。


大富豪の思考エンジンの作り方としては、

何枚組で出すか?
何の数字で出すか?
をそれぞれ考えて、出し方を検討する必要がありますが、
ざっくり言うと、いきなり2を出すのはもったいないし、2・2で出すとものすごくもったいない。
戦略としては、3に近い札をもっていればなるべく早めに出して、
強い札は温存しておくという形になります。
3を2枚もってるなら、自分に手番が来れば即だした方がいい。
そういうルールをAIに入れるとして、評価としては
Σwxという形で表現できると思います。
wは重みで、xはその特徴が成立しているかどうか。
色々なルールを取り入れるとして、そのルールの和で評価する時、どのルールを優先するべきかを
重みで表現するわけです。
例えば、2を二枚持ってるけど、二枚同時に出すよりは、分けて出したほうがいいとか。
3を持ってるので、2を出して手番を取ってから3を出そうとか。


期待値で考えてもわかりやすいかもしれません
3に近い札をもっている程負ける確率が高く、2にちかい札を持つ程、勝つ確率が高い
足してやれば期待値がでます。勝利確率と言ってもいいかもしれません
一方で沢山札を持っていると危険で、少ないと勝てる確率が上がります、
また、他のプレイヤーとの札の差もあるかもしれません
自分が3枚しか残りが無くても、他に一枚しかもってないプレイヤーがいれば
自分が劣勢のはずです。


次の方向性は、相手の札を予想する方向です。
自分の持っている札と場に出た札は、CPUは完全に暗記することができます。
これはコンピュータの有利なところだし、捨てられた札を暗記していてもズルではありません
人間もやろうと思えばできるからです。
麻雀やポーカーの強い人は覚えているでしょう。
そうすれば、各自が持っている札を絞り込むことができますから、
類推ができるようになります。
相手の手札の出し方も類推の手がかりになるかもしれません。
6・6と出してきた場合、9・9などを持っていて、一気に札を減らそうと考えているかもしれません。




トランプゲームで先読み探索までは通常しないと思いますが、
通常2は出さないけど、3を持ってるなら3を捨てるために2は出すみたいな
特殊なルールを沢山組み込むわけです。
この重みを自分でつけていくならば、それは旧来のエキスパートシステム的なAIになるでしょう。
AIを作る側からすると盆栽作りみたいで可愛いです。


重みがよく分からないので、シミュレーションをして重みをつくる参考にしたり、
重みがランダムの初期状態のAI同士を戦わせて、ゲームの結果から学習させて行く方向もあるでしょう。
これは適切なルールさえ組み込んでおけば、重みは自動的に修正されて強くなってくれそうで
楽ですし、なんだかかっこいいです。


とりあえずは、ざっくり動くものを作ってみて、作りながら考えてみようと思います。

横断歩道シミュレーションゲームwwww

unity Game uploaderに投稿されてたけど、凄いwwww
横断歩道システム
http://unitygameuploader.jpn.org/game/4818.html

大衆シミュレーションでもあるし、GTAみたいな通行人轢き殺すゲームでもあるし、
なんかAIっぽい雰囲気もかなりするし、
軽快なBGMがすごいいい味を出してるwww

大阪の人とか信号変わる前に渡るのが当たり前で、文化って違うしね。
そういう方向もあるかもなあ

昔、クロスハイウェイってゲームあったなあ
自分も、自転車は車道を走らないといけないので、
車道脇を走って車に気をつけるゲームを考えたことがある。
歩道を走ると減点で、警察に切符を切られる。
でも、車道には迷惑駐車がいて、車道側に迂回すると、
後ろからトラックに追突されるとかww

ランキングを追加

クイズゲームタワーディフェンスにランキングを入れてみました。
ただ、DB使わずに、アペンドモードでファイルに書き出してるだけなので、
レスポンス悪い&壊れるかもw


クイズゲーム
Unity Web Player | UnitychanQuiz
タワーディフェンス
Unity Web Player | td

タワーディフェンスはミッション完了間際に砲台を壊して資源回収しないと
資源量的に厳しいかも(^_^;)

クイズゲームは、UnityGameUploader様に登録してみました。
あと、うに部屋にも登録してみました。
タワーディフェンスはもうちょっと作り込みます。


UnityGameUploader | Unityのゲームをアップロードしよう


unityroom.com


ランキング作成と新しいスコアの追加処理
ランキング作成はログを読み込んでソートして上位10個表示のみ(読み込みONLY)
新規追加は、追加書き込みでログを追加して、全体をソートして自分の順位を返す。
書き込みで一応ロックを入れてみました。
壊れるときは壊れるでしょうw
本来は一週間でクリアしたいところ(賑わってるならデイリーでもいい)
ランキングが固定化されると意味無いですから。
大事なのは短期ランキング

if($act eq "ranking")
{
	open (FH, $filename);
	while(<FH>)
	{
#		print $_."<br>\n";
		push @list,$_;
	}
	close(FH);
	@list = sort {(split(/<>/,$b))[0] <=>(split(/<>/,$a))[0] } @list;
	for(my $i=0;$i<=9;$i++)
	{
		my ($score,$datetime) = split(/<>/,$list[$i]);
		if( $score eq "") { last; }
		print $i+1;
		print "位 ".$score." (".$datetime.")\n";
	}
}
if($act eq "add")
{
	open (FH, ">> $filename");
	flock(FH, 2);
	seek(FH, 0, 2);
	print FH $score."<>".$datetime."<>\n";
	close(FH);

	open (FH, $filename);
	while(<FH>)
	{
		push @list,$_;
	}
	close(FH);
	@list = sort {(split(/<>/,$b))[0] <=>(split(/<>/,$a))[0] } @list;
	for(my $i=0;$i<@list;$i++)
	{
		my ($score2,$datetime2) = split(/<>/,$list[$i]);
		if($score eq $score2)
		{
			print "あなたは";
			print $i+1;
			print "位です\n";
			last;
		}
	}

}

TowerDefenseを作ってみる(4)

  • 破壊の炎エフェクト
  • 射撃音、破壊音などAudioを追加
  • ミッション制を導入(クリアで難易度が上がっていく)

f:id:yasu9780:20150510015704p:plain

とりあえず遊べるようになりましたので、WebPlayer版も公開してみます。
http://rafeel.s602.xrea.com/td/td.html
マウス右クリックだとUnityPlayerのメニューが出るのがうざかった。
しかし、バイナリファイルが740KBしかない。小さいなあ(^-^;)


今後は、

  • レーザー攻撃砲台の追加
  • 砲台のレベルアップ
  • 敵を遅くするサポート砲台
  • 破壊されると分裂する敵
  • 空軍
  • 経路の切り替え
  • 複数の経路の出現
  • 爆弾を落とすなどスペシャルスキル

といったところを実装して行こうと思います

TowerDefenseを作ってみる(3)

  • 敵を三種類(普通、速い、ボス)
  • 砲台を二種類(近距離高速高攻撃、遠距離低速低攻撃)

砲台設置はゴールド必要(敵を破壊するとゴールドが手に入る)
砲台は設置後もマウスでクリックすると破壊してゴールドを半額回収できる
ボスはHPが6000あるので、範囲外の砲台を破壊してゴールド回収しながら
新たに設置しないと倒せません。

f:id:yasu9780:20150509155043p:plain

演出とかしてないのでみため寂しいですが、仕組み的にはかなり完成に近づいてきました。
このキューブを、ゴーレムとかに置き換えればいいわけです。


あとはレベルデザイン的に、出現する敵の種類や順番、パスなどを
管理しやすくして、クリアするごとにアンロックして、次に挑戦できるみたいな仕組みですね。
エクセルで表をつくって読み込むのが良さそうです(^-^;)


マウスでクリックして砲台設置の部分はこんな感じ

if (Input.GetMouseButtonDown(1) )
{
	Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
	RaycastHit hit = new RaycastHit();
	if (Physics.Raycast(ray, out hit) && hit.collider.gameObject.tag=="Plane" && gold>=300 ) {
		gold-=300;
		GameObject selectedGameObject = hit.collider.gameObject;
		GameObject obj = (GameObject)Instantiate(Tank2Prefab, selectedGameObject.transform.position, Tank2Prefab.transform.rotation);
		obj.GetComponent<Tank>().type=2;
	}
}

光線飛ばして、当った先がPlaneで、かつ、ゴールド300以上持ってたら、砲台2を設置して、ゴールド300回収

TowerDefenseを作ってみる(2)

このへんを入れてみました。

  • 敵が2秒間隔で連続してやってくる
  • 敵が進む経路をWayPointとして設定できる

基本形なところはだいぶできました。
黄色のcubeが経路なので、右に進んで下にV字行って戻ってきて、また右に進むという経路になります。

f:id:yasu9780:20150509095610p:plain

WayPointはUnityのStandardAssetsのAIcarの自動運転の仕組みなどでも使われています。tsubakit1.hateblo.jp


今回は画面上の黄色のcubeを左から順番にたどっていく感じで作りました。

Vector3の配列としてwpを持ち、シーン上の黄色のcubeの位置を読み込んで、
初期は0として、次のwaypointに到達するとstateを進めて、次のwaypointを目指す。
最後のwaypointに到達したらゴール。
標準のcomponentがあるようですが、自前で作っても簡単ですね。
車を町で走らせる場合なども、同じ仕組みで行けますね。
実際の座標も、実際にシーンで置いてみて決められるので、ゲームエンジン的な仕組みだと思います。

void Start () {
	wp = new Vector3[10];
	wpState=0;
	wp[0] = GameObject.Find("Waypoint000").transform.position;
	wp[1] = GameObject.Find("Waypoint001").transform.position;
	wp[2] = GameObject.Find("Waypoint002").transform.position;
	wp[3] = GameObject.Find("Waypoint003").transform.position;
	wp[4] = GameObject.Find("Waypoint004").transform.position;
	transform.position = wp[0];
}
void Update () {
	if( Vector3.Distance( transform.position,wp[wpState] )<=0.2f )
	{
		wpState++;
		if(wpState>=5)
		{
			Main.life--;
			GameObject.Destroy(this.gameObject);
		}
	}
	else
	{
		transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(wp[wpState] - transform.position), 2f);
		transform.position += transform.forward * speed;
	}
}

TowerDefenseを作ってみる

TowerDefenseを作ってみようと思います。

まずは、マウスでクリックした位置に砲台をおける。
敵は一体のみで、左から右へ進んでくる
砲台を置いておくと、敵を攻撃してくれる
敵を逃して右へ抜けるとライフが一つ減る。
といった感じです
f:id:yasu9780:20150509011506p:plain

マウスでクリックした位置に砲台を置くというのは
色々検索してみましたが、マウス座標は二次元、それをカメラを考慮して
ワールド座標系に変換するのですが、
カメラが上から見た構図ならいいんですが、俯瞰でやや斜めだと
ネットでよくあるサンプルはづれてしまうのでダメでした。

苦肉の策で、先に砲台をおける場所にPlaneをおいておいて、
マウスクリックでRaycastしてPlaneを特定して、その位置に砲台を置くやり方をやってみました。
ワールド座標系への変換も、カメラと大地との角度はわかってるので、
投影を計算すれば大丈夫と思うんですが、なぜかそういうサンプルが見つかりませんでした。

http://www40.atwiki.jp/spellbound/pages/1416.html
例えばここのサンプルだと、たしかにカメラとの距離を設定すれば
クリックした位置の三次元座標はとれますが、それは地面から浮いてるんです。
クリックした位置で、かつ、地面上の三次元座標が欲しいのですが

planeをしきつめておくやり方でうまくできるので、こっちで行きます。
確実に位置が指定できますし。


タンクは砲台をchildにしてるので、childのみを敵に向かって回転させつつ、
タイマーで弾を撃ってます。実際はホーミングミサイルみたいなもので、打てば確実に当たります。

いくつかTowerDefenseを実際に遊んでみましたが、
攻撃砲台の種類としては、

  • 通常攻撃(射程・威力が違う)
  • 範囲攻撃
  • 敵をつきぬけるレーザー攻撃

その他のユニットは、

  • 資源採掘プラント
  • 敵を遅くするビームを出す

といったものがありました。

敵に関しては(順番に来るのでWaveと表現されている)

  • 足が早いもの
  • 破壊されると分裂するもの
  • ボス(大きく、HPが高い)

みたいな感じですね。

SF的には遅くするビームですが、魔法的には遅くする呪文。
クラッシュ・オブ・クランも、レーザー攻撃以外はみなありますね。
あっちには、敵を止める魔法や、味方が壁を飛び越える魔法があったり
あと、空軍がありますね。バルーンとかドラゴンとか。対空砲もありますし
レイヤーが2つあるみたいな感じで。

敵は道を歩いていくるだけで味方を攻撃しないのが多いと思いますが、
DMMの千年戦争アイギスは攻撃してくるみたいですね(これは遊んでない)




こういう3Dなタワーディフェンスが作れたら楽しそうですね
https://www.assetstore.unity3d.com/en/#!/content/3933

https://d2ujflorbtfzji.cloudfront.net/package-screenshot/5f0f03a9-4203-483e-8fc7-a7f618877850_scaled.jpg