feat: add event log panel, Chinese font support, and documentation

- Add EventLog.cs: scrollable event log panel showing game events
  - Color-coded entries for different event types
  - Toggle visibility, clear button, timestamps
  - Auto-scroll to newest entries

- Add Chinese font support (Source Han Sans SC)
  - SourceHanSansSC-Regular.otf font file
  - ChineseFontSetup.cs editor tool for TMP font asset generation
  - Configure as fallback font for TextMeshPro

- Fix particle system velocity curve warnings in WeatherEffects.cs
  - Ensure all velocity axes use consistent curve mode

- Add comprehensive README.md with project documentation
  - Architecture overview, features, tech stack
  - Quick start guide, Unity client structure
  - Communication protocol, development notes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
empty
2026-01-01 16:46:56 +08:00
parent 6c66764cce
commit a261eaa8ab
16 changed files with 21057 additions and 72 deletions

176
README.md Normal file
View File

@@ -0,0 +1,176 @@
# The Island - 荒岛生存模拟游戏
一个实时多人互动的荒岛生存模拟游戏,玩家可以通过命令与 AI 角色互动,帮助他们在荒岛上生存。
## 项目架构
```
the-island/
├── backend/ # Python FastAPI 后端服务
│ └── app/
│ ├── main.py # 应用入口
│ ├── server.py # WebSocket 服务器
│ ├── engine.py # 游戏引擎核心逻辑
│ ├── models.py # SQLAlchemy 数据模型
│ ├── schemas.py # Pydantic 消息模式
│ ├── llm.py # LLM 集成 (对话生成)
│ └── database.py # 数据库配置
├── frontend/ # Web 调试客户端
│ ├── app.js # JavaScript 客户端
│ └── debug_client.html # 调试页面
├── unity-client/ # Unity 6 游戏客户端
│ └── Assets/
│ ├── Scripts/ # C# 游戏脚本
│ ├── Fonts/ # 字体资源 (含中文支持)
│ └── Editor/ # 编辑器工具
└── island.db # SQLite 数据库
```
## 功能特性
### 游戏系统
- **生存机制**: 角色有 HP、能量、心情三大属性
- **昼夜循环**: 黎明 → 白天 → 黄昏 → 夜晚
- **天气系统**: 晴天、多云、雨天、暴风雨、炎热、雾天
- **社交系统**: 角色间自主社交互动
- **休闲模式**: 自动复活、降低难度
### 玩家命令
| 命令 | 格式 | 金币消耗 | 效果 |
|------|------|----------|------|
| feed | `feed <角色名>` | 10g | +20 能量, +5 HP |
| heal | `heal <角色名>` | 15g | +30 HP |
| talk | `talk <角色名> [话题]` | 0g | 与角色对话 |
| encourage | `encourage <角色名>` | 5g | +15 心情 |
| revive | `revive <角色名>` | 10g | 复活死亡角色 |
| check | `check` | 0g | 查看所有状态 |
| reset | `reset` | 0g | 重置游戏 |
### AI 角色
- **Jack** (勇敢) - 蓝色
- **Luna** (狡猾) - 粉色
- **Bob** (诚实) - 绿色
每个角色有独特性格,会根据性格做出不同反应和社交行为。
## 技术栈
### 后端
- **Python 3.11+**
- **FastAPI** - 异步 Web 框架
- **WebSocket** - 实时双向通信
- **SQLAlchemy** - ORM 数据持久化
- **SQLite** - 轻量级数据库
- **Anthropic Claude** - LLM 对话生成
### Unity 客户端
- **Unity 6 LTS** (6000.3.2f1)
- **TextMeshPro** - 高质量文本渲染
- **NativeWebSocket** - WebSocket 通信
- **2.5D 风格** - 精灵 + Billboard UI
## 快速开始
### 1. 启动后端服务
```bash
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```
### 2. 启动 Unity 客户端
1. 使用 Unity 6 打开 `unity-client` 文件夹
2. 打开 `Assets/Scenes/main.unity`
3. 点击 Play 运行游戏
### 3. Web 调试客户端 (可选)
在浏览器打开 `frontend/debug_client.html`
## Unity 客户端结构
### 核心脚本
| 脚本 | 功能 |
|------|------|
| `NetworkManager.cs` | WebSocket 连接管理、消息收发 |
| `GameManager.cs` | 游戏状态管理、角色生成 |
| `UIManager.cs` | 主 UI 界面 (顶部状态栏、底部命令输入) |
| `EventLog.cs` | 事件日志面板 (显示游戏事件) |
| `AgentVisual.cs` | 角色视觉组件 (精灵、血条、对话框) |
| `EnvironmentManager.cs` | 环境场景 (沙滩、海洋、天空) |
| `WeatherEffects.cs` | 天气粒子效果 (雨、雾、热浪) |
### 视觉特性
- 程序化生成的 2.5D 角色精灵
- Billboard UI (始终面向摄像机)
- 动态天气粒子系统
- 渐变天空盒 (随时间变化)
- 海浪动画效果
## 中文字体支持
项目使用 **思源黑体 (Source Han Sans SC)** 支持中文显示。
### 手动配置步骤
1. 选择 `Assets/Fonts/SourceHanSansSC-Regular.otf`
2. 右键 → Create → TextMeshPro → Font Asset → SDF
3. 打开 Edit → Project Settings → TextMesh Pro
4. 在 Fallback Font Assets 中添加生成的字体资产
## 通信协议
### WebSocket 端点
```
ws://localhost:8000/ws/{username}
```
### 事件类型
```python
# 核心事件
TICK # 游戏心跳
AGENTS_UPDATE # 角色状态更新
AGENT_SPEAK # 角色发言
AGENT_DIED # 角色死亡
# 时间系统
PHASE_CHANGE # 时段变化 (黎明/白天/黄昏/夜晚)
DAY_CHANGE # 新的一天
WEATHER_CHANGE # 天气变化
# 玩家互动
FEED # 喂食反馈
HEAL # 治疗反馈
TALK # 对话反馈
ENCOURAGE # 鼓励反馈
REVIVE # 复活反馈
# 社交系统
SOCIAL_INTERACTION # 角色间社交
AUTO_REVIVE # 自动复活 (休闲模式)
```
## 环境变量
创建 `.env` 文件:
```env
ANTHROPIC_API_KEY=your_api_key_here
```
## 开发说明
### 添加新命令
1.`backend/app/schemas.py` 添加事件类型
2.`backend/app/engine.py` 添加命令处理逻辑
3.`unity-client/Assets/Scripts/Models.cs` 添加数据模型
4.`unity-client/Assets/Scripts/NetworkManager.cs` 添加事件处理
### 调试
- Unity 控制台查看日志
- Web 调试客户端查看原始消息
- 后端日志查看服务器状态
## 许可证
MIT License

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 21528455f756640db912f845f44864a6

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 18b316c9d4e944c9ead9102780fda528
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 05d7311017e2a4618aeb1598563375bc
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: ce5da230aa9d2439c998f40a36e72588
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontNames:
- Source Han Sans SC
fallbackFontReferences: []
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,379 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using TheIsland.Network;
using TheIsland.Models;
namespace TheIsland.UI
{
/// <summary>
/// 事件日志面板 - 显示游戏事件历史
/// </summary>
public class EventLog : MonoBehaviour
{
private static EventLog _instance;
public static EventLog Instance => _instance;
// 自动创建 EventLog 实例
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void AutoCreate()
{
if (_instance == null)
{
var go = new GameObject("EventLog");
go.AddComponent<EventLog>();
DontDestroyOnLoad(go);
Debug.Log("[EventLog] 自动创建实例");
}
}
// UI 组件
private Canvas _canvas;
private GameObject _panel;
private ScrollRect _scrollRect;
private RectTransform _content;
private Button _toggleBtn;
private TextMeshProUGUI _toggleText;
private List<GameObject> _entries = new List<GameObject>();
private bool _visible = true;
private int _unread = 0;
private bool _ready = false;
private void Awake()
{
if (_instance != null && _instance != this)
{
Destroy(gameObject);
return;
}
_instance = this;
}
private void Start()
{
Debug.Log("[EventLog] Start - 开始初始化");
StartCoroutine(InitCoroutine());
}
private System.Collections.IEnumerator InitCoroutine()
{
// 等待一帧确保 Canvas 准备好
yield return null;
_canvas = FindAnyObjectByType<Canvas>();
if (_canvas == null)
{
Debug.LogError("[EventLog] 找不到 Canvas");
yield break;
}
Debug.Log($"[EventLog] 找到 Canvas: {_canvas.name}");
BuildUI();
// 等待 NetworkManager
int retries = 0;
while (NetworkManager.Instance == null && retries < 20)
{
Debug.Log("[EventLog] 等待 NetworkManager...");
yield return new WaitForSeconds(0.25f);
retries++;
}
if (NetworkManager.Instance != null)
{
SubscribeEvents();
_ready = true;
AddLog("事件日志已就绪", Color.yellow);
Debug.Log("[EventLog] 初始化完成");
}
else
{
Debug.LogError("[EventLog] NetworkManager 超时");
}
}
private void OnDestroy()
{
if (NetworkManager.Instance != null)
{
var n = NetworkManager.Instance;
n.OnConnected -= OnConnected;
n.OnAgentSpeak -= OnSpeak;
n.OnSocialInteraction -= OnSocial;
n.OnAgentDied -= OnDeath;
n.OnFeed -= OnFeed;
n.OnHeal -= OnHeal;
n.OnEncourage -= OnEncourage;
n.OnRevive -= OnRevive;
n.OnTalk -= OnTalk;
n.OnSystemMessage -= OnSystem;
n.OnWeatherChange -= OnWeather;
n.OnPhaseChange -= OnPhase;
n.OnDayChange -= OnDay;
}
}
private void SubscribeEvents()
{
var n = NetworkManager.Instance;
n.OnConnected += OnConnected;
n.OnAgentSpeak += OnSpeak;
n.OnSocialInteraction += OnSocial;
n.OnAgentDied += OnDeath;
n.OnFeed += OnFeed;
n.OnHeal += OnHeal;
n.OnEncourage += OnEncourage;
n.OnRevive += OnRevive;
n.OnTalk += OnTalk;
n.OnSystemMessage += OnSystem;
n.OnWeatherChange += OnWeather;
n.OnPhaseChange += OnPhase;
n.OnDayChange += OnDay;
Debug.Log("[EventLog] 事件订阅完成");
}
// 事件处理
private void OnConnected() => AddLog("已连接服务器", Color.green);
private void OnSpeak(AgentSpeakData d) => AddLog($"{d.agent_name}: \"{d.text}\"", Color.white);
private void OnSocial(SocialInteractionData d) => AddLog($"{d.initiator_name} -> {d.target_name}: {d.dialogue}", new Color(0.6f, 0.9f, 1f));
private void OnDeath(AgentDiedData d) => AddLog($"{d.agent_name} 死亡!", Color.red);
private void OnFeed(FeedEventData d) => AddLog($"{d.user} 喂食 {d.agent_name}", new Color(0.5f, 1f, 0.5f));
private void OnHeal(HealEventData d) => AddLog($"{d.user} 治疗 {d.agent_name}", new Color(0.5f, 1f, 0.5f));
private void OnEncourage(EncourageEventData d) => AddLog($"{d.user} 鼓励 {d.agent_name}", new Color(0.5f, 1f, 0.5f));
private void OnRevive(ReviveEventData d) => AddLog($"{d.user} 复活 {d.agent_name}", Color.cyan);
private void OnTalk(TalkEventData d) => AddLog($"{d.agent_name}: \"{d.response}\"", Color.white);
private void OnSystem(SystemEventData d) => AddLog(d.message, Color.yellow);
private void OnWeather(WeatherChangeData d) => AddLog($"天气: {d.new_weather}", new Color(0.7f, 0.85f, 1f));
private void OnPhase(PhaseChangeData d) => AddLog($"时间: {d.new_phase}", new Color(1f, 0.9f, 0.7f));
private void OnDay(DayChangeData d) => AddLog($"第 {d.day} 天!", new Color(1f, 0.9f, 0.7f));
private void BuildUI()
{
// 切换按钮
var toggleObj = new GameObject("LogToggle");
toggleObj.transform.SetParent(_canvas.transform, false);
var toggleRect = toggleObj.AddComponent<RectTransform>();
toggleRect.anchorMin = new Vector2(0, 1);
toggleRect.anchorMax = new Vector2(0, 1);
toggleRect.pivot = new Vector2(0, 1);
toggleRect.anchoredPosition = new Vector2(10, -75);
toggleRect.sizeDelta = new Vector2(90, 24);
var toggleImg = toggleObj.AddComponent<Image>();
toggleImg.color = new Color(0.2f, 0.35f, 0.5f, 0.9f);
_toggleBtn = toggleObj.AddComponent<Button>();
_toggleBtn.targetGraphic = toggleImg;
_toggleBtn.onClick.AddListener(Toggle);
var toggleTextObj = new GameObject("Text");
toggleTextObj.transform.SetParent(toggleObj.transform, false);
_toggleText = toggleTextObj.AddComponent<TextMeshProUGUI>();
_toggleText.text = "隐藏日志";
_toggleText.fontSize = 12;
_toggleText.color = Color.white;
_toggleText.alignment = TextAlignmentOptions.Center;
var ttRect = toggleTextObj.GetComponent<RectTransform>();
ttRect.anchorMin = Vector2.zero;
ttRect.anchorMax = Vector2.one;
ttRect.sizeDelta = Vector2.zero;
// 主面板
_panel = new GameObject("LogPanel");
_panel.transform.SetParent(_canvas.transform, false);
var panelRect = _panel.AddComponent<RectTransform>();
panelRect.anchorMin = new Vector2(0, 0);
panelRect.anchorMax = new Vector2(0, 1);
panelRect.pivot = new Vector2(0, 0.5f);
panelRect.offsetMin = new Vector2(10, 80);
panelRect.offsetMax = new Vector2(360, -80);
var panelImg = _panel.AddComponent<Image>();
panelImg.color = new Color(0.05f, 0.07f, 0.1f, 0.95f);
// 标题
var header = new GameObject("Header");
header.transform.SetParent(_panel.transform, false);
var headerRect = header.AddComponent<RectTransform>();
headerRect.anchorMin = new Vector2(0, 1);
headerRect.anchorMax = new Vector2(1, 1);
headerRect.pivot = new Vector2(0.5f, 1);
headerRect.sizeDelta = new Vector2(0, 28);
headerRect.anchoredPosition = Vector2.zero;
header.AddComponent<Image>().color = new Color(0.12f, 0.15f, 0.2f);
var titleObj = new GameObject("Title");
titleObj.transform.SetParent(header.transform, false);
var titleTmp = titleObj.AddComponent<TextMeshProUGUI>();
titleTmp.text = "事件日志";
titleTmp.fontSize = 14;
titleTmp.fontStyle = FontStyles.Bold;
titleTmp.color = Color.white;
titleTmp.alignment = TextAlignmentOptions.MidlineLeft;
var titleRect = titleObj.GetComponent<RectTransform>();
titleRect.anchorMin = Vector2.zero;
titleRect.anchorMax = Vector2.one;
titleRect.offsetMin = new Vector2(8, 0);
titleRect.offsetMax = new Vector2(-50, 0);
// 清除按钮
var clearObj = new GameObject("Clear");
clearObj.transform.SetParent(header.transform, false);
var clearRect = clearObj.AddComponent<RectTransform>();
clearRect.anchorMin = new Vector2(1, 0.5f);
clearRect.anchorMax = new Vector2(1, 0.5f);
clearRect.pivot = new Vector2(1, 0.5f);
clearRect.sizeDelta = new Vector2(45, 20);
clearRect.anchoredPosition = new Vector2(-4, 0);
var clearImg = clearObj.AddComponent<Image>();
clearImg.color = new Color(0.5f, 0.25f, 0.25f);
var clearBtn = clearObj.AddComponent<Button>();
clearBtn.targetGraphic = clearImg;
clearBtn.onClick.AddListener(Clear);
var clearTextObj = new GameObject("Text");
clearTextObj.transform.SetParent(clearObj.transform, false);
var clearTmp = clearTextObj.AddComponent<TextMeshProUGUI>();
clearTmp.text = "清除";
clearTmp.fontSize = 11;
clearTmp.color = Color.white;
clearTmp.alignment = TextAlignmentOptions.Center;
var ctRect = clearTextObj.GetComponent<RectTransform>();
ctRect.anchorMin = Vector2.zero;
ctRect.anchorMax = Vector2.one;
ctRect.sizeDelta = Vector2.zero;
// 滚动区域
var scrollObj = new GameObject("Scroll");
scrollObj.transform.SetParent(_panel.transform, false);
var scrollRect = scrollObj.AddComponent<RectTransform>();
scrollRect.anchorMin = Vector2.zero;
scrollRect.anchorMax = Vector2.one;
scrollRect.offsetMin = new Vector2(4, 4);
scrollRect.offsetMax = new Vector2(-4, -32);
scrollObj.AddComponent<Image>().color = new Color(0, 0, 0, 0.3f);
scrollObj.AddComponent<Mask>().showMaskGraphic = true;
_scrollRect = scrollObj.AddComponent<ScrollRect>();
_scrollRect.horizontal = false;
_scrollRect.vertical = true;
_scrollRect.movementType = ScrollRect.MovementType.Clamped;
_scrollRect.scrollSensitivity = 25;
_scrollRect.viewport = scrollRect;
// 内容容器
var contentObj = new GameObject("Content");
contentObj.transform.SetParent(scrollObj.transform, false);
_content = contentObj.AddComponent<RectTransform>();
_content.anchorMin = new Vector2(0, 1);
_content.anchorMax = new Vector2(1, 1);
_content.pivot = new Vector2(0.5f, 1);
_content.anchoredPosition = Vector2.zero;
_content.sizeDelta = new Vector2(0, 0);
var layout = contentObj.AddComponent<VerticalLayoutGroup>();
layout.spacing = 2;
layout.padding = new RectOffset(2, 2, 2, 2);
layout.childControlWidth = true;
layout.childControlHeight = true;
layout.childForceExpandWidth = true;
layout.childForceExpandHeight = false;
contentObj.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
_scrollRect.content = _content;
Debug.Log("[EventLog] UI 构建完成");
}
public void AddLog(string msg, Color color)
{
if (_content == null) return;
var entry = new GameObject($"E{_entries.Count}");
entry.transform.SetParent(_content, false);
entry.AddComponent<Image>().color = _entries.Count % 2 == 0
? new Color(0.08f, 0.1f, 0.13f, 0.9f)
: new Color(0.06f, 0.08f, 0.11f, 0.9f);
var le = entry.AddComponent<LayoutElement>();
le.minHeight = 36;
le.preferredHeight = 36;
// 颜色条
var bar = new GameObject("Bar");
bar.transform.SetParent(entry.transform, false);
var barRect = bar.AddComponent<RectTransform>();
barRect.anchorMin = new Vector2(0, 0);
barRect.anchorMax = new Vector2(0, 1);
barRect.pivot = new Vector2(0, 0.5f);
barRect.sizeDelta = new Vector2(3, -4);
barRect.anchoredPosition = new Vector2(1, 0);
bar.AddComponent<Image>().color = color;
// 文本
var textObj = new GameObject("Text");
textObj.transform.SetParent(entry.transform, false);
var tmp = textObj.AddComponent<TextMeshProUGUI>();
string time = System.DateTime.Now.ToString("HH:mm:ss");
tmp.text = $"<color=#666><size=10>{time}</size></color> {msg}";
tmp.fontSize = 12;
tmp.color = color;
tmp.alignment = TextAlignmentOptions.MidlineLeft;
tmp.textWrappingMode = TextWrappingModes.Normal;
tmp.overflowMode = TextOverflowModes.Ellipsis;
tmp.richText = true;
var textRect = textObj.GetComponent<RectTransform>();
textRect.anchorMin = Vector2.zero;
textRect.anchorMax = Vector2.one;
textRect.offsetMin = new Vector2(8, 2);
textRect.offsetMax = new Vector2(-4, -2);
_entries.Add(entry);
while (_entries.Count > 100)
{
Destroy(_entries[0]);
_entries.RemoveAt(0);
}
if (!_visible)
{
_unread++;
UpdateToggle();
}
LayoutRebuilder.ForceRebuildLayoutImmediate(_content);
Canvas.ForceUpdateCanvases();
_scrollRect.verticalNormalizedPosition = 0;
}
private void Clear()
{
foreach (var e in _entries) Destroy(e);
_entries.Clear();
_unread = 0;
UpdateToggle();
LayoutRebuilder.ForceRebuildLayoutImmediate(_content);
AddLog("已清除", Color.yellow);
}
private void Toggle()
{
_visible = !_visible;
_panel.SetActive(_visible);
if (_visible) _unread = 0;
UpdateToggle();
}
private void UpdateToggle()
{
if (_toggleText != null)
_toggleText.text = _visible ? "隐藏日志" : (_unread > 0 ? $"日志({_unread})" : "显示日志");
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 29d056ffaee4442e2b947b862a50d329

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3a714afb8c6c4492e838e7fcc1e6de1b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -28,6 +28,7 @@ namespace TheIsland.UI
private Button _resetButton; private Button _resetButton;
private GameObject _notificationPanel; private GameObject _notificationPanel;
private TextMeshProUGUI _notificationText; private TextMeshProUGUI _notificationText;
// EventLog 现在自己管理初始化
#endregion #endregion
#region State #region State
@@ -149,6 +150,7 @@ namespace TheIsland.UI
CreateTopBar(); CreateTopBar();
CreateBottomBar(); CreateBottomBar();
CreateNotificationPanel(); CreateNotificationPanel();
// EventLog 自己管理初始化,不在这里创建
} }
private void CreateTopBar() private void CreateTopBar()

View File

@@ -191,8 +191,10 @@ namespace TheIsland.Visual
var velocityOverLifetime = _fogSystem.velocityOverLifetime; var velocityOverLifetime = _fogSystem.velocityOverLifetime;
velocityOverLifetime.enabled = true; velocityOverLifetime.enabled = true;
velocityOverLifetime.x = new ParticleSystem.MinMaxCurve(-0.2f, 0.2f); // 所有轴使用相同的曲线模式 (Constant)
velocityOverLifetime.y = new ParticleSystem.MinMaxCurve(0.05f, 0.1f); velocityOverLifetime.x = 0f;
velocityOverLifetime.y = 0.08f;
velocityOverLifetime.z = 0f;
var colorOverLifetime = _fogSystem.colorOverLifetime; var colorOverLifetime = _fogSystem.colorOverLifetime;
colorOverLifetime.enabled = true; colorOverLifetime.enabled = true;
@@ -234,8 +236,10 @@ namespace TheIsland.Visual
var velocityOverLifetime = _heatSystem.velocityOverLifetime; var velocityOverLifetime = _heatSystem.velocityOverLifetime;
velocityOverLifetime.enabled = true; velocityOverLifetime.enabled = true;
// 所有轴使用相同的曲线模式 (Constant)
velocityOverLifetime.x = 0f;
velocityOverLifetime.y = 1f; velocityOverLifetime.y = 1f;
velocityOverLifetime.x = new ParticleSystem.MinMaxCurve(-0.3f, 0.3f); velocityOverLifetime.z = 0f;
var colorOverLifetime = _heatSystem.colorOverLifetime; var colorOverLifetime = _heatSystem.colorOverLifetime;
colorOverLifetime.enabled = true; colorOverLifetime.enabled = true;
@@ -277,7 +281,10 @@ namespace TheIsland.Visual
var velocityOverLifetime = _cloudSystem.velocityOverLifetime; var velocityOverLifetime = _cloudSystem.velocityOverLifetime;
velocityOverLifetime.enabled = true; velocityOverLifetime.enabled = true;
// 所有轴使用相同的曲线模式 (Constant)
velocityOverLifetime.x = 0.3f; velocityOverLifetime.x = 0.3f;
velocityOverLifetime.y = 0f;
velocityOverLifetime.z = 0f;
var renderer = cloudObj.GetComponent<ParticleSystemRenderer>(); var renderer = cloudObj.GetComponent<ParticleSystemRenderer>();
renderer.material = CreateCloudMaterial(); renderer.material = CreateCloudMaterial();

File diff suppressed because one or more lines are too long

View File

@@ -15,7 +15,7 @@ MonoBehaviour:
assetVersion: 2 assetVersion: 2
m_TextWrappingMode: 1 m_TextWrappingMode: 1
m_enableKerning: 1 m_enableKerning: 1
m_ActiveFontFeatures: 00000000 m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0 m_enableExtraPadding: 0
m_enableTintAllSprites: 0 m_enableTintAllSprites: 0
m_enableParseEscapeCharacters: 1 m_enableParseEscapeCharacters: 1
@@ -36,17 +36,14 @@ MonoBehaviour:
m_fallbackFontAssets: [] m_fallbackFontAssets: []
m_matchMaterialPreset: 1 m_matchMaterialPreset: 1
m_HideSubTextObjects: 0 m_HideSubTextObjects: 0
m_defaultSpriteAsset: {fileID: 11400000, guid: c41005c129ba4d66911b75229fd70b45, m_defaultSpriteAsset: {fileID: 11400000, guid: c41005c129ba4d66911b75229fd70b45, type: 2}
type: 2}
m_defaultSpriteAssetPath: Sprite Assets/ m_defaultSpriteAssetPath: Sprite Assets/
m_enableEmojiSupport: 1 m_enableEmojiSupport: 1
m_MissingCharacterSpriteUnicode: 0 m_MissingCharacterSpriteUnicode: 0
m_EmojiFallbackTextAssets: [] m_EmojiFallbackTextAssets: []
m_defaultColorGradientPresetsPath: Color Gradient Presets/ m_defaultColorGradientPresetsPath: Color Gradient Presets/
m_defaultStyleSheet: {fileID: 11400000, guid: f952c082cb03451daed3ee968ac6c63e, m_defaultStyleSheet: {fileID: 11400000, guid: f952c082cb03451daed3ee968ac6c63e, type: 2}
type: 2}
m_StyleSheetsResourcePath: m_StyleSheetsResourcePath:
m_leadingCharacters: {fileID: 4900000, guid: d82c1b31c7e74239bff1220585707d2b, type: 3} m_leadingCharacters: {fileID: 4900000, guid: d82c1b31c7e74239bff1220585707d2b, type: 3}
m_followingCharacters: {fileID: 4900000, guid: fade42e8bc714b018fac513c043d323b, m_followingCharacters: {fileID: 4900000, guid: fade42e8bc714b018fac513c043d323b, type: 3}
type: 3}
m_UseModernHangulLineBreakingRules: 0 m_UseModernHangulLineBreakingRules: 0

View File

@@ -165,7 +165,8 @@ PlayerSettings:
androidSupportedAspectRatio: 1 androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.4 androidMaxAspectRatio: 2.4
androidMinAspectRatio: 1 androidMinAspectRatio: 1
applicationIdentifier: {} applicationIdentifier:
Standalone: com.DefaultCompany.unity-client
buildNumber: buildNumber:
Standalone: 0 Standalone: 0
VisionOS: 0 VisionOS: 0