Сетевой чат в Unity: Часть 3 — Звуки и продвинутые функции

от автора

Третья часть из серии статей на тему создания сетевого чата в Unity с использованием Netcode for GameObjects.

Привет!

В первых двух частях мы создали сетевой чат с командами, эмодзи и форматированием. Теперь пришло время добавить финальные штрихи — звуковые уведомления, приватные сообщения и другие продвинутые функции.

Представь, что мы превращаем твою простую рацию из первой части в настоящий командный центр космического корабля!


Что нужно знать перед началом

Важно: Эта часть требует завершенный код из первой части и второй части!

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


Звуковые уведомления: Слышим новые сообщения

Когда приходит новое сообщение, хорошо бы услышать звуковой сигнал. Это как звонок телефона — ты сразу понимаешь, что кто-то написал тебе.

Добавляем звуки к существующему ChatSystem

В твоем скрипте ChatSystem.cs из предыдущих частей добавь эти переменные после всех существующих переменных из первой и второй части:

Напоминание: К этому моменту у тебя уже должны быть все переменные из первых двух частей:

  • Из 1-й части: messageInput, sendButton, chatScrollRect, messagePrefab, messageContainer, maxMessages, messageObjects

  • Из 2-й части: все переменные для команд и функции ProcessEmojis, ProcessFormatting, CreateSystemMessage

[Header("Звуки")] public AudioSource audioSource; public AudioClip messageSound; public AudioClip systemSound; public AudioClip privateMessageSound; 

Теперь создай функцию для воспроизведения звуков:

private void PlayMessageSound(bool isSystemMessage = false, bool isPrivateMessage = false) {     if (audioSource != null)     {         AudioClip clipToPlay = null;                  if (isPrivateMessage)         {             clipToPlay = privateMessageSound;         }         else if (isSystemMessage)         {             clipToPlay = systemSound;         }         else         {             clipToPlay = messageSound;         }                  if (clipToPlay != null)         {             audioSource.PlayOneShot(clipToPlay);         }     } } 

Что происходит в этом коде?

  1. AudioSource — компонент Unity для воспроизведения звуков

  2. messageSound — звук для обычных сообщений

  3. systemSound — звук для системных сообщений

  4. privateMessageSound — звук для приватных сообщений

  5. PlayMessageSound — функция, которая выбирает правильный звук и проигрывает его


Приватные сообщения: Личные разговоры

Иногда игроки хотят поговорить наедине, не мешая остальным. Для этого создадим систему приватных сообщений.

Добавляем приватные сообщения

private void ProcessPrivateMessage(string message) {     // Формат: /w Игрок1 Привет!     string[] parts = message.Split(' ');          if (parts.Length < 3)     {         CreateSystemMessage("Использование: /w [игрок] [сообщение]");         return;     }          string targetPlayerName = parts[1];     string privateMessage = string.Join(" ", parts, 2, parts.Length - 2);          // Находим ID целевого игрока     ulong targetPlayerId = FindPlayerByName(targetPlayerName);          if (targetPlayerId != ulong.MaxValue)     {         // Обрабатываем эмодзи и форматирование как в обычных сообщениях (из 2-й части)         privateMessage = ProcessEmojis(privateMessage);         privateMessage = ProcessFormatting(privateMessage);                  SendPrivateMessageServerRpc(privateMessage, targetPlayerId);     }     else     {         CreateSystemMessage($"Игрок '{targetPlayerName}' не найден!");     } }  private ulong FindPlayerByName(string playerName) {     // Проверяем, что NetworkManager существует     if (NetworkManager.Singleton == null)     {         return ulong.MaxValue;     }      foreach (var client in NetworkManager.Singleton.ConnectedClients)     {         string currentPlayerName = client.Key == NetworkManager.Singleton.LocalClientId ? "Ты" : $"Игрок {client.Key}";         if (currentPlayerName.ToLower() == playerName.ToLower())         {             return client.Key;         }     }     return ulong.MaxValue; // Игрок не найден }  [ServerRpc(RequireOwnership = false)] private void SendPrivateMessageServerRpc(string message, ulong targetPlayerId, ServerRpcParams serverRpcParams = default) {     var senderId = serverRpcParams.Receive.SenderClientId;          // Отправляем сообщение только отправителю     ClientRpcParams senderParams = new ClientRpcParams     {         Send = new ClientRpcSendParams         {             TargetClientIds = new ulong[] { senderId }         }     };     ReceivePrivateMessageClientRpc(message, senderId, targetPlayerId, true, senderParams);          // Отправляем сообщение только получателю (если это не сам отправитель)     if (targetPlayerId != senderId)     {         ClientRpcParams targetParams = new ClientRpcParams         {             Send = new ClientRpcSendParams             {                 TargetClientIds = new ulong[] { targetPlayerId }             }         };         ReceivePrivateMessageClientRpc(message, senderId, targetPlayerId, false, targetParams);     } }  [ClientRpc] private void ReceivePrivateMessageClientRpc(string message, ulong senderId, ulong targetPlayerId, bool isSender, ClientRpcParams clientRpcParams = default) {     CreatePrivateMessage(message, senderId, targetPlayerId, isSender); }  private void CreatePrivateMessage(string message, ulong senderId, ulong targetPlayerId, bool isSender) {     // Проверяем, что шаблон сообщения существует     if (messagePrefab == null)     {         Debug.LogError("MessagePrefab не назначен!");         return;     }          // Проверяем, что контейнер существует     if (messageContainer == null)     {         Debug.LogError("MessageContainer не назначен!");         return;     }          GameObject messageObj = Instantiate(messagePrefab, messageContainer);     TMP_Text messageText = messageObj.GetComponentInChildren<TMP_Text>();          // Проверяем, что текстовый компонент найден     if (messageText == null)     {         Debug.LogError("TMP_Text компонент не найден в MessagePrefab!");         Destroy(messageObj);         return;     }          // Проверяем, что NetworkManager существует     if (NetworkManager.Singleton == null)     {         Debug.LogError("NetworkManager.Singleton is null!");         Destroy(messageObj);         return;     }          string senderName = senderId == NetworkManager.Singleton.LocalClientId ? "Ты" : $"Игрок {senderId}";     string targetName = targetPlayerId == NetworkManager.Singleton.LocalClientId ? "тебе" : $"Игроку {targetPlayerId}";          if (isSender)     {         messageText.text = $"💬 [Ты → {targetName}]: {message}";         messageText.color = Color.cyan; // Сообщения от тебя - голубые     }     else     {         messageText.text = $"💬 [{senderName} → тебе]: {message}";         messageText.color = Color.magenta; // Сообщения к тебе - розовые     }          messageObjects.Add(messageObj);          if (messageObjects.Count > maxMessages)     {         GameObject oldMessage = messageObjects[0];         messageObjects.RemoveAt(0);         Destroy(oldMessage);     }          Canvas.ForceUpdateCanvases();     chatScrollRect.verticalNormalizedPosition = 0f;          // Играем звук приватного сообщения     PlayMessageSound(false, true); } 

Что происходит в этом коде?

  1. ProcessPrivateMessage — обрабатывает команду /w игрок сообщение

  2. FindPlayerByName — находит ID игрока по имени (ищет «Ты» или «Игрок X»)

  3. SendPrivateMessageServerRpc — отправляет приватное сообщение только нужным клиентам

  4. ReceivePrivateMessageClientRpc — получает приватное сообщение с правильной адресацией

  5. CreatePrivateMessage — создает красивое приватное сообщение с разными цветами

Примеры использования:

  • /w Ты Привет! — отправить сообщение самому себе

  • /w Игрок 2 Как дела? — отправить сообщение игроку с ID 2

Приватные сообщения выделяются цветом: голубые — от тебя, розовые — к тебе.


Интеграция звуков с существующими функциями

У тебя уже есть функции ProcessEmojis, ProcessFormatting и CreateSystemMessage из второй части. Теперь нужно просто обновить функцию CreateSystemMessage, чтобы она воспроизводила звук.

Найди свою функцию CreateSystemMessage из второй части и добавь в конце (перед закрывающей скобкой):

// Добавить в конец существующей функции CreateSystemMessage PlayMessageSound(true, false); 

Также обнови свою функцию CreateMessageInChat из первой части, добавив в конце:

// Добавить в конец существующей функции CreateMessageInChat // Играем звук только если сообщение не от нас самих if (senderId != NetworkManager.Singleton.LocalClientId) {     PlayMessageSound(false, false); } 

Обновляем обработку команд

Теперь нужно добавить обработку приватных сообщений в твою существующую функцию ProcessCommand из второй части.

Найди свою функцию ProcessCommand и добавь новую команду /w перед существующей проверкой if (command.StartsWith("help")):

// Добавить в ProcessCommand перед if (command.StartsWith("help")): if (command.StartsWith("w ") || command.StartsWith("whisper ")) {     ProcessPrivateMessage(commandMessage); // Передаем оригинальную команду с "/" } else if (command.StartsWith("help")) // не меняй существующий if - просто добавь else {     ShowHelpMessage(); } // ... остальные команды остаются как есть (else if) 

И обнови свою существующую функцию ShowHelpMessage из второй части, добавив строку о приватных сообщениях:

// Добавить в твою существующую функцию ShowHelpMessage эту строку: "/w [игрок] [сообщение] - приватное сообщение\n" + 

Просто вставь эту строку в список команд в нужном месте.

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


Важное замечание о существующих функциях

Не нужно ничего менять в функции SendMessage — она уже правильно настроена во второй части.

Во второй части мы обновили SendMessage для обработки команд до отправки на сервер. А функции SendMessageServerRpc, ReceiveMessageClientRpc и CreateMessageInChat из первой части остались без изменений — они просто передают и отображают уже обработанное сообщение.

Важно: Эмодзи и форматирование обрабатываются в SendMessage (во 2-й части), поэтому CreateMessageInChat получает уже готовое сообщение.


Дополнительные продвинутые функции

1. Автоответчик

Добавь эти переменные в начало ChatSystem.cs:

[Header("Автоответчик")] public bool autoReplyEnabled = false; public string autoReplyMessage = "Сейчас не могу ответить, играю!"; 

Создай функцию для переключения автоответчика:

private void ToggleAutoReply() {     autoReplyEnabled = !autoReplyEnabled;     string status = autoReplyEnabled ? "включен" : "выключен";     CreateSystemMessage($"Автоответчик {status}"); } 

И добавь команду в существующую ProcessCommand после всех остальных команд но перед финальной else:

// Добавить в ProcessCommand после команды /joke, но перед финальной else: else if (command.StartsWith("autoreply")) {     ToggleAutoReply(); } 

2. Фильтр слов

Добавь переменные для фильтрации:

[Header("Фильтр")] public bool filterEnabled = true; public string[] badWords = { "плохое", "слово", "спам" }; 

Создай функцию фильтрации (можешь использовать ее в SendMessage перед отправкой):

private string FilterMessage(string message) {     if (!filterEnabled) return message;          string filteredMessage = message;     foreach (string badWord in badWords)     {         string replacement = new string('*', badWord.Length);         filteredMessage = filteredMessage.Replace(badWord, replacement);     }          return filteredMessage; } 

3. Сохранение истории чата

private void SaveChatHistory() {     string history = "";     foreach (GameObject messageObj in messageObjects)     {         TMP_Text messageText = messageObj.GetComponentInChildren<TMP_Text>();         if (messageText != null)         {             history += messageText.text + "\n";         }     }          try     {         string fileName = $"ChatHistory_{System.DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt";         System.IO.File.WriteAllText(fileName, history);         CreateSystemMessage($"История чата сохранена в файл: {fileName}");     }     catch (System.Exception e)     {         CreateSystemMessage($"Ошибка сохранения: {e.Message}");     } } 

Добавь команду в ProcessCommand после всех остальных команд но перед финальной else:

// Добавить в ProcessCommand после команды /autoreply, но перед финальной else: else if (command.StartsWith("save")) {     SaveChatHistory(); } 

Как настроить звуки в Unity

  1. Создай AudioSource:

    • Добавь компонент AudioSource к объекту с ChatSystem

    • Перетащи его в поле audioSource

  2. Добавь звуковые файлы:

    • Импортируй звуковые файлы (.wav, .mp3) в папку Assets

    • Перетащи их в соответствующие поля: messageSound, systemSound, privateMessageSound

  3. Настрой громкость:

    • В компоненте AudioSource установи подходящую громкость

    • Проверь, что звуки не слишком громкие


Полный список функций чата

Теперь твой чат поддерживает:

Основные функции:

  • Отправка и получение сообщений

  • Система команд

  • Эмодзи и форматирование

  • Звуковые уведомления

Команды:

  • /help — справка (из 2-й части)

  • /w [игрок] [сообщение] — приватное сообщение (новая!)

  • /time — время (из 2-й части)

  • /players — список игроков (из 2-й части)

  • /roll — бросить кости (из 2-й части)

  • /joke — шутка (из 2-й части)

  • /color [цвет] — сменить цвет (из 2-й части)

  • /autoreply — автоответчик (новая!)

  • /save — сохранить историю (новая!)

Эмодзи: (из 2-й части)

  • :) 😊 :D 😄 <3 ❤️ :fire: 🔥 и многие другие

