milkcocoaとjThreeを利用して、リアルタイムストラテジーゲームを何時間で作れるか試してみます。
開始時刻:2014年10月3日午前11時
##0時間7分まで
リポジトリ作成
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
地面を表示するようにしましょう
<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/ )も使っておきましょう。
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分まで
ユニットをクリックして選択、他の場所をクリックして移動させられるようにしましょう。
ユニットの選択はjThreeのclick関数で行い、移動先は通常のマウスイベントでマウスの座標から計算しています。
rts.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." );
} );
移動できるようになりました。
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
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
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
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でユニットの移動をリアルタイムに共有できるようになりました。
ブラウザを開くと、ユニットが増えます。
git tag 1h43m
git push origin 1h43m
今日はこのくらいにしておきます、疲れた・・・
ブラウザを2つ開いて、ユニットの位置が同期されるか、確かめてみてください。