Godot, пиксели, и скиллы в Дыре. (II)

Предыдущая часть

Всем привет и снова в эфире Радио Дыра. Сегодня у нас в гостях Родерик, Альберта и Эриза, и они поведают нам о своих скиллах. Навыках/умениях, если вы не любите англицизмы.

Техническая стороная вопроса

Как я уже писал в предыдущей статье, ради эксперимента, в этой игре я решил задействовать по максимуму инструмент Godot, который зовется просто - Resources. Не уверен, что называть это "инструментом" будет совсем уж корректно, но и фиг с ним. Нам, в Дыре, не до нюансов.

Итак, каждый персонаж - это ресурс, что позволяет без проблем всё это дело сохранять/загружать, не парясь о парсинге. Вполне удобно. При боязни взлома можно дополнительно зашифровать сэйвы, но лично я это не делал. Кому это надо, в конце концов? На данный момент сетевой части у игры нет, а если человек хочет играть с читами на своём телефоне - кому от этого хуже? Поэтому сэйвы сохраняются в простом бинарном .scn формате.

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

extends Resource class_name Skill enum SkillArea{ Single, Line, All, Row } enum Target{ Self, Ally, Enemy } export var level = 0 export var animation = "Attack" export (SkillArea) var area = SkillArea.Single export (Target) var target = Target.Enemy export var description : String export var name: String export var melee: bool = true export var cd: int = 0 export (int) var mana_cost = 0 export (int) var hp_cost = 0 export(Array, Resource) var effects setget set_custom_effect export (PackedScene) var missile var current_cd = 0

Если посмотреть внимательно, то моя помощь в понимании того, что есть в этом классе отпадает. Но если лень, но пробегусь по основным моментам. Есть target, который отвечает за то, на кого этот скилл используется - на себя, друзей, врагов. Есть SkillArea (не просто Area чтобы не путаться со встроенным классом) - отвечает за область применения. Думаю, тут понятно, что работает только с целями типа "враги" и "друзья" :)
Есть поле missile - которое хранит сцену для скиллов, которые имеют дополнительный визуальный эффект, есть animation - т.е. та анимация, которую будет совершать персонаж при выполнении скилла. Ну и всякое по мелочи.

Интересное тут - это строка "export(Array, Resource) var effects", что ведет нас к новому ресурсу - Effect. Неожиданно, да?

Если говорить просто, то скилл - это набор параметров для использования, а массив эффектов - это то, какую боль он будет причинять врагу. Когда навык используется персонажем, то к его цели применяются все эти разнообразные эффекты: урон, урон огнём, заморозка, яд и прочие весёлые штуки. Чтобы понять это проще, можно посмотреть на код Effect'a.

class_name Effect enum EffectType{ # Damage types Heal = 0, Damage = 1, # Base damage Poison = 2, Fire = 3, Burn = 4, Ice = 5, Stun = 6, Freeze = 7, # Same as stun, but different effect Provoke = 8, CounterAttack = 9, # Make damage while being under attack! Piercing = 10, # Make damage while being under attack! } const icons = { EffectType.Damage: preload("res://Images/Frames/Icons/Damage.atlastex"), EffectType.Poison: preload("res://Images/Frames/Icons/Poison.atlastex"), EffectType.Fire: preload("res://Images/Frames/Icons/Fire.atlastex"), EffectType.Burn: preload("res://Images/Frames/Icons/Burning.atlastex"), EffectType.Ice: preload("res://Images/Frames/Icons/Ice.atlastex"), EffectType.Freeze: preload("res://Images/Frames/Icons/Freeze.atlastex"), EffectType.Stun: preload("res://Images/Frames/Icons/Stun.atlastex"), EffectType.CounterAttack: preload("res://Images/Frames/Icons/CounterAttack.atlastex"), } export (String) var idle_animation export (String) var active_animation export (String) var formula = "strength*1" export (int) var duration = 0 export (EffectType) var type = EffectType.Damage export (PackedScene) var effect export (bool) var show_until_end = false var turn_left := 0 var dot_value := 0

Тут, как водится, множество параметров, которые позволяют выставить почти что любой эффект. idle_animation и active_animation - нужны для эффектов, вроде контратаки, которые совершаются не в свой ход. Пример - есть скилл контратаки у товарища Альберто: визуально это выражается тем, что он меняет стойку и когда монстр пытается его ударить, вместо этого Альберто сам совершает по нему удар.
Duration - длительность, для долгоиграющих эффектов, вроде DoT, баффов, и прочих радостей жизни. Effect - для визуального отображения скилла, будь то яд, заморозка или что-то подобное.
Ну а formula - она и есть формула, которая с помощью достаточно свежей штуки от Godot, Expression, парсится и выдает число, на которое нужно похилять/продамажить цель.

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

Ну и как оно всё работает?

А работает оно всё очень просто. Как только персонаж заканчивает анимацию, сначала выбираются цели для скилла, потом к каждой цели поочередно применяются эффекты оного. Происходит это примерно так:

var result = get_numbers(target_character, effect) match effect.type: Effect.EffectType.Damage,\ Effect.EffectType.Fire,\ Effect.EffectType.Ice: if target.has_effect(Effect.EffectType.CounterAttack): log_battle("%s evaded!" % [target.name]) else: target.get_damage(result, effect.type) log_battle("%s took %d damage" % [target.name, result]) Effect.EffectType.Heal: target.heal(result) _: target.add_effect(effect, result)

Если смотреть по строчкам: сначала мы парсим формулу, затем смотрим, наносит ли скилл урон - если наносит, то причиняем боль (либо уворачиваемся, либо что-то ещё, если будут другие эффекты). Если это хил, то хиляем. Ну и если не то, и не другое - значит, эффект длительный (какой-нибудь бафф, или, наоборот, яд, стан или заморозка), и мы добавляем его "на будущее".
Примерно так оно у меня и работает. Любая система умений и навыков не идеальна, но конкретно такая лично мне показалась вполне себе удобной :) Спасибо, что дочитали.

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

99
4 комментария

Спасибо за разбор тех.части - это интересно! А где можно про Expression почитать?

Ответить