RTS(Real-Time-Strategy)ゲームを何時間で作れるか


milkcocoaとjThreeを利用して、リアルタイムストラテジーゲームを何時間で作れるか試してみます。

開始時刻：２０１４年１０月３日午前１１時

##0時間７分まで

リポジトリ作成

    git clone git@github.com:syuhei176/2hour-rts.git


* gulp導入
* 画像ファイルなどを入れておきます。
* 3Dの部分は、jThree( http://jthree.jp/ )を利用


```
git tag 0h7m
```

まだ何も表示されません
https://github.com/syuhei176/2hour-rts/tree/0h7m


地面を表示するようにしましょう


```html

  <head>
      <geo id="sky" type="Sphere" param="200 64 64" />
      <txr id="blueSky" src="data/img/sky.png" />
      <mtl id="sky-mtl" type="MeshPhong" param="map: #blueSky; side: 2;"/>
      <geo type="Circle" param="200 64" />
      <txr id="groundTxr" src="data/img/ground.jpg" param="repeat: 50; wrap: 0;" />
      <mtl id="ground-mtl" type="MeshLambert" param="map: #groundTxr;"/>
      <rdr />
  </head>
```



ではJavaScriptを書き始めます。
milkcocoa( https://mlkcca.com/ )も使っておきましょう。

```js

jThree( function( j3 ) {//j3 === jThree
    var milkcocoa = new MilkCocoa("https://io-hogehoge.mlkcca.com:443");
},function() {//WebGL非対応ブラウザ向け
	alert( "Your browser does not support WebGL." );
} );
```

##0時間53分まで

ユニットをクリックして選択、他の場所をクリックして移動させられるようにしましょう。

https://github.com/syuhei176/2hour-rts/tree/0h53m

ユニットの選択はjThreeのclick関数で行い、移動先は通常のマウスイベントでマウスの座標から計算しています。

rts.js

```js

jThree( function( j3 ) {//j3 === jThree
    var milkcocoa = new MilkCocoa("https://io-hogehoge.mlkcca.com:443");

    var selected = null;

    j3("#unit1").click(function() {
    	selected = j3(this);
    	j3("#cursor").position(j3(this).position());
    });

    $(window).mousedown(function(e) {
    	if(selected) {
	    	var pos = translateDisplay2World(e.pageX, e.pageY);
		    selected.animate({positionX : pos.x, positionY : "+=0", positionZ : pos.z}, 1000);
		    selected = null;
	    	j3("#cursor").position([100, 0, 100]);
	    }
    });

    var width = document.body.clientWidth;
    var height = document.body.clientHeight;
    function translateDisplay2World(x, y) {
    	return {
    		z : -(x - width/2) / 10,
    		x : (y - height/2) / 10
    	}
    }
},function() {//WebGL非対応ブラウザ向け
	alert( "Your browser does not support WebGL." );
} );

```

移動できるようになりました。


![スクリーンショット 2014-10-03 11.51.58.png](https://qiita-image-store.s3.amazonaws.com/0/20848/423926d1-8ad2-f552-087e-dbc5bcb80117.png)


    git tag 0h53m
    git push origin 0h53m


##1時間43分まで

milkcocoaでユニットの移動をリアルタイムに共有できるようにします。

ユニットをクラス化して行きます。

* PlayerManager
* Player
* Unit

ソース：https://github.com/syuhei176/2hour-rts/tree/1h43m

PlayerManagerに新しくユニットを作ることや、移動することを命令します。そして命令自体をmilkcocoaのsend APIで共有します。

player_manager.js

```js

function PlayerManager(dataStore) {
	var self = this;
	this.dataStore = dataStore;
	this.players = {};
	this.units = {};
	this.listeners = {
		"create-unit" : []
	}
	this.dataStore.on("send", function(e) {
    	if(e.value.cmd == "player-create") {
    		var np = new Player(e.value.pid);
    		self.players[e.value.pid] = np;
    	}else if(e.value.cmd == "unit-create") {
    		var nu = new Unit(e.value.uid);
    		self.units[e.value.uid] = nu;
    		self.emit("create-unit", {
    			unit_id : e.value.uid
    		});
    	}else if(e.value.cmd == "unit-move") {
    		if(!self.units[e.value.uid]) {
	    		var nu = new Unit(e.value.uid);
	    		self.units[e.value.uid] = nu;
	    		self.emit("create-unit", {
	    			unit_id : e.value.uid
	    		});
			}
    		self.units[e.value.uid].move(e.value.pos)
    	}
	});
}

PlayerManager.prototype.get_unit = function(id) {
	this.units[id];
}


PlayerManager.prototype.on = function(event, l) {
	this.listeners[event].push(l);
}

PlayerManager.prototype.emit = function(event, args) {
	this.listeners[event].forEach(function(l) {
		l(args);
	});
}

PlayerManager.prototype.create_player = function() {
	var player_id = new Date().getTime().toString(36);
	this.dataStore.send({
		cmd : "player-create",
		pid : player_id
	});
	return player_id;
}

PlayerManager.prototype.create_unit = function() {
	var unit_id = new Date().getTime().toString(36);
	this.dataStore.send({
		cmd : "unit-create",
		uid : unit_id
	});
	return unit_id;
}

PlayerManager.prototype.move_unit = function(id, pos) {
	this.dataStore.send({
		cmd : "unit-move",
		uid : id,
		pos : pos
	});
}
```

Unitクラスは、ユニットの作成（表示）と移動に責任を持ちます。

unit.js

```js

function Unit(id) {
	this.unit_id = id;
	var x = Math.random() * 5 - 10;
    jThree("scene").append('<obj id="unit'+this.unit_id+'" style="rotateY: 0; position: '+x+' -30 0;"><mesh geo="#unit-geo" mtl="#unit-mtl" /></obj>')
	 console.log("#unit"+this.unit_id);
}

Unit.prototype.get_id = function() {
	return this.unit_id;
}

Unit.prototype.get_elem = function() {
	return jThree("#unit" + this.unit_id);
}

Unit.prototype.move = function(pos) {
    jThree("#unit" + this.unit_id).animate({positionX : pos.x, positionY : "+=0", positionZ : pos.z}, 1000);
}
```

rts.js

```js

jThree( function( j3 ) {//j3 === jThree
    var milkcocoa = new MilkCocoa("https://io-fi0i1mtqo.mlkcca.com:443");
    var dataStore = milkcocoa.dataStore("rts");

    var selected = null;
    var manager = new PlayerManager(dataStore);
    var myself_id = manager.create_player();
    var myunit_id = manager.create_unit();


    manager.on("create-unit", function(e) {
	    j3("#unit"+e.unit_id).click(function() {
	    	selected = e.unit_id;
	    	j3("#cursor").position(j3(this).position());
	    });
    });

    $(window).mousedown(function(e) {
    	if(selected) {
	    	var pos = translateDisplay2World(e.pageX, e.pageY);

	    	manager.move_unit(selected, pos);

		    selected = null;
	    	j3("#cursor").position([100, 0, 100]);
	    }
    });

    var width = document.body.clientWidth;
    var height = document.body.clientHeight;
    function translateDisplay2World(x, y) {
    	return {
    		z : -(x - width/2) / 12,
    		x : (y - height/2) / 12
    	}
    }

},function() {//WebGL非対応ブラウザ向け
	alert( "Your browser does not support WebGL." );
} );
```

milkcocoaでユニットの移動をリアルタイムに共有できるようになりました。
ブラウザを開くと、ユニットが増えます。

![スクリーンショット 2014-10-03 14.40.43.png](https://qiita-image-store.s3.amazonaws.com/0/20848/bdfb0ec5-168a-f98a-570a-ce0412e7a01f.png)


    git tag 1h43m
    git push origin 1h43m


今日はこのくらいにしておきます、疲れた・・・

http://myrts.mlkcca-app.com

ブラウザを２つ開いて、ユニットの位置が同期されるか、確かめてみてください。