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

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
20-Окт-2020 20:31

Здравствуйте снова. В этом выпуске я расскажу о том, как исправил механику карабканья, показанную во втором выпуске, покажу механику взаимодействия, для создания интерактива. Это по-прежнему будет доработка персонажа, так что окружающий мир будет подвергнут минимальным изменениям, но главный герой будет очень сильно улучшен. Правда до дерева навыков ещё далеко, поэтому оставайтесь на связи и я покажу как можно реализовать всё, что придёт нам в голову.Предыдущие статьи:
Улучшение системы карабканья из второго выпуска и другоеВ общем покажу весь код своего персонажа и постараюсь прокомментировать его наиболее понятно.
# В этот раз будет очень много кода, потому что я не представляю себе все эти системы по отдельности.
extends KinematicBody2D
signal timer_ended # Сигнал о отключении таймера в _process
const 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 = 0
var 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_cast
  ray_cast.add_exception($WallRight)
  ray_cast.add_exception(self)
func _process(_delta: float) -> void: # метод _process
  if timer > 0 or timer_enabled:
    timer -= _delta    # Уменьшаем таймер на _delta
  if timer <= 0 and timer_enabled:
    timer_enabled = false
    timer = 0    # Сбрасываем значение и выключаем таймер
    emit_signal("timer_ended") # Испускаем сигнал таймера.
  if self.direction != 0:
    self.ray_cast.cast_to *= -1
    self.prev_direction = self.direction  # обновляем предыдущее направление если текущее не равно 0
func _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 += GRAVITY
    else:        # Иначе падаем в 4 раза медленнее
      self.velocity.y += float(GRAVITY) / 4
  self.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_FLOOR
    is_double_jump = true
  elif self.is_on_wall():
    self.current_state = States.ON_WALL
    is_double_jump = true
  elif self.is_on_floor() and self.is_on_wall():
    self.current_state = States.ON_WALL
func fall() -> void:
  self.velocity.y += GRAVITY
func 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 = false
func 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_pressed
  if (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 = 0
    elif self.walls[2]:  # Почти то же самое что с движением по левой стене, только направления местами поменял
      if direction < 0:
        climb_up()
      elif direction > 0:
        climb_down()
      else:
        self.velocity.y = 0
#    else:  # Я думал что это будет нужно, но видимо это осталось лишним
#      self.velocity.y = 0
  else: # Иначе если не карабкаемся по стене и от неё не прыгаем просто передвигаемся
    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")
  return
func jump() -> void: # Совершенно никаких изменений со второго выпуска в прыжке
  if Input.is_action_just_pressed("ui_accept"):
    if is_on_floor():
      self.velocity.y = -JUMP_POWER
    if !is_on_floor() and is_double_jump:
      is_double_jump = false
      self.velocity.y = -JUMP_POWER
func wall_jump() -> void:
  if Input.is_action_just_pressed("ui_accept") and Input.is_action_pressed("ui_climb"):
    self.is_wall_jump = true
    self.velocity.y = -JUMP_POWER
    if walls[0]:
      self.timer = 0.3
      self.timer_enabled = true
      self.right_pressed = 1    # Это приравнивание как я понял вынужденная мера из-за слишком простого механизма перемещения
      yield(self, "timer_ended")  # Подождать сигнал таймера
      self.right_pressed = Input.get_action_strength("ui_right")
      # Сбросить перемещение влево
    elif walls[2]:
      self.timer = 0.3
      self.timer_enabled = true
      self.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:                # И если это не null
      if 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 += 1
func _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
===========

Похожие новости: Теги для поиска: #_godot, #_razrabotka_igr (Разработка игр), #_gdscript, #_programmirovanie (программирование), #_godot, #_razrabotka_igr (
Разработка игр
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 09-Май 20:21
Часовой пояс: UTC + 5