Mô tả cách hoạt động của thư viện đồ họa trong thư viện đồ họa đã được đề cập trong phần 4.1
6.3. Kiến trúc quản lý ảnh
6.3.1. Sơ đồ lớp
Sơ đồ các lớp quản lý ảnh
Hình 6-42-Sơ đồ lớp quản lý lưu trữ
6.3.2. Ý nghĩa các thành phần
STT Tên thành
phần Ý nghĩa
1 ImageManager Lớp quản lý truy xuất các ảnh sử dụng trong game
2 Sprite Lớp quản lý ảnh animation
3 SpriteManager Lớp quản lý các Sprite
Bảng 6-15-Ý nghĩa các lớp quản lý hình ảnh
6.4. Kiến trúc xử lý logic
6.4.1. Sơ đồ kiến trúc
Hình 6-43-Kiến trúc xử lý logic
Ý nghĩa các thành phần
ST
T Tên thành phần Ý nghĩa
1 GamePanel Lớp quản lý xử lý chung của game. Làm nhiệm vụ chuyển đổi giữa các loại màn hình trong game và quản lý framework chính của game.
2 GameLogic Nhóm các lớp quản lý các thông tin về logic của game như quan hệ giữa các công trình, quân lính, phép thuật,... trong game.
3 GameQuest Lớp quản lý các vòng chơi trong game. Đọc nội dung từ tập tin XML.
4 GameAI Lớp xử lý AI trong game.
5 GameManager Các lớp xử lý cho các loại màn hình chính của game.
6.4.2. Cách hoạt động
6.4.2.1. Cơ chế hoạt động của framework game
Game hoạt động theo cơ chế gồm 4 bước : Update, Render, Draw, Sleep1. Toàn bộ cơ chế này của game được quản lý bởi lớp GamePanel. Lớp GamePanel sẽ nhận sự kiện phát sinh và truyền các sự kiện đó đến những lớp xử lý game tương ứng. Đồng thời, lớp GamePanel cũng sẽ chuyển đổi giữa các lớp xử lý 3 loại màn hình trong game.
Hình 6-44-Cơ chế hoạt động xử lý các loại vòng chơi chính của game
Cơ chế hoạt động của framework game bao gồm các bước sau:
- Bước 1: Khi game khởi tạo, lớp GamePanel sẽ đọc các thư viện AI của game vào chương trình dưới dạng các plugin.
- Bước 2: Sau khi nạp các plugin AI, lớp GamePanel sẽ lưu lại thành một danh sách các interface IAIPlugins. Các AI này sẽ cung cấp các chức năng xử lý thông tin.
- Bước 3: Lớp GamePanel cũng khởi tạo các lớp quản lý 3 loại màn hình của game là WorldManager, BattleManager và TownManager. Ba lớp xử lý này sẽ cung cấp các giá trị cho lớp GamePanel biết khi nào cần chuyển qua các màn hình khác. - Bước 4: Trong quá trình thực thi, các lớp quản lý game sẽ sử dụng các AI của game để xử lý lối chơi cho máy.
6.4.2.2. Cơ chế hoạt động các lớp quản lý logic game
Các lớp xử lý logic của game bao gồm 3 phần chính : GameType, GameInfo và GameInstance
GameType : đây là các lớp quản lý các thông tin logic của game như các loại đối tượng chính trong game (công trình, phép thuật, công nghệ,...) Các lớp này được lưu trữ trong lớp GameLogic và được tạo ra dựa trên nội dung file xml mô tả logic của game.
GameInfo : đây là các lớp mô tả thông tin của các đối tượng trong game. Các lớp này có thể là các đối tượng thông tin có trong logic của game. Các lớp này được tạo ra từ lớp GameType tương ứng. Ngoài ra còn có một nhóm các lớp quản lý các thông tin không có trong GameType như lớp quản lý các người chơi, nhóm quân lính.
GameInstance : đây là các lớp xử lý các đối tượng thể hiện được lên màn hình của game như các quân lính chuyển động trên bản đồ, thị trấn hay trong các trận chiến, các công trình,...
Hình 6-45-Cơ chế xử lý thông tin trong game
Cơ chế xử lý thông tin trong game bao gồm các bước sau :
- Bước 1: Lớp GameLogic đọc thông tin logic của game từ tập tin Logic.xml.
- Bước 2: Lớp GameLogic tạo ra các lớp GameType tương ứng ứng với từng loại đối tượng thông tin cụ thể.
- Bước 3: Trong quá trình game thực thi, các lớp GameInfo (chức thông tin của các đối tượng hiện tại trong game như thông tin các quân lính hiện tại, anh hùng hiện tại... ) sẽ tạo nên các đối tượng thông tin trong game từ các lớp GameType. Ví dụ khi thuê một loại quân lính nào đó, lớp UnitInfo sẽ sử dụng lớp UnitType để khởi tạo các giá trị.
- Bước 4: Khi cần thể hiện ra màn hình các đối tượng thông tin của game, các lớp GameInstance sẽ được tạo ra từ các lớp GameInfo. Ví dụ khi chiến đấu, các lớp GameInfo được lưu trong thông tin của nhóm quân đó sẽ được tạo thành các đối tượng Unit để thể hiện quân lính chuyển động trên màn hình. Trong quá trình thực thi game, các lớp GameInstance sẽ cập nhật thông tin của game vào các lớp GameInfo tương ứng của nó.
6.4.2.3. Cơ chế xử lý vòng chơi trong game
Các vòng chơi trong game sẽ được xử lý dựa trên lớp GameQuest. Lớp này làm nhiệm vụ đọc cái vòng chơi từ tập tin Quests.xml.
Hình 6-46-Cơ chế xử lý các vòng chơi trong game
Cơ chế xử lý vòng chơi:
- Bước 1: Lớp GameQuest đọc thông tin các vòng chơi từ tập tin Quests.xml.
- Bước 5: Lớp GameQuest tạo ra các đối tượng QuestType từ nội dung của tập tin Quests.xml.
- Bước 6: Lớp GameLogic sử dụng lớp GameQuest để khởi tạo vòng chơi cần thiết.
6.4.3. Vấn đề về kỹ thuật lập trình
Vấn đề
Tối ưu hóa những giải thuật cho lập trình game trên mobile là điều tối quan trọng nhưng điều đó vẫn chưa đủ và vẫn chưa giúp game đạt được hiệu suất cao
nhất có thể. Điều này xuất phát từ kỹ thuật lập trình, cách sử dụng các phép toán, các câu lệnh,...
Trong lập trình, có những thao tác rất đơn giản và tốc độ của nó không quá chậm hơn so với những thao tác sau khi đã được tối ưu. Tuy nhiên, nếu thực hiện một lần chỉ làm chậm đi một khoảng thời gian nhỏ thì sau khi thực hiện đoạn lệnh đó một ngàn hay một triệu lần thì khoảng thời gian đã mất đi trở nên một con số đáng kể. Điều này có thể dễ dàng thấy trong các thuật toán mã hóa nơi đòi hỏi các chương trình cài đặt thuật toán đó phải chạy với tốc độ nhanh nhất có thể được. Vấn đề này càng trở nên quan trọng trong lập trình game. Một giây game cần phải tạo ra 10 khung hình, 1 phút game cần tạo ra 600 khung hình. Trong khi đó mỗi khung hình lại là kết quả của nhiều thao tác tính toán. Chỉ với những tính toán đơn giản đó, ta đã có thể thấy được tầm quan trọng trong việc tối ưu mã nguồn.
Giải pháp
Nhằm mục đích đạt được tốc độ nhanh nhất có thể, chúng em đã tận dụng một số kỹ thuật lập trình để ít chiếm bộ nhớ cũng như cài thiện phần nào đó tốc độ của game. Các kỹ thuật như sử dụng biến với kích thước vừa phải, hạn chế những phương thức public, thay thế nhiều nhất có thể các thao tác tính toán bình thường bằng các phép toán trên bit (dịch trái, dịch phải, XOR, AND, OR),...
Kết luận
Chúng em đã cố gắng tìm hiểu những kỹ thuật lập trình nhằm tối ưu mã nguồn giúp game vận hành ổn định hơn. Những thao tác như sử dụng các cờ dựa trên mỗi bit và kiểm tra bằng các phép toán AND, OR cũng giúp chúng em giảm thiểu đáng kể lượng biến cần dùng qua đó giúp các xử lý, giải thuật đạt hiệu quả tốt hơn.
6.4.4. Kiểm tra các quan hệ 1-n giữa các đối tượng
Vấn đề
Trong một game dàn trận thông thường, để xây dựng một công trình hay nghiên cứu một công nghệ nào đó thường đòi hỏi người chơi phải xây một số các nhà nào đó trước hoặc nghiên cứu trước một số công nghệ nào đó. Mối quan hệ này
đôi khi là quan hệ 1-n. Vậy tìm ra giải pháp kiểm tra các điều kiện này một cách nhanh chóng và hợp lý sẽ giảm bớt chi phí xử lý logic của game.
Giải pháp
Vấn đề về mối ràng buộc này của công trình và công nghệ hoàn toàn giống nhau nên ta chỉ cần giải quyết vấn đề kiểm tra các quan hệ này cho công trình.
Cách đơn giản nhất để kiểm tra một công trình có được phép xây dựng hay không là ta duyệt tuần tự qua danh sách các công trình cần thiết, với mỗi công trình cần thiết ta kiểm tra xem công trình đó có nằm trong danh sách các công trình đã có hay không. Cách làm nay buộc ta phải duyệt danh sách quá nhiều lần, tốc độ sẽ càng chậm hơn khi số phần tử trong 2 danh sách trên tăng lên. Chính vì vậy, cần phải tìm một giải pháp khác, hiệu quả hơn để giải quyết vấn đề ràng buộc.
Nhằm giải quyết vấn đề trên, chúng em quyết định chọn giải pháp sử dụng biến để đánh dấu các công trình cần thiết. Biến này là một số nguyên. Mỗi công trình trong game khi đọc vào trong bộ nhớ sẽ được gán một chỉ số index là thứ tự đọc vào bộ nhớ của công trình đó. Với mỗi công trình cần thiết, bit ở một vị trí index của công trình đó bật lên 1. Khi cần kiểm tra, ta tính một giá trị biến đánh dấu cho các công trình đã có và đem kết quả AND với từng biến đánh dấu của mỗi công trình. Nếu kết quả bằng với biến đánh dấu của của công trình đó thì sẽ được phép xây dựng công trình. Hình dưới là ví dụ cho thấy kết quả AND giữa 2 biến sẽ xác định công trình có được phép xây dựng hay không. Hình 25 công trình muốn xây dựng cần phải có các công trình ở vị trí 0, 1 và 3. Hình 25(a) công trình không được xây dựng do công trình ở vị trí 3 chưa được xây dựng nên giá trị AND khác giá trị đánh dấu ban đầu. Hình 25(b) công trình được phép xây dựng do tất cả các công trình cần thiết đều đã có nên kết quả AND bằng với giá trị các công trình biến đánh dấu cho các công trình cần thiết.
Hình 6-47-Kết quả AND bit xác định công trình có được phép xây dựng không
Vì bộ nhớ mobile không cho phép xây dựng game với quá nhiều công trình nên chúng em sử dụng biến đánh dấu 8 byte cho phép đánh dấu tối đa 64 công trình. Đây cũng là số lượng công trình khá lớn và hợp lý đối với game nói chung cũng như game trên mobile nói riêng. Thậm chí các game trên nền PC như Age of Empires II cũng chỉ có 28 công trình tất cả.
Kết luận
Với giải pháp này, việc kiểm tra chỉ còn phải duyệt trên một danh sách, các phép kiểm tra thực hiện bằng cách AND các bit nên chi phí tìm kiếm giảm đi rất nhiều.
6.5. Cơ chế mở rộng trong game
6.5.1. Cơ chế mở rộng thông tin logic của game
Các thông tin xử lý logic trong game như các thị trấn, quân lính, anh hùng, tài nguyên, thuộc tính nguyên tố, công trình, công nghệ, phép thuật đều được đặc tả từ tập tin XML. Các thông tin này sau khi đọc lên sẽ được đưa tạo thành các lớp GameType. Trong quá trình xử lý game, khi cần thiết, các lớp GameInfo có thể được khởi tạo từ các lớp GameType. Game chỉ lưu trữ các lớp GameInfo cho xử lý của game. Các lớp GameType chỉ nhằm mục đích khởi tạo các GameInfo tương ứng. Khi cần thể hiện các đối tượng ra màn hình như các ngôi nhà trên bản đồ, quân lính di chuyển,... thì các lớp GameInstance sẽ được tạo ra từ các lớp GameInfo. Các lớp này cũng sẽ cập nhật thông tin cho các lớp GameInfo của nó. Chi tiết về xử lý các lớp GameType, GameInfo, GameInstance trình bày trong phần 6.4.2.2.
Ý nghĩa cơ chế xử lý công trình trong game:
- Bước 1: Lớp GameLogic đọc thông tin công trình tập tin Quest.xml. - Bước 7: Lớp GameLogic tạo ra các đối tượng BuildingType và TownType từ các thông tin đọc từ tập tin Logic.xml. Bước 2.1 tạo ra đối tượng BuildlingType và bước 2.2 tạo ra đối tượng TownType.
- Bước 8: Xử lý thông tin logic trong quá trình game thực thi.
a. Bước 3.1: Lớp TownInfo được khởi tạo dựa trên các thông tin của TownType.
b. Bước 3.2: Khi xây dựng công trình, các đối tượng BuildingInfo sẽ được tạo ra và lưu vào trong lớp TownInfo. Đồng thời, các lớp BuildingInfo cũng dựa trên các thông tin có trong TownInfo để tạo ra các công trình và cập nhật thêm thông tin cho TownInfo (thông tin các công trình có thể được xây dựng tiếp theo, các quân lính được phép thuê, các công nghệ, phép thuật có thể học,...)
c. Bước 3.3: Lớp BuidlingInfo dựa trên lớp BuildingType để khởi tạo. - Bước 9: Tương tác giữa các đối tượng thể hiện và các đối tượng thông tin a. Bước 4.1: Trong quá trình thực thi, lớp Town cập nhật các thông tin vào TownInfo (thông tin các công trình, quân lính, ... hiện có hay sẵng sàng để tạo). Lớp Town cũng được khởi tạo và lấy các thông tin từ TownInfo.
b. Bước 4.2: Lớp Town tương tác với lớp Building để thể hiện các công trình lên màn hình.
c. Bước 4.3: Lớp Building được khởi tạo từ BuildingInfo và cập nhật các thông tin cần thiết vào BuildingInfo.
Các đối tượng xử lý thông tin khác trong game cũng được hoạt động theo cơ chế tương tự. Các xử lý đều dựa trên các thông tin đặc tả từ tập tin Logic.xml.
6.5.2. Cơ chế mở rộng xử lý của game
Các xử lý trong game được mở rộng dưới dạng các plugin AI. Các plugin này giúp máy có thể thao tác với người chơi như chiến đấu, di chuyển trong thế giới game, xây dựng.
Các plugin AI này cần cài đặt interface IAIPlugins. public interface IAIPlugins
{
string Name { get; } int Level { get; }
List<int> NextAIBattle(ref UnitOnBM unit, byte[] matrix, int numCellOnRow);
List<int> NextAIWorld(List<TeamOnWM> listTeam, int idParty, byte[] matrix, int numCellOnRow);
}
Ý nghĩa các thành phần :
Name : Tên của AI. Level: Cấp độ của AI.
NextAIBattle: Xử lý AI cho chiến đấu. o Ý nghĩa các tham số:
− unit: đối tượng quân lính cần tính AI. UnitOnBM là đối tượng thể hiện của quân lính trên bản đồ chiến đấu của game.
− matrix: mảng thể hiện ma trận lưu bản đồ của trận chiến trong game.
− numCellOnRow: do ma trận lưu bản đồ của trận chiến được tổ chức dưới dạng một mảng 1 chiều nên cần thêm tham số cho biết có bao nhiêu ô trên một dòng.
o Giá trị trả về: danh sách các số nguyên thể hiện kết quả của AI. Ý nghĩa giá trị trả về:
Vị trí Ý nghía
0, 1 Tọa độ x, y quân lính cần di chuyển đến.
2 Hành động quân lính cần thực hiện sau khi di chuyển đến vị trí đó. Vị trí này có thể chứa 2 loại giá trị:
− Giá trị -1: không sử dụng phép thuật. Khi đó, giá trị tiếp theo ở vị trí thứ 3 sẽ lưu chỉ số của quân lính cần tấn công. Nếu giá trị ở vị trí 3 là -1 thì sẽ không tấn công.
− Các giá trị còn lại: chỉ số của phép sẽ sử dụng.
3
khác nhau:
− Nếu giá trị ở vị trí 2 là -1 thì giá trị ở vị trí 3 sẽ lưu chỉ số của quân lính sẽ tấn công. Khi đó, nếu giá trị ở vị trí thứ 3 là -1 thì sẽ không có quân lính nào cần tấn công.
− Nếu giá trị ở vị trí thứ 2 khác -1 thì giá trị ở vị trí thứ 3 sẽ tùy theo loại phép thuật cần thực hiện mà mang các ý nghĩa các nhau
o Nếu ở vị trí thứ 2 là chỉ số của phép thuật tấn công hay hỗ trợ thì vị trí 3 sẽ là chỉ số của quân lính cần tấn công.
o Nếu vị trí thứ 2 là chỉ số của phép thuật tạo quân lính thì ở vị