MMORPG Базис

Аватара пользователя
blackstrip
Админ
Сообщения: 1197
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: MMORPG Базис

Сообщение blackstrip » Сб июн 01, 2024 10:24 am

Разработка интерфейса игры

В предыдущей версии Basis, написанной прямо на Android-овской яве, интерфейсы ввода (окошки) были совсем не игрового вида:

Изображение

Когда-то разрабатывался интерфейс Orter чтоб из пиксельных картинок складывать окошки viewtopic.php?p=2778#p2778

Он делал по текстовому "скрипту" окошко из кусков картинки (тайлов) с анимацией:

Изображение

Развиваем эту идею. Забираем из Orter один из базовых видов скина окна:

Изображение

Эти 16 элементов позволяют отрисовать любую табличку (окошко). Просто рамку, рамку разделенную на несколько частей по горизонтали (например, заголовок окна вверху и основная часть окна внизу) или вертикали (например, окно персонажа, где слева он нарисован, а справа список характеристик) и даже сетку из прямоугольников или сетку, содержающую еще сетки/таблицы внутри себя (сложное окно с кучей элементов в разных местах).

Т.к. на стенках таблички будут различные дополнительные элементы (например, горящий огонь у рас огня), то надо побольше пустого места вокруг них. Расширяем скин до тайлов 13х13 пикселей. Общий квадрат получается 52х52 пикселя. И рисуем объемные границы:

Изображение

Из этого скина можно собрать пустую рамку или таблицу на прозрачном фоне. А хотелось бы чтобы она была с фоном и с кнопками. И еще чтобы можно было рисовать, например, кнопки на залитом фоне или границы таблицы на залитом фоне или кнопки, ограненные границами таблицы.

Поэтому следующая итерация - набор-конструктор из фрагментов скина: рамка, залитый фон в форме рамки, залитый фон вне рамки, выпуклая кнопка снаружи рамки, нажатая кнопка снаружи рамки, залитый фон внутри рамки, выпуклая кнопка внутри рамки, нажатая кнопка внутри рамки:

Изображение

Анимацию добавим, раскопировав этот ряд вниз (сделаем 4 кадра). Пусть каждая из границ таблицы болтается, надувается, изгибается. При отрисовке необязательно анимировать сразу все части окна, можно какие-то анимировать, а какие-то держать статичными. Пока на скине анимируем все вообще, потом будем выбирать программно:

Изображение

Ну и раскрасим скин под нежить (фиолетовое подгнившее мясо с серыми сосудами, гнойные блестящие кнопки так и оставим желтовато-серыми):

Изображение

Аватара пользователя
blackstrip
Админ
Сообщения: 1197
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: MMORPG Базис

Сообщение blackstrip » Сб июн 01, 2024 11:16 am

Дизайнер окон - часть первая

Игра будет на лету из скина-конструктора собирать сочетания элементов 13х13 пикселей (рамка такая-то, внутри то-то, снаружи то-то) и кидать в нужное место окна (по очереди в каждый тайл окна). Исходную информацию (какие элементы комбинировать) будем загружать из файла. Файл будем делать в дизайнере окон.

Городить дизайнер окон не нужно, т.к. уже есть редактор мозаики PaintCAD 4Windows. Только одна проблема - он не умеет собирать комбинации из тайлов. Поэтому для него надо сгенерировать все необходимые комбинации и дать ему уже готовым набором картинок.

Воспользуемся Scriptaint-ом из PaintCAD 4Windows для комбинирования тайлов и создания этого набора для редактора мозаики. Пишем скрипт для комбинаций. Возьмем за основу первый кадр с ровными границами рамок.

Входной файл даем не с розовым фоном, а с прозрачным, чтоб через одни тайлы было видно другие:

Изображение

(а в самой игре воспользуемся еще и альфа-каналом чтоб фон или границы окон, или кнопки были с прозрачностью если нужно)

Скрипт комбинации фрагментов пишем на основе стандартного скриптаинтского, оставив только процедуры залитого прямоугольника (закрасим фоном фиолетовым) и написав дополнительную процедуру imgdrop (копирует сразу квадрат 52х52 пикселя из координат x1,y1 скина в нужное место набора по координатам x2,y2):

Код: Выделить всё

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
</head>
<body>
<div id="content">
<script type="text/javascript">

function _fillrect(x, y, w, h, c) {
codestr += '<div style="position:absolute; left:' + x + 'px; top:' + y + 'px; width:' + w + 'px; height:' + h + 'px; background-color:' + c + '; clip:rect(0,'+w+'px,'+h+'px,0);"><\/div>';
}

function fillrect(x1, y1, x2, y2, c) {
_fillrect(x1,y1,x2-x1+1,y2-y1+1,c);
}


function imgdrop(iurl, x1, y1, x2, y2) {
codestr += '<div style="position:absolute; left:' + x1 + 'px; top:' + y1 + 'px; width:52px; height:52px;overflow:hidden;">';
codestr += '<div style="position:absolute; left:' + x2 + 'px; top:' + y2 + 'px; width:260px; height:208px;"><img src="' + iurl + '"><\/div>';
codestr += '<\/div>';
}

function rgb(r,g,b) {
var rs = Math.floor(r).toString(16); if (rs.length<2) rs='0'+rs;
var gs = Math.floor(g).toString(16); if (gs.length<2) gs='0'+gs;
var bs = Math.floor(b).toString(16); if (bs.length<2) bs='0'+bs;
return '#'+rs+gs+bs;
}

