[Game Maker Adventure] Chương 005: Operator: +, -, *, /, %
Tóm tắt chương trước
Bạn mơ thấy một giấc mơ kì lạ, tỉnh dậy và ngay lập tức bị kéo vào không gian trong cuốn sách.
Mặc dù vẫn còn rất nhiều nghi vấn nhưng bạn cũng không thể tìm ra lời giải thích thoả đáng.
Kiến thức chương này
- Toán tử (operator) thường được phân làm 3 loại: Unary, Binary và Ternany (1 input, 2 input và 3 input).
- Các phép toán trong C# được xử lí giống trong toán học thông thường.
- Không nên thực hiện quá nhiều phép toán trên một statement vì sẽ khiến code khó đọc.
- Đừng chia cho 0.
Cốt truyện
Cả ngày hôm qua toàn những chuyện kì lạ.
Dị giới, thế giới trong sách, rồi còn giấc mơ đó nữa…
Quá nhiều câu hỏi vẫn còn chưa được giải đáp, bạn hạ quyết tâm phải trở nên mạnh mẽ thật nhanh để có thể biết nhiều hơn về những gì đang xảy ra với mình.
Linh tính mách bảo rằng, Ma quốc chắc chắn sẽ cho bạn câu trả lời…
Operator
Cơ bản thì toán tử (operator) là kí hiệu cho phép ta kết hợp các biến hoặc các giá trị lại với nhau.
Cho tới nay, chúng ta đã được biết các toán tử sau:
- Assignment Operator (toán tử gán): =
- Addition Operator (cộng): +
- Subtraction Operator (trừ): –
- Multiplication Operator (nhân): *
- Division Operator (chia): /
Ngoài ra, còn rất rất nhiều các toán tử khác như !=, >>, ^, ||, <=, ++, |, !, >=, ?, &, new, delegate,… (vâng, toán tử có cả chữ nữa).
Toán tử khi kết hợp với các kiểu dữ liệu thì lại còn phức tạp hơn nữa.
Nhưng không sao, chúng ta sẽ từ từ gặp chúng.
Các toán tử chung qui được phân làm 3 loại chính:
- Unary Operator (Toán tử một ngôi): chỉ có 1 input. VD: -a, x++, –x…
- Binary Operator (Toán tử hai ngôi): gồm 2 input. VD: 2+3, a*2, b/2…
- Ternary Operator (Toán tử ba ngôi): gồm 3 input. VD a? b : d (nếu a đúng thì a = b, nếu a sai thì a = d) Phần này sẽ giới thiệu ở các chương sau.
Cộng (+), Trừ (-), Nhân (*), Chia (/), Lấy Dư (%)
C# cũng như các ngôn ngữ lập trình khác đều có những toán tử cơ bản và chúng rất giống với toán học thực tế.
Dưới đây là một số thí dụ về cách dùng các toán tử cơ bản với 2 biến float x và y như sau:
Addition (+): phép cộng
float x;
float y;
x = 5f + 2f; //x = 7 sau dong nay
x = x + 1f; //x = 8 sau dong nay
y = x + 1f; //y = 9 sau dong nay
Console.WriteLine(x + y); //17 la ket qua duoc in ra man hinh
Subtraction (-): phép trừ
float x;
float y;
x = 5f - 3f; //x = 2 sau dong nay
x = x - 1f; //x = 1 sau dong nay
y = x - 1f; //y = 1 sau dong nay
Console.WriteLine(x - y); //0 la ket qua duoc in ra man hinh
Multiplication (*): phép nhân
float x;
float y;
x = 5f * 3f; //x = 15 sau dong nay
x = x * 2f; //x = 30 sau dong nay
y = x; //y = 30 sau dong nay
Console.WriteLine(x * y); //900 la ket qua duoc in ra man hinh
Division (/): phép chia. Division cũng hay được gọi tắt là div.
float x;
float y;
x = 5f / 2f; //x = 2.5 sau dong nay
x = x / 2f; // x = 1.25 sau dong nay
y = x / 2f; //y = 0.075 sau dong nay
Console.WriteLine(x / y); //2 la ket qua duoc in ra man hinh
Modulus (%): phép chia lấy phần dư, thường được gọi tắt là mod.
float x;
float y;
x = 4 % 3; //x = 1 sau dong nay
x = x % 5; // x = 1 sau dong nay
y = x % 2; //y = 1 sau dong nay
Console.WriteLine(x % y); //0 la ket qua duoc in ra man hinh
Ta có thể để ý thấy, giá trị của x được gán nhiều lần, thậm chí chính nó còn nằm trong vế bên phải. VD: x = x + 1f;
Điều này rất bình thường trong code bởi dấu gán (=) chỉ mang ý nghĩa là “sao chép”, máy tính sẽ thực hiện phép toán bên phải (x + 1f) trước, sau đó mới sao chép giá trị đó vào lại x.
Compound-assignment operators (gán tắt)
Thông thường, một nhân vật bị trúng đòn và mất máu sẽ được code như sau:
float hitPoint = 300f;
float damageTake = 50f;
hitPoint = hitPoint - damageTake; //hitPoint sau dong nay bang 250f;
Dòng hitPoint = hitPoint – damageTake; có thể được code lại là:
- hitPoint -= damageTake;
Dấu -= được gọi là dấu gán tắt (compound-assignment operator) do đây thực chất chỉ là một cách viết tắt nhằm khiến code đẹp và dễ đọc hơn.
Ngoài dấu -= còn có +=, *=, /=, %=. VD:
- hitPoint /= damageTake; nghĩa là hitPoint = hitPoint / damageTake;
Thứ tự tính toán
Nếu trong một statement có rất nhiều phép tính thì thứ tự +, -, *, / sẽ làm giống y hệt những gì toán học đã qui ước.
- Nhân chia trước, cộng trừ sau.
- Thực hiện phép tính trong ngoặc trước.
- Các phép toán phải thực hiện từ trái qua phải.
C# cũng tuân theo qui ước toán học, nó sẽ thực hiện phép tính trong ngoặc trước: (2+1) = 3. Sau đó thực hiện lần lượt từ trái qua phải: 6/2 = 3, rồi nhân 3 = 9.
float x;
x = 6f / 2f * (2 + 1); //ket qua x = 9
Cơ mà nếu bạn không chắc thì chỉ cần… thêm dấu ngoặc đơn vào là xong!
Tuy vậy, việc bạn thực hiện rất nhiều các phép toán trên một statement lại là điều rất hiếm xảy ra.
Giả sử bạn có một nhân vật với 500 máu, kẻ địch gây cho bạn 100 sát thương nhưng bạn có thể giảm được 20% sát thương do đã mặc giáp. Bạn tính lượng máu còn lại sau khi giảm qua giáp như thế này:
float currentHP = 500f;
float damageGet = 100f;
float defDecreaseDmg = 0.2f;
currentHP -= damageGet - (damageGet * defDecreaseDmg);
Dòng currentHP -= damageGet – (damageGet * defDecreaseDmg); là một thí dụ về việc code xấu bởi bạn chẳng hiểu chuyện gì đang diễn ra khi nhìn vào công thức cả – code bắt buộc phải dễ đọc.
Hãy tưởng tưởng sau 1 tuần, 1 tháng, 1 năm, chính bạn hoặc một ai đó đọc code của bạn sẽ phải suy luận ngược ra ý nghĩa dòng code đó, rất mất thời gian và chỉ phát bực!
Để giải quyết vấn đề ấy, người ta sẽ lập ra các biến mới để code tường minh hơn. Ta sửa lại như sau:
float currentHP = 500f;
float damageGet = 100f;
float defDecreaseDmg = 0.2f;
float dmgAfterDecrease= damageGet - (damageGet * defDecreaseDmg);
currentHP -= dmgAfterDecrease;
Hoặc thậm chí tường minh hơn nữa (điểm trừ: code bị dài):
float currentHP = 500f;
float damageGet = 100f;
float defDecreaseDmg = 0.2f;
float dmgReduce = damageGet * defDecreaseDmg;
float dmgAfterDecrease = damageGet - dmgReduce;
currentHP -= dmgAfterDecrease;
Phép chia cho số 0
Lời khuyên của mình là:
Đừng chia cho số 0!
@gamesnhalam
Mặc dù Unity có thể xử lí tốt vấn đề này (ít nhất là không làm crash game) nhưng trong một số trường hợp hãy để ý tới phép chia số 0.
Kết quả thông thường sẽ rơi vào 2 loại:
- Lỗi: máy bỏ qua hoặc crash luôn.
- Kết quả bị đẩy tới vô cực.
Cả 2 trường hợp dù rơi vào đâu cũng rất nguy hiểm.
Quest
Bạn cuối cùng cũng đọc tới cuối chương này.
Chương Trước | Tổng quan | Chương Kế