Files
mahjong/код/2019-09-11.js
2019-09-11 12:11:33 +03:00

521 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Ввести зависимости.
eval(dl["апи"]);
eval(dl["Раскладка"]);
eval(dl["Фишка"]);
eval(dl["тема.заглушка"]);
// Костяк.
мж.ресурсы = [
[Б + "модели/фишка/2019-09-08.osgt", "mod"],
[Б + "текстуры/заглушка.png", "tex.stub"],
[Б + "шейдеры/освещение-изображение.vert", "ver"],
[Б + "шейдеры/освещение-изображение.frag", "fra"],
[Б + "раскладки/X_shaped.layout", "lay"],
];
мж.начали = new Уведомитель();
мж.начать = function()
{
муром.камера.позиция = [0, -70, 0];
муром.камера.вращение = [90, 0, 0];
мж.сцена = муром.узлы.создатьСферу("sce", 0);
мж.сцена.вращение = [60, 0, 0];
var мир = муром.узлы.узел("mir");
мир.добавитьДитя(мж.сцена);
мж.начали.уведомить();
};
мж.задатьНейтральныйМатериал = function()
{
var мат = муром.материалы.создатьМатериал("N");
var изо = муром.ресурсы.ресурс("tex.stub");
мат.задатьТекстуру("image", изо);
var вер = муром.ресурсы.ресурс("ver").содержимое;
var фра = муром.ресурсы.ресурс("fra").содержимое;
мат.задатьШейдеры(вер, фра);
мж.сцена.задатьМатериал(мат);
};
мж.разобратьРаскладку = function()
{
var содержимое = муром.ресурсы.ресурс("lay").содержимое;
мж.раскладка = new Раскладка();
мж.раскладка.разобрать(содержимое);
};
мж.фишки = [];
мж.создатьФишки = function()
{
for (var номер in мж.раскладка.позиции)
{
var ф = new Фишка();
ф.позиция = мж.раскладка.позиции[номер];
мж.фишки.push(ф);
}
};
мж.размерФишки = {
"ширина": 2.0,
"высота": 3.0,
"глубина": 1.0,
};
мж.создатьУзлыФишек = function()
{
const шагФишки = 2.0;
const коэффициенты = {
"x": мж.размерФишки.ширина / шагФишки,
"y": -мж.размерФишки.высота / шагФишки,
"z": мж.размерФишки.глубина,
};
var мод = муром.ресурсы.ресурс("mod");
for (var номер in мж.фишки)
{
var имя = номер.toString();
var узел = муром.узлы.создатьУзел(имя, мод);
мж.сцена.добавитьДитя(узел);
var ф = мж.фишки[номер];
var п = ф.позиция;
узел.позиция = [
п[2] * коэффициенты.x,
п[1] * коэффициенты.y,
п[0] * коэффициенты.z,
];
ф.узел = узел;
}
};
мж.центрироватьСцену = function()
{
var границы = {
"лево": 1000,
"право": -1000,
"верх": -1000,
"низ": 1000,
};
for (var номер in мж.фишки)
{
const ф = мж.фишки[номер];
const x = ф.узел.позиция[0];
const y = ф.узел.позиция[1];
if (x < границы.лево)
{
границы.лево = x;
}
if (x > границы.право)
{
границы.право = x;
}
if (y < границы.низ)
{
границы.низ = y;
}
if (y > границы.верх)
{
границы.верх = y;
}
}
const ширина = границы.право - границы.лево + мж.размерФишки.ширина;
const высота = границы.верх - границы.низ + мж.размерФишки.высота;
мж.сцена.позиция = [-ширина / 2.0, 0, высота / 2.0];
};
// http://www.rubl.com/rules/mahjong-solitaire-rules.html
мж.задатьФишкамГруппыПоследовательно = function()
{
var группы = [];
// Генерируем группы.
const группВсего = 42;
const группПоубля = 34;
for (var г = 0; г < группВсего; ++г)
{
const четыреДубля = (г < группПоубля);
const колвоДублей = четыреДубля ? 4 : 1;
for (var д = 0; д < колвоДублей; ++д)
{
группы.push(г);
}
}
// Задаём.
for (var номер in мж.фишки)
{
var ф = мж.фишки[номер];
ф.группа = Number(группы[номер]);
}
};
мж.применитьТемуФишек = function()
{
const R = RR();
// Создать текстуры.
var обозначения = [];
var текстуры = [];
for (var номер in R)
{
var обозначение = R[номер][0];
обозначения.push(обозначение);
var имя = "tile.tex/" + обозначение;
var содержимое = R[номер][1];
var текстура = муром.ресурсы.создатьРесурс(имя, содержимое);
текстуры.push(текстура);
}
// Создать материалы.
var нейтраль = [];
var выбор = [];
var вер = муром.ресурсы.ресурс("ver").содержимое;
var фра = муром.ресурсы.ресурс("fra").содержимое;
// Нейтраль.
for (var номер = 0; номер < 42; ++номер)
{
var имя = "tile.mat/" + обозначения[номер];
var изо = текстуры[номер];
var мат = муром.материалы.создатьМатериал(имя);
мат.задатьТекстуру("image", изо);
мат.задатьШейдеры(вер, фра);
нейтраль.push(мат);
}
// Выбор.
for (var номер = 42; номер < 83; ++номер)
{
var имя = "tile.mat/" + обозначения[номер];
var изо = текстуры[номер];
var мат = муром.материалы.создатьМатериал(имя);
мат.задатьТекстуру("image", изо);
мат.задатьШейдеры(вер, фра);
выбор.push(мат);
}
// Применить тему.
for (var номер in мж.фишки)
{
var ф = мж.фишки[номер];
ф.нейтраль = нейтраль[ф.группа];
ф.выбор = выбор[ф.группа];
ф.показатьНейтраль();
}
};
мж.маскаВыбора = 0x2;
мж.сделатьФишкиВыбираемыми = function()
{
for (var номер in мж.фишки)
{
var ф = мж.фишки[номер];
ф.узел.задатьМаску(мж.маскаВыбора);
}
}
мж.индексПозиции = function(п)
{
return п[0] * 1000000 + п[1] * 1000 + п[2];
};
мж.индексПозиций = {};
мж.проиндексироватьПозиции = function()
{
for (var номер in мж.фишки)
{
var ф = мж.фишки[номер];
var и = мж.индексПозиции(ф.позиция);
мж.индексПозиций[и] = true;
}
};
мж.естьСоседи = function(позиция, смещениеПоля, смещениеСтолбца)
{
for (var смещениеРяда = -1; смещениеРяда <= 1; ++смещениеРяда)
{
var сосед = [
Number(позиция[0]) + смещениеПоля,
Number(позиция[1]) + смещениеРяда,
Number(позиция[2]) + смещениеСтолбца,
];
var и = мж.индексПозиции(сосед);
if (и in мж.индексПозиций)
{
return true;
}
}
// Соседей нет.
return false;
};
мж.можноВыбратьФишку = function(ф)
{
// Проверяем наличие фишек с левой и правой сторон одновременно.
var слева = this.естьСоседи(ф.позиция, 0, -2);
var справа = this.естьСоседи(ф.позиция, 0, 2);
if (слева && справа)
{
return false;
}
// Проверяем наличие фишек непосредственно сверху.
for (var смещение = -1; смещение <= 1; ++смещение)
{
if (this.естьСоседи(ф.позиция, 1, смещение))
{
return false;
}
}
// Фишка не заблокирована.
return true;
};
мж.номерВыбраннойФишки = null;
мж.выбраннаяФишка = null;
мж.выбранаФишка = new Уведомитель();
мж.выбратьФишку = function()
{
// Определить щелчок.
if (муром.мышь.нажатыеКнопки.length == 1)
{
var узел =
муром.камера.узелВПозиции(
муром.мышь.позиция,
мж.маскаВыбора
);
if (узел)
{
var номер = Number(узел.имя);
var ф = мж.фишки[номер];
if (мж.можноВыбратьФишку(ф))
{
мж.номерВыбраннойФишки = номер;
мж.выбраннаяФишка = ф;
мж.выбранаФишка.уведомить();
}
}
}
};
мж.отладитьВыборФишки = function()
{
мж.выбранаФишка.подписать(function(){
console.log(
"Выбор. Номер: '" +
мж.номерВыбраннойФишки +
"' Группа: '" +
мж.выбраннаяФишка.группа +
"'"
);
});
};
мж.показатьВыбраннуюФишку = function()
{
мж.выбраннаяФишка.показатьВыбор();
};
мж.выбранныеФишки = [];
мж.фишкиРазличаются = new Уведомитель();
мж.фишкиСовпадают = new Уведомитель();
мж.фишкиСравнили = new Уведомитель();
мж.сравнитьВыбранныеФишки = function()
{
// Собираем.
мж.выбранныеФишки.push(мж.выбраннаяФишка);
// Удостоверяемся в наличии пары фишек.
if (мж.выбранныеФишки.length != 2)
{
return;
}
var ф1 = мж.выбранныеФишки[0];
var ф2 = мж.выбранныеФишки[1];
// Убираем дубликат при двойном выборе одной фишки.
if (ф1.имя == ф2.имя)
{
мж.выбранныеФишки.shift();
return;
}
// Сравниваем.
if (ф1.группа == ф2.группа)
{
мж.фишкиСовпадают.уведомить();
}
else
{
мж.фишкиРазличаются.уведомить();
}
мж.фишкиСравнили.уведомить();
};
мж.отладитьСравнениеФишек = function()
{
мж.фишкиСовпадают.подписать(function(){
console.log("Фишки совпадают");
});
мж.фишкиРазличаются.подписать(function(){
console.log("Фишки различаются");
});
};
мж.скрытьСовпадающиеФишки = function()
{
мж.выбранныеФишки[0].скрыть();
мж.выбранныеФишки[1].скрыть();
};
мж.убратьСовпадающиеФишки = function()
{
var ф1 = мж.выбранныеФишки[0];
var ф2 = мж.выбранныеФишки[1];
var и1 = мж.индексПозиции(ф1.позиция);
var и2 = мж.индексПозиции(ф2.позиция);
delete мж.индексПозиций[и1];
delete мж.индексПозиций[и2];
};
мж.очиститьОтображениеВыбора = function()
{
мж.выбранныеФишки[0].показатьНейтраль();
мж.выбранныеФишки[1].показатьНейтраль();
};
мж.очиститьВыбор = function()
{
мж.номерВыбраннойФишки = 0;
мж.выбраннаяФишка = null;
мж.выбранныеФишки = [];
};
мж.оставшиесяФишки = [];
мж.задатьОставшиесяФишки = function()
{
мж.оставшиесяФишки = мж.фишки.slice();
};
мж.обновилиОставшиесяФишки = new Уведомитель();
мж.обновитьОставшиесяФишки = function()
{
var и1 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[0]);
мж.оставшиесяФишки.splice(и1, 1);
var и2 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[1]);
мж.оставшиесяФишки.splice(и2, 1);
мж.обновилиОставшиесяФишки.уведомить();
};
мж.доступныеДляВыбораФишки = function()
{
var фишки = [];
for (var номер in мж.оставшиесяФишки)
{
var ф = мж.оставшиесяФишки[номер];
if (мж.можноВыбратьФишку(ф))
{
фишки.push(ф);
}
}
return фишки;
};
мж.естьХод = function()
{
var фишки = мж.доступныеДляВыбораФишки();
for (var н1 in фишки)
{
for (var н2 in фишки)
{
var ф1 = фишки[н1];
var ф2 = фишки[н2];
if (
(ф1.имя != ф2.имя) &&
(ф1.группа == ф2.группа)
) {
return true;
}
}
}
return false;
}
мж.победа = new Уведомитель();
мж.поражение = new Уведомитель();
мж.проверитьЗавершение = function()
{
var кончилисьФишки = (мж.оставшиесяФишки.length == 0);
if (кончилисьФишки)
{
мж.победа.уведомить();
return;
}
if (!мж.естьХод())
{
мж.поражение.уведомить();
}
};
мж.отладитьЗавершение = function()
{
мж.победа.подписать(function(){
console.log("Игра завершена. ПОБЕДА!");
});
мж.поражение.подписать(function(){
console.log("Игра завершена. ПОРАЖЕНИЕ :(");
});
};
мж.задатьОтображениеЗавершения = function()
{
мж.победа.подписать(function(){
муром.камера.цветОчистки = [0.2, 0.5, 0.2];
});
мж.поражение.подписать(function(){
муром.камера.цветОчистки = [0.5, 0.2, 0.2];
});
};
// Игра.
мж.начали.подписатьМного([
мж.задатьНейтральныйМатериал,
мж.разобратьРаскладку,
мж.создатьФишки,
мж.создатьУзлыФишек,
мж.центрироватьСцену,
мж.задатьФишкамГруппыПоследовательно,
мж.применитьТемуФишек,
мж.сделатьФишкиВыбираемыми,
мж.отладитьВыборФишки,
мж.проиндексироватьПозиции,
мж.отладитьСравнениеФишек,
мж.задатьОставшиесяФишки,
мж.отладитьЗавершение,
мж.задатьОтображениеЗавершения,
]);
муром.мышь.нажатыеКнопкиИзменились.подписать(мж.выбратьФишку);
мж.выбранаФишка.подписатьМного([
мж.показатьВыбраннуюФишку,
мж.сравнитьВыбранныеФишки,
]);
мж.фишкиСовпадают.подписатьМного([
мж.убратьСовпадающиеФишки,
мж.обновитьОставшиесяФишки,
function(){
setTimeout(мж.скрытьСовпадающиеФишки, 200);
},
]);
мж.фишкиРазличаются.подписать(function(){
setTimeout(мж.очиститьОтображениеВыбора, 200);
});
мж.фишкиСравнили.подписать(function(){
setTimeout(мж.очиститьВыбор, 200);
});
мж.обновилиОставшиесяФишки.подписать(мж.проверитьЗавершение);
// Начать после загрузки ресурсов.
муром.ресурсы.получить(мж.ресурсы, мж.начать);