function flushcode() {
document.getElementById('content').innerHTML=codestr;
}

function cls() {
codestr='';
flushcode();
}

function req(s) {
document.title=s;
}

//code start
b=13;
a=b*4;
sw=a*12;
req('setsize w='+a+' h='+sw);
codestr='';
filna='winskin0.png';
cls();
fillrect(0,0,a-1,sw-1,rgb(255,100,255));


//1
imgdrop(filna,0,0,-a*5,0);
imgdrop(filna,0,0,0,0);


//2
imgdrop(filna,0,a,-a*2,0);
imgdrop(filna,0,a,-a*5,0);
imgdrop(filna,0,a,0,0);

//3
imgdrop(filna,0,a*2,-a*6,0);
imgdrop(filna,0,a*2,0,0);


//4
imgdrop(filna,0,a*3,-a*2,0);
imgdrop(filna,0,a*3,-a*6,0);
imgdrop(filna,0,a*3,0,0);


//5
imgdrop(filna,0,a*4,-a*7,0);
imgdrop(filna,0,a*4,0,0);


//6
imgdrop(filna,0,a*5,-a*2,0);
imgdrop(filna,0,a*5,-a*7,0);
imgdrop(filna,0,a*5,0,0);

//7
imgdrop(filna,0,a*6,0,0);

//8
imgdrop(filna,0,a*7,-a*2,0);
imgdrop(filna,0,a*7,0,0);

//9
imgdrop(filna,0,a*8,-a*3,0);
imgdrop(filna,0,a*8,-a*0,0);


//10
imgdrop(filna,0,a*9,-a*3,0);
imgdrop(filna,0,a*9,-a*0,0);
imgdrop(filna,0,a*9,-a*5,0);

//11
imgdrop(filna,0,a*10,-a*4,0);
imgdrop(filna,0,a*10,-a*0,0);


//12
imgdrop(filna,0,a*11,-a*4,0);
imgdrop(filna,0,a*11,-a*0,0);
imgdrop(filna,0,a*11,-a*5,0);

flushcode();

//code end
</script>
</div>
</body>
</html>
Запускаем скрипт и он собирает из конструктора уже подготовленные шаблоны для различных вариантов комбинаций. Игра будет делать тоже самое, но на лету, эти шаблоны нигде храниться не будут кроме как в массиве "если нужен элемент номер X, то сложи из конструктора тайлы A, B, C".

Изображение

Паинткадовский раскладыватель рисунка на мозаику раскладывает слева-направо продвигаясь по рядам вниз. Можно, конечно, добавить в него раскладывание в другом направлении, но это совсем другая история и пока что легче вертикально разложить шаблоны.

Поэтому располагаем шаблоны вертикально, чтобы в случае, если придумаем новые комбинации тайлов, то добавлять их в конец (вниз), не меняя номера ранее существовавших. Т.е. верхний ряд комбинированных тайлов 13х13 будет иметь номера 1, 2, 3, 4 всегда, второй ряд пониже будет 5, 6, 7, 8, даже если внизу мы добавим новый шаблон с элементами 100, 101, 102, 103 и т.д.

Получился вот такой ряд шаблонов из комбинированных тайлов:

Изображение

Их мы и скормим раскладывателю на элементы в PaintCAD 4Windows и загрузим в дизайнер окон (редактор мозаики).

На этих тайлах везде сделана окантовка и сочетание только двух элементов из четырех возможных (залитого фона, кнопки, нажатой кнопки и прозрачного фона). Можно было бы сделать еще и шаблоны из трех элементов и даже из четырех (например, перекрестье из окантовки и четыре разных элемента с ее разных сторон), но тогда количество шаблонов сильно увеличится. Если шаблоны только из двух элементов, то это накладывает ограничения на рисование окон. Возможно позже будут добавлены часть шаблонов из трех-четырех элементов если это потребуется. Пока что рисуем окна из этих двухэлементных.

Аватара пользователя
blackstrip
Админ
Сообщения: 1197
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: MMORPG Базис

Сообщение blackstrip » Сб июн 01, 2024 11:47 am

Дизайнер окон - часть вторая

Загрузив набор шаблонов в паинткад вызываем раскладыватель рисунка на мозаику:

Изображение

Указываем размер элементарного тайла 13х13 и путь куда сохраним массив тайлов:

Изображение

Открываем тайлы в редакторе мозаики:

Изображение

Создаем матрицу нужного размера и складываем из тайлов, например, окно ввода:

Изображение

Размер шрифта (номера тайлов) в редакторе мозаики выбирается исходя из двух цифр в номере, трехцифирные номера накладываются друг на друга. Убрав по кнопке "Детали (D)" номера тайлов можно смотреть что получается. Также и рисовать окно можно выключив номера, выбирая тайлы по нажатию E (кнопка "Эффекты(E)"), далее выбирая в меню "Залить выделение картинкой" и выбирая конкретный тайл из файлов в диалоговом окне с предпросмотром:

Изображение

Окно ввода нежити получилось вот такое. Поле ввода из тайлов нажатой кнопки, есть поля для значка, для заголовка. Над полем ввода можно написать поясняющий текст, пока просто накрутим там трубок из границ окна, внизу две кнопки - ок и отмена:

