C là một ngôn ngữ lắt léo, không hoàn thiện và là một thành công lớn. Dennis M. Ritchie
STDIO Tiếp tục chuỗi bài viết Hướng Dẫn Hiện Thực Game Zero Với Unity, ở phần trước, tôi đã giới thiệu và hướng dẫn các bạn cách hiện thực gameplay của game Zero. Trong phần 3 này, tôi sẽ giúp các bạn hoàn thiện gameplay với các tính năng thú vị hơn với người chơi là hiển thị điểm số hiện tại và vòng tròn thời gian (Progress Timer).
Nội dung bài viết

Giới thiệu

Tiếp tục chuỗi bài viết Hướng Dẫn Hiện Thực Game Zero Với Unity, ở phần trước, tôi đã giới thiệu và hướng dẫn các bạn cách hiện thực gameplay của game Zero. Trong phần 3 này, tôi sẽ giúp các bạn hoàn thiện gameplay với các tính năng thú vị hơn với người chơi là hiển thị điểm số hiện tại và thời gian (Progress Timer).

Tiền đề bài viết

Bài viết thuộc chuỗi bài viết Hướng Dẫn Hiện Thực Game Zero Với Unity, giúp bạn đọc biết cách quản lý project và xây dựng một game đơn giản với Unity.

Đối tượng hướng đến

Bài viết hướng đến đối tượng MỚI BẮT ĐẦU với Lập trình game trên Unity. Script hướng dẫn trong bài được viết bằng ngôn ngữ C# nên bạn đọc cần có kiến thức tương đối về C# để có thể đọc hiểu tốt.

Bạn đọc vui lòng tham khảo bài viết Hiện Thực Game Zero Với Unity - Phần 2 - Hiện Thực Gameplay để nắm được gameplay và các thành phần cơ bản của gameplay.

Các bài viết thuộc series

Lưu trữ điểm số và hiển thị

Static.s_score

Điểm số trong Zero được sử dụng duy nhất trong Gameplay, do Zero không hỗ trợ các tính năng như Leaderboard (bảng xếp hạng), hay Statistic (bảng thống kê các số liệu người chơi đạt được), … nên bạn hoàn toàn có thể lưu trữ điểm số ở GameManager. Tuy nhiên, tôi khuyến khích các bạn hiện thực theo hướng tổng quát hoá, có thể tái ứng dụng trong các trò chơi khác có quy mô lớn hơn.

Để hiện thực tổng quát, tôi đặt biến lưu trữ điểm số tại lớp Static (dòng 13, Statics.cs):

public static int s_score;

Thuộc tính này có thể truy cập ở bất cứ nơi nào trong project. Do lớp Static được tôi đặt trong namespace Stdio nên bạn đọc cần lưu ý dòng code sau (dòng 2, GameManager.cs):

using Stdio;

namespace Stdio phải được import trước khi sử dụng bất cứ thành phần nào chứa trong nó. Đây là một kỹ thuật quản lý code của C# nên bạn đọc không cần thắc mắc tại sao lại cần thiết làm điều này.

s_score sẽ được cập nhật lại khi người chơi vượt qua một level. Tôi sẽ dừng lại và cùng các bạn xem xét một chút về cấu trúc của game và có hướng hiện thực hiệu quả nhất.

Hàm CheckAnswer thuộc script ButtonManager như sau:

public void CheckAnswer()
{
       GameManager manager = GameObject.FindGameObjectWithTag("GameManager").GetComponent<GameManager>();

       if(gameObject.name == "BtnRight")
       {
              if (manager.IsRightAnswer())
                     manager.GenerateNextCalculation();
              else
                     Static.S_Debug("You're wrong!");
       }
       else
       {
              if (!manager.IsRightAnswer())
                     manager.GenerateNextCalculation();
              else
                     Static.S_Debug("You're wrong!");
       }
}

Tham khảo bài viết Hiện Thực Game Zero Với Unity – Phần 2 – Hiện Thực Gameplay.

Ta thấy, với mỗi button đều có hai trường hợp xảy ra. Nếu s_score được cập nhật trực tiếp ở mỗi button, bạn cần sao chép đoạn code đó sang vị trí tương ứng ở button còn lại, chưa kể đến hai phím mũi tên được gắn chức năng của hai button mà tôi đã hiện thực ở bài viết trước. Do đó hiện thực theo cách này sẽ khá bất tiện và kém hiệu quả.

Nếu để ý, bạn sẽ thấy với mỗi trường hợp trả lời đúng, hàm GenerateNextCalculation sẽ được gọi để tạo thử thách tiếp theo, bất kể là với phím hay button nào. Do đó, tôi thêm đoạn code xử lý s_score vào hàm GenerateNextCalculation như sau (dòng 90, GameManager.cs):

Static.s_score++;

Nếu xem xét kĩ hàm Start tại GameManager.cs, bạn sẽ thấy tôi khởi tạo giá trị cho s_score bằng -1. Do ngay khi game bắt đầu, tôi cho tạo một thử thách đầu tiên dẫn đến việc tăng s_score lên khi chưa bắt đầu chơi. Đây chỉ là một mẹo nhỏ nhưng các bạn cần lưu ý để hiện thực game được hiệu quả hơn.

