Advertisement
  1. Code
  2. Coding Fundamentals
  3. Game Development

Как создать HUD индикатор перезарядки

Scroll to top
Read Time: 11 min

() translation by (you can also view the original English article)

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

В ролевых играх, многопользовательских онлайн аренах (таких как League of Legends или DOTA) или даже в стратегиях в реальном времени эти показатели часто имеют решающее значение для игрока.

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

Все демонстрационные материалы были сделаны с помощью стабильной версией Construct 2 R168 и могут быть открыты и запущены в бесплатной версии. Весь исходный код примеров содержит комментарии.

Давай углубимся.

Основы механики индикатора перезарядки

Индикатор перезарядки в основе представляет собой визуальную отображение механизма индикатора, а механика индикатора перезарядки - в основном представляет собой таймер. Рассмотрим действие, которое выполняет персонаж. В тот момент, когда действие выполняется, запускается таймер, и пока этот таймер работает, персонаж не может выполнить действие снова. Это и есть индикатор перезарядки.

С программной точки зрения, чтобы предотвратить действие, выполняемое в период перезарядки, логическая переменная приобретает значение true, когда действие выполняется. При попытке выполнить свое действие код проверяет, действительно ли значение логической переменной false и не позволяет выполнять действие. В конце работы таймера логическая переменная возвращается к значению false, позволяя выполнить действие снова. 

Рассмотрим следующий пример в качестве иллюстрации этого понятия:

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

Давайте посмотрим на псевдокод:

1
//An object Character has a boolean variable "Cooldown", a numeric variable "cTimer" and another numeric variable "cEndTime"

2
3
On clicked Button
4
    txtHistory.text = txtHistory.text & newline & "The character performs an action"
5
    Character.cTimer = 0
6
    Character.cEndTime = txtTimer.text //The text object "Cooldown duration"

7
    Character.Cooldown = True
8
    Button.Enabled = False
9
    
10
If Character.Cooldown = True
11
    Character.cTimer = Character.cTimer + dt
12
    If Character.cTimer >= Character.cEndTime
13
        txtHistory.text = txtHistory.text & newline & "The character is ready to perform an action"
14
        Character.cTimer = -1
15
        Character.Cooldown = False
16
        Button.Enabled = True
17
    Else & Every 0.5 seconds
18
        txtHistory.text = txtHistory.text & newline & "The action is on cooldown. " & Character.cEndTime - Character.cTimer & " seconds of cooldown remaining."
19
20
    

Функция On clicked Button выполняемая при нажатии кнопки может быть выполнена только в том случае, если кнопка включена, и ее код выполняется только один раз после нажатия. Это действие пользователя запускает таймер, и устанавливает значение Cooldown в значение true.

Когда кнопка нажата, переменная Character.cEndTime будет обозначать время окончания периода восстановления; это значение устанавливается на основе значения в текстовом объекте txtTimer, рядом с кнопкой Action.

Также в этот момент значение cTimer «сбрасывается» на 0, так как оно становится "новым" таймером, а для режима Cooldown устанавливается значение true, чтобы разрешить выполнение второй части кода. Наконец мы отключаем кнопку. (Мы могли бы просто оставить её активной и добавить еще одно условие к нашей функции On clicked Button, проверяя, является ли значение Cooldown false до того, как продолжить, но отключение кнопки будет лучшей обратной связью).

Примечание: В этом примере и псевдокоде нет обработчика ошибок, чтобы предотвратить ввод других данных, кроме числа в текстовый объект. Ввод чего-либо приведет к тому, что cEndTime будет установлен в значение 0 - что, будет обозначать, отсутствие перезарядки вообще.

Строка 10 вышеуказанного псевдокода выполняется каждый тик; она проверяет, является ли значение Character.Cooldown равным true и, если это так, добавляет значение dt к текущему значению Character.cTimer.

dt, сокращённо от «delta time», представляет собой системную переменную, которая возвращает время, прошедшее между рендерингом предыдущего кадра и рендерингом текущего кадра. Это означает, что, насколько бы мощным ни был компьютер игрока, и независимо от того, на какой скорости работает игра, мы можем гарантировать, что период перезарядки длится одинаковое количество времени. (Если бы мы определяли период перезарядки по количеству тиков или кадров, которые истекли, длина периода в секундах будет различаться на разных компьютерах.) Название переменной dt или ее применение могут отличаться в зависимости от вашего движка программирования.

Если перезарядка все еще активна, мы проверяем, текущее значение cTimer, больше оно или равно значению cEndTime; если это так, мы дошли до конца периода восстановления. Мы устанавливаем обратную связь и значение Character.Cooldown равное false, чтобы этот раздел кода не выполнялся снова, пока пользователь не нажмет кнопку Action. Мы также снова активируем кнопку Action.

Если перезарядка все еще активна, мы показываем обратную связь, которая объясняет это. Этот бит обратной связи на самом деле является нашим индикатором перезарядки в текстовом варианте.

Итак, это основы механики индикатора перезарядки, основанный на таймере. В оставшейся части этой статьи давайте сосредоточимся на самих индикаторах перезарядки и посмотрим, как их реализовать.

Базовый индикатор перезарядки

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

Рассмотрим следующий пример:

Нажмите кнопку в любом месте экрана, чтобы выполнить действие. Обратите внимание, что зеленая полоса становится красной во время перезарядки и изменяется по ширине от 0 до ее первоначальной ширины. Как и в основном текстовом примере, вы можете установить время перезарядки.

В этом примере индикатор (под названием CooldownBar) представляет собой не что иное, как цветной спрайт, растянутый до ширины 100 пикселей. Когда действие выполняется, его ширина устанавливается равной 0 пикселям. Затем каждый тик, в котором переменная Cooldown равна true, ширина устанавливается в соответствии с текущим значением cTimer.

Давайте посмотрим на псевдокод:

1
//Using the same "Character" object as in the basic example, this time the object is visible on screen

2
3
On any mouse click & Character.Cooldown = False
4
    Character.cTimer = 0
5
    Character.cEndTime = txtEndTimer.text
6
    Character.Cooldown = True
7
    CooldownBar.Width = 0
8
    CooldownBar.AnimationFrame = 1
9
    
10
If Character.Cooldown = True
11
    Character.cTimer = Character.cTimer + dt
12
    CooldownBar.Width = (CooldownBar.MaxWidth / Character.cEndTime) * Character.cTimer
13
    
14
    If Character.cTimer >= Character.cEndTime
15
        Character.cTimer = -1
16
        Character.Cooldown = False
17
        CooldownBar.Width = CooldownBar.MaxWidth
18
        CooldownBar.AnimationFrame = 0

Механизм индикатора очень похож на тот, который описан в предыдущем примере, поэтому давайте сосредоточимся на самом CooldownBar. Объект имеет два кадра анимации: зеленый квадрат размером 32x32 пикселей и красный квадрат размеров 32x32 пикселей. Он также содержит переменную числовой переменной MaxWidth, которая установлена ​​в значение 100 (пикселей), максимальная ширина полосы.

Каждый тик, пока Cooldown имеет значение true, значение CooldownBar.width устанавливается на часть значения CooldownBar.MaxWidth. Мы определяем эту часть, разделив максимальную ширину полосы на время окончания восстановления, а затем умножив этот результат на текущее время переменной cTimer.

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

Улучшение дизайна

Мы могли бы пойти немного дальше в визуальном плане. Вот несколько мыслей:

Начальная точка CooldownBar установлена ​​в центре, что дает ощущение общего роста. Если вы предпочитаете, вы можете установить эту точку в левом или правом краю объекта, чтобы придать ей более «линейное» ощущение.

Этот пример очень прост; сама панель состоит только из двух кадров разного цвета, чтобы усилить аспект перезарядки. Пока панель красная, пользователь понимает, что действие не может быть выполнено, так как красный цвет обычно обозначает цвет, используемый для обозначения «стоп». Но не забывайте о игроках с нарушением зрения! Не забудьте использовать цвета которые действительно отличаются друг от друга, чтобы даже они смогли отличить их друг от друга или используйте другой метод визуальной обратной связи, кроме изменения цвета.

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

Вот краткая иллюстрация предыдущих пунктов:

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

Восстановление навыков

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

Рассмотрим пример, в котором нажатие на одну из кнопок бросает соответствующее оружие, а также показывает оставшееся время для перезарядки:

Как вы можете видеть, каждая кнопка навыка будет отображать "незаполненный" черный индикатор и таймер во время периода восстановления. Черный индикатор - это всего лишь черный цвет спрайта, помещенный над кнопкой навыка со степенью прозрачности 45%, а таймер - текстовый объект. Каждый экземпляр кнопки навыка имеет свой собственный экземпляр объектов SkillCover и txtSkillTimer.

На этот раз переменные Cooldown, sTime и sEndTime привязаны к каждому экземпляру SkillButton. Кроме того, исходная точка для черного спрайта SkillCover находится около нижнего края.

Рассмотрим этот псевдокод:

1
//Object "SkillButton" with variables "Cooldown" (boolean), "sTime" (numeric), "sEndTime" (numeric), and a specific animation frame to know which instance is being clicked/selected.