Изображение

В игре можно сделать и не такие высокие окна, т.к. полэкрана обычно занимает виртуальная клавиатура. Это пока что будет окно для тестов скинов.

Аватара пользователя
blackstrip
Админ
Сообщения: 1197
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: MMORPG Базис

Сообщение blackstrip » Сб июн 01, 2024 4:59 pm

Экспорт окон и загрузка их в игру

Матрица тайлов сохраняется в редакторе мозаики в TLO-файл. В этом файле записаны построчно ширина матрицы в тайлах, высота матрицы в тайлах, и потом номера тайлов поочередно с левого верхнего до правого нижнего построчно:

Изображение

Загружаем файл, отрисовываем тайлы.

Анимация для нежити:
1) выбираем случайное число от 1 до 8,
2) если оно от 1 до 4 - будет статичный тайл соответствующего кадра анимации (1 - 4),
3) если оно от 5 до 8 - то будет анимированный тайл (по очереди кадры от 1 до 4), начинающийся с первого кадра для 5 (т.е. кадры 1,2,3,4), со второго для 6 (т.е. кадры 2, 3, 4, 1), с третьего для 7 (т.е. кадры 3, 4, 1, 2) и с четвертого для 8 (т.е. кадры 4, 1, 2, 3).

В итоге каждый тайл окна живет собственной жизнью, часть статичны, часть анимированы, анимация назначается им случайно при загрузке окна.

Выглядит анимация как перекачка чего-то по серым сосудам на фоне фиолетового мяса (можно его затекстурировать, можно даже анимировать, пока это не сделано):

Изображение

Аватара пользователя
blackstrip
Админ
Сообщения: 1197
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: MMORPG Базис

Сообщение blackstrip » Чт июн 06, 2024 9:03 pm

Украшения на окнах

Скин окон для людей - камни в ветвях.

Изображение

Расширим формат скина - добавим справа две колонки. Первая колонка - это фоновые украшения. Вторая колонка - это украшения спереди окна.

В украшения спереди (вторая колонка украшений) нарисуем листья, дрожащие на ветру и отбрасывающие тени на окно. В колонки украшений также можно добавлять дополнительное оформление интерфейса в честь каких-либо событий в игре.

Изображение

Новый скрипт для генерации тайлов для дизайнера окон, учитывающий эти колонки (на вход даем png-скин с прозрачностью):

Код: Выделить всё

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
</head>
<body>
<div id="content">
<script type="text/javascript">

function _fillrect(x, y, w, h, c) {
codestr += '<div style="position:absolute; left:' + x + 'px; top:' + y + 'px; width:' + w + 'px; height:' + h + 'px; background-color:' + c + '; clip:rect(0,'+w+'px,'+h+'px,0);"><\/div>';
}

function fillrect(x1, y1, x2, y2, c) {
_fillrect(x1,y1,x2-x1+1,y2-y1+1,c);
}


function imgdrop(iurl, x1, y1, x2, y2) {
codestr += '<div style="position:absolute; left:' + x1 + 'px; top:' + y1 + 'px; width:52px; height:52px;overflow:hidden;">';
codestr += '<div style="position:absolute; left:' + x2 + 'px; top:' + y2 + 'px; width:260px; height:208px;"><img src="' + iurl + '"><\/div>';
codestr += '<\/div>';
}

function imgdrops(iurl, x1, y1, x2, y2) {
codestr += '<div style="position:absolute; left:' + x1 + 'px; top:' + y1 + 'px; width:13px; height:13px;overflow:hidden;">';
codestr += '<div style="position:absolute; left:' + x2 + 'px; top:' + y2 + 'px; width:260px; height:208px;"><img src="' + iurl + '"><\/div>';
codestr += '<\/div>';
}


function rgb(r,g,b) {
var rs = Math.floor(r).toString(16); if (rs.length<2) rs='0'+rs;
var gs = Math.floor(g).toString(16); if (gs.length<2) gs='0'+gs;
var bs = Math.floor(b).toString(16); if (bs.length<2) bs='0'+bs;
return '#'+rs+gs+bs;
}

function flushcode() {
document.getElementById('content').innerHTML=codestr;
}

function cls() {
codestr='';
flushcode();
}

function req(s) {
document.title=s;
}

//code start
b=13;
a=b*4;
sw=a*12;
req('setsize w='+a+' h='+sw);
codestr='';
filna='winskin1.png';
cls();
fillrect(0,0,a-1,sw-1,rgb(255,100,255));


//1
imgdrop(filna,0,0,-a*8,0);
imgdrop(filna,0,0,-a*5,0);
imgdrop(filna,0,0,0,0);
imgdrop(filna,0,0,-a*9,0);

//2
imgdrop(filna,0,a,-a*8,0);
imgdrop(filna,0,a,-a*2,0);
imgdrop(filna,0,a,-a*5,0);
imgdrop(filna,0,a,0,0);
imgdrop(filna,0,a,-a*9,0);

//3
imgdrop(filna,0,a*2,-a*8,0);
imgdrop(filna,0,a*2,-a*6,0);
imgdrop(filna,0,a*2,0,0);
imgdrop(filna,0,a*2,-a*9,0);


//4
imgdrop(filna,0,a*3,-a*8,0);
imgdrop(filna,0,a*3,-a*2,0);
imgdrop(filna,0,a*3,-a*6,0);
imgdrop(filna,0,a*3,0,0);
imgdrop(filna,0,a*3,-a*9,0);

