Игра Маджонг | Mahjong game
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

483 lines
16KB

  1. мж.ресурсы = [
  2. [БАЗА + "модели/фишка/2019-09-08.osgt", "mod"],
  3. [БАЗА + "текстуры/заглушка.png", "tex.stub"],
  4. [БАЗА + "шейдеры/освещение-изображение.vert", "ver"],
  5. [БАЗА + "шейдеры/освещение-изображение.frag", "fra"],
  6. [БАЗА + "раскладки/X_shaped.layout", "lay"],
  7. /*
  8. [БАЗА + "классы/Раскладка/2019-08-16.js", "Layout"],
  9. [БАЗА + "классы/Фишка/2019-09-07.js", "Tile"],
  10. [БАЗА + "темыФишек/заглушка/2019-09-08.js", "theme.stub"],
  11. */
  12. ];
  13. мж.начали = new Уведомитель();
  14. мж.начать = function()
  15. {
  16. муром.камера.позиция = [0, -70, 0];
  17. муром.камера.вращение = [90, 0, 0];
  18. мж.сцена = муром.узлы.создатьСферу("sce", 0);
  19. мж.сцена.вращение = [60, 0, 0];
  20. var мир = муром.узлы.узел("mir");
  21. мир.добавитьДитя(мж.сцена);
  22. мж.начали.уведомить();
  23. };
  24. мж.задатьНейтральныйМатериал = function()
  25. {
  26. var мат = муром.материалы.создатьМатериал("N");
  27. var изо = муром.ресурсы.ресурс("tex.stub");
  28. мат.задатьТекстуру("image", изо);
  29. var вер = муром.ресурсы.ресурс("ver").содержимое;
  30. var фра = муром.ресурсы.ресурс("fra").содержимое;
  31. мат.задатьШейдеры(вер, фра);
  32. мж.сцена.задатьМатериал(мат);
  33. };
  34. мж.разобратьРаскладку = function()
  35. {
  36. //eval(муром.ресурсы.ресурс("Layout").содержимое);
  37. var содержимое = муром.ресурсы.ресурс("lay").содержимое;
  38. мж.раскладка = new Раскладка();
  39. мж.раскладка.разобрать(содержимое);
  40. };
  41. мж.фишки = [];
  42. мж.создатьФишки = function()
  43. {
  44. //eval(муром.ресурсы.ресурс("Tile").содержимое);
  45. for (var номер in мж.раскладка.позиции)
  46. {
  47. var ф = new Фишка();
  48. ф.позиция = мж.раскладка.позиции[номер];
  49. мж.фишки.push(ф);
  50. }
  51. };
  52. мж.размерФишки = {
  53. "ширина": 2.0,
  54. "высота": 3.0,
  55. "глубина": 1.0,
  56. };
  57. мж.создатьУзлыФишек = function()
  58. {
  59. const шагФишки = 2.0;
  60. const коэффициенты = {
  61. "x": мж.размерФишки.ширина / шагФишки,
  62. "y": -мж.размерФишки.высота / шагФишки,
  63. "z": мж.размерФишки.глубина,
  64. };
  65. var мод = муром.ресурсы.ресурс("mod");
  66. for (var номер in мж.фишки)
  67. {
  68. var имя = номер.toString();
  69. var узел = муром.узлы.создатьУзел(имя, мод);
  70. мж.сцена.добавитьДитя(узел);
  71. var ф = мж.фишки[номер];
  72. var п = ф.позиция;
  73. узел.позиция = [
  74. п[2] * коэффициенты.x,
  75. п[1] * коэффициенты.y,
  76. п[0] * коэффициенты.z,
  77. ];
  78. ф.узел = узел;
  79. }
  80. };
  81. мж.центрироватьСцену = function()
  82. {
  83. var границы = {
  84. "лево": 1000,
  85. "право": -1000,
  86. "верх": -1000,
  87. "низ": 1000,
  88. };
  89. for (var номер in мж.фишки)
  90. {
  91. const ф = мж.фишки[номер];
  92. const x = ф.узел.позиция[0];
  93. const y = ф.узел.позиция[1];
  94. if (x < границы.лево)
  95. {
  96. границы.лево = x;
  97. }
  98. if (x > границы.право)
  99. {
  100. границы.право = x;
  101. }
  102. if (y < границы.низ)
  103. {
  104. границы.низ = y;
  105. }
  106. if (y > границы.верх)
  107. {
  108. границы.верх = y;
  109. }
  110. }
  111. const ширина = границы.право - границы.лево + мж.размерФишки.ширина;
  112. const высота = границы.верх - границы.низ + мж.размерФишки.высота;
  113. мж.сцена.позиция = [-ширина / 2.0, 0, высота / 2.0];
  114. };
  115. // http://www.rubl.com/rules/mahjong-solitaire-rules.html
  116. мж.задатьФишкамГруппыПоследовательно = function()
  117. {
  118. var группы = [];
  119. // Генерируем группы.
  120. const группВсего = 42;
  121. const группПо4Дубля = 34;
  122. for (var г = 0; г < группВсего; ++г)
  123. {
  124. const четыреДубля = (г < группПо4Дубля);
  125. const колвоДублей = четыреДубля ? 4 : 1;
  126. for (var д = 0; д < колвоДублей; ++д)
  127. {
  128. группы.push(г);
  129. }
  130. }
  131. // Задаём.
  132. for (var номер in мж.фишки)
  133. {
  134. var ф = мж.фишки[номер];
  135. ф.группа = Number(группы[номер]);
  136. }
  137. };
  138. мж.применитьТемуФишек = function()
  139. {
  140. //eval(муром.ресурсы.ресурс("theme.stub").contents);
  141. const R = RR();
  142. // Создать текстуры.
  143. var обозначения = [];
  144. var текстуры = [];
  145. for (var номер in R)
  146. {
  147. var обозначение = R[номер][0];
  148. обозначения.push(обозначение);
  149. var имя = "tile.tex/" + обозначение;
  150. var содержимое = R[номер][1];
  151. var текстура = муром.ресурсы.создатьРесурс(имя, содержимое);
  152. текстуры.push(текстура);
  153. }
  154. // Создать материалы.
  155. var нейтраль = [];
  156. var выбор = [];
  157. var вер = муром.ресурсы.ресурс("ver").содержимое;
  158. var фра = муром.ресурсы.ресурс("fra").содержимое;
  159. // Нейтраль.
  160. for (var номер = 0; номер < 42; ++номер)
  161. {
  162. var имя = "tile.mat/" + обозначения[номер];
  163. var изо = текстуры[номер];
  164. var мат = муром.материалы.создатьМатериал(имя);
  165. мат.задатьТекстуру("image", изо);
  166. мат.задатьШейдеры(вер, фра);
  167. нейтраль.push(мат);
  168. }
  169. // Выбор.
  170. for (var номер = 42; номер < 83; ++номер)
  171. {
  172. var имя = "tile.mat/" + обозначения[номер];
  173. var изо = текстуры[номер];
  174. var мат = муром.материалы.создатьМатериал(имя);
  175. мат.задатьТекстуру("image", изо);
  176. мат.задатьШейдеры(вер, фра);
  177. выбор.push(мат);
  178. }
  179. // Применить тему.
  180. for (var номер in мж.фишки)
  181. {
  182. var ф = мж.фишки[номер];
  183. ф.нейтраль = нейтраль[ф.группа];
  184. ф.выбор = выбор[ф.группа];
  185. ф.показатьНейтраль();
  186. }
  187. };
  188. мж.маскаВыбора = 0x2;
  189. мж.сделатьФишкиВыбираемыми = function()
  190. {
  191. for (var номер in мж.фишки)
  192. {
  193. var ф = мж.фишки[номер];
  194. ф.узел.задатьМаску(мж.маскаВыбора);
  195. }
  196. }
  197. мж.индексПозиции = function(п)
  198. {
  199. return п[0] * 1000000 + п[1] * 1000 + п[2];
  200. };
  201. мж.индексПозиций = {};
  202. мж.проиндексироватьПозиции = function()
  203. {
  204. for (var номер in мж.фишки)
  205. {
  206. var ф = мж.фишки[номер];
  207. var и = мж.индексПозиции(ф.позиция);
  208. мж.индексПозиций[и] = true;
  209. }
  210. };
  211. мж.естьСоседи = function(позиция, смещениеПоля, смещениеСтолбца)
  212. {
  213. for (var смещениеРяда = -1; смещениеРяда <= 1; ++смещениеРяда)
  214. {
  215. var сосед = [
  216. Number(позиция[0]) + смещениеПоля,
  217. Number(позиция[1]) + смещениеРяда,
  218. Number(позиция[2]) + смещениеСтолбца,
  219. ];
  220. var и = мж.индексПозиции(сосед);
  221. if (и in мж.индексПозиций)
  222. {
  223. return true;
  224. }
  225. }
  226. // Соседей нет.
  227. return false;
  228. };
  229. мж.можноВыбратьФишку = function(ф)
  230. {
  231. // Проверяем наличие фишек с левой и правой сторон одновременно.
  232. var слева = this.естьСоседи(ф.позиция, 0, -2);
  233. var справа = this.естьСоседи(ф.позиция, 0, 2);
  234. if (слева && справа)
  235. {
  236. return false;
  237. }
  238. // Проверяем наличие фишек непосредственно сверху.
  239. for (var смещение = -1; смещение <= 1; ++смещение)
  240. {
  241. if (this.естьСоседи(ф.позиция, 1, смещение))
  242. {
  243. return false;
  244. }
  245. }
  246. // Фишка не заблокирована.
  247. return true;
  248. };
  249. мж.номерВыбраннойФишки = null;
  250. мж.выбраннаяФишка = null;
  251. мж.выбранаФишка = new Уведомитель();
  252. мж.выбратьФишку = function()
  253. {
  254. // Определить щелчок.
  255. if (муром.мышь.нажатыеКнопки.length == 1)
  256. {
  257. var узел =
  258. муром.камера.узелВПозиции(
  259. муром.мышь.позиция,
  260. мж.маскаВыбора
  261. );
  262. if (узел)
  263. {
  264. var номер = Number(узел.имя);
  265. var ф = мж.фишки[номер];
  266. if (мж.можноВыбратьФишку(ф))
  267. {
  268. мж.номерВыбраннойФишки = номер;
  269. мж.выбраннаяФишка = ф;
  270. мж.выбранаФишка.уведомить();
  271. }
  272. }
  273. }
  274. };
  275. мж.отладитьВыборФишки = function()
  276. {
  277. мж.выбранаФишка.подписать(function(){
  278. console.log(
  279. "Выбор. Номер: '" +
  280. мж.номерВыбраннойФишки +
  281. "' Группа: '" +
  282. мж.выбраннаяФишка.группа +
  283. "'"
  284. );
  285. });
  286. };
  287. мж.показатьВыбраннуюФишку = function()
  288. {
  289. мж.выбраннаяФишка.показатьВыбор();
  290. };
  291. мж.выбранныеФишки = [];
  292. мж.фишкиРазличаются = new Уведомитель();
  293. мж.фишкиСовпадают = new Уведомитель();
  294. мж.фишкиСравнили = new Уведомитель();
  295. мж.сравнитьВыбранныеФишки = function()
  296. {
  297. // Собираем.
  298. мж.выбранныеФишки.push(мж.выбраннаяФишка);
  299. // Удостоверяемся в наличии пары фишек.
  300. if (мж.выбранныеФишки.length != 2)
  301. {
  302. return;
  303. }
  304. var ф1 = мж.выбранныеФишки[0];
  305. var ф2 = мж.выбранныеФишки[1];
  306. // Убираем дубликат при двойном выборе одной фишки.
  307. if (ф1.имя == ф2.имя)
  308. {
  309. мж.выбранныеФишки.shift();
  310. return;
  311. }
  312. // Сравниваем.
  313. if (ф1.группа == ф2.группа)
  314. {
  315. мж.фишкиСовпадают.уведомить();
  316. }
  317. else
  318. {
  319. мж.фишкиРазличаются.уведомить();
  320. }
  321. мж.фишкиСравнили.уведомить();
  322. };
  323. мж.отладитьСравнениеФишек = function()
  324. {
  325. мж.фишкиСовпадают.подписать(function(){
  326. console.log("Фишки совпадают");
  327. });
  328. мж.фишкиРазличаются.подписать(function(){
  329. console.log("Фишки различаются");
  330. });
  331. };
  332. мж.скрытьСовпадающиеФишки = function()
  333. {
  334. мж.выбранныеФишки[0].скрыть();
  335. мж.выбранныеФишки[1].скрыть();
  336. };
  337. мж.убратьСовпадающиеФишки = function()
  338. {
  339. var ф1 = мж.выбранныеФишки[0];
  340. var ф2 = мж.выбранныеФишки[1];
  341. var и1 = мж.индексПозиции(ф1.позиция);
  342. var и2 = мж.индексПозиции(ф2.позиция);
  343. delete мж.индексПозиций[и1];
  344. delete мж.индексПозиций[и2];
  345. };
  346. мж.очиститьОтображениеВыбора = function()
  347. {
  348. мж.выбранныеФишки[0].показатьНейтраль();
  349. мж.выбранныеФишки[1].показатьНейтраль();
  350. };
  351. мж.очиститьВыбор = function()
  352. {
  353. мж.номерВыбраннойФишки = 0;
  354. мж.выбраннаяФишка = null;
  355. мж.выбранныеФишки = [];
  356. };
  357. мж.оставшиесяФишки = [];
  358. мж.задатьОставшиесяФишки = function()
  359. {
  360. мж.оставшиесяФишки = мж.фишки.slice();
  361. };
  362. мж.обновилиОставшиесяФишки = new Уведомитель();
  363. мж.обновитьОставшиесяФишки = function()
  364. {
  365. var и1 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[0]);
  366. мж.оставшиесяФишки.splice(и1, 1);
  367. var и2 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[1]);
  368. мж.оставшиесяФишки.splice(и2, 1);
  369. мж.обновилиОставшиесяФишки.уведомить();
  370. };
  371. мж.доступныеДляВыбораФишки = function()
  372. {
  373. var фишки = [];
  374. for (var номер in мж.оставшиесяФишки)
  375. {
  376. var ф = мж.оставшиесяФишки[номер];
  377. if (мж.можноВыбратьФишку(ф))
  378. {
  379. фишки.push(ф);
  380. }
  381. }
  382. return фишки;
  383. };
  384. мж.естьХод = function()
  385. {
  386. var фишки = мж.доступныеДляВыбораФишки();
  387. for (var н1 in фишки)
  388. {
  389. for (var н2 in фишки)
  390. {
  391. var ф1 = фишки[н1];
  392. var ф2 = фишки[н2];
  393. if (
  394. (ф1.имя != ф2.имя) &&
  395. (ф1.группа == ф2.группа)
  396. ) {
  397. return true;
  398. }
  399. }
  400. }
  401. return false;
  402. }
  403. мж.победа = new Уведомитель();
  404. мж.поражение = new Уведомитель();
  405. мж.проверитьЗавершение = function()
  406. {
  407. var кончилисьФишки = (мж.оставшиесяФишки.length == 0);
  408. if (кончилисьФишки)
  409. {
  410. мж.победа.уведомить();
  411. return;
  412. }
  413. if (!мж.естьХод())
  414. {
  415. мж.поражение.уведомить();
  416. }
  417. };
  418. мж.отладитьЗавершение = function()
  419. {
  420. мж.победа.подписать(function(){
  421. console.log("Игра завершена. ПОБЕДА!");
  422. });
  423. мж.поражение.подписать(function(){
  424. console.log("Игра завершена. ПОРАЖЕНИЕ :(");
  425. });
  426. };
  427. мж.задатьОтображениеЗавершения = function()
  428. {
  429. мж.победа.подписать(function(){
  430. муром.камера.цветОчистки = [0.2, 0.5, 0.2];
  431. });
  432. мж.поражение.подписать(function(){
  433. муром.камера.цветОчистки = [0.5, 0.2, 0.2];
  434. });
  435. };