Третья часть из серии статей на тему создания сетевого чата в 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); } } }
Что происходит в этом коде?
-
AudioSource— компонент Unity для воспроизведения звуков -
messageSound— звук для обычных сообщений -
systemSound— звук для системных сообщений -
privateMessageSound— звук для приватных сообщений -
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); }
Что происходит в этом коде?
-
ProcessPrivateMessage— обрабатывает команду/w игрок сообщение -
FindPlayerByName— находит ID игрока по имени (ищет «Ты» или «Игрок X») -
SendPrivateMessageServerRpc— отправляет приватное сообщение только нужным клиентам -
ReceivePrivateMessageClientRpc— получает приватное сообщение с правильной адресацией -
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
-
Создай AudioSource:
-
Добавь компонент
AudioSourceк объекту сChatSystem -
Перетащи его в поле
audioSource
-
-
Добавь звуковые файлы:
-
Импортируй звуковые файлы (.wav, .mp3) в папку Assets
-
Перетащи их в соответствующие поля:
messageSound,systemSound,privateMessageSound
-
-
Настрой громкость:
-
В компоненте
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: Звуки, приватные сообщения, дополнительные функции
ссылка на оригинал статьи https://habr.com/ru/articles/935080/
Добавить комментарий