//5
imgdrop(filna,0,a*4,-a*8,0);
imgdrop(filna,0,a*4,-a*7,0);
imgdrop(filna,0,a*4,0,0);
imgdrop(filna,0,a*4,-a*9,0);


//6
imgdrop(filna,0,a*5,-a*8,0);
imgdrop(filna,0,a*5,-a*2,0);
imgdrop(filna,0,a*5,-a*7,0);
imgdrop(filna,0,a*5,0,0);
imgdrop(filna,0,a*5,-a*9,0);

//7
imgdrop(filna,0,a*6,-a*8,0);
imgdrop(filna,0,a*6,0,0);
imgdrop(filna,0,a*6,-a*9,0);

//8
imgdrop(filna,0,a*7,-a*8,0);
imgdrop(filna,0,a*7,-a*2,0);
imgdrop(filna,0,a*7,0,0);
imgdrop(filna,0,a*7,-a*9,0);

//9
imgdrop(filna,0,a*8,-a*8,0);
imgdrop(filna,0,a*8,-a*3,0);
imgdrop(filna,0,a*8,-a*0,0);
imgdrop(filna,0,a*8,-a*9,0);


//10
imgdrop(filna,0,a*9,-a*8,0);
imgdrop(filna,0,a*9,-a*3,0);
imgdrop(filna,0,a*9,-a*5,0);
imgdrop(filna,0,a*9,-a*0,0);
imgdrop(filna,0,a*9,-a*9,0);

//11
imgdrop(filna,0,a*10,-a*8,0);
imgdrop(filna,0,a*10,-a*4,0);
imgdrop(filna,0,a*10,-a*0,0);
imgdrop(filna,0,a*10,-a*9,0);


//12
imgdrop(filna,0,a*11,-a*8,0);
imgdrop(filna,0,a*11,-a*4,0);
imgdrop(filna,0,a*11,-a*5,0);
imgdrop(filna,0,a*11,-a*0,0);
imgdrop(filna,0,a*11,-a*9,0);

flushcode();

//code end
</script>
</div>
</body>
</html>
Он генерирует шаблоны с листьями, докидывая на фон окна одну колонку и вперед вторую колонку украшений:

Изображение

Тестовое окно в дизайнере окон с тайлами из этих шаблонов:

Изображение

Собирает вот такое окошко:

Изображение

В игре анимированное тестовое окно выглядит так - каждый тайл все время анимируется, статичных нет, но анимация со случайного кадра, как будто ветер обдувает порывами разные части окна и листья дрожат то в одной части, то в другой части окна. FPS у скина нежити было 8 кадров в секунду, для людей побыстрей - 10 кадров в секунду:

Изображение

Аватара пользователя
blackstrip
Админ
Сообщения: 1197
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: MMORPG Базис

Сообщение blackstrip » Ср июн 12, 2024 9:42 pm

Случайные элементы на окнах

Случайные элементы на окнах добавили бы разнообразности в их вид. При каждом новом создании окна они будут расставляться случайно по элементам окна.

Добавим в скин еще две колонки - случайные элементы на фоне (сзади окна) и случайные элементы спереди окна. Перенесем листья в колонку случайных элементов спереди окна, тогда они будут не на всех рамках, а только в их некоторых местах (палка с листьями, потом без, потом снова с листьями и т.д.). Для случайных элементов на фоне нарисуем разные цветы, грибы, корни, траву.

Изображение

Отрисовывая окно, добавляем случайные элементы на фон и спереди. Получилось вот такое окно. Фоновые случайные элементы видны и через прозрачные области окна (растут с той стороны окна).

Также в скине теперь выпрямлены кнопки в нажатом и отпущенном состоянии, ветки вокруг кнопок частично закрывают блеск их граней.

Изображение

Аватара пользователя
blackstrip
Админ
Сообщения: 1197
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: MMORPG Базис

Сообщение blackstrip » Вс июн 16, 2024 6:12 pm

Скин фракции воздуха - генерация случайных облаков в Scriptaint

Облака, тучи и небо.

Облака будут как наборы эллипсов, вытянутых по горизонтали. Если внутри каждого тайла их можно разложить случайно, то на стыках тайлов нужно иметь одинаковые связующие эллипсы, чтоб тайлы стыковались друг с другом в любых комбинациях.

В Scriptaint записываем скрипт, раскладываем кружки первого кадра. В секциях //linkver и //linkhor связующие облака между тайлами. Элементы горизонтальных и вертикальных линий рамки (//0left, //1left, //2left и //0top, //1top, //2top) сделаем как одинаковые тайлы.

Анимация облаков - их сдвиги по горизонтали и вертикали на 0 или 1/-1 пиксель либо вытягивание облаков (увеличение по горизонтали и уменьшение по вертикали или, наоборот, уменьшение по горизонтали и увеличение по вертикали).

Под низ для контроля вылезания облаков за границы тайлов положим картинку с сеткой (3g.bmp).

Java-скрипт для Scriptaint, рисующий жестко заданный первый кадр и случайные кадры 2-4, получился такой:

