0

Cách tạo một thanh Cooldown trong game

Thanh cooldown là một thành phần đồ họa không chỉ có ở trong game mà còn ở trong rất nhiều các phần mềm đang thịnh hành hiện nay. Nó dùng để diễn tả khoảng thời gian mà người chơi hoặc người dùng phải chờ để có thể thực hiện một hành động nào đó.

Trong những game nhập vai hoăc chiến thuật như DOTA ,LOL hoặc StarCraft thì đây là một trong nhưng thành phần quan trọng nhất ảnh hưởng đến cục diện trận đấu của game.

Trong bài hướng dẫn này, chúng ta sẽ tìm hiểu cách làm sao để tạo được một thanh cooldown bất kể ngôn ngữ bạn dùng là gì, tất cả sẽ chỉ là code dựng (psuedo-code) và cơ chế hoạt động của thanh cooldown. Bạn có thể lấy demo ở phần cuối của bài viết.

Cơ chế hoạt động cơ bản

Thanh cooldown thực tế là một hình ảnh đồ họa cho việc cooldown và việc cooldown có thể gọi ngắn gọn là việc hẹn giờ cho thứ gì đó. Ví dụ : Khi một hoạt động nào đó được xảy ra, quá trình đếm thời gian bắt đầu, khi quá trình này kết thúc, hành động đó lại có thể được xảy ra lần nữa. Đó là cooldown.

Nếu đứng từ góc độ lập trình, để ngăn chặn một hành động trong quá trình cooldown, ta đặt một biến bool và gán giá trị cho nó bằng “true” khi hành động được thực hiện. Khi chúng ta có gắng thực thi hành động này thì đoạn code sẽ kiểm tra xem biến bool ta đặt ra có phải bằng “false” không và theo như ta gán ở phía trên thì hành động này sẽ không được xảy ra.Khi quá trình đếm thời gian đã kết thúc, ta gán giá trị cho biến bool đó bằng “false” và hành động sẽ được thực hiện.

Khi nút Action được kích hoạt, quá trình đếm được bắt đầu và nút Action bị tắt đi. Trong quá trình đếm ngược , khoảng thời gian được hiển thị và đến cho đến khi nó kết thúc. Nút Action sẽ lại được kích hoạt lại.

Ta hãy xem đoạn code sau :

01. //An object Character has a boolean variable "Cooldown", a numeric variable "cTimer" and another numeric variable "cEndTime"
02. 
03. On clicked Button
04.    txtHistory.text = txtHistory.text & newline & "The character performs an action"
05.    Character.cTimer = 0
06.    Character.cEndTime = txtTimer.text //The text object "Cooldown duration"
07.    Character.Cooldown = True
08.    Button.Enabled = False
09.     
10. If Character.Cooldown = True
11.    Character.cTimer = Character.cTimer + dt
12.   If Character.cTimer >= Character.cEndTime
13.    txtHistory.text = txtHistory.text & newline & "The character is ready to perform an action"
14.        	Character.cTimer = -1
15.        	Character.Cooldown = False
16.       	Button.Enabled = True
17.   Else & Every 0.5 seconds
18.       	 txtHistory.text = txtHistory.text & newline & "The action is on cooldown. " & Character.cEndTime - Character.cTimer & " seconds of cooldown remaining."

Hàm “On clicked Button” chỉ được thực thi khi nút bấm được kích hoạt và phần code bên dưới sẽ chỉ được thực thi khi sau cú click. Đó là hành động người dùng bắt đầu đếm thời gian và đặt “Cooldown” là “true”.

Khi nút bấm được kích hoạt, biến “Character.cEndTime” là thời điểm cho khoảng cooldown kết thúc. Giá trị này được đặt vào đối tượng text “txtTimer” ngay bên cạnh nút Action.

Đồng thời tại thời điểm này, giá trị của “cTimer” được đặt về 0 vì nó được coi là một vòng thời gian đếm ngược mới. “Cooldown” đặt về “true” để cho phép phần thứ 2 của đoạn code được kích hoạt. Cuối cùng, chúng ta vô hiệu hóa nút đi.

Dòng thứ 10 của đoạn code trên được thực thi vào mỗi giây, nó kiểm tra giá trị của “Character.Cooldown” là “true” và nếu thỏa mãn điều kiện nó sẽ thêm giá trị của “dt” vào giá trị hiện tại của “Character.Timer”.

dt” là viết tắt cho delta time, là một biến hệ thống đại diện cho khoảng thời gian cần thiết để vẽ từ khung hình trước cho đến khung hình hiện tại. Điều này có nghĩa là, cho dù máy tính có mạnh mẽ đến đâu, thì chúng ta đều có thể đảm bảo rằng khoangt hời gian đếm ngược cũng sẽ chạy từng đó thời gian.

Nếu như vẫn còn thời gian đếm ngược, chúng ta sẽ kiểm tra giá trị của “cTimer” xem có lớn hơn “cEndTime” không, nếu có, chúng ta phải đi đến cái kết thúc của việc đếm ngược. Chúng ta đặt “Character.Cooldown” là “false” để cho đoạn code này không được thực thi tiếp cho dến khi người dùng ấn nút Action lại.

Đó là tất cả giải thích về cơ chế đếm ngược hay còn gọi là cooldown, sau đây chúng ta sẽ tập trung vào việc làm sao tạo được thanh cooldown.

Thanh Cooldown cơ bản

Một thanh cooldown là một thành phần đồ họa mà nó thay đổi kích thước và hiển thị liên tục . Nó là cơ chế cho người chơi biết có thể tiếp tục thực hiện một hành động.

Thanh bar chuyển từ màu xanh sang màu đỏ thể hiện việc cooldown, nó mở rộng từ 0 cho đến độ rộng ban đầu.

Trong ví dụ trên, thanh bar chỉ đơn thuần là một hình ảnh có độ rộng bằng 100 pixel. Khi hành đông được thực thi, độ rộng giảm về 0 pixel. Sau đó, mỗi giây khi biến “Cooldown” là “true”, độ rộng được trả về với giá trị cũ dựa vào giá trị của “cTimer”.

Hãy xem đoạn code sau:

01	//Using the same "Character" object as in the basic example, this time the object is visible on screen
02 
03 	On any mouse click & Character.Cooldown = False
04    	Character.cTimer = 0
05    	Character.cEndTime = txtEndTimer.text
06    	Character.Cooldown = True
07    	CooldownBar.Width = 0
08    	CooldownBar.AnimationFrame = 1
09     
10	If Character.Cooldown = True
11    	Character.cTimer = Character.cTimer + dt
12    	CooldownBar.Width = (CooldownBar.MaxWidth / Character.cEndTime) *Character.cTimer
13     
14    	If Character.cTimer >= Character.cEndTime
15        	Character.cTimer = -1
16        	Character.Cooldown = False
17        	CooldownBar.Width = CooldownBar.MaxWidth
18        	CooldownBar.AnimationFrame = 0

Cơ chế đếm ngược khá giống với ví dụ bên trên nên chúng ta sẽ tập trung vào “CooldownBar”. Đối tượng này có hai khung hình là hình vuông màu xanh 32x32px và màu đỏ 32x32px. Nó còn có thuộc tính “MaxWidth” được đặt là 100 , là chiều rộng lớn nhất của thanh bar.

Mỗi giây, nếu “Cooldown” là “true”, “CooldownBar.width” được đặt là một phần của “CooldownBar.MaxWidth”. Chúng ta xác định phần này bằng giá trị của việc chia độ rộng lớn nhất với thời gian kết thúc của việc đếm ngược vào sau đó nhân kết quả với giá trị “cTimer”.

Ở thời điểm bắt đầu và kết thúc của việc đếm ngược, chúng ta cần phải đảm bảo chuyển khung hình sang đỏ khi quá trình bắt đầu và sang xanh khi quá trình kết thúc.

Một số cải tiến.

Chúng ta có thể thay đổi điểm bắt đầu của thanh bar nhiều cách khác nhau:

Đếm ngược cho kĩ năng nhân vật

Trong một số game, nút kĩ năng còn thể hiện luôn việc đếm ngược thời gian tái kích hoạt cho kĩ năng. Như ví dụ dưới đây :

Như bạn đã thấy, mỗi kĩ năng có một thanh bar màu đen và một bộ đếm giờ thể hiện việc cooldown. Thanh bar màu đen thực chất là một hình ảnh được đặt trên nút kĩ năng có độ mờ bằng 45%, và bộ đếm thời gian là một đối tượng text. Mỗi nút kĩ năng đều có thực thể của nó là “SkillCover” và “txtSkillTimer”.

Lần này, các biến “Cooldown” , “sTime” và “sEndTime” được gắn vào mỗi thực thể “SkillButton” . Và điểm gốc cho “SkillCover” là cạnh đáy của nó.

Xem đoạn code sau :

01	//Object "SkillButton" with variables "Cooldown" (boolean), "sTime" (numeric), "sEndTime" (numeric), and a specific animation frame to know which instance is being clicked/selected.
02	//Object "SkillCover" with a variable "Skill" set accordingly to the animation frame of the SkillButton they are related to.
03	//Object "txtSkillTimer" with a variable "Skill" for the same purpose as above.
04	On SkillButton clicked & SkillButton.Cooldown = False
05	    SkillButton.sTime = 0
06	    SkillButton.Cooldown = True
07	    Create Proj & ProjImage objects
08	    ProjImage.AnimationFrame = SkillButton.AnimationFrame //To either throw a dagger or a ninja star
09     
10	    txtSkillTimer.Skill = SkillButton.AnimationFrame
11	    &
12	    SkillCover.Skill = SkillButton.AnimationFrame
13	        Set txtSkillTimer's position to the bottom of SkillButton
14	        Set SkillCover's position to the bottom of SkillButton
15	        Set txtSkillTimer in Front of SkillButton
16	        Set SkillCover behind txtSkillTimer //Still in front of SkillButton
17	        txtSkillTimer.Visible = True
18	        SkillCover.Visible = True
19	        SkillCover.Height = SkillButton.Height
20	 
21	For each SkillButton & SkillButton.Cooldown = True
22	    SkillButton.sTime = SkillButton.sTime + dt
23     
24	    txtSkillTimer.Skill = SkillButton.AnimationFrame
25	    &
26	    SkillCover.Skill = SkillButton.AnimationFrame
27	        txtSkillTimer.text = SkillButton.sEndTime - SkillButton.sTime
28	        SkillCover.height = SkillButton.Height - ((SkillButton.Height / SkillButton.sEndTime) * SkillButton.sTime)
29	     
30	        If SkillButton.sTime >= SkillButton.sEndTime
31	            SkillButton.sTime = -1
32	            SkillButton.Cooldown = False
33                     
34	            txtSkillTimer.Skill = SkillButton.AnimationFrame
35	            &
36	            SkillCover.Skill = SkillButton.AnimationFrame
37	                txtSkillTimer.Visible = False
38	                SkillCover.Visible = False

Ở đây, chúng ta chọn đúng thực thể của “txtSkillTimer” và “SkillCover”. Không giống như thanh cooldown trước, “Skillcover” bắt đầu từ đầy cho đến vơi, che toàn bộ chiều cao của “SkillButton”, và sau đó trong quá trình đếm ngược sẽ bắt đầu giảm chiều cao để hở ra hình ảnh của nút.

Để làm được việc này, chúng ta cho “SkillCover” chiều cao bằng với “SkillButton” để bắt đầu, và sau mỗi khung hình, sẽ trừ đi (“SkillButton.Height” / “SkillButton.sEndTime”) * “SkillButton.sTime” từ chiều cao đủ của nó.

Bạn có thể làm nhiều hơn với “SkillCover”, tất cả đều dựa vào trí tưởng tượng và kĩ năng mĩ thuật của bạn.

Kết luận

Bạn có thể dùng rất nhiều cách để tạo một thanh cooldown bar .Không có một khuôn mẫu nào có định cho nó. Tất cả đều phụ thuộc vào kĩ năng của bạn. Bạn có thể lấy hướng dẫn ở đây :

https://github.com/tutsplus/HUD-Cooldown-Bars

Cảm ơn bạn đã đọc bài hướng dẫn và mong được nghe những phản hồi từ phía bạn.

REF : https://gamedevelopment.tutsplus.com/tutorials/how-to-code-hud-cooldown-bars--cms-20983


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí