共计 4127 个字符,预计需要花费 11 分钟才能阅读完成。
技术背景
ChatGPT 在游戏开发中能大幅提升交互体验,以下是典型应用场景:

- 智能 NPC 对话:为角色生成动态回应,告别固定台词树
- 玩家支持系统:自动解答游戏机制问题,降低客服压力
- 剧情生成:根据玩家选择实时衍生分支故事线
- 语言学习类游戏:构建自然语言练习环境
前置准备
- API 密钥申请:
- 登录 OpenAI 平台(https://platform.openai.com)
- 在 API Keys 页面点击 ”Create new secret key”
-
建议设置使用限额(免费试用版有 18 美元额度)
-
费用须知:
- gpt-3.5-turbo 模型每 1000 tokens 约 $0.002
- 1 个中文汉字≈1.33 个 tokens
- 可在 Billing 页面设置用量警报
核心实现
1. 构建网络请求
IEnumerator SendChatRequest(string prompt) {
string apiUrl = "https://api.openai.com/v1/chat/completions";
using(UnityWebRequest request = new UnityWebRequest(apiUrl, "POST")) {
// 设置请求头
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("Authorization", "Bearer YOUR_API_KEY");
// 构造请求体
var requestBody = new {
model = "gpt-3.5-turbo",
messages = new[] {new { role = "user", content = prompt}
},
temperature = 0.7
};
string jsonBody = JsonUtility.ToJson(requestBody);
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
yield return request.SendWebRequest();
if(request.result == UnityWebRequest.Result.Success) {ProcessResponse(request.downloadHandler.text);
} else {Debug.LogError($"请求失败: {request.error}");
}
}
}
2. 流式响应处理
对于长回复,建议使用 Server-Sent Events(SSE):
IEnumerator HandleStreamingResponse(UnityWebRequest request) {while(!request.isDone) {if(request.downloadedBytes > 0) {
string newData = request.downloadHandler.text;
// 提取增量内容
var delta = ParseDeltaContent(newData);
UpdateUI(delta);
}
yield return null;
}
}
完整代码示例
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
public class ChatGPTManager : MonoBehaviour {[SerializeField] string apiKey;
[SerializeField] float timeout = 10f;
public void AskGPT(string question) {StartCoroutine(SendRequestCoroutine(question));
}
IEnumerator SendRequestCoroutine(string prompt) {
string apiUrl = "https://api.openai.com/v1/chat/completions";
var requestBody = new {
model = "gpt-3.5-turbo",
messages = new[] {new { role = "system", content = "你是一个游戏中的 NPC"},
new {role = "user", content = prompt}
},
max_tokens = 150
};
string jsonBody = JsonUtility.ToJson(requestBody);
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);
using(UnityWebRequest request = new UnityWebRequest(apiUrl, "POST")) {request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("Authorization", $"Bearer {apiKey}");
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.timeout = (int)timeout;
float startTime = Time.time;
yield return request.SendWebRequest();
if(Time.time - startTime > timeout) {Debug.LogWarning("请求超时");
yield break;
}
switch(request.result) {
case UnityWebRequest.Result.Success:
var response = JsonUtility.FromJson<ChatGPTResponse>(request.downloadHandler.text);
Debug.Log(response.choices[0].message.content);
break;
case UnityWebRequest.Result.ConnectionError:
// 网络连接错误处理
break;
case UnityWebRequest.Result.ProtocolError:
// HTTP 错误处理
HandleHttpError(request.responseCode);
break;
}
}
}
void HandleHttpError(long responseCode) {switch(responseCode) {
case 401:
Debug.LogError("API 密钥无效");
break;
case 429:
Debug.LogWarning("请求过于频繁");
break;
case 503:
Debug.LogWarning("服务暂时不可用");
break;
}
}
}
[System.Serializable]
public class ChatGPTResponse {public Choice[] choices;
[System.Serializable]
public class Choice {public Message message;}
[System.Serializable]
public class Message {public string content;}
}
性能优化
- 请求频率控制:
- 使用
Time.deltaTime计算请求间隔 -
对非关键对话启用队列机制
-
缓存策略:
private Dictionary<string, string> responseCache = new Dictionary<string, string>(); string GetCachedResponse(string prompt) {if(responseCache.TryGetValue(prompt, out string cached)) {return cached;} return null; } -
线程优化:
- 使用
UniTask替代协程降低开销 - 复杂 JSON 解析放在后台线程
避坑指南
- 429 错误:遵守每分钟 3 次请求的限制(免费账户)
- 敏感信息:
- 不要硬编码 API 密钥
- 使用 Unity 的
PlayerPrefs加密存储 - 考虑使用后端中转服务
- 上下文管理:
List<Message> conversationHistory = new List<Message>(); void AddToHistory(string role, string content) { conversationHistory.Add(new Message { role = role, content = content }); // 保持合理的历史长度 if(conversationHistory.Count > 10) {conversationHistory.RemoveAt(0); } }
扩展思考
打字机效果实现
IEnumerator TypewriterEffect(string fullText, TextMeshProUGUI target) {
target.text = "";
foreach(char c in fullText) {
target.text += c;
yield return new WaitForSeconds(0.05f);
}
}
本地化处理
- 请求时指定语言参数:
{ "messages": [ { "role": "system", "content": "请用简体中文回答" } ] }
实践建议
尝试为对话系统添加以下功能:
1. 情绪分析(通过 prompt 指定角色性格)
2. 话题引导机制
3. 基于玩家选择的动态剧情生成
最后留个思考题:如何设计一个能记住玩家游戏进度的对话系统?可以考虑将会话 ID 与玩家存档关联,并在每次对话时传入关键剧情节点信息。
正文完