Код: Выделить всё

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
</head>
<body>
<div id="content">
<script type="text/javascript">
function _fillrect(x, y, w, h, c) {
codestr += '<div style="position:absolute; left:' + x + 'px; top:' + y + 'px; width:' + w + 'px; height:' + h + 'px; background-color:' + c + '; clip:rect(0,'+w+'px,'+h+'px,0);"><\/div>';
}

function fillrect(x1, y1, x2, y2, c) {
_fillrect(x1,y1,x2-x1+1,y2-y1+1,c);
}

function _fillrecttrans(x, y, w, h, c, tr) {
codestr += '<div style="position:absolute; left:' + x + 'px; top:' + y + 'px; width:' + w + 'px; height:' + h + 'px; background-color:' + c + '; clip:rect(0,'+w+'px,'+h+'px,0); filter: alpha(Opacity='+tr+'); opacity='+(tr/100)+';"><\/div>';
}

function fillrecttrans(x1, y1, x2, y2, c, tr) {
_fillrecttrans(x1,y1,x2-x1+1,y2-y1+1,c,tr);
}

function textout(t, x, y, c, f, s, w, styl) {
codestr += '<div style="position:absolute; left:' + x + 'px; top:' + y + 'px; color:' + c + '; font-family:' + f + '; font-size:' + s + 'px; font-weight:' + w + '; font-style:' + styl + ';">' + t + '<\/div>';
}

function textouttrans(t, x, y, c, f, s, w, styl, tr) {
codestr += '<div style="position:absolute; left:' + x + 'px; top:' + y + 'px; color:' + c + '; font-family:' + f + '; font-size:' + s + 'px; font-weight:'
+ w + '; font-style:' + styl + '; filter: alpha(Opacity='+tr+'); opacity='+(tr/100)+';">' + t + '<\/div>';
}

function textoutframe(t, x1, y1, x2, y2, c, f, s, w, styl, align) {
codestr += '<div style="position:absolute; left:' + x1 + 'px; top:' + y1 + 'px; width:' + (Math.abs(x2-x1)+1) + 'px; height:' + (Math.abs(y2-y1)+1) + 'px; color:' + c + '; font-family:' + f + '; font-size:' + s + 'px; font-weight:'
+ w + '; font-style:'+ styl + '; text-align:'+align+';">' + t + '<\/div>';
}

function textoutframetrans(t, x1, y1, x2, y2, c, f, s, w, styl, align, tr) {
codestr += '<div style="position:absolute; left:' + x1 + 'px; top:' + y1 + 'px; width:' + (Math.abs(x2-x1)+1) + 'px; height:' + (Math.abs(y2-y1)+1) + 'px; color:' + c + '; font-family:' + f + '; font-size:' + s + 'px; font-weight:'
+ w + '; font-style:'+ styl + '; text-align:'+align+'; filter: alpha(Opacity='+tr+'); opacity='+(tr/100)+';">' + t + '<\/div>';
}

function imgout(iurl, x, y) {
codestr += '<div style="position:absolute; left:' + x + 'px; top:' + y + 'px;"><img src="' + iurl + '"><\/div>';
}

function imgouttrans(iurl, x, y,tr) {
codestr += '<div style="position:absolute; left:' + x + 'px; top:' + y + 'px; filter: alpha(Opacity='+tr+'); opacity='+(tr/100)+';"><img src="' + iurl + '"><\/div>';
}

function imgoutframe(iurl, x1, y1, x2, y2, align) {
codestr += '<div style="position:absolute; left:' + x1 + 'px; top:' + y1 + 'px; width:' + (Math.abs(x2-x1)+1) + 'px; height:' + (Math.abs(y2-y1)+1) + 'px; text-align:'+align+';"><img src="' + iurl + '"><\/div>';
}

function imgoutframetrans(iurl, x1, y1, x2, y2, align, tr) {
codestr += '<div style="position:absolute; left:' + x1 + 'px; top:' + y1 + 'px; width:' + (Math.abs(x2-x1)+1) + 'px; height:' + (Math.abs(y2-y1)+1) + 'px; text-align:'
+align+'; filter: alpha(Opacity='+tr+'); opacity='+(tr/100)+';"><img src="' + iurl + '"><\/div>';
}

function setpixel(x,y,c) {
_fillrect(x,y,1,1,c);
}

function rect(x1, y1, x2, y2, c, w) {
line(x1,y1,x2,y1,c,w);
line(x1,y1,x1,y2,c,w);
line(x2,y1,x2,y2,c,w);
line(x1,y2,x2,y2,c,w);
}

function line(x1, y1, x2, y2, c, w) {
var i,ly,fx,lx,fy,cy,t,dx,dy,dw;
dw=Math.floor(w/2);
if ((x1==x2)&(y1==y2)) {_fillrect(x1-dw,y1-dw,w,w,c);return;};
if (x1<=x2) {dx=1;} else {dx=-1;}; if (y1<=y2) {dy=1;} else {dy=-1;};
if (Math.abs(x2-x1)>Math.abs(y2-y1)) {
var cx = x1; var cy = y1; fx = cx; lx = cx;
while (cx!=(x2+dx)) {
ly = cy; cy = Math.floor((cx-x1)*(y2-y1)/(x2-x1)+y1);
if ((cx!=x1)&(ly!=cy)) {if (fx>lx) {t=fx;fx=lx;lx=t;}; _fillrect(fx-dw,ly-dw,Math.abs(lx-fx)+w,w,c); fx=cx;};
lx=cx; cx=cx+dx;
} ly = cy; if (fx>lx) {t=fx;fx=lx;lx=t;}; _fillrect(fx-dw,ly-dw,Math.abs(lx-fx)+w,w,c);
} else {
var cx = x1; var cy = y1; fy = cy; ly = cy;
while (cy!=(y2+dy)) {
lx = cx; cx = Math.floor((cy-y1)*(x2-x1)/(y2-y1)+x1);
if ((cy!=y1)&(lx!=cx)) {if (fy>ly) {t=fy;fy=ly;ly=t;}; _fillrect(lx-dw,fy-dw,w,Math.abs(ly-fy)+w,c); fy=cy;};
ly=cy; cy=cy+dy;
} lx = cx; if (fy>ly) {t=fy;fy=ly;ly=t;}; _fillrect(lx-dw,fy-dw,w,Math.abs(ly-fy)+w,c);}
}

function spiralcircle(x1, y1, x2, y2, c, w, st) {
var t,i,cx,cy,lx,ly,rx,ry,nx,ny,li,im;
if (x2<x1) {t=x2;x2=x1;x1=t;};
if (y2<y1) {t=y2;y2=y1;y1=t;};
var ast = 1;
if (st>0) ast=st;
cx=x1+0.5+(x2-x1)/2; cy=y1+0.5+(y2-y1)/2;
rx=Math.abs(x2-x1)/2; ry=Math.abs(y2-y1)/2; li=0;
for (i=0;i<=720;i=i+ast) {
if (li>=360) break; li=i;
nx = Math.floor(cx+Math.cos(i*Math.PI/180)*rx);
ny = Math.floor(cy-Math.sin(i*Math.PI/180)*ry);
im=i%360; if (i>0) {
if (((im>45)&(im<135))|((im>225)&(im<315))) {if (nx!=lx) line(lx,ly,nx,ny,c,w);} else {if (ny!=ly) line(lx,ly,nx,ny,c,w);};
}; lx=nx;ly=ny;}
}

function fillcircle(x1, y1, x2, y2, c) {
var t,i,dx,dy,cx,cy,rx,ry;
if (x2<x1) {t=x2;x2=x1;x1=t;};
if (y2<y1) {t=y2;y2=y1;y1=t;};
cx=x1+0.5+(x2-x1)/2; cy=y1+0.5+(y2-y1)/2;
rx=Math.abs(x2-x1)/2; ry=Math.abs(y2-y1)/2;
if (Math.floor(ry)!=0)
for (i=0;i<=ry;i++) {
dx=Math.sqrt(rx*rx*(1-i*i/(ry*ry)));
dy=i;
fillrect(Math.floor(cx-dx),Math.floor(cy+dy+0.2),Math.floor(cx+dx),Math.floor(cy+dy+0.2),c);
fillrect(Math.floor(cx-dx),Math.floor(cy-dy-0.2),Math.floor(cx+dx),Math.floor(cy-dy-0.2),c);
}
if (Math.floor(rx)!=0)
for (i=0;i<=rx;i++) {
dy=Math.sqrt(ry*ry*(1-i*i/(rx*rx)));
dx=i;
fillrect(Math.floor(cx+dx+0.2),Math.floor(cy-dy),Math.floor(cx+dx+0.2),Math.floor(cy+dy),c);
fillrect(Math.floor(cx-dx-0.2),Math.floor(cy-dy),Math.floor(cx-dx-0.2),Math.floor(cy+dy),c);
}
}

function circle(x1, y1, x2, y2, c, w) {
var t,i,dx,dy,cx,cy,rx,ry,dw;
if (x2<x1) {t=x2;x2=x1;x1=t;};
if (y2<y1) {t=y2;y2=y1;y1=t;};
dw=Math.floor(w/2);
cx=x1+0.5+(x2-x1)/2; cy=y1+0.5+(y2-y1)/2;
rx=Math.abs(x2-x1)/2; ry=Math.abs(y2-y1)/2;
if (Math.floor(ry)!=0)
for (i=0;i<=ry;i++) {
dx=Math.sqrt(rx*rx*(1-i*i/(ry*ry)));
dy=i;
_fillrect(Math.floor(cx+dx-dw),Math.floor(cy+dy+0.2-dw),w,w,c);
_fillrect(Math.floor(cx-dx-dw),Math.floor(cy+dy+0.2-dw),w,w,c);
_fillrect(Math.floor(cx+dx-dw),Math.floor(cy-dy-0.2-dw),w,w,c);
_fillrect(Math.floor(cx-dx-dw),Math.floor(cy-dy-0.2-dw),w,w,c);
}
if (Math.floor(rx)!=0)
for (i=0;i<=rx;i++) {
dy=Math.sqrt(ry*ry*(1-i*i/(rx*rx)));
dx=i;
_fillrect(Math.floor(cx+dx+0.2-dw),Math.floor(cy+dy-dw),w,w,c);
_fillrect(Math.floor(cx-dx-0.2-dw),Math.floor(cy+dy-dw),w,w,c);
_fillrect(Math.floor(cx+dx+0.2-dw),Math.floor(cy-dy-dw),w,w,c);
_fillrect(Math.floor(cx-dx-0.2-dw),Math.floor(cy-dy-dw),w,w,c);
}
}

function rgb(r,g,b) {
var rs = Math.floor(r).toString(16); if (rs.length<2) rs='0'+rs;
var gs = Math.floor(g).toString(16); if (gs.length<2) gs='0'+gs;
var bs = Math.floor(b).toString(16); if (bs.length<2) bs='0'+bs;
return '#'+rs+gs+bs;
}

function flushcode() {
document.getElementById('content').innerHTML=codestr;
}

function cls() {
codestr='';
flushcode();
}

function req(s) {
document.title=s;
}

//code start
req('setsize w=52 h=208');
codestr='';
cls();
fillrect(0,0,52,52*4,'#FF00FF');
imgout('3g.bmp',0,0);
imgout('3g.bmp',0,52);
imgout('3g.bmp',0,52*2);
imgout('3g.bmp',0,52*3);

var i = 0;
var x1 = [];
var y1 = [];
var w1 = [];
var h1 = [];
var n = 0;
var tw = 13;

//linkver
x1[n]=3; y1[n]=10; w1[n]=7; h1[n]=5; n++;
x1[n]=3; y1[n]=10+tw; w1[n]=7; h1[n]=5; n++;
x1[n]=3; y1[n]=10+tw*2; w1[n]=7; h1[n]=5; n++;
x1[n]=3+tw*1; y1[n]=10; w1[n]=7; h1[n]=5; n++;
x1[n]=3+tw*1; y1[n]=10+tw; w1[n]=7; h1[n]=5; n++;
x1[n]=3+tw*1; y1[n]=10+tw*2; w1[n]=7; h1[n]=5; n++;
x1[n]=3+tw*3; y1[n]=10; w1[n]=7; h1[n]=5; n++;
x1[n]=3+tw*3; y1[n]=10+tw; w1[n]=7; h1[n]=5; n++;
x1[n]=3+tw*3; y1[n]=10+tw*2; w1[n]=7; h1[n]=5; n++;

//linkhor
x1[n]=10; y1[n]=3; w1[n]=6; h1[n]=4; n++;
x1[n]=10+tw; y1[n]=3; w1[n]=6; h1[n]=4; n++;
x1[n]=10+tw*2; y1[n]=3; w1[n]=6; h1[n]=4; n++;
x1[n]=10; y1[n]=3+tw*1; w1[n]=6; h1[n]=4; n++;
x1[n]=10+tw; y1[n]=3+tw*1; w1[n]=6; h1[n]=4; n++;
x1[n]=10+tw*2; y1[n]=3+tw*1; w1[n]=6; h1[n]=4; n++;
x1[n]=10; y1[n]=3+tw*3; w1[n]=6; h1[n]=4; n++;
x1[n]=10+tw; y1[n]=3+tw*3; w1[n]=6; h1[n]=4; n++;
x1[n]=10+tw*2; y1[n]=3+tw*3; w1[n]=6; h1[n]=4; n++;

//0top
x1[n]=3+tw*2; y1[n]=3; w1[n]=6; h1[n]=5; n++;
x1[n]=5+tw*2; y1[n]=2; w1[n]=6; h1[n]=4; n++;
//1top
x1[n]=3+tw*2; y1[n]=3+tw*1; w1[n]=6; h1[n]=5; n++;
x1[n]=5+tw*2; y1[n]=2+tw*1; w1[n]=6; h1[n]=4; n++;
//2top
x1[n]=3+tw*2; y1[n]=3+tw*3; w1[n]=6; h1[n]=5; n++;
x1[n]=5+tw*2; y1[n]=2+tw*3; w1[n]=6; h1[n]=4; n++;


//0left
x1[n]=3+tw*0; y1[n]=2+tw*2; w1[n]=4; h1[n]=4; n++;
x1[n]=2+tw*0; y1[n]=5+tw*2; w1[n]=6; h1[n]=5; n++;
//1left
x1[n]=3+tw*1; y1[n]=2+tw*2; w1[n]=4; h1[n]=4; n++;
x1[n]=2+tw*1; y1[n]=5+tw*2; w1[n]=6; h1[n]=5; n++;
//2left
x1[n]=3+tw*3; y1[n]=2+tw*2; w1[n]=4; h1[n]=4; n++;
x1[n]=2+tw*3; y1[n]=5+tw*2; w1[n]=6; h1[n]=5; n++;

x1[n]=3; y1[n]=2; w1[n]=8; h1[n]=6; n++;

x1[n]=2; y1[n]=5; w1[n]=7; h1[n]=4; n++;


x1[n]=2+tw*3; y1[n]=1; w1[n]=6; h1[n]=4; n++;
x1[n]=2+tw*3; y1[n]=4; w1[n]=7; h1[n]=5; n++;

x1[n]=3+tw*1; y1[n]=2; w1[n]=7; h1[n]=5; n++;
x1[n]=5+tw*1; y1[n]=5; w1[n]=5; h1[n]=4; n++;


x1[n]=1+tw*0; y1[n]=1+tw*1; w1[n]=5; h1[n]=3; n++;
x1[n]=4+tw*0; y1[n]=4+tw*1; w1[n]=6; h1[n]=3; n++;
x1[n]=2+tw*0; y1[n]=7+tw*1; w1[n]=5; h1[n]=4; n++;

x1[n]=2+tw*1; y1[n]=2+tw*1; w1[n]=5; h1[n]=4; n++;
x1[n]=2+tw*1; y1[n]=2+tw*1; w1[n]=9; h1[n]=5; n++;
x1[n]=1+tw*1; y1[n]=5+tw*1; w1[n]=7; h1[n]=4; n++;