Hiển thị điểm số ra màn hình

Để đưa s_score hiển thị lên màn hình game, tôi sử dụng UI Text. Thao tác với UI Text bạn đọc xem thêm bài viết Thiết Kế Giao Diện Người Dùng Trên Unity. Trước khi thao tác với UI, bạn cần import thư viện như sau (dòng 3, GameManager.cs):

using UnityEngine.UI;

Tôi khởi tạo một thuộc tính có kiểu Text để tiện xử lý (dòng 19, GameManager.cs). Sau khi cập nhật điểm số, thuộc tính này cũng được thay đổi theo như sau (dòng 91, GameManager.cs):

m_scoreText.text = Static.s_score.ToString();

Chi tiết về cách hiện thực bạn đọc xem thêm trong project đính kèm.

Đến đây, bạn có thể chạy thử và xem thành quả đạt được.

ss_1

Hiện thực Progress Timer

Progress Timer trong Zero được biểu diễn dưới dạng Clock (đồng hồ). Khoảng thời gian đã trôi qua của một level được thể hiện bằng tỉ lệ phần được vẽ của Clock.

Unity hỗ trợ hiện thực đúng như mong muốn của tôi với UI Image. Các bước hiện thực Progress Timer:

  • Tạo UI Image, đặt tên là ProgressTimer.
  • Kéo sprite spr_clock từ spritesheet vào thuộc tính Source Image của Progress Timer.
  • Chọn Image Type là Filled. Các thông số còn lại được thiết lập như sau:

ss_2

Chú ý thuộc tính Fill Amount. Thuộc tính này quyết định tỉ lệ hình sẽ được hiển thị, 0 tương ứng với hình hoàn toàn không được hiển thị và 1 tương ứng với toàn bộ hình đều được hiển thị.

Đồng bộ Progress Timer với thời gian thực của game

Progress Timer tạo ra ở trên chỉ là hình ảnh hiển thị của thời gian chơi trong game, chúng ta sẽ quản lý thời gian với Script.

Để quản lý thời gian, tôi sử dụng hai thuộc tính CurrentTime LevelTime. CurrentTime là thời gian hiện tại, tính từ thời điểm một level mới được bắt đầu, LevelTime chính là thời gian tối đa người chơi có được trong level đó. Ngoài ra, để thay đổi tỉ lệ vẽ của ProgressTimer, tôi sử dụng thêm một thuộc tính UI Text. Khai báo các thuộc tính trên như sau (dòng 21-23, GameManager.cs):

private float          m_currentTime;
private float          m_levelTime;
public  Image          m_progressTimer;

Tương tự như phần hiển thị điểm số đề cập ở trên, ta phải import thư viện UnityEngine.UI trước khi sử dụng Image.

Tại hàm Start, tôi thêm phần khai báo giá trị ban đầu cho các thuộc tính trên như sau (dòng 39-40, GameManager.cs):

m_levelTime = 1.5f;
m_currentTime = 0f;

Quản lý thời gian và cập nhật Progress Timer (dòng 49-53, GameManager.cs):

m_currentTime += Time.deltaTime;
if (m_currentTime >= m_levelTime)
            m_currentTime = 0f;

m_progressTimer.fillAmount = m_currentTime / m_levelTime;

Thuộc tính fillAmount của Progress Timer truyền vào từ Unity Editor sẽ được cập nhật lại tương ứng với currentTime. Lưu ý là fillAmount sẽ thay đổi trong khoảng (0, 1) còn currentTime thay đổi trong khoảng (0, levelTime). Do đó chúng ta sẽ điều chỉnh lại currentTime theo tỉ lệ phù hợp trước khi gán vào fillAmount.

Cuối cùng, để currentTime cập nhật lại từ đầu sau mỗi level, tôi thêm dòng sau vào hàm GenerateNextCalculation (dòng 93, GameManager.cs):

m_currentTime = 0f;

Đến đây cơ bản gameplay đã hoàn thiện. Bạn có thể chạy thử và xem thành quả đạt được. Nếu vẫn còn thắc mắc hoặc khó khăn, bạn đọc có thể xem thêm project đính kèm.

ss_3

Trong bài viết sau, tôi sẽ hiện thực về quản lý trạng thái game và hiện thực hệ thống scene/popup trong Unity.

Download Project

STDIO_ZeroUnity-3.

Bạn cần hỗ trợ các dự án kết nối không dây?

Quí doanh nghiệp, cá nhân cần hỗ trợ, hợp tác các dự án IoT, kết nối không dây. Vui lòng liên hệ, hoặc gọi trực tiếp 0942.111912.

  • TỪ KHÓA
  • Arduino
  • ESP32
  • ESP8266
  • Wifi
  • Bluetooth
  • Zigbee
  • Raspberry Pi
THẢO LUẬN
ĐÓNG