Русский
Русский
English
Статистика
Реклама

Механики для реализации платформера на Godot engine. 5 часть

Здравствуйте. В предыдущем опросе читатели выбрали следующие пункты на момент создания данной статьи: система характеристик оружия, система здоровья персонажа. А вот дерево навыков я так и не сообразил как правильно реализовать Точнее как создать интерфейс, чтобы отображать и управлять деревом.Предыдущие части:

Система здоровья

Ну начнём пожалуй с системы здоровья персонажа. Я решил создать отдельный файл для всего необходимого. Он назван health_system.gd и лежит в папке скриптов. Важно: это не синглтон, а просто скрипт. Дальше вы поймёте почему.
# Теперь я буду использовать синтаксис javascript. В нём хоть var подсвечивается.extends Object # Расширяем базовый объектclass_name Health # Подписываем класс как Health и после он доступен из любого места игры как тот-же Node, или Node2D.signal death # Добавляем сигнал "death", чтобы испускать его, когда персонаж умирает. Этим персонажем может быть не обязательно даже игрок, или вообще что-то живое.var health: int = 100 setget set_health, get_health # Здоровье и setget для его измененияvar max_health: int = 100# верхний иvar min_health: int = 0# нижний предел здоровьяfunc set_health(new_health: int) -> void: # Функция для того, чтобы ставить new_health здоровья игроку при вызове, что будет не больше или меньше чем можно# warning-ignore:narrowing_conversion # О том что clamp возвращает целое значение, отрезая дробную часть.health = clamp(new_health, min_health, max_health) # Ограничиваем здоровьеif health == min_health: # А если здоровья - заданный минимум - мы умираем, меньше не будет.emit_signal("death") # Испускаем сигнал о том что нечто с этим здоровьем умерлоreturnfunc get_health() -> int:return health # получаем текущее здоровье. Если возвращать константу - игрок будет бессмертным, но константа должна быть больше максимального получаемого урона в игре, иначе мы всё равно умрём.func set_min_max_health(new_max: int = 100, new_min: int = 0) -> void: # Задача верхнего и нижнего предела здоровья. Тут поддерживается отрицательный минимум, что позволит создать эффект грани жизни и смерти, что поднимет адреналин игрока, как было в первой части того же Assasin's creed, что улучшало ощущение хорошей игры.self.max_health = new_maxself.min_health = new_minreturnfunc damaged(dmg: int = 0) -> void: # Получение урона.self.health -= dmg # После некоторых разбирательств я выяснил следующее: set_health() вызывается вместо стандартного "=" и подобных, что позволяет не писать логику смерти в получении урона.return
Чтобы его добавить к персонажу нужно всего-лишь добавить к переменным
# ...var health: Health = Health.new()# ...# И подключаем сигнал смерти в _readyfunc _ready():health.connect("death", self, "dead") #сигнал "смерть" к self.dead(). Смерть я писал в предыдущих выпусках, а если точнее в 3-ей части.
И теперь игрок имеет здоровье. Правда нас всё по-прежнему убивает с 1 удара, потому что я не рассказал об оружии, что будет наносить N урона, а не просто убивать.

Система оружия

А если точнее базовое оружие, которое можно прикреплять к разным объектам и брать данные от него.Ближе к делу, поэтому начну сразу с кода.
extends Nodeclass_name Weapon # Подписываем как Weapon, чтобы можно было прикреплятьenum WeaponTypes {MILLITARY, RANGED, BLOCKER} # Ближний бой, дальний и блокировщикexport (NodePath) var weapon_owner_node_path: NodePath # Путь к владельцуexport (int) var damage: int = 10 # уронexport (int) var critical_damage: int = 20 # критический уронexport (float) var critical_damage_chance = 0.2 # шанс критического урона. Бросаем кубик, если число меньше этого - атакуем критическим урономexport (WeaponTypes) var weapon_type: int = 0 # Тип оружия из перечисленияexport (int) var max_damage_distance: int = 0x20 # Дальность атаки чтобы нанести максимальный урон, если больше - урон будет меньше. В разработке. По умолчанию 32 пикселяvar weapon_owner: Node # Заготовка weapon_owner, чтобы в _ready задать из NodePath, что позволит немного оптимизировать множественные вызовыvar use: FuncRef func _ready() -> void:weapon_owner = WeaponController.get_node_(weapon_owner_node_path)match weapon_type: # ставим в use нужный FuncRef, что вызывается с помощью use.call_func() аргументы в скобки.WeaponTypes.MILLITARY:use = funcref(self, "attack") # Обычная атакаWeaponTypes.RANGED:use = funcref(self, "ranged_attack") # Дальняя атакаWeaponTypes.BLOCKER:use = funcref(self, "block") # Блок атаки врагаfunc attack(enemy: Entity) -> bool:print("attack")enemy.health.damaged(self.damage)return true # Удачность нанесения уронаfunc ranged_attack(enemy: Entity) -> bool:var dmg: float = damageif weapon_owner.global_position.distance_to(enemy.global_position) > max_damage_distance:dmg -= damage / 4enemy.health.damaged(round(dmg))return truefunc block(enemy: Entity) -> bool:print(randi() > critical_damage_chance) # В разработке. Нужно чтобы гасить урон от атак врагов, но я до конца не придумал как реализовать его.return true
Добавляем этот узел к объекту, к примеру к пуле:
extends Entity # Тут я не буду рассказывать обо всём, потому что этот урок о том как прикреплять скрипты здоровья и сцены оружия, а не о создании пушек и других ловушек. О пушке расскажу в следующем уроке о механизмах и ловушках.var direction = Vector2(-1, 0) setget set_directionconst SPEED: int = 40onready var weapon: Weapon = $Weapon # Задаём оружиеfunc _ready():health.connect("death", self, "dead") # health есть уже в Entity, но это единственное что есть в нём.func _physics_process(delta):var motion: Vector2 = direction * SPEED * deltavar collision = move_and_collide(motion, false)if collision != null and collision.collider != null:var coll = collision.colliderif coll.name == "TileMap":self.dead()else:weapon.use.call_func(coll) # Атакуем объект со здоровьемself.dead()print(coll.health.get_health())func set_direction(vec: Vector2) -> void:direction = vecfunc dead():self.queue_free() # Метод смерти просто освобождает этот объект через queue_free()
Вот как выглядит сцена пули:Надеюсь этой картинки хватит чтобы понять как работает сцена Weapon.

Заключение

На этот раз на этом всё. Вышла довольно короткая статья, так как в этот раз я не смог подготовить весь запланированный материал, то есть дерево навыков, а то что показал довольно просто реализовать. Удачной разработки и до следующих выпусков.
Источник: habr.com
К списку статей
Опубликовано: 15.11.2020 16:06:22
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Разработка игр

Godot

Gdscript

Программирование

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru