Серия «геймдев. Первые шаги.»

4

Учебный проект № 2 «Камень, ножницы, бумага» в Godot

Серия геймдев. Первые шаги.

Вот что получилось:

Ниже я рассказываю, как я это делал.

Дисклеймер.
Сделал пост после того как все получилось. Формат я еще не освоил, пробую разное, еще не понял как лучше.


1. Начало: создаём проект

Я запустил Godot и нажал New Project. Назвал его «rock-paper-scissors», выбрал удобную папку и кликнул Create & Edit.


2. Подготавливаю ресурсы

Мне понадобились три картинки (камень, ножницы, бумага) и два звука — для победы и поражения. Я нашёл в интернете простые иконки в формате PNG с прозрачностью и два коротких звуковых файла WAV. Всё сложил в папку assets внутри папки проекта. В Godot эта папка отображается в FileSystem.

Содержимое папки проекта (уже на момент завершения). Проект крохотный, поэтому все в одном. Выделил картинки о которых идет речь выше.

Содержимое папки проекта (уже на момент завершения). Проект крохотный, поэтому все в одном. Выделил картинки о которых идет речь выше.


3. Создаю главную сцену

Я нажал Scene → New Scene и добавил корневой узел Control. Это будет основа интерфейса.

Теперь нужны кнопки. Я кликнул правой кнопкой по узлу Control → Add Child Node → выбрал Button. Назвал её b_rock. В инспекторе у кнопки нашёл свойство Text и ввёл «Камень». Точно так же создал ещё две кнопки: b_paper с текстом «Бумага» и b_scissors с текстом «Ножницы». Расставил их внизу экрана.

Дерево сцены с узлами (уже на момент завершения) Control, b_rock, b_paper, b_scissors. По иконкам можно различить класс объекта.

Дерево сцены с узлами (уже на момент завершения) Control, b_rock, b_paper, b_scissors. По иконкам можно различить класс объекта.

*если кому надо, можно легко открыть документацию объекта, в этом плане программа балует.

Как открыть документацию объекта (нажатие ПКМ).

Как открыть документацию объекта (нажатие ПКМ).


4. Добавляю места для картинок

Мне нужно показать, что выбрал игрок, а что — компьютер. Добавил два узла TextureRect (Add Child Node → TextureRect). Один назвал PlayerTexture, другой — ComputerTexture. Разместил их слева и справа над кнопками.

В Инспектор кнопки под Icon я перетянул мои картинки зажав мышкой.

В Инспектор кнопки под Icon я перетянул мои картинки зажав мышкой.


5. Создаю текстовые метки

Для слов считалки и результата нужны два Label. Добавил их: CountdownLabel (расположил сверху) и ResultLabel (чуть ниже). Пока они пустые, но это нормально (на скрине выше вы их не видите, но они суслик).


6. Таймер для анимации

Мне нужен таймер, который будет каждые полсекунды менять слово в считалке. Добавил узел Timer (Add Child Node → Timer), назвал CountdownTimer. В инспекторе установил Wait Time = 0.5 и One Shot = false (чтобы срабатывал многократно).

Инспектор таймера

Инспектор таймера


7. Звуки победы и поражения

Добавил два AudioStreamPlayer (Add Child Node → AudioStreamPlayer). Назвал их sound_win и sound_lose. В инспекторе у каждого загрузил соответствующий звуковой файл в поле Stream. Нашел просто системные звуки в винде.

Присвоил файлы перетащив в инспектор из файловой системы.

Присвоил файлы перетащив в инспектор из файловой системы.


8. Пишу скрипт

Теперь самое интересное — код. Я выделил корневой узел Control и нажал Attach Script. Оставил настройки по умолчанию и нажал Create. Открылся редактор кода.

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

Как открыть листинг скрипта.

Как открыть листинг скрипта.

Листинг стр.1-27

Листинг стр.1-27

Листинг стр.27-49

Листинг стр.27-49

Листинг стр.49-61

Листинг стр.49-61

Листинг стр.61-91

Листинг стр.61-91

Весь код целиком (если кто научит вставлять с сохранением форматирования, буду благодарен):

extends Control

enum Choice {ROCK, PAPER, SCISSORS} # исправил опечатку SCISSARS -> SCISSORS

