Tổng Quan
1. Unity version: 2022.1.20f1
- Như develop đang sử dụng.
- Nếu update version unity sẽ được thông báo qua các kênh chat telegram/slack....
2. Git Flow :
a. master
: Luôn ở trạng thái có thể deploy, release ra live users.
b. hotfixes:
Nhánh xử lý những critical bugs, khẩn cấp
c. release :
Release app các version.
d. develop :
nhánh này sẽ là nhánh chính để phát triển và là nơi tất cả các nhà phát triển trong nhóm sẽ làm việc để triển khai các tính năng mới hoặc sửa lỗi trước khi phát hành.
Những thành viên khi làm feature mới, cần tách 1 branch mới từ develop ra, sau khi hoàn thiện thì sẽ được merge trực tiếp với develop.
3. Đối với đối tác:
- Bên OS nên đồng bộ với
develop
vào mỗi sáng[8h-11h]
các ngày làm việc. - Nếu cần merge code xử lý gấp cần thông báo qua các kênh chat telegram/slack....
I.Organization
[Tên khóa học viết tắt + tên game]
+---Resources
| ....
+---Scene
| [Tên khóa học viết tắt + tên game].unity
\---Scripts
....
Vd: Khóa học Early Education và game cần làm là Matching1 => EEMatching1
+---EEMatching1
+---Resources
| BlankBox.png
| Colum.prefab
+---Scene
| EEMatching1.unity
\---Scripts
EEM1.cs
EEM1BlankBox.cs
+Thư mục Resource (số 1) ( image/audio/animation/scriptableobject...) nên sắp xếp theo độ liên quan ( feature ) -> ở đây là liên quan đến chính game cần làm, không chia theo type vì resource của game không quá nhiều và không quá phức tạp.
Note:Vì hiện tại game là nhánh phân tầng cuối cùng của dự án, các tầng trên đã mix sort by type vs sort by features với nhau nên tầng cuối không phân tầng tránh làm rối project.
Vd:
+Thư mục Scene chứa Scene của game.
+Thư mục Script chứa mã của game.
Lưu ý :
-
Kế thừa GameBase và bật biến
_isTestDataEnable = true;
lên và gọi hàmLoadData
để lấy data test cho các game. -
Các data từ cần dạy nằm trong list
_wordsForTeach
-
Các data từ gay nhiễu nằm trong list
_wordsForDisturbance
-
Đọc data dùng hàm
MKStorageHelper.ResourceLoad
( vì sau này data sẽ nằm trong appdata ko phải trong asset) / Audio dùngSoundManager.GetInstance().Play(...)
-
Dùng chung
CommonCanvas prefab
=> cho tất cả các game -
Các màu sắc random cho từng game ( đa phần là 6 màu trừ game con cá là 4 màu ) được bỏ ở
ScriptableObjects/CommonResource.asset
-
Target game cho điện thoại là chủ yếu ->
canvas đc set theo tỉ lệ logical resolution design
của IPhoneX812x375
Resouce asset
phải đáp ứng được cho điện thoại độ phân giảiHD/HDR
B1: Nên phảiexport
ảnh trên figmax2/x3
( vì kích thước mặc định đang là logical resolution design = SD )
B2:Set Pixel Per Unit
hoặcSet size ảnh
-> để đảm bảo mật độ điểm ảnh hiển thị trên HDR ko bị mờ và vỡ
II. Naming
1. Project Files
Bao gồm : ScriptableObject, Image, Audio, Animation, Prefabs, Font, Database...
- Không dùng
Space
trong tên . - Sử dụng
PascalCase
Vd:EventSystem,GameControlller,SoundPlaceholder...
- Tránh sử dụng
filetype
trong tên
Vd: Thay vì BoxItemBackgroundPng -> nên đặt là BoxItemBackground
- Sử dụng gạch dưới
_
để kết hợp 2 hoặc nhiều khái niệu nếu dùngPascalCase
không mô tả được hết
Vd: EEMBoxNormal_Blue,EEMBoxNormal_Red....
- Nên bắt đầu tên bằng thứ mà đối tượng đó thuộc về.
Vd: EEMBoxNormal,EEMGameItem....
- Phần script/scene/resource của game =
[Tên khóa học (viết tắt) + tên game (viết tắt) + Nội dung]
//Vd: Khóa học Early Education có game Matching thì
//EEM1.cs
//EEM1GameItem.cs
2. Scene/Hierarchy
-
Cách đặt tên như phần
A. Project Files
-
Sử dụng
Empty Game Object
để làm container khi cần thiết (không sử dụng nếu chúng chỉ chứa 1-2 đối tượng.)
-
Đối với Game/Feature phước tạp. Sử dụng
Empty Game Object
để đặt tên và phân tách cho các phần xử lý các logic .
III.Coding Rules
- Giữ các
fields
vàmethods
ở chế độprivate
, trừ khi bạn cần chúng ở chế độ công khai. - Nếu bạn muốn hiển thị các trường trong Inspector mà không thực sự làm cho biến có thể truy cập được đối với các lớp khác, hãy sử dụng thuộc tính
[SerializeField]
và riêng tư, thay vì đặt chúng ở chế độ công khai.
Lưu ý: Làm như vậy, bạn có thể nhận được cảnh báo "Trường không bao giờ được gán cho, sẽ luôn có giá trị mặc định của nó". Gán giá trị mặc định cho trường với = default. - Cố gắng
tránh sử dụng Singletons
. Thay vào đó nên sử dụngScriptableObjects
cho một lớp tập trung, tương tự có thể được truy cập từ nhiều đối tượng. - Không sử dụng
var
khi khai báo một biến. Luôn viết loại của nó một cách rõ ràng. Tránh sử dụng các biến tĩnh static
.Không hardcode những con "số ma thuật"
. Ví dụ: Player di chuyểnvar x = xInput * 0.035f
. Tại sao lại là số đó ? Thay vào đó, hãy dùng biến có tên rõ ràng cho nó - và có thể comment mô tả chi tiết về con số đó để người khác có thể hiểu.
IV.Coding Convention
1.Tóm tắt
2.Quy Định Đặt Tên
A.Class/Function/NameSpace/Enum/Public Fields/Public Properties
- Phải được viết dưới dạng StudlyCaps(PascalCase) viết hoa chữ cái đầu của mỗi từ.
class MyClass
class MyHero
class LogicRace
void SetCurrentStep();
int GetCurrentStep();
void CreateHero();
enum Direction {
None,
Vertical,
Horizontal,
Both
};
B.Variables.
Gồm local variables, parameters
viết dưới dạng camelCase.
vd:
int _heroHp;
int enemyCount = 0;
public static int s_currentSceneIndex = 0;
Các biến nên được thêm tiền tố ( prefix ) tùy thuộc chúng là :
- hằng số (constants)
- biến tĩnh (statics)
- hay thành viên của class (class members).
Độ ưu tiên:
constant > static > member
Loại | Prefix | Ví dụ |
---|---|---|
Constants | k_ | k_myConstant |
Statics | s_ | s_myStatic |
Members | _ | _myMember |
Static Members | ms_ | myStaticMember |
C.Interface.
-
Luôn sử dụng chữ cái "I" làm tiền tố với tên Interface
-
VD
public interface IUser
{
}
3.Naming.
Tên phải được đặt cẩn thận, rõ ràng để chỉ rõ mục đích của bất cứ điều gì đang hướng đến.
Đừng ngần ngại sử dụng tên dài.
vd:
State _currentState;//State is an enum
std::string GetAbsolutepath();
bool HasChild();
int heroActionsTrackerControl;
Giá trị của biến kiểu boolean
phải là câu trả lời, được hỏi từ chính tên của nó. Đừng sử dụng phủ định.
DO:
bool _isPainting;
bool _isFound;
bool hasChild();
DON’T
bool _paint;
bool _isNotFound;
bool hasNoChild();
Tương tự ta cũng áp dụng cho các functions/methods
trả về kiểu bool
.
a. Các Function/Method
nên có một tên rõ ràng để nói rõ những gì chúng làm.
b. Các phương thức Get/Set
chỉ nên Get
và Set
các members và không nên làm thêm bất kỳ tác vụ nào khác.
DO:
int GetCurrentStep()
{
return _curentStep;
}
DON’T
int GetCurrentStep()
{
if(_hp>=10)
{
_curentStep+=1;
}
return _curentStep;
}
Compute/find
nên được sử dụng cho các hoạt động tính toán và tìm kiếm.
Init/Initialize
khi khởi tạo một đối tượng (mặc dù tốt hơn nếu các đối tượng được khởi tạo trong constructor).
Create/Allocate
tạo hoặc khởi tạo các đối tượng khác.
Sử dụng tên hàm cho các hành động ví dụ :
```Start/Stop, Pause/Resume, Show/Hide....``
4.Comment
Luôn luôn sử dụng //
Bằng cách này, khi bạn tìm kiếm một cái gì đó bạn sẽ thấy ngay nếu nó đã bình luận hay không.
5.Formatting
a.Nên sử dụng khoảng cách bằng Tab , không sử dụng Space.
b.Dấu ngoặc nhọn
Nếu có một đoạn mã, thì phải có đóng mở ngoặc nhọn, ngay cả khi đó là một lệnh đơn, vì mình sẽ không biết được liệu còn ai đó có thể thêm một lệnh khác sau đó không ?
Dấu ngoặc nhọn mở được đặt ở dòng tiếp theo và không nên có mã sau dấu ngoặc đóng (ngoại trừ do while).
DO:
for (uint32_t i = 0; i < 100; i++) {
}
if (a == 0) {
} else {
}
do
{
} while (true); // the only statement allowed to follow the closing brace.
c.Switch
- Trường hợp có nhiều hơn 2 dòng lệnh ở mỗi case , thì ta phải sử dụng dấu ngoặc nhọn cho tất cả các trường hợp.
- Các case phải được trên dòng riêng của mình.
switch (State)
{
case HeroState::Attack:
{
DoSomeThing();
DoSomeThingElse();
}
break;
case HeroState::Run:
{
DoSomeThing();
DoSomeThingElse();
}
break;
default:
break;
}
- Trường hợp tất cả các case statemnts , chỉ có một câu lệnh đơn thì ta có thể không cần dấu ngoặc nhọn. Ví dụ :
switch(x)
{
case MyEnum: : MyID1: return "MyID1";
case MyEnum: : MyID2: return "MyID2";
default: assert(false); break;
}
OR
switch(x)
{
case MyEnum: : MyID1: Statement ("MyID1", o_value); break;
case MyEnum: : MyID2: Statement("MyID2", o_value); break;
default: assert(false); break;
}
6.Class
Trình tự khai báo
Thứ tự khai báo trong một class body nên như sau:
Bởi, nhóm tầm nhìn:
public
protected
private
Sau đó, trong mỗi nhóm:
Typedefs
Constructors
Destructor
Operators
Member functions - Grouped by semantic
Member variables - Grouped by semantic
Không tạo MEMBER function nếu bạn không truy cập bất kỳ thành viên nào.( cần truy cập mới tạo ) |
---|
Chia các hàm lớn thành các phần nhỏ hơn để cải thiện khả năng đọc mã. |
---|
7.Format Code
Sử dụng chuẩn tương tự dotnet:
File config đã được export từ bản visual studio 2019 : ( có thể import vào sử dụng trên các IDE như visual stuido, visual sudio code... )
https://github.com/eduhub123/MonkeyX/blob/develop/MonkeyX/.editorconfig
Ref:
- https://www.c-sharpcorner.com/UploadFile/8a67c0/C-Sharp-coding-standards-and-naming-conventions/
- https://github.com/UnityTechnologies/open-project-1Screen Shot 2022-09-06 at 16.40.56Screen Shot 2022-09-06 at 16.50.11Screen Shot 2022-10-04 at 18.04.22