RU

Отрисовка шкалы

Aleks Versus Moderator 13.02.2014 13:11 24 comments 15119 views

Переписал. Отказался от обезличивания. Примеры оставил самые простые. Умных слов и сложных предложений старался избегать, но не всегда получалось. Сейчас всё выглядит так. Примеры кода прилагаются (собственно они один в один как в трактате).

Как сделать полоску здоровья, маны и пр.

Spoiler

Отрисовка шкалы.

Все мы видели в различных играх полоски здоровья, маны, выносливости и прочих ресурсов и показателей героя. Выглядят они примерно одинаково: шкала фиксированной ширины, которая по мере игры то заполняется, то опустошается. Собственно, на отношении заполненной части шкалы к её ширине и строятся все алгоритмы отрисовки шкалы.

На примере шкалы здоровья рассмотрим построение такой шкалы в QSP.

Если в школе вы изучали пропорции, будет намного легче вникнуть в суть.

Итак. На протяжении всей игры шкала здоровья имеет фиксированную ширину. Эта ширина соответствует максимальному уровню здоровья. Ширина заполненной части шкалы соответствует текущему значению здоровья. Оба эти значения хранятся в специальных переменных, которые мы конечно же знаем. В нашем примере это будут переменные:

health['all'] - текущий уровень здоровья 
health['max'] - максимальный уровень здоровья

Следует отметить, что численно ширина шкалы может не совпадать со значением максимального уровня здоровья. Так же и заполненная часть - с текущим уровнем здоровья. Эх, если бы всё было так просто, нам бы не пришлось ничего считать.

Мы рассмотрим несколько способов отрисовки шкалы.

Первый - отрисовка шкалы символами.

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

|||||||||||||||||||| - полная шкала 
.................... - пустая шкала

Проще всего сделать это, используя цикл:

i = 0 
:for 
if i<20: 
    $scale = $scale + '|' 
    i = i + 1 
    jump 'for' 
end

Данный цикл создаст текстовую строку из двадцати символов вертикальной черты в переменной $scale. Но этого нам мало. У нас ведь есть промежуточные состояния. Когда герой имеет всего половину от максимального уровня здоровья, четверть, или даже двести тридцать семь четыреста сорок вторых. То есть нам нужно получить что-то вроде этого:

|||||||||||||||..... - заполнена на три четверти 
||||||||||.......... - заполнена наполовину

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

20 символов соответствует health['max'] 
x  символов соответствует health['all']

Таким образом, чтобы узнать, сколько палочек нам следует нарисовать в нашей шкале, нам достаточно вычислить x. Согласно пропорции:

20/health['max'] = x / health['all']

x = (20 * health['all']) / health['max']

Теперь, когда мы знаем x (что соответствует ширине заполненной части шкалы), мы можем усовершенствовать наш цикл отрисовки шкалы. Пока i меньше x, добавляем в $scale палочку, потом точку.

x = (health['all'] * 20) / health['max'] 
i = 0 
:for 
if i<20: 
    if i < x: 
        $scale = $scale + '|' 
    else 
        $scale = $scale + '.' 
    end 
    i = i + 1 
    jump 'for' 
end

Чтобы вывести шкалу, придётся использовать *pl $scale или pl $scale. Я рекомендую оформить алгоритм в отдельной локации в виде функции и вызывать по мере необходимости. Тогда вы можете использовать один алгоритм для отрисовки всех шкал в игре: здоровье, мана, выносливость, сила и пр. и пр. Вот как выглядит данный алгоритм в виде функции:

! ----scale.symbols----
args[0] = args[0]	&	! текущее значение параметра
args[1] = args[1]	&	! максимальное значение параметра
if args[2] = 0: args[2] = 20	&	! ширина шкалы в символах (по умолчанию 20 символов)
! вычисляем ширину заполненной части - в символах:
args['x'] = (args[0] * args[2]) / args[1]
! выполняем цикл:
args['i'] = 0 
:for 
if args['i']<args[2]: 
    if args['i'] < args['x']: 
        $args['scale'] = $args['scale'] + '|' 
    else 
        $args['scale'] = $args['scale'] + '.' 
    end 
    args['i'] = args['i'] + 1 
    jump 'for' 
end
$result = $args['scale']

Такая функция позволяет быстро и легко вывести шкалу в любом месте игры, для любого параметра, и любой ширины:

