RU

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

Aleks Versus Moderator 13.02.2014 13:11 24 comments 15143 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)

Вот мой пример прорисовки шкалы. На Aero работает отлично, а на классическом есть некоторые проблемы

#начало
usehtml = 1

maxhp = 200
hp = 50

gt 'шкала'

# шкала
shkala = (100 * hp) / maxhp

'<table>
<tr>
<td>'
i = 1
  :loop_i
     *p '<img src = "shkala1.png">'
     i += 1
  if i <= shkala: jump 'loop_i'
j = shkala
  :loop_j
     *p '<img src = "shkala.png">'
     j += 1
  if j <= 100: jump 'loop_j' 
'</td>
</tr>
</table>'

Скачать

Исправил код и пример. Теперь все корректно отображается как в Aero так и в классическом.

Aleks Versus Moderator 02.08.2014 13:52 (11 years ago)

Darkshok,
пример хорошо иллюстрирует первый способ отрисовки (по сабжу). Просто вместо символов используются картинки. Поскольку картинки в один пиксель шириной, более удобным способом будет второй.
Вопрос мой в следующем: зачем размещать изображения в отдельных ячейках? И ещё замечу, чтобы корректно выглядело в классике, пишем в теге таблицы cellpadding=0 cellspacing=0.

Добавлено позже:
Пардон. Не заметил сразу. Теги в таблице записываются в разных строках. В классике имеется досадный баг с этими переносами строк. Следует собрать таблицу одной строкой. Или через оператор *p, или суммировать в переменную, а после вывести результат на экран.

Aleks Versus,
это не баг.

Aleks Versus,
Да ты был прав. Собрав таблицу одной строкой и используя оператор *p все стало работать нормально и в классическом. Спасибо за совет.

зачем размещать изображения в отдельных ячейках?

Просто когда я размещал изображения в одной ячейке ( без *p ), то они выставлялись сверху в низ. А до использования оператора *p я сам не додумался.

Aleks Versus Moderator 02.08.2014 15:53 (11 years ago)

Nex,
я больше не знаю, как это назвать.

Если речь идёт про то, что
<img/><img/>
отображается в одну строку, а
<img/>
<img/>
в две, то это нормальное поведение. Багом было бы любое другое поведение.

Aleks Versus,
это, скажем так, особенность, или фича. Специально сделано. Но обсуждать наверное лучше в отдельной теме.

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

Spoiler

В нужный локациях в описании пишем <<1>> <<2>> <<3>> <<4>> <<5>> и так до десяти. Далее в стартовой локации задаем переменную hp =10, во всех местах, где тратится здоровье пишем длинный кусок кода, весь писать не буду напишу часть, дальше сами поймете if hp =5 : 1=? 2=? 3 =? 4=? 5=? 6=! 7=! и т.д. и в конце каждого if обязательно пишем goto $curloc и end. Надеюсь идея всем понятна, это вариант для новичко типо меня, которые не поняли что значит :for :).

Aleks Versus Moderator 04.08.2014 08:31 (11 years ago)

SneakBug8,
В шапке под спойлером есть способ, не использующий метки. Он подробно прокомментирован и требует минимума знаний по html. Использовать его просто. Можно даже не вникать, как работает. Кидаешь код в отдельную локацию, обзываешь её например “показать_здоровье”, а потом просто делаешь вызов в нужном месте (применительно к твоему образчику, где максимум здоровья - 10):

$func('показать_здоровье',hp,10)

Там же в первом посте есть архив с примерами. Я его обновил. Теперь оба примера прокомментированы. Быть может это поспособствует пониманию переходов по меткам и прочего.

Log in or Register to post comments.