GameBox.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. (function(exports){
  2. var LAYER_BOUNTY = 1000;
  3. var LAYERHEIGHT = 1;
  4. var DOWNVECTOR = new THREE.Vector3(0,-1,0);
  5. var UPVECTOR = new THREE.Vector3(0,1,0);
  6. var PALLETE = [0x03B5AA, 0x0A1128, 0xF2F6D0, 0x5F464B, 0xFCD0A1 ];
  7. var basicMaterial = new THREE.MeshPhongMaterial({
  8. specular: 0x030303,
  9. color : 0x00ff00,
  10. alphaTest: 0.9,
  11. shininess: 50,
  12. side: THREE.DoubleSide
  13. });
  14. var basicGeometry = new THREE.BoxGeometry(1,1,1);
  15. function GameBox(sizex, sizey, sizez){
  16. this.size = new THREE.Vector3(sizex,sizey,sizez);
  17. this.layers = [];
  18. for(var i=0;i<sizey;i++){
  19. var nlayer = new Layer(sizex,sizez);
  20. nlayer.position.copy(new THREE.Vector3(0,i,0));
  21. this.layers.push(nlayer);
  22. }
  23. this.droppables = [];
  24. this.moveVector = new THREE.Vector3(0,-1,0);
  25. this.platform = new THREE.Object3D();
  26. this.platform.position.copy(new THREE.Vector3(-this.size.x/2,1.501,-this.size.z/2));
  27. this.layerNode = new THREE.Object3D();
  28. for(var i = 0 ; i < this.layers.length; i ++ )
  29. this.layerNode.add(this.layers[i]);
  30. this.platform.add(this.layerNode);
  31. this.createFloor(0xf0f0f0);
  32. //init
  33. this._init();
  34. }
  35. GameBox.prototype._init = function(){
  36. this.moveVec = new THREE.Vector3(0,0,0);
  37. this.rmoveVec = new THREE.Vector3(0,0,0);
  38. this._axis = DOWNVECTOR;
  39. this._degrees = 0;
  40. this._oldAxis = DOWNVECTOR;
  41. this._oldDegrees = 0;
  42. this.toBeFree = [];
  43. this.score = 0;
  44. this.paused = false;
  45. this.finished = false;
  46. };
  47. GameBox.prototype.createFloor = function(color){
  48. var geometry = new THREE.BoxGeometry( this.size.x, 1, this.size.z);
  49. var texture = new THREE.TextureLoader().load( "textures/checker.png" );
  50. texture.wrapS = THREE.RepeatWrapping;
  51. texture.wrapT = THREE.RepeatWrapping;
  52. texture.repeat.set( this.size.x/2, this.size.z/2 );
  53. //var material = new THREE.MeshBasicMaterial( {color: color, side: THREE.DoubleSide, shading: THREE.FlatShading} );
  54. var material = new THREE.MeshPhongMaterial({
  55. specular: 0x030303,
  56. color : color,
  57. map : texture,
  58. alphaTest: 0.9,
  59. shininess: 2,
  60. side: THREE.DoubleSide
  61. });
  62. var plane = new THREE.Mesh( geometry, material );
  63. plane.receiveShadow = true;
  64. plane.position.x += this.size.x/2 - 0.5;
  65. plane.position.z += this.size.z/2 - 0.5;
  66. plane.position.y -= 1.0;
  67. this.platform.add(plane);
  68. // Add top light
  69. var l = new THREE.DirectionalLight( 0xffffff, 0.55 );
  70. l.castShadow = true;
  71. l.shadowCameraRight = 30;
  72. l.shadowCameraLeft = -30;
  73. l.shadowCameraTop = 30;
  74. l.shadowCameraBottom = -30;
  75. l.shadow.mapSize.width = 512;
  76. l.shadow.mapSize.height = 512;
  77. l.position.copy(new THREE.Vector3( 0 , 50, 0));
  78. l.castShadow = true;
  79. this.platform.add(l);
  80. };
  81. GameBox.prototype.init = function(scene){
  82. scene.add(this.platform);
  83. };
  84. GameBox.prototype.progress = function() {
  85. if(this.paused || this.finished)return;
  86. this.score += 5;
  87. this.free();
  88. this.checkLayers();
  89. for(var i = this.droppables.length-1 ; i >= 0 ; i-- )
  90. this.droppables[i].progress(DOWNVECTOR, this._axis,this._degrees);
  91. for(var i = 0 ; i < this.droppables.length ; i ++ ){
  92. var geometry = this.droppables[i].getGeometry();
  93. var flag = false;
  94. for(var j=0; j < geometry.length; j ++)
  95. if(this.checkCollision(geometry[j]))flag = true;
  96. if(flag){
  97. this.droppables[i].progress(UPVECTOR, this._oldAxis,this._oldDegrees);
  98. geometry = this.droppables[i].getGeometry();
  99. this.randomDrop();
  100. }
  101. for(var j=0; j < geometry.length; j ++){
  102. try{
  103. this.occupy(this.droppables[i].color, geometry[j], !flag);
  104. }
  105. catch(e){
  106. this.lost();
  107. return true;
  108. }
  109. }
  110. if(flag)
  111. this.droppables.splice( i, 1 );
  112. }
  113. return flag;
  114. };
  115. GameBox.prototype.progressToNext = function(){
  116. while(!this.progress()){}; // drop to floor
  117. };
  118. GameBox.prototype.randomDrop = function(){
  119. var shape = new SHAPESARRAY[parseInt(Math.random()*SHAPESARRAY.length - 0.0000001)](PALLETE[parseInt(Math.random()*12345) % 5])
  120. this.drop(shape);
  121. };
  122. GameBox.prototype.checkLayers = function(){
  123. var flag = false;
  124. for(var i = this.layers.length-1; i >= 0; i --) {
  125. if(this.layers[i].isComplete()){
  126. flag = true;
  127. this.layers.splice(i,1);
  128. this.layers.push(new Layer(this.size.x,this.size.z));
  129. this.score += LAYER_BOUNTY;
  130. }
  131. }
  132. if(flag){
  133. this.layerNode.children.length = 0;
  134. for(var i = 0 ; i < this.layers.length && flag; i ++){
  135. this.layers[i].position.copy(new THREE.Vector3(0,i,0));
  136. this.layerNode.add(this.layers[i]);
  137. }
  138. }
  139. };
  140. GameBox.prototype.occupy = function(color, vec, temp){
  141. try{
  142. this.getQuanto(vec.x,vec.y,vec.z).occupy(color, temp);
  143. }
  144. catch(e){}
  145. if(temp){
  146. this.toBeFree.push(vec);
  147. }
  148. };
  149. GameBox.prototype.drop = function(shape) {
  150. var rpos = new THREE.Vector3( parseInt(Math.random()*(this.size.x-4))+2 ,(this.layers.length-2) * LAYERHEIGHT , parseInt(Math.random()*(this.size.z-4))+2);
  151. shape.position.copy(rpos);
  152. var geometry = shape.getGeometry();
  153. for(var j=0; j < geometry.length; j ++)
  154. if(this.checkCollision(geometry[j]))this.lost();
  155. this.droppables.push(shape);
  156. };
  157. GameBox.prototype.move = function(x,z, axis, degrees) {
  158. this.moveVec.set(x,0,z);
  159. this.rmoveVec.set(-x,0,-z);
  160. this._oldAxis = this._axis;
  161. this._oldDegrees = this._degrees;
  162. this._axis = axis;
  163. this._degrees = degrees;
  164. this.free();
  165. for(var i = this.droppables.length-1 ; i >= 0 ; i-- )
  166. this.droppables[i].progress(this.moveVec , axis, degrees);
  167. for(var i = 0 ; i < this.droppables.length ; i ++ ){
  168. var geometry = this.droppables[i].getGeometry();
  169. var flag = false;
  170. for(var j=0; j < geometry.length; j ++)
  171. if(this.checkCollision(geometry[j]))flag = true;
  172. if(flag){
  173. this.droppables[i].progress(this.rmoveVec , this._oldAxis, this._oldDegrees);
  174. this._axis = this._oldAxis;
  175. this._degrees = this._oldDegrees;
  176. geometry = this.droppables[i].getGeometry();
  177. }
  178. for(var j=0; j < geometry.length; j ++)
  179. this.occupy(this.droppables[i].color, geometry[j], true);
  180. }
  181. };
  182. GameBox.prototype.free = function(){
  183. // free old
  184. for(var i = 0 ; i < this.toBeFree.length; i ++)
  185. this.getQuanto(this.toBeFree[i]).free();
  186. this.toBeFree = [];
  187. };
  188. GameBox.prototype.checkCollision = function(x,y,z){
  189. if(typeof x == "object"){z = x.z;y=x.y;x=x.x;}
  190. if(x<0 || y < 0 || z < 0)return true;
  191. if(x >= this.size.x || z >= this.size.z)
  192. return true;
  193. if(y >= this.size.y)
  194. return this.lost();
  195. return this.getQuanto(x,y,z).occupied;
  196. };
  197. GameBox.prototype.getSpeed = function(){
  198. return 0.55 - 0.02 * parseInt(this.score / 10000);
  199. };
  200. GameBox.prototype.lost = function(){
  201. this.paused = true;
  202. this.finished = true;
  203. return -1;
  204. };
  205. GameBox.prototype.restart = function(){
  206. this.paused = false;
  207. this.finished = false;
  208. for(var x = 0; x < this.size.x; x++)
  209. for(var y = 0; y < this.size.y; y++)
  210. for(var z = 0; z < this.size.z; z++)
  211. this.getQuanto(x,y,z).free();
  212. this.droppables = [];
  213. this._init();
  214. this.drop(new window.Shapes.Box(0x00ff20));
  215. return;
  216. };
  217. GameBox.prototype.getQuanto = function(x,y,z){
  218. if(typeof x == "object"){z = x.z;y=x.y;x=x.x;}
  219. if(x<0 || y < 0 || z < 0)return true;
  220. if(x >= this.size.x || y >= this.size.y || z >= this.size.z)return true;
  221. return this.layers[y].points[x][z];
  222. };
  223. // GameBox.prototype.occupyLayer = function(x) {
  224. // for(var i = 0;i<this.size.x;i++)
  225. // this.layers[x].points[i][4].occupy(0x00ff00);
  226. // this.layers[x].points[5][4].free();
  227. // };
  228. // LAYER /////////////////////////////////////////////////////////////////////////
  229. /////////////////////////////////////////////////////////////////////////////////
  230. function Layer(x,y){
  231. THREE.Object3D.apply(this);
  232. this.points = [];
  233. for( var i = 0; i < x ; i ++){
  234. this.points[i] = [];
  235. for ( var j = 0; j < y ; j ++){
  236. this.points[i][j] = new Quanto();
  237. this.points[i][j].position.copy(new THREE.Vector3(i,0,j));
  238. this.add(this.points[i][j]);
  239. }
  240. }
  241. };
  242. Layer.prototype = Object.create(THREE.Object3D.prototype);
  243. Layer.prototype.constructor = Layer;
  244. Layer.prototype.isComplete = function(){
  245. for(var i = 0; i < this.points.length; i ++)
  246. for(var j = 0;j < this.points[i].length; j++)
  247. if(!this.points[i][j].occupied)return false;
  248. return true;
  249. }
  250. // Quanto /////////////////////////////////////////////////////////////////////////
  251. /////////////////////////////////////////////////////////////////////////////////
  252. function Quanto(){
  253. THREE.Object3D.apply(this);
  254. this.occupied = false;
  255. };
  256. Quanto.prototype = Object.create(THREE.Object3D.prototype);
  257. Quanto.prototype.constructor = Quanto;
  258. Quanto.prototype.occupy = function(color , temp){
  259. if(this.occupied)
  260. throw new Error("Quanto is already occupied!!!");
  261. if(!this.cube){
  262. var geometry = basicGeometry.clone();
  263. //var material = new THREE.MeshBasicMaterial( {color: color} );
  264. var material = basicMaterial.clone();
  265. this.cube = new THREE.Mesh( geometry, material );
  266. this.cube.castShadow = true;
  267. this.cube.receiveShadow = true;
  268. }
  269. this.cube.material.color.set(color);
  270. this.add( this.cube );
  271. this.occupied = true;
  272. if(temp)this.occupied = false;
  273. };
  274. Quanto.prototype.free = function(){
  275. this.children.length = 0;
  276. this.occupied = false;
  277. }
  278. Quanto.prototype.toBoxCoords = function(Layer){
  279. return this.position + Layer;
  280. }
  281. // Shape /////////////////////////////////////////////////////////////////////////
  282. /////////////////////////////////////////////////////////////////////////////////
  283. function Shape(color){
  284. THREE.Object3D.call(this);
  285. this.position.copy(new THREE.Vector3(0,0,0));
  286. this.array = [this.position.clone()]; // Array of positions specifying the shape
  287. this.color = color;
  288. this.qrot = new THREE.Quaternion();
  289. this.qrot.setFromAxisAngle(UPVECTOR, 0);
  290. };
  291. Shape.prototype = Object.create(THREE.Object3D.prototype);
  292. Shape.prototype.constructor = Shape;
  293. Shape.prototype.progress = function(moveVector, axis, degrees ){
  294. this.position.add(moveVector);
  295. this.qrot.setFromAxisAngle( axis, degrees);
  296. };
  297. Shape.prototype.getGeometry = function(){
  298. var narr = [];
  299. for(var i=0;i<this.array.length;i++){
  300. narr[i] = this.array[i].clone().applyQuaternion(this.qrot);
  301. narr[i].add(this.position);
  302. narr[i].x = parseInt(narr[i].x + sign(narr[i].x)*0.5);
  303. narr[i].y = parseInt(narr[i].y + sign(narr[i].y)*0.5);
  304. narr[i].z = parseInt(narr[i].z + sign(narr[i].z)*0.5);
  305. }
  306. return narr;
  307. };
  308. window.sign = function(x) { return x ? x < 0 ? -1 : 1 : 0; };
  309. ////////////////////////////////////////////////////////////////////////////////////////////
  310. ///////////////////////////////////////////////////////////////////////////////////////////
  311. ////////////////////////// SHAPES //////////////////////////////////////////
  312. function Cross(color){
  313. Shape.call(this);
  314. this.position = new THREE.Vector3(0,0,0);
  315. this.array = [new THREE.Vector3(0,0,0),
  316. new THREE.Vector3(1,0,0),
  317. new THREE.Vector3(0,1,0),
  318. new THREE.Vector3(0,0,1),
  319. new THREE.Vector3(-1,0,0),
  320. new THREE.Vector3(0,-1,0)
  321. ]; // Array of positions specifying the shape
  322. this.color = color;
  323. };
  324. Cross.prototype = Object.create(Shape.prototype);
  325. Cross.prototype.constructor = Cross;
  326. function Line(color){
  327. Shape.call(this);
  328. this.position = new THREE.Vector3(0,0,0);
  329. this.array = [new THREE.Vector3(0,0,0),
  330. new THREE.Vector3(0,0,1),
  331. new THREE.Vector3(0,0,-1)
  332. ]; // Array of positions specifying the shape
  333. this.color = color;
  334. };
  335. Line.prototype = Object.create(Shape.prototype);
  336. Line.prototype.constructor = Line;
  337. function Light(color){
  338. Shape.call(this);
  339. this.position = new THREE.Vector3(0,0,0);
  340. this.array = [new THREE.Vector3(0,0,0),
  341. new THREE.Vector3(0,0,1)
  342. ]; // Array of positions specifying the shape
  343. this.color = color;
  344. };
  345. Light.prototype = Object.create(Shape.prototype);
  346. Light.prototype.constructor = Light;
  347. function Corner(color){
  348. Shape.call(this);
  349. this.position = new THREE.Vector3(0,0,0);
  350. this.array = [new THREE.Vector3(0,0,0),
  351. new THREE.Vector3(0,0,1),
  352. new THREE.Vector3(1,0,0),
  353. new THREE.Vector3(-1,0,0)
  354. ]; // Array of positions specifying the shape
  355. this.color = color;
  356. };
  357. Corner.prototype = Object.create(Shape.prototype);
  358. Corner.prototype.constructor = Corner;
  359. function Axis(color){
  360. Shape.call(this);
  361. this.position = new THREE.Vector3(0,0,0);
  362. this.array = [new THREE.Vector3(0,0,0),
  363. new THREE.Vector3(1,0,0),
  364. new THREE.Vector3(0,1,0),
  365. new THREE.Vector3(0,0,1)
  366. ]; // Array of positions specifying the shape
  367. this.color = color;
  368. };
  369. Axis.prototype = Object.create(Shape.prototype);
  370. Axis.prototype.constructor = Axis;
  371. var SHAPESARRAY = [Line, Shape, Shape, Line, Light, Light, Axis, Corner];
  372. exports.Shapes = {
  373. Cross : Cross,
  374. Line : Line,
  375. Box : Shape,
  376. Axis : Axis,
  377. Corner: Corner,
  378. Light : Light
  379. };
  380. exports.GameBox = GameBox;
  381. })(window);