*PL	$func('scale.symbols',health['all'],health['max'],30)	&	! выведет в окно основного описания шкалу здоровья шириной 30 символов 
PL	$func('scale.symbols',mana['all'],mana['max'])	&	! выведет в окно дополнительного описания шкалу маны шириной 20 символов (по умолчанию)

Второй способ - отрисовка шкалы в виде таблицы.

Способ основан на умении QSP рисовать разноцветные таблицы по разметке html.

Дело в том, что в этом случае нам не важна ширина шкалы. Ширина заполненной и незаполненной части вычисляется в процентном отношении. Иными словами:

health['max'] соответствует 100% ширины таблицы
health['all'] соответствует x

Заполненную часть шкалы будет представлять первая ячейка таблицы, раскрашенная в один цвет, незаполненную - вторая, раскрашенная в другой цвет. Но тут стоит учитывать один нюанс: нельзя делать ячейку шириной в 0%. Т.е. если шкала опустошена, или заполнена по-максимуму, достаточно одной ячейки. Всё это вылилось в весьма простенький код, который я привожу сразу для отдельной функции:

! -----scale.table------
args[0] = args[0]	&	! текущее значение параметра
args[1] = args[1]	&	! максимальное значение параметра
if args[2] = 0: args[2] = 350	&	! ширина шкалы (таблицы) в пикселях. По умолчанию 350 px
if $args[3] = "": $args[3]="FF0000"	&	! цвет заполненной части шкалы в формате RRGGBB. По умолчанию - красный
! сначала "создаём" соответствующую таблицу
$args['table']='<TABLE width=<<args[2]>> border=0 cellspacing=0 cellpadding=0><TR>'
! вычисляем ширину в процентах заполненной части
args['x'] = (args[0] * 100) / args[1]
! вычисляем ширину в процентах незаполненной части
args['empty'] = 100 - args['x']
! Если ширина заполненной части больше нуля процентов, добавляем в таблицу ячейку с указанным цветом (красный по-умолчанию)
if args['x']>0:
	$args['table']+="<TD width=<<args['x']>>% bgcolor=#"+$args[3]+">&nbsp;</TD>"
end
! Если ширина незаполненной части шкалы больше нуля процентов, добавляем в таблицу ячейку с другим цветом (серый).
if args['empty']>0:
	$args['table']+="<TD width=<<args['empty']>>% bgcolor=#888888>&nbsp;</TD>"
end
! "закрываем" таблицу
$args['table']+='</TR></TABLE>'
! результат
$result = $args['table']

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

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

Примечание №1 к первому способу: для отрисовки шкал символами используйте моноширинные шрифты, например Courier.

Примечание №2 к первому способу: В условии сравнения i и x используется знак “строго меньше”, потому что цикл считается с нуля. Если бы i изначально была равна единице, в условии цикла i сравнивалась бы не с числом 20, а 21. Тогда в условии сравнения i и x можно было бы использовать знак “меньше либо равно”.

Примечание №3 к первому способу: этот способ позволяет отрисовывать шкалу в том числе и картинками. Используйте вместо символов картинки шириной 1-2 пикселя (вставляются html-тегом <img src=“…”>.

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

Примеры шкал

Edited at 03.04.2014 21:23 (11 years ago)

Выделил в отдельную тему.

Непонятно, зачем называть “get.scale” если можно просто “scale”.

Такой код

'<font face="Courier" color=#00ff00>|</font>'

для отрисовки одного символа - чересчур. На полоску одинаковых символов достаточно будет и одного тега “font”.

Если используется и рассматривается только цикл, то рассуждения про альтернативные способы - лишнее.

Переписал код слегка:

Spoiler
! --- get.scale --- 
! args[0]  - текущее значение параметра 
! args[1]  - максимальное значение параметра 
! $args[2] - цвет шкалы, не обязательно (по умолчанию '#888888')
! args[3]  - ширина шкалы в символах, не обязательно (по умолчанию 20)
! $args[4] - символы, не обязательно (по умолчанию '|.')

!проверка параметров
if args[1] = 0: args[1] = 1
if NO STRCOMP($args[2],'^#[0-9a-fA-F]{6}$'): $args[2] = '#888888'
if args[3] <= 0: args[3] = 20
if LEN($args[4]) != 2: $args[4] = '|.'
$args['|'] = MID($args[4],1,1)
$args['.'] = MID($args[4],2,1)

!рисуем шкалу
args['x'] = (args[0] * args[3]) / args[1] 
args['i'] = 0
:for 
if args['i'] < args[3]: 
    if args['i'] < args['x']: 
        $result += $args['|'] 
    else 
        $result += $args['.']
    end 
    args['i'] += 1 
    jump 'for' 
end 

!выставляем шрифт
$result = '<font face="Courier" color=' + $args[2] + '>' +  _
          $result +  _
          '</font>'
! --- get.scale ---

Пример вызова:

$func('get.scale',mana['now'],mana['max'],$mana['scaleColor'],mana['scaleLength'])
Aleks Versus Moderator 14.02.2014 16:36 (12 years ago)

Соберусь, добью. Хочу всё-таки подробнее и про шкалу с изображениями, и способ без цикла сделать.

newsash,
у него там в оригинале двумя цветами одна полоска раскрашивается. “Пустая” и “полная” части полосы различаются цветом.

Nex:

у него там в оригинале двумя цветами одна полоска раскрашивается. “Пустая” и “полная” части полосы различаются цветом.

Можно ещё отдельный параметр (необязательный) добавить для цвета “пустой” полоски и по умолчанию сделать его совпадающим с цветом “полной” части.
А вообще я лишь предложил альтернативный вариант кода, а захочет Aleks Versus его использовать или нет - это уже ему решать. :)

В Зоне+ - графическая шкала.

!usage : gs 'showFillbar',[name,max,filled,filledCol,emptyCol]

!вообще-то это делается с помощью progressbar или, в случае его отсутствия div или canvas,
!но пришлось поизвращаться с таблицами из-за кривости местного хтмля

*nl '<table width="100%" cellspacing="0" cellpadding="0" ALIGN=CENTER><tr>'
	*p '<td width="20"><font color="#<<$args[3]>>"><<$args[0]>></font></td>'
	!*p '<td><<$args[0]>></td>'
	filledWidth=args[2]*100/args[1]
	emptyWidth=100-filledWidth
	if filledWidth>0:
		*p '<td bgcolor="#<<$args[3]>>" width="<<filledWidth>>%"><<args[2]>></td>'
	end
	if emptyWidth>0:
		*p '<td bgcolor="#<<$args[4]>>" width="<<emptyWidth>>%">'
		if args[5]:*p args[1]-args[2]
		*p '</td>'
	end
*p '</tr></table>'
Aleks Versus Moderator 20.02.2014 06:40 (12 years ago)

О! Прекрасный способ, KOLANICH. До чего просто. Можно и картинку воткнуть: растягивать по ширине даже классический плеер умеет.

Парни вы конечно молодцы, но например мне и простые “100%” здоровья не мешают, думаю многим также.

KlimKlim:

Парни вы конечно молодцы, но например мне и простые “100%” здоровья не мешают, думаю многим также.

Это вопрос видения автора - кто-то пишет текстом, кто-то рисует шкалу, кто-то изгаляется над шрифтом в зависимости от здоровья.

Ну это спасибо не ко мне, а к моддеру, пожелавшему остаться анонимным - код его. Но код довольно очевидный, подобное в эпоху до хтмл5 использовали для всяких прогрессбаров. Просто вкладывали див в див, выравнивание - по левому, а ширину внутреннего меняли от 0% до 100%. С картинкой, мне кажется, тут облом выйдет (движок не может в ксс).

Aleks Versus Moderator 25.02.2014 07:31 (11 years ago)

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

P.S.: А какие клёвые штуки можно делать в QN!

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

Насчёт растягивания - если чрезмерно растянуть изображение, мне кажется, оно будет выглядеть очень похабно. Хотя однопиксельная одномерная картинка должна выглядеть норм - получится такой же прогрессбар, только неоднотонный в поперечном направлении.

Aleks Versus Moderator 26.02.2014 06:38 (11 years ago)

KOLANICH:

Т.е. предлагаешь сделать гибрид, заменив символы на картинки? Подойдёт для хранения чего либо с явно выраженной дискретностью

Эм. Это я предлагал ещё в самом начале.

KOLANICH:

Хотя однопиксельная одномерная картинка должна выглядеть норм

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

Spoiler


Столбик/строка из пикселей разных цветов с растягиванием в направлении, перпендикулярному ему/ей.

это точка наверное.

Точка - нульмерная.
Ну а шкала получилась красивая. Предлагаю запилить некий аналог буста для куспа.

Aleks Versus Moderator 03.04.2014 21:51 (11 years ago)

Переписал. Думаю, лучше не получится.

Log in or Register to post comments.