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

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

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

Предыдущие статьи:

Улучшение системы карабканья из второго выпуска и другое

В общем покажу весь код своего персонажа и постараюсь прокомментировать его наиболее понятно.
# В этот раз будет очень много кода, потому что я не представляю себе все эти системы по отдельности.extends KinematicBody2Dsignal timer_ended # Сигнал о отключении таймера в _processconst UP_VECTOR: Vector2 = Vector2(0, -1) # Направление вверхconst GRAVITY: int = 40# Скорость паденияconst MOVE_SPEED: int = 100# Скорость перемещенияconst JUMP_POWER: int = 480# Сила прыжкаconst CLIMB_SPEED: int = 40# Скорость карабканьяconst WALL_JUMP_SPEED: int = 80# Скорость прыжка от стеныenum States {ON_FLOOR, ON_WALL} # Как я выяснил, этому скрипту нужно только 2 состоянияonready var ray_cast: Object = $RayCast2D # Для реализации взаимодействия с другими объектами. Будет пояснён позжеvar velocity: Vector2 = Vector2.ZERO # Ускорение.var walls: Array = [false, false, false] # Для определения стен. Стена слева, стена сверху, стена справа.var timer_enabled: bool = false# Отвечает за включение таймераvar climbing: bool = false# Поднимаемся мы по стене, или просто падаем вдоль неёvar is_wall_jump: bool = false# Прыгаем ли мы от стены, или нетvar is_double_jump: bool = true # Двойной ли прыжокvar right_pressed: float = 0# Трансляция силы нажатия на стрелки влево и вправо, что позволяет подменить значенияvar left_pressed: float = 0var timer: float = 0# Таймерvar prev_direction: float = 0# Предыдущее направление. Нужно для того чтобы анимация бездействия воспроизводилась в обоих направленияхvar direction: float = 0# Текущее направление движения.var keys: int = 0 # Количество ключей. Нужно для открытия дверей, соответственноvar current_state: int = States.ON_FLOOR# Текущее состояние персонажаfunc _ready():ray_cast.add_exception($WallLeft) # говорит что не нужно обрабатывать лучу ray_castray_cast.add_exception($WallRight)ray_cast.add_exception(self)func _process(_delta: float) -> void: # метод _processif timer > 0 or timer_enabled:timer -= _delta# Уменьшаем таймер на _deltaif timer <= 0 and timer_enabled:timer_enabled = falsetimer = 0# Сбрасываем значение и выключаем таймерemit_signal("timer_ended") # Испускаем сигнал таймера.if self.direction != 0:self.ray_cast.cast_to *= -1self.prev_direction = self.direction# обновляем предыдущее направление если текущее не равно 0func _physics_process(_delta: float) -> void:self.control_character()self.pause_opened()# Вызываем для проверки - открыта ли паузаif (!self.climbing):# Если не карабкаемся, то проверяемif (!self.is_wall_jump): # Если прыжок от стены то увеличиваем self.velocity.y на гравитациюself.velocity.y += GRAVITYelse:# Иначе падаем в 4 раза медленнееself.velocity.y += float(GRAVITY) / 4self.velocity = self.move_and_slide(self.velocity, UP_VECTOR) # Обновить self.velocity из текущего состоянияfunc check_states() -> void:if self.is_on_floor():self.current_state = States.ON_FLOORis_double_jump = trueelif self.is_on_wall():self.current_state = States.ON_WALLis_double_jump = trueelif self.is_on_floor() and self.is_on_wall():self.current_state = States.ON_WALLfunc fall() -> void:self.velocity.y += GRAVITYfunc update_controls(): # Обновляем информации о нажатиях на кнопки "влево" и "вправо" if !is_wall_jump: # Если не прыгаем от стены сейчас - обновляемself.left_pressed = Input.get_action_strength("ui_left")self.right_pressed = Input.get_action_strength("ui_right")func control_character() -> void:# Об этом я уже рассказывалcheck_states()# Проверить состоянияupdate_controls()# Обновить данные о нажатии на стрелки влево и вправоself.interact_with()# Взаимодействие с другими объектами+match current_state:States.ON_WALL:self.climb()self.move()if !climbing:self.jump()self.fall()self.wall_jump()States.IN_AIR:self.jump()self.move()self.fall()States.ON_FLOOR:self.jump()self.move()func climb():if (walls[0] or walls[2]):# Если стена слева или справа - self.climbing = нажато ли событие "ui_climb". Тут вам самим нужно создать событие self.climbing = Input.is_action_pressed("ui_climb")else:# Иначе просто не карабкаемсяself.climbing = falsefunc climb_up() -> void:# Ползем вверх по стенеself.velocity.y = (CLIMB_SPEED)func climb_down() -> void:# ползем вниз по стенеself.velocity.y = (-CLIMB_SPEED)func move() -> void: # Перемещение. Я его доделал, чтобы по левой стенеself.direction = self.right_pressed - self.left_pressedif (self.climbing and !self.is_wall_jump):if self.walls[0]:# Если левая стенаif direction > 0:# Если движемся вправо - карабкаемся вверхclimb_up()elif direction < 0:# Иначе если движемся влево - спускаемся внизclimb_down()else:# Иначе никак не двигаемся по вертикалиself.velocity.y = 0elif self.walls[2]:# Почти то же самое что с движением по левой стене, только направления местами поменялif direction < 0:climb_up()elif direction > 0:climb_down()else:self.velocity.y = 0#else:# Я думал что это будет нужно, но видимо это осталось лишним#self.velocity.y = 0else: # Иначе если не карабкаемся по стене и от неё не прыгаем просто передвигаемсяself.velocity.x = self.direction * float(MOVE_SPEED) * (1 + (float(self.is_wall_jump) / 2))if !(climbing): # Анимацииif direction == 0:$AnimatedSprite.flip_h = (-self.prev_direction >= 0)$AnimatedSprite.play("idle")else:$AnimatedSprite.flip_h = direction < 0$AnimatedSprite.play("run")returnfunc jump() -> void: # Совершенно никаких изменений со второго выпуска в прыжкеif Input.is_action_just_pressed("ui_accept"):if is_on_floor():self.velocity.y = -JUMP_POWERif !is_on_floor() and is_double_jump:is_double_jump = falseself.velocity.y = -JUMP_POWERfunc wall_jump() -> void:if Input.is_action_just_pressed("ui_accept") and Input.is_action_pressed("ui_climb"):self.is_wall_jump = trueself.velocity.y = -JUMP_POWERif walls[0]:self.timer = 0.3self.timer_enabled = trueself.right_pressed = 1# Это приравнивание как я понял вынужденная мера из-за слишком простого механизма перемещенияyield(self, "timer_ended")# Подождать сигнал таймераself.right_pressed = Input.get_action_strength("ui_right") # Сбросить перемещение влево elif walls[2]:self.timer = 0.3self.timer_enabled = trueself.left_pressed = 1# Это приравнивание как я понял вынужденная мера из-за слишком простого механизма перемещенияyield(self, "timer_ended")self.left_pressed = Input.get_action_strength("ui_left")# Сбросить перемещение вправо self.is_wall_jump = false # Перестаём прыгать от стеныfunc interact_with() -> void: # Метод взаимодействияif Input.is_action_pressed("ui_use"):# Если нужная кнопка нажатаvar coll: Object = self.ray_cast.get_collider()# Определяем что столкнулосьif coll:# И если это не nullif coll.has_method("open"):# Проверяем, дверь это или объект взаимодействияuse_key(coll)elif coll.has_method("interact"):use_object(coll)func use_object(collider: Object) -> void:# Используй объектcollider.interact(self)# В дополнительном уроке так активировались порталыfunc use_key(collider: Object) -> void:# Метод открывает все двери.if self.keys > 0:# Если ключи естьcollider.open()# Открой объектself.keys -= 1# И убери ключ из инвентаря за ненадобностьюfunc key_picked_up():self.keys += 1func _on_WallRight_body_entered(_body):# Я уже рассказывал об этих определителях стен.if (_body.name != self.name):# Если с ними что-то столкнулось - они изменят соответствующуюself.walls[2] = true# переменную в массиве walls на true или false.func _on_WallRight_body_exited(_body):# self.walls[2] = false#func _on_WallLeft_body_entered(_body):#if (_body.name != self.name):#self.walls[0] = true#func _on_WallLeft_body_exited(_body):#self.walls[0] = false#func dead():# $Particles2D.emitting = true # Если вы добавили частицы крови - можете убрать комментарийLevelMgr.goto_scene("res://scenes/dead_screen/dead_screen.tscn") # Переход на экран смерти. Сделать чтобы отлет частиц был виден пока не придумал какfunc pause_opened(): # Открывает окно паузыif Input.is_action_just_pressed("ui_cancel"): # Если соответствующая кнопка нажата$PositionResetter/WindowDialog.popup_centered()

Заключение

На данный момент это самый актуальный код персонажа, который я только создал. Из-за того, что код полностью готов, мне нечего добавить к нему отдельно. А так как я вынес уроки по ловушкам в отдельный цикл, то мне также нечего сказать про примеры использования системы взаимодействий. Также мне стало интересно, что вы предпочли бы узнать в следующей части и представил ниже опрос составленный из пришедших мне в голову идей для механик. Спасибо за прочтение и до следующих публикаций.
Источник: habr.com
К списку статей
Опубликовано: 20.10.2020 18:21:10
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