《不尬的诗》
自信满满写首诗
坐到电脑前
不出一刻钟
写不出来
糊弄一下提交上去
还挺爽
Note: 必须使用国际版的UnityHub
Unity版本: 2022.3.58f1
git lfs install
git clone git@github.com:Vanishing-Games/Unity-Template.git
git submodule update --init --recursive
git lfs checkout
unity国际版
https://www.logiconsole.com/fuck-unity-cn/
💡 GitHub 支持 Mermaid 渲染,确保你直接在 GitHub 上查看以获得图形化展示。
点击展开文件结构图
flowchart TD
%% 根目录
Root["📁 Root 项目根目录"]
subgraph UnityProject["Unity 工程目录"]
direction TB
Assets["📁 Assets - 所有项目资源的根目录"]
Packages["📁 Packages - Unity 包管理文件夹"]
ProjectSettings["📁 ProjectSettings - 项目设置"]
end
subgraph RootSub["根目录下子模块"]
CodeUnfucker["📁 CodeUnfucker - 代码静态分析与自动生成工具"]
Scripts["📁 Scripts - 项目相关脚本"]
Settings["📁 Settings - 项目相关设置"]
Docs["📁 Docs - 项目相关文档"]
end
Root --> UnityProject
Root --> RootSub
subgraph AssetsSub["Assets 子目录"]
Arts["📁 Arts - 原始美术素材"]
Audios["📁 Audios - 原始音乐音效素材"]
Configurations["📁 Configurations - 全局配置表"]
Core["📁 Core - 通用底层模块代码"]
Demos["📁 Demos - 功能测试/开发隔离区"]
Editor["📁 Editor - Unity 特殊文件夹(编辑器脚本)"]
Plugins["📁 Plugins - 第三方库和插件"]
ProjectMain["📁 ProjectMain - 游戏主逻辑相关"]
Resources["📁 Resources - Unity 特殊文件夹(运行时资源加载)"]
StreamingAssets["📁 StreamingAssets - Unity 特殊文件夹(流式资源)"]
Tests["📁 Tests - 项目测试代码"]
end
Assets --> AssetsSub
subgraph ProjectMainSub["ProjectMain 子目录"]
Scenes["📁 Scenes - 出包场景"]
end
ProjectMain --> ProjectMainSub
G["📁 GameAssets - 随游戏打包的最终资源"]
BuiltInGameAssets["📁 Built-InGameAssets - 序列化进场景的资产"]
PackedAssets["📁 PackedAssets - 需要打包的资源"]
Assets --> G
G --> BuiltInGameAssets
G --> PackedAssets
subgraph TestsSub["Tests 子目录"]
EditorTests["📁 Editor - 编辑器测试"]
PlayMode["📁 PlayMode - Play 模式测试"]
end
Tests --> TestsSub
// -----------------------------------------------------------------------------
// Copyright (c) 2025 Vanishing Games. All Rights Reserved.
// Author: YourName
// Created: 2025-06-30
// -----------------------------------------------------------------------------
- 尽量使用 标准美式英语拼写
- 所有命名都应遵循
PascalCase或camelCase - 命名应清晰,有描述性,避免缩写和歧义.
- 函数命名为 动词
| 用途 | 做法 |
|---|---|
| 私有成员变量 | 使用 m_ 或后缀 _ |
| 静态变量 | 使用 s_ |
| 布尔变量 | is / has / can 前缀 |
| 全局变量 (慎用) | g_ |
| 常量 | 全大写蛇形 e.g., MAX_SIZE |
| 输入/输出参数 | in / out 前缀 |
-
使用英文作为主要注释语言
-
代码即注释 禁止毫无意义的注释
//无用注释 int count = 0; // 初始化计数器为0 count++; // 计数器加1
-
详细注释应针对函数功能、使用说明、注意事项、TODO、FIXME,或复杂逻辑等
虚幻源码
// Fresnel term for iridescent microfacet BRDF model // Simplified version which relies on Schlick's Fresnel and de facto does not take into // account Fresnel phase shift & polarization. float3 F_ThinFilm(float NoV, float NoL, float VoH, float3 F0, float3 F90, float ThinFilmIOR, float ThinFilmTickness)
-
对于算法,对于每一个步骤写出注释
Unity 源码
real3 EvalIridescence(real eta_1, real cosTheta1, real iridescenceThickness, real3 baseLayerFresnel0, real iorOverBaseLayer = 0.0) { real3 I; // iridescenceThickness unit is micrometer for this equation here. Mean 0.5 is 500nm. real Dinc = 3.0 * iridescenceThickness; // Note: Unlike the code provide with the paper, here we use schlick approximation // Schlick is a very poor approximation when dealing with iridescence to the Fresnel // term and there is no "neutral" value in this unlike in the original paper. // We use Iridescence mask here to allow to have neutral value // Hack: In order to use only one parameter (DInc), we deduced the ior of iridescence from current Dinc iridescenceThickness // and we use mask instead to fade out the effect real eta_2 = lerp(2.0, 1.0, iridescenceThickness); // Following line from original code is not needed for us, it create a discontinuity // Force eta_2 -> eta_1 when Dinc -> 0.0 // real eta_2 = lerp(eta_1, eta_2, smoothstep(0.0, 0.03, Dinc)); // Evaluate the cosTheta on the base layer (Snell law) real sinTheta2Sq = Sq(eta_1 / eta_2) * (1.0 - Sq(cosTheta1)); // Handle TIR: // (Also note that with just testing sinTheta2Sq > 1.0, (1.0 - sinTheta2Sq) can be negative, as emitted instructions // can eg be a mad giving a small negative for (1.0 - sinTheta2Sq), while sinTheta2Sq still testing equal to 1.0), so we actually // test the operand [cosTheta2Sq := (1.0 - sinTheta2Sq)] < 0 directly:) real cosTheta2Sq = (1.0 - sinTheta2Sq); // Or use this "artistic hack" to get more continuity even though wrong (no TIR, continue the effect by mirroring it): // if( cosTheta2Sq < 0.0 ) => { sinTheta2Sq = 2 - sinTheta2Sq; => so cosTheta2Sq = sinTheta2Sq - 1 } // ie don't test and simply do // real cosTheta2Sq = abs(1.0 - sinTheta2Sq); if (cosTheta2Sq < 0.0) I = real3(1.0, 1.0, 1.0); else { real cosTheta2 = sqrt(cosTheta2Sq); // First interface real R0 = IorToFresnel0(eta_2, eta_1); real R12 = F_Schlick(R0, cosTheta1); real R21 = R12; real T121 = 1.0 - R12; real phi12 = 0.0; real phi21 = PI - phi12; // Second interface // The f0 or the base should account for the new computed eta_2 on top. // This is optionally done if we are given the needed current ior over the base layer that is accounted for // in the baseLayerFresnel0 parameter: if (iorOverBaseLayer > 0.0) { // Fresnel0ToIor will give us a ratio of baseIor/topIor, hence we * iorOverBaseLayer to get the baseIor real3 baseIor = iorOverBaseLayer * Fresnel0ToIor(baseLayerFresnel0 + 0. 0001); // guard against 1.0 baseLayerFresnel0 = IorToFresnel0(baseIor, eta_2); } real3 R23 = F_Schlick(baseLayerFresnel0, cosTheta2); real phi23 = 0.0; // Phase shift real OPD = Dinc * cosTheta2; real phi = phi21 + phi23; // Compound terms real3 R123 = clamp(R12 * R23, 1e-5, 0.9999); real3 r123 = sqrt(R123); real3 Rs = Sq(T121) * R23 / (real3(1.0, 1.0, 1.0) - R123); // Reflectance term for m = 0 (DC term amplitude) real3 C0 = R12 + Rs; I = C0; // Reflectance term for m > 0 (pairs of diracs) real3 Cm = Rs - T121; for (int m = 1; m <= 2; ++m) { Cm *= r123; real3 Sm = 2.0 * EvalSensitivity(m * OPD, m * phi); //vec3 SmP = 2.0 * evalSensitivity(m*OPD, m*phi2.y); I += Cm * Sm; } // Since out of gamut colors might be produced, negative color values are clamped to 0. I = max(I, float3(0.0, 0.0, 0.0)); } return I; }
- 不使用过细命名空间
- 使用 CSharpier 标准
为提升代码可读性和维护性,类内部成员建议按照如下顺序排列(以实际示例为准):
- 事件(Event)
- 属性(Property)
- 公有方法(public)
- 索引器(Indexer)
- 运算符重载、显式接口实现
- 构造函数、析构函数
- Unity 生命周期函数(如 Awake、OnEnable、Start、Update、OnDisable、OnDestroy 等)
- 保护方法(protected)
- 私有方法(private)
- 嵌套类型(类、结构体、枚举等)
- 常量、静态只读字段(
const/static readonly) - 静态字段、静态属性、静态事件
- 实例只读字段(
readonly) - 实例字段(含
[SerializeField]字段)
Unity 生命周期函数补充说明:
- 所有生命周期函数建议统一放在构造/析构函数之后,保护/私有方法之前。
- 推荐顺序:Awake → OnEnable → Start → Update → FixedUpdate → LateUpdate → OnDisable → OnDestroy → 其他回调(如 OnTriggerEnter、OnCollisionEnter、OnGUI 等)。
- 建议用
#region Unity Lifecycle包裹所有生命周期函数,便于查阅和维护。 - 生命周期函数内部建议只做必要的初始化、状态切换、事件注册/注销等,复杂逻辑应拆分到私有方法中。
注意:
- 同一类型成员建议按访问修饰符排序(public > protected > private)。
- Unity 项目中
[SerializeField]字段建议靠前。 - 可使用
#region分组提升可读性。
示例:
public class Example : MonoBehaviour
{
// 1. 事件
public event Action OnChanged;
// 2. 属性
public int Count { get; private set; }
// 3. 公有方法
public void DoSomething() { ... }
// 4. 索引器
public int this[int index] { get { ... } set { ... } }
// 5. 运算符重载
public static Example operator +(Example a, Example b) { ... }
// 6. 构造/析构
public Example(int id) { ... }
~Example() { ... }
// 7. Unity 生命周期函数
private void OnEnable() { ... }
private void Update() { ... }
private void OnDisable() { ... }
// 8. 保护方法
protected void OnSomething() { ... }
// 9. 私有方法
private void Helper() { ... }
// 10. 嵌套类型
private class Nested { ... }
// 11. 常量、静态只读字段
public const int MaxValue = 100;
private static readonly string Version = "1.0";
// 12. 静态字段/属性/事件
private static int s_counter;
public static int Counter => s_counter;
public static event Action OnStaticEvent;
// 13. 实例只读字段
private readonly int _id;
// 14. 实例字段
[SerializeField] private string name;
private int count;
}type_category_?subcategory_?action_?subcategory_001
ui_button_select
ui_button_shop_select
gp_proj_fire_hit_small_001
gp_proj_fire_hit_small_002
gp_booster_bomb_activate
mus_core_jungle_001
- 使用snake_case
- 使用关键词大写来突出信息,如: mus_factory_main_STOP
- 使用camelCase来表示一个物体,如: enemy_fireDemon_death
- 使用英文
- 简明扼要
- 层层嵌套: 按照从概括到具体的原则逐层嵌套
- 合理排序: 方便按照字母顺序合理且高效地对名称进行排序
- 统一数位: xxx 如 001
- 使用动词形式: bomb_activation vs. bomb_activate
- 使用正常时态: chest_destroyed vs. chest_destroy
- 保持单复数一致
- 使用游戏主题来命名: 不要使用机制来命名
- 名称不要过长
- 适当使用描述词如
loop表明音乐为循环 - 缩写必须在表中有
- 同一物体,团队用词要统一
| 缩写 | 全称 |
|---|---|
| gp | gameplay |
| plr | player |
| char | character |
| amb | ambience |
| mus | music |
clip_01 # 没有上下文,不明所以
awesome_sound1 # 数字前没加下划线
boss_enemy_eggman # enemy 比 boss 更宽泛;应改用 enemy_boss_eggman
GreatArt_1 GreatArt_2 GreatArt_10 # 数位不一致
sfx_env_forest_daytime_birds_chirping_loop_ambient_lowIntensity_01.wav # 太长
- Work Flow: GitHub Flow
- 信息提交规范: Conventional Commits
- 信息提交语言: 中英皆可
中文参考视频: 十分钟学会正确的github工作流,和开源作者们使用同一套流程
- 开发任务的追踪入口,与 PR、Projects 联动
- 提高沟通效率
实践时建议使用各种成熟的Project模板.
- 无缝衔接 Issue 和 PR
- 支持自动化
TDD(Test-Driven Development)
- ConsolePro
- Odin
- DOTween