2
//Object "SkillCover" with a variable "Skill" set accordingly to the animation frame of the SkillButton they are related to.

3
//Object "txtSkillTimer" with a variable "Skill" for the same purpose as above.

4
5
On SkillButton clicked & SkillButton.Cooldown = False
6
    SkillButton.sTime = 0
7
    SkillButton.Cooldown = True
8
    Create Proj & ProjImage objects
9
    ProjImage.AnimationFrame = SkillButton.AnimationFrame //To either throw a dagger or a ninja star

10
    
11
    txtSkillTimer.Skill = SkillButton.AnimationFrame
12
    &
13
    SkillCover.Skill = SkillButton.AnimationFrame
14
        Set txtSkillTimer's position to the bottom of SkillButton

15
        Set SkillCover's position to the bottom of SkillButton
16
        Set txtSkillTimer in Front of SkillButton
17
        Set SkillCover behind txtSkillTimer //Still in front of SkillButton

18
        txtSkillTimer.Visible = True
19
        SkillCover.Visible = True
20
        SkillCover.Height = SkillButton.Height
21
22
For each SkillButton & SkillButton.Cooldown = True
23
    SkillButton.sTime = SkillButton.sTime + dt
24
    
25
    txtSkillTimer.Skill = SkillButton.AnimationFrame
26
    &
27
    SkillCover.Skill = SkillButton.AnimationFrame
28
        txtSkillTimer.text = SkillButton.sEndTime - SkillButton.sTime
29
        SkillCover.height = SkillButton.Height - ((SkillButton.Height / SkillButton.sEndTime) * SkillButton.sTime)
30
    
31
        If SkillButton.sTime >= SkillButton.sEndTime
32
            SkillButton.sTime = -1
33
            SkillButton.Cooldown = False
34
                    
35
            txtSkillTimer.Skill = SkillButton.AnimationFrame
36
            &
37
            SkillCover.Skill = SkillButton.AnimationFrame
38
                txtSkillTimer.Visible = False
39
                SkillCover.Visible = False
40
41
        

Здесь мы выбираем правильный экземпляр txtSkillTimer и SkillCover. (Это метод Construct 2, мы определяем правильные экземпляры в соответствии со значением Skill, который должен соответствовать кадру анимации текущего объекта SkillButton, который был либо нажат, либо выбран в режиме цикла For each).

В отличие от предыдущих индикаторов перезарядки, SkillCover начинается со "заполненного", охватывая всю высоту SkillButton, а затем во время перезарядки медленно уменьшается, открывая изображение кнопки.

Для этого мы задаем SkillCover высоту, которая соответствует высоте SkillButton, и затем каждый кадр вычитает (SkillButton.Height / SkillButton.sEndTime) * SkillButton.sTime из его максимальной высоты. Это в принципе, та же самая формула, которую мы использовали раньше, чтобы рассчитать долю времени восстановления, которая истекла, но только наоборот.

Некоторые игры будут форматируют время по-разному и позволяют игроку настроить вид, который он предпочитает. Например, одна минута и сорок секунд могут отображаться как 1:40 или 100 секунд. Чтобы применить это к своей собственной игре, запустите проверку условия If, прежде чем отображать текст txtSkillTimer, чтобы узнать, какой формат выбрал игрок, и соответствующим образом отформатировать текст. Некоторые игры или игроки иногда предпочитают не отображать время как текст вообще. Некоторые игры или игроки иногда предпочитают не отображать время как текст вообще.

Есть еще много всего, что вы могли бы сделать с помощью SkillCover. Вы могли бы поиграть с прозрачностью, чтобы затемнить кнопку больше или меньше 45%. Поскольку это спрайт, который перекрывает другое изображение, вы также можете поиграть с режимом смешивания, например, чтобы обесцветить основное изображение и восстановления его цветов все больше и больше по мере перезарядки. Вы даже можете добавить эффекты webGL или шейдеры в соответствии с остальной частью вашего интерфейса или дизайна. Что касается индикатора перезарядки, это зависит от вашего воображения и художественного стиля.

Итог

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

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

Если вы задумаетесь об этом на секунду, вы также можете использовать этот метод для контроля скорости стрельбы для оружия: до тех пор, пока пистолет находится на перезарядке, он не выстрелит, даже если кнопка Fire нажата; в момент завершения перезарядки, может быть запущен другой снаряд. В этом случае не требуется индикатор перезарядки.

Вы можете загрузить все примеры и открыть их в бесплатной версии Construct 2 R168 или более поздней.

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

Рекомендации

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.