Форматирование: (из 2-й части)

  • **жирный** *курсив* __подчеркнутый__


Заключение

Поздравляю! Теперь у тебя есть сетевой чат с множеством функций:

  • Базовый функционал (из 1-й части) — отправка сообщений

  • Система команд (из 2-й части) — интерактивность

  • Эмодзи и форматирование (из 2-й части) — красота

  • Приватные сообщения (новое!) — личное общение

  • Звуковые уведомления (новое!) — удобство

  • Дополнительные функции (новое!) — автоответчик, фильтр, сохранение

Этот чат можно использовать в любых сетевых играх Unity. Игроки смогут общаться, координировать действия, выражать эмоции и даже вести личные разговоры.


Что дальше?

Теперь у тебя есть сетевой чат! Вот несколько идей для дальнейшего развития:

  1. Система ролей — админы, модераторы, обычные игроки

  2. Голосовой чат — добавить поддержку голосовых сообщений

  3. Каналы — разные чаты для разных команд

  4. История сообщений — сохранение между сессиями

  5. Блокировка игроков — система игнора

Главное — твой чат работает, игроки довольны, а ты научился создавать настоящие сетевые системы!

Удачи в создании твоих сетевых игр! Общение между игроками делает любую игру намного интереснее и веселее.


Краткое резюме серии

Часть 1: Основы — базовая отправка и получение сообщений
Часть 2: Команды, эмодзи, форматирование, система смены цветов
Часть 3: Звуки, приватные сообщения, дополнительные функции


ссылка на оригинал статьи https://habr.com/ru/articles/935080/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *