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

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

unityアプリで、サーバーから情報取得

f:id:yasu9780:20150507194758p:plain

なんとか動いた(´・ω・`)

テストした時は動いたはずなのに、なぜか動かない。
WWWのエラー内容を見ると、crossdomainうんたらのエラーだった。
えー? ローカルアクセスなんですけど?

http://qiita.com/mokemokechicken/items/d02317ed716ebdaf4caf
ここを見て、crossdomain.xmlを用意して、WWWサーバーのルートに置いたら、どうにか読めた。
通信も日頃perlで書いてるとなんとも思わないけど、C#だとなんか書きにくい。
とりあえずWebPlayerにしてテスト続行してみる。


WebPlayer版を入れ替えました。
http://rafeel.s602.xrea.com/webplay.html

トップ画面に、サーバー集計の結果が出るようになりました。
数字が増えてたら、誰かが遊んでるってことで(^_^;)
キャッシュが残ってるとアプリが古いままなんで表示されないかも。
f:id:yasu9780:20150507210912p:plain

UnityからHTTPでGETする

ソケット通信とか遠回りで考えていたけど、HTTPのGETはあっさり動いた(^_^;)
WWWはここに仕様がある。バイナリのダウンロードもできる模様(完了も判る)
Unity - Scripting API:

ローカルの自宅サーバーのCGIにURL引数付きで投げた例
別にルーターの外でも問題ない。

using UnityEngine;
using System.Collections;

public class Main : MonoBehaviour {
	void Start ()
	{
		StartCoroutine( GET("http://192.168.1.26/memo/unity.cgi?a=get&k=name") ); 
	}
	IEnumerator GET(string url)
	{
		WWW www = new WWW(url);
		yield return www;
		if (www.error == null) {
		    Debug.Log(www.text);
		}
		else {
		    Debug.Log("fail");
		}

	}
}

 サーバーサイドはperlで書いたCGIだが、DBはKeyValue型のTokyoCabinetというメモリ型DBを用いている。(うちの24H稼動サーバーでは大変お世話になっている)

#!/usr/bin/perl

use CGI::Carp qw(fatalsToBrowser); 
use CGI;
use Jcode;
use TokyoTyrant;

our $cgi = CGI->new;
print CGI::header(-charset=>"utf-8");

our $key   = $cgi->param('k');
our $value = $cgi->param('v');
our $act   = $cgi->param('a');

our $tb = TokyoTyrant::RDB->new();
$tb->open( "localhost", ポート番号は秘密です);

if($act eq "set")
{
	$tb->put( $key , $value );
}
if($act eq "get")
{
	$value = $tb->get( $key );
	print $key."<>".$value."\n";
}

$tb->close();
exit;

WebPlayerからHTML上のJSを呼び出す

unity側でこれを動かすと

Application.ExternalCall("MyFunc","hoge");

WebPlayerを表示させているHTML内のJavaScript内の
MyFunc関数が、引数hogeと共に呼ばれます。


色々な所で解説されている業なんですが、
Unity WebPlayerとブラウザ内UIの連携 - peroon's diary

FirefoxIEでは動きましたが、なぜかChromeだけWebPlayerが重くなって、
壊れてから動きますw
解説サイトのデモも同じ仕様だったので、chromeの仕様変更の関係かな?
もともとWebPlayer限定の手法ですが。


なんか調べると、ソケット通信もPCとサーバーではできるけど、
Androidとサーバーの通信は、Proしか無理らしい。$25のasset買えばできるらしいけど。
下記スライドに書いてあった。

www.slideshare.net


このへん見るとwebソケット通信ならできてるみたいだけど……take4.hatenablog.com

WebPlayerでデータを保存する

PlayerPrefsという仕組みでデータ保存できるようなので、クイズゲームに仕込んでみました。
http://rafeel.s602.xrea.com/webplay.html


具体的にはジャンル別に解答数・正解数を保存して、正解率を表示します。
例えばこんな感じ。

string temp="";
int currentSection = int.Parse(values[0]);
int goodsec =PlayerPrefs.GetInt( "GOOD" +currentSection );
int totalsec=PlayerPrefs.GetInt( "TOTAL"+currentSection );
if( totalsec>=1 ) {
	float rate = 100f*goodsec/totalsec;
	temp = " 正解率("+rate.ToString("F1")+"%) ("+totalsec+"回)";
}
GameMaster.TargetSection2=currentSection;

正解時には、KEY更新

int goodsec =PlayerPrefs.GetInt( "GOOD"+GameMaster.TargetSection2 );
int totalsec=PlayerPrefs.GetInt( "TOTAL"+GameMaster.TargetSection2 );
PlayerPrefs.SetInt( "GOOD"+GameMaster.TargetSection2  , goodsec+1  );
PlayerPrefs.SetInt( "TOTAL"+GameMaster.TargetSection2 , totalsec+1 );

ただ、試してみると保存されるのはクライアントサイドで、
サーバーで保存されるわけではないですね。
ChromeFirefoxIEで試しましたが、ブラウザ別に個別保存でした。
クッキーに入れてるのかもしれない。

サーバーサイド保存だと面白かったんですが……
CGIでサーバーを作って、ソケット通信でもやってみようかな?
それともサーバーサイドで保存する仕組みを調べてみましょう。

ヘリコプターを飛ばしてみる

f:id:yasu9780:20150506015408p:plain

こちらのFreeのヘリコプターを利用して
https://www.assetstore.unity3d.com/en/#!/content/8128

ヘリコプターを飛ばしてみました。


ローターは分離されてるので、ローターを回します。

rb = GetComponent<Rigidbody>();
rotor = GameObject.Find("Rotor_Control");
ry=0f;
void Update () {
	ry += 30f;//Time.deltaTime * speed;
	rotor.transform.rotation = Quaternion.Euler(270, ry, 0);
}

肝心のヘリの操縦ですが

まず、離陸w

if (Input.GetKey (KeyCode.Space)) {
	rb.AddForce( transform.up * 20f );
}

矢印キーの上・後ろで、前進・後進
要はヘリを傾ける+落ちない程度に揚力
(揚力はヘリ機体に垂直にかけてるので、傾けると傾けたほうに進む)

float v = Input.GetAxis ("Vertical");
if( v>0.1 )
{
	rx = -20f;
	rb.AddForce( transform.up * 8f );
}
else if( v<-0.1 )
{
	rx = 20f;
	rb.AddForce( transform.up * 8f );
}
else
{
	rx=0;
}

旋回は、

transform.rotation = Quaternion.Euler( new Vector3(rx,ry2,0) );
float h = Input.GetAxis ("Horizontal");
if( h>0.1f )
{
	ry2+=1;
}
else if( h<-0.1f )
{
	ry2-=1;
}

いくらなんでも単純すぎるかww

壁を考慮したゾンビとモブ子たちの戦い

まだ壁抜けしちゃう場合があるといえばあるんですが、
だいぶできてきました。
デバッグはかなりキツかったです(´・ω・`)

もともと壁なんて無かった頃を思えば前進でしょうw
f:id:yasu9780:20150505120213p:plain

考慮しないといけないのが、射撃とかアニメーションの中に前進移動が組み込まれていて、
その場合、壁は考慮されないで移動してします。
かといって、AnimatorのApplyRootMotionのチェックを外してしまうと、
歩いてるのにいっさい移動しないという、かなり不自然な感じになります(´・ω・`)
座標移動とアニメーション動作が連動しないというか。
個別には、壁が目の前なら撃たないとか、色々逃げ道はあるので、解決策を考えていきます。

というわけで、次はプレイヤーに移ります。
これをやらないと鑑賞ゲームになってしまいますのでw

迂回してくるゾンビ

f:id:yasu9780:20150505010421p:plain

モブ子さんは固定ですが、
複数のゾンビが、経路探索して、モブ子さんのところを目指すようになりました。
壁に囲まれている場合は、開いている所を通って近づいてきます。
ゾンビらしからぬ賢さw


次は、モブ子さんが動いても、ゾンビの経路探索が追従するようにすることと、
逆にモブ子さんからゾンビ方向への経路探索も仕込んでいきます。

基本的には同じような処理なのでなんとかなると思います。