x1[n]=2+tw*3; y1[n]=1+tw*1; w1[n]=6; h1[n]=3; n++;
x1[n]=2+tw*3; y1[n]=4+tw*1; w1[n]=8; h1[n]=6; n++;


x1[n]=1+tw*0; y1[n]=2+tw*3; w1[n]=8; h1[n]=6; n++;
x1[n]=3+tw*0; y1[n]=6+tw*3; w1[n]=5; h1[n]=3; n++;
x1[n]=5+tw*0; y1[n]=5+tw*3; w1[n]=6; h1[n]=4; n++;

x1[n]=3+tw*1; y1[n]=4+tw*3; w1[n]=7; h1[n]=5; n++;
x1[n]=1+tw*1; y1[n]=2+tw*3; w1[n]=8; h1[n]=4; n++;

x1[n]=1+tw*3; y1[n]=1+tw*3; w1[n]=6; h1[n]=5; n++;
x1[n]=2+tw*3; y1[n]=4+tw*3; w1[n]=7; h1[n]=4; n++;


var nx = [];
var ny = [];
var nw = [];

var rand1 = Math.floor(Math.random()*3)-1;
var rand2 = Math.floor(Math.random()*3)-1;
var rand3 = Math.floor(Math.random()*3)-1;
var rand4 = Math.floor(Math.random()*3)-1;

for (i=0;i<9;i++) nx[i] = rand1;
for (i=9+0;i<9+9;i++) nx[i] = rand2;
for (i=9+9;i<9+9+6;i++) nx[i] = rand3;
for (i=9+9+6;i<9+9+6+6;i++) nx[i] = rand4;
for (i=9+9+6+6;i<x1.length;i++) nx[i] = Math.floor(Math.random()*3)-1;

rand1 = Math.floor(Math.random()*3)-1;
rand2 = Math.floor(Math.random()*3)-1;
rand3 = Math.floor(Math.random()*3)-1;
rand4 = Math.floor(Math.random()*3)-1;

for (i=0;i<9;i++) ny[i] = rand1;
for (i=9+0;i<9+9;i++) ny[i] = rand2;
for (i=9+9;i<9+9+6;i++) ny[i] = rand3;
for (i=9+9+6;i<9+9+6+6;i++) ny[i] = rand4;
for (i=9+9+6+6;i<x1.length;i++) ny[i] = Math.floor(Math.random()*3)-1;

rand1 = Math.floor(Math.random()*3)-1;
rand2 = Math.floor(Math.random()*3)-1;
rand3 = Math.floor(Math.random()*3)-1;
rand4 = Math.floor(Math.random()*3)-1;

for (i=0;i<9;i++) nw[i] = rand1;
for (i=9+0;i<9+9;i++) nw[i] = rand2;
for (i=9+9;i<9+9+6;i++) nw[i] = rand3;
for (i=9+9+6;i<9+9+6+6;i++) nw[i] = rand4;
for (i=9+9+6+6;i<x1.length;i++) nw[i] = Math.floor(Math.random()*3)-1;




//frame 1
for (i=0;i<x1.length;i++) {
fillcircle(x1[i],y1[i],x1[i]+w1[i],y1[i]+h1[i],'#FFFFFF');
}

//frame 2
for (i=0;i<x1.length;i++) {
if (nw[i]==0) {
x1[i]=x1[i]+nx[i];
y1[i]=y1[i]+ny[i];
} else {
w1[i]=w1[i]+nw[i];
h1[i]=h1[i]-nw[i];
}
fillcircle(x1[i],y1[i]+52,x1[i]+w1[i],y1[i]+52+h1[i],'#FFFFFF');
}

//frame 3
for (i=0;i<x1.length;i++) {
if (nw[i]==0) {
x1[i]=x1[i]-nx[i];
y1[i]=y1[i]-ny[i];
} else {
w1[i]=w1[i]-nw[i];
h1[i]=h1[i]+nw[i];
}
fillcircle(x1[i],y1[i]+52*2,x1[i]+w1[i],y1[i]+52*2+h1[i],'#FFFFFF');
}

//frame 4
for (i=0;i<x1.length;i++) {
if (nw[i]==0) {
x1[i]=x1[i]-nx[i];
y1[i]=y1[i]-ny[i];
} else {
w1[i]=w1[i]-nw[i];
h1[i]=h1[i]+nw[i];
}
fillcircle(x1[i],y1[i]+52*3,x1[i]+w1[i],y1[i]+52*3+h1[i],'#FFFFFF');
}


flushcode();

//code end
</script>
</div>
</body>
</html>
Запуская скрипт много раз - добиваемся облаков нормального вида в каждом из 4 кадров, т.к. иногда получаются облака с множественными дырками, иногда вообще структуры рамки из-за этого не видно.

Изображение

Дальше добавляем тени на облака, делаем фиолетовые (цвета туч) кнопки и голубое небо в качестве фона. Скин вышел такой (пока без дополнительных элементов, позже можно будет дорисовать, а также изменить цветовую гамму):

Изображение

Грузим скин в игру. FPS для этого скина уже не 8 или 10 кадров в секунду, а всего 3, т.к. облака летают медленно обычно. На тестовом окне получается вот так:

Изображение

Ответить

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 0 гостей