@onready var computer_chose_pik = $Sprite2D # если хочешь оставить для фона или чего-то ещё

@onready var sound_win = $sound_win

@onready var sound_lus = $sound_lus

@export var countdown_label: Label

@export var result_label: Label

@export var player_texture: TextureRect

@export var computer_texture: TextureRect

var rock_texture = preload("res://rock.png")

var paper_texture = preload("res://paper.png")

var scissors_texture = preload("res://scissors.png")

var countdown_words = ["камень", "ножницы", "бумага", "раз", "два", "три"]

var current_word_index = 0

var is_counting = false

var player_choice = -1

var computer_choice = -1

func _ready() -> void:

randomize() # для случайности

# Запуск считалки

func start_countdown(p_choice: int, c_choice: int):

result_label.text = ""

computer_texture.texture = null

if is_counting:

return

is_counting = true

player_choice = p_choice

computer_choice = c_choice

current_word_index = 0

countdown_label.text = countdown_words[current_word_index]

$CountdownTimer.start()

# Сигнал таймера (имя должно быть таким, как создалось при подключении)

func _on_countdown_timer_timeout():

current_word_index += 1

if current_word_index < countdown_words.size():

countdown_label.text = countdown_words[current_word_index]

else:

$CountdownTimer.stop()

is_counting = false

show_result()

# Установка текстуры для TextureRect

func set_choice_texture(texture_rect: TextureRect, choice: int):

match choice:

0:

texture_rect.texture = rock_texture

1:

texture_rect.texture = paper_texture

2:

texture_rect.texture = scissors_texture

# Показ результата после считалки

func show_result():

# Устанавливаем картинки

set_choice_texture(player_texture, player_choice)

set_choice_texture(computer_texture, computer_choice)

# Определяем победителя и выводим текст

if player_choice == computer_choice:

result_label.text = "Ничья!"

elif (player_choice == 0 and computer_choice == 2) or \

(player_choice == 2 and computer_choice == 1) or \

(player_choice == 1 and computer_choice == 0):

result_label.text = "Вы выиграли!"

sound_win.play() # звук победы

else:

result_label.text = "Вы проиграли!"

sound_lus.play() # звук поражения

# Обработчики кнопок (теперь запускают считалку)

func _on_b_rock_pressed() -> void:

computer_choice = randi_range(0, 2) # случайный выбор компьютера

start_countdown(Choice.ROCK, computer_choice)

func _on_b_paper_pressed() -> void:

computer_choice = randi_range(0, 2)

start_countdown(Choice.PAPER, computer_choice)

func _on_b_scissors_pressed() -> void:

computer_choice = randi_range(0, 2)

start_countdown(Choice.SCISSORS, computer_choice)


9. Подключаю сигналы

Теперь нужно связать кнопки и таймер с функциями в скрипте.

Кнопки:

Я выбрал в дереве сцены кнопку b_rock, перешёл во вкладку Node (рядом с Inspector), нашёл сигнал pressed() и нажал Connect. В появившемся окне оставил цель — Control, нажал Connect. Так я подключил сигнал к функции _on_b_rock_pressed. То же самое сделал для b_paper и b_scissors.

Функция сразу встает в скрипт главного нода.

Подключение сигнала к кнопкам (это делалось немного ранее, я сразу подключал и тестировал, переделывал их срабатывание, прошу прощения за рванное повествование)

Подключение сигнала к кнопкам (это делалось немного ранее, я сразу подключал и тестировал, переделывал их срабатывание, прошу прощения за рванное повествование)

Таймер:

Выбрал узел CountdownTimer, во вкладке Node нашёл сигнал timeout() и подключил его к Control. В скрипте автоматически появляется функция _on_countdown_timer_timeout(), когда вы ее добавляете

Сигнал таймера.

Сигнал таймера.


10. Связываю экспортированные переменные

В скрипте я объявил @export var countdown_label, result_label, player_texture, computer_texture. Теперь нужно указать, каким узлам они соответствуют.

Я выделил корневой узел Control и в инспекторе увидел поля с этими именами. Перетащил мышкой:

  • CountdownLabel → в поле Countdown Label

  • ResultLabel → в поле Result Label

  • spr_computer_chose → в поле Player Texture и в поле Computer Texture


11. Проверяю пути к ресурсам

В коде я указал пути "res://assets/rock.png" и т.д. Убедился, что файлы лежат именно там. Звуки уже загружены в узлы sound_win и sound_lose, так что в коде просто вызываю play().

Вызов <!--noindex--><a href="https://pikabu.ru/story/uchebnyiy_proekt__2_kamen_nozhnitsyi_bumaga_v_godot_13827264?u=http%3A%2F%2Fsound_lus.play&t=sound_lus.play&h=3314efdcb3a28dd2ec6df23f220479a37326ff62" title="http://sound_lus.play" target="_blank" rel="nofollow noopener">sound_lus.play</a><!--/noindex-->() в коде.

Вызов sound_lus.play() в коде.


12. Запускаю и наслаждаюсь

Нажал F5 — игра запустилась. Нажимаю на кнопку «Камень» — появляется считалка, потом картинка камня у меня и случайная у компьютера, и результат. Звуки работают. Идеально!

Игровой процесс

Игровой процесс


Что я понял и что можно улучшить

Не бояться экспериментировать. Я получил именно то, что хотел: анимированную считалку, картинки, звуки.

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

Удачи в разработке!

Показать полностью 16
5

Учебный проект "Орел и решка" в Godot

Серия геймдев. Первые шаги.

Всем привет! Решил разобраться в основах Godot и на коленке собрал классическую монетку. Хочу показать процесс эволюции проекта: от сухих цифр в консоли до полноценной анимации со звуком.

Шаг 1: Логика на кончиках пальцев (Текстовый вывод)

Первым делом нужно было понять, как заставить движок выбирать случайное число. В Godot за это отвечает функция randi().

Логика была простая:

  1. Генерируем случайное число (0 или 1).

  2. Если 0 — пишем «Орел», если 1 — «Решка».

Для теста я просто выводил результат в консоль через print(). На этом этапе важно было убедиться, что рандом работает честно.


Шаг 2: Добавляем визуал (Кнопка и картинки)

Сидеть в консоли скучно, пора переносить это в интерфейс. Я создал узел Control, добавил Button для клика и TextureRect для отображения монетки.

Что изменилось в коде: Вместо текста я начал подставлять текстуры. Подключил два спрайта: coin_heads.png и coin_tails.png.

func _on_button_pressed():
var random_number = randi() % 2
if random_number == 0:
coin_texture_rect.texture = heads_texture
else:
coin_texture_rect.texture = tails_texture

Теперь при нажатии на кнопку картинка мгновенно менялась. Но выглядело это слишком резко — магии не хватало.


Шаг 3: Оживляем проект (Анимация и звук)

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

Идея такая:

  1. Создаем массив из 4 кадров вращения монетки.

  2. При нажатии на кнопку запускаем Timer.

  3. По сигналу таймера timeout меняем кадры по кругу.

  4. После нескольких полных циклов останавливаемся и показываем финальный результат.

Финальный код скрипта:

Листинг 1/3

Листинг 1/3

Листинг 2/3

Листинг 2/3

Листинг 3/3

Листинг 3/3

Итог

Добавил узел AudioStreamPlayer для звука клика — и проект сразу ощущается как готовая мини-игра.

Что я вынес для себя:

  • Timer — отличный инструмент не только для геймплея, но и для простых анимаций.

  • Флаг is_animating критически важен, чтобы игрок не "сломал" анимацию повторными нажатиями.

Для первого микро-проекта на Godot результатом доволен. Дальше — больше!

Видео первый раз писал, сорян за шакалов.

Показать полностью 3 1
2

Тут я буду вести записи отчёты по моей деятельности в геймдеве

Серия геймдев. Первые шаги.

Это мое хобби и утешение.

Далее март, апрель я буду каждую неделю выдавать отчёт что я сделал, сколько помидорок или груш "съел".

Главная задача: сделать игру с геймплеем на 3 часа на godot.

1. Разобраться в движке, сделать 4 учебных проекта:

- Орёл решка;

- камень ножницы бумага;

- повторить проект с ютуб.

2. Написать дизайн документ.

3. Сделать демо с механиками без графики.

4. Когда будет демо готово к испытаниям, придумать что делать дальше. Найти тестировщиков, визуальный стиль, музыку и т.д.

Показать полностью
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества