Trong các trò chơi và phần mềm ngày nay, thanh Cooldown đã trở thành một thành phần đồ họa quan trọng. Nó dùng để cho người chơi hoặc người dùng biết phải chờ một thời gian nhất định để thực hiện một hành động. Trong game nhập vai và chiến thuật như DOTA, LOL và StarCraft, thanh Cooldown đóng vai trò quan trọng trong cục diện trận đấu.
Mục lục
Trong bài viết này, chúng ta sẽ tìm hiểu cách tạo thanh Cooldown bằng code, không phụ thuộc vào ngôn ngữ lập trình. Đây chỉ là code giả và cơ chế hoạt động của thanh Cooldown. Bạn có thể xem demo ở cuối bài viết.
Cơ chế hoạt động của thanh Cooldown
Thực tế, thanh Cooldown là một hình ảnh đồ họa thể hiện thời gian chờ đợi và thời gian chờ đợi còn lại cho một hành động. Khi một hành động được thực hiện, quá trình đếm thời gian bắt đầu. Khi quá trình này kết thúc, hành động đó có thể được thực hiện lại. Đó chính là Cooldown.
Nếu nhìn từ góc độ lập trình, để ngăn chặn một hành động trong quá trình Cooldown, chúng ta đặt một biến bool và gán giá trị “true” khi hành động được thực hiện. Khi muốn thực hiện hành động này, chỉ cần kiểm tra xem biến bool có giá trị “false” không, nếu có, hành động này sẽ không được thực hiện. Khi quá trình đếm thời gian kết thúc, gán giá trị “false” cho biến bool đó và hành động sẽ được thực hiện.
Khi nút “Action” được kích hoạt, quá trình đếm thời gian 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ị cho đến khi kết thúc. Sau đó, nút “Action” lại được kích hoạt lại.
Ví dụ về Cooldown trong game
Dưới đây là đoạn mã:
// Character là một đối tượng có biến bool "Cooldown", biến số "cTimer" và biến số "cEndTime"
// Khi nhấp vào nút Button
txtHistory.text = txtHistory.text & newline & "Nhân vật thực hiện một hành động"
Character.cTimer = 0
Character.cEndTime = txtTimer.text // Định thời gian Cooldown trong đối tượng text "txtTimer"
Character.Cooldown = True
Button.Enabled = False
If Character.Cooldown = True
Character.cTimer = Character.cTimer + dt
If Character.cTimer >= Character.cEndTime
txtHistory.text = txtHistory.text & newline & "Nhân vật đã sẵn sàng thực hiện hành động"
Character.cTimer = -1
Character.Cooldown = False
Button.Enabled = True
Else Every 0.5 seconds
txtHistory.text = txtHistory.text & newline & "Hành động đang trong quá trình cooldown. Còn " & Character.cEndTime - Character.cTimer & " giây nữa"
Trong đoạn mã này, hàm “On clicked Button” chỉ được thực thi khi nút được kích hoạt và đoạn mã bên dưới chỉ được thực thi sau khi click. Đó là hành động bắt đầu đếm thời gian và đặt “Cooldown” là “true”.
Khi nút được kích hoạt, biến “Character.cEndTime” sẽ là thời điểm kết thúc của Cooldown. Giá trị này được lấy từ đối tượng text “txtTimer” ngay bên cạnh nút “Action”.
Tại thời điểm này, giá trị “cTimer” được đặt về 0 vì đây là một vòng đếm ngược mới. “Cooldown” được đặt “true” để cho phần tiếp theo của đoạn mã được thực thi. Cuối cùng, việc bấm nút bị vô hiệu hóa.
Dòng số 10 trong đoạn mã trên được thực thi mỗi giây, kiểm tra giá trị “Character.Cooldown” là “true” và nếu thỏa mãn, thêm giá trị của “dt” vào giá trị hiện tại của “Character.Timer”.
“dt” là biến đại diện cho khoảng thời gian cần thiết để vẽ từ khung hình trước đến khung hình hiện tại. Điều này đảm bảo rằng dù máy tính có mạnh đến đâu, thì tỷ lệ Cooldown sẽ chạy đồng đều.
Nếu vẫn còn thời gian Cooldown, kiểm tra giá trị “cTimer” xem có lớn hơn “cEndTime” không, nếu có, chuyển đến kết thúc đếm ngược. Gán giá trị “Character.Cooldown” là “false” để đoạn mã này không được thực thi cho tới khi người dùng nhấn nút “Action” lại.
Sau tất cả, đó là cơ chế đếm ngược hay còn gọi là Cooldown. Bài viết tiếp theo, chúng ta sẽ tập trung vào cách tạo thanh Cooldown.
Tạo thanh Cooldown trong game
Một thanh Cooldown là một thành phần đồ họa 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 đến độ rộng ban đầu.
Trong ví dụ trên, thanh bar chỉ đơn thuần là một hình ảnh có chiều rộng 100 pixel. Khi hành động được thực hiện, chiều rộng giảm xuống 0 pixel. Sau đó, mỗi giây khi biến “Cooldown” là “true”, chiều rộng được phục hồi với giá trị cũ dựa trên giá trị của “cTimer”.
Dưới đây là đoạn mã:
// Sử dụng đối tượng "Character" như trong ví dụ cơ bản trước, lần này đối tượng thể hiện trên màn hình
On any mouse click & Character.Cooldown = False
Character.cTimer = 0
Character.cEndTime = txtEndTimer.text
Character.Cooldown = True
CooldownBar.Width = 0
CooldownBar.AnimationFrame = 1
If Character.Cooldown = True
Character.cTimer = Character.cTimer + dt
CooldownBar.Width = (CooldownBar.MaxWidth / Character.cEndTime) * Character.cTimer
If Character.cTimer >= Character.cEndTime
Character.cTimer = -1
Character.Cooldown = False
CooldownBar.Width = CooldownBar.MaxWidth
CooldownBar.AnimationFrame = 0
Trong đoạn mã này, cơ chế đếm ngược tương tự như ví dụ trước, chúng ta 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”. Phần này được xác định bằng cách chia chiều rộng lớn nhất cho thời gian kết thúc của Cooldown và nhân kết quả với giá trị “cTimer”.
Bạn có thể tạo nhiều loại thanh Cooldown khác nhau, tất cả phụ thuộc vào trí tưởng tượng và kỹ năng mỹ thuật của bạn.
Ví dụ khác về Cooldown trong game
Một số trò chơi có hiển thị thời gian Cooldown của kỹ năng trên nút kỹ năng. Ví dụ dưới đây thể hiện cách làm:
Mỗi kỹ năng có một thanh bar màu đen và một bộ đếm giờ thể hiện 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ức độ mờ là 45%, và bộ đếm thời gian là một đối tượng text. Mỗi nút kỹ năng có thực thể riêng của nó là “SkillCover” và “txtSkillTimer”.
Lần này, biến “Cooldown”, “sTime” và “sEndTime” được gán vào từng thực thể “SkillButton”. Và điểm gốc của “SkillCover” là cạnh dưới của nó.
Dưới đây là đoạn mã:
// Đối tượng "SkillButton" có biến "Cooldown" (bool), "sTime" (số), "sEndTime" (số) và khung hình ảnh để biết chính xác thực thể nào được nhấp/chọn.
// Đối tượng "SkillCover" có biến "Skill" được đặt phù hợp với khung hình ảnh của "SkillButton" liên quan.
// Đối tượng "txtSkillTimer" có biến "Skill" cùng mục đích như trên.
On SkillButton clicked & SkillButton.Cooldown = False
SkillButton.sTime = 0
SkillButton.Cooldown = True
Create Proj & ProjImage objects
ProjImage.AnimationFrame = SkillButton.AnimationFrame // Để tung ra dạ dao hay dấu sao ninja
txtSkillTimer.Skill = SkillButton.AnimationFrame &
SkillCover.Skill = SkillButton.AnimationFrame
Set txtSkillTimer's position to the bottom of SkillButton
Set SkillCover's position to the bottom of SkillButton
Set txtSkillTimer in Front of SkillButton
Set SkillCover behind txtSkillTimer // Vẫn nằm phía trước SkillButton
txtSkillTimer.Visible = True
SkillCover.Visible = True
SkillCover.Height = SkillButton.Height
For each SkillButton & SkillButton.Cooldown = True
SkillButton.sTime = SkillButton.sTime + dt
txtSkillTimer.Skill = SkillButton.AnimationFrame &
SkillCover.Skill = SkillButton.AnimationFrame
txtSkillTimer.text = SkillButton.sEndTime - SkillButton.sTime
SkillCover.height = SkillButton.Height - ((SkillButton.Height / SkillButton.sEndTime) * SkillButton.sTime)
If SkillButton.sTime >= SkillButton.sEndTime
SkillButton.sTime = -1
SkillButton.Cooldown = False
txtSkillTimer.Skill = SkillButton.AnimationFrame &
SkillCover.Skill = SkillButton.AnimationFrame
txtSkillTimer.Visible = False
SkillCover.Visible = False
Ở đây, chúng ta đã chọn đúng thực thể “txtSkillTimer” và “SkillCover”. Không giống như thanh Cooldown trước, “SkillCover” bắt đầu từ đầy trọn và hơi dần để hở ra hình ảnh của nút khi đếm ngược diễn ra.
Để làm điều này, chúng ta gán chiều cao của “SkillCover” bằng chiều cao của “SkillButton” ở thời điểm ban đầu, rồi sau mỗi khung hình, trừ đi (“SkillButton.Height” / “SkillButton.sEndTime”) nhân với “SkillButton.sTime” từ chiều cao ban đầu của nó.
Bạn có thể tạo nhiều loại thanh Cooldown khác nhau, tất cả phụ thuộc vào sự sáng tạo và kỹ năng của bạn.
Rất mong nhận được những phản hồi từ phía bạn và cảm ơn đã đọc bài hướng dẫn này.
Ref: Link tham khảo