Hướng dẫn làm game ghép hình trong html5
Va chạm là tình huống rất phổ biến và xuất hiện ở khắp nơi trong thế giới video game. Trong series game Mario Bros, Mario húc đầu vào ô gạch để phá ô đó hoặc nhận được item thưởng. Hay ở tựa game Flappy Bird "cây nhà lá vườn", khi khi chú chim đâm phải ống cống, trò chơi sẽ kết thúc. Show
Để các sự kiện như thế xảy ra, người làm game cần phải xây dựng những cơ chế để phát hiện va chạm giữa các vật thể trong game, từ các nhân vật, đến đường bay viên đạn, địa hình,... Nghe thì đơn giản, nhưng đây lại là một vấn đề nan giải trong thiết kế game, nhất là trong các tựa game 3D phức tạp với nhiều vật thể. Có lẽ khi chơi game, bạn thi thoảng gặp những lỗi như: bị kẹt vào tường, đi được xuyên tường, bị chui góc lag và rơi ra ngoài thế giới,... thì khả năng cao trách nhiệm thuộc về cơ chế phát hiện va chạm của game đã không hoạt động chính xác Ở bài viết này, mình xin được cùng các bạn tìm hiểu và phát triển tính năng phát hiện va chạm cho tựa game 2D đơn giản Tetris đang còn dở dang ở bài trước đó, và qua đó có cái nhìn tổng quan về cơ chế phát hiện va chạm trong video game nói chung. Ý tưởngỞ game Tetris, các hình khối (Tetromino) sẽ bị thay đổi vị trí cứ sau mỗi game tick hoặc khi người chơi nhấn phím di chuyển hay xoay khối. Như vậy, chúng ta đơn giản chỉ cần kiểm tra xem, với mỗi lần khối Tetromino bị thay đổi vị trí đó, nó có bị đè lên bất cứ phần tử nào khác hay không. Cụ thể, ta phải thực hiện từng bước kiểm tra giữa khối Tetromino với các phần tử:
Và may mắn nữa là ở trong game Tetris, khối Tetromino hiện đang rơi là thứ duy nhất di chuyển. Nếu là game khác có nhiều phần tử di chuyển trong trò chơi (người chơi, kẻ địch, NPC, viên đạn,...), bạn sẽ phải kiểm tra va chạm giữa tất cả phần tử đó với nhau và với vật thể đứng yên khác. Thử tưởng tượng một game phức tạp với môi trường cực rộng và có hàng nghìn phần tử lớn nhỏ khác nhau. Chưa kể, game lại phải render liên tục với số khung hình 60FPS (khác xa với Tetris là gần 1 giây mới trôi qua được 1 tick). Rõ ràng là đây không phải điều đơn giản. Với vấn đề trên, có rất nhiều phương pháp khác nhau để tối ưu hóa hiệu năng, tuy nhiên nó nằm ngoài khuôn khổ của bài này, và làm game cũng không phải chuyên môn của mình (dòng đời xô đẩy vào làm Web mất rồi ). Nếu bạn có đam mê viết game, đừng ngại ngùng mà theo đuổi và tìm hiểu sâu hơn nhéGiờ ta bắt đầu bắt tay vào làm từ những gì đã có ở phần bài viết trước. Tiến hànhCó tổng cộng 4 hành động mà chúng ta cần phải kiểm tra va chạm: khối di chuyển xuống, khối di chuyển sang trái/phải và khối bị xoay. Bắt các sự kiện nhấn phímTrước hết, mình sẽ thêm hàm lắng nghe những sự kiện nhấn phím, giúp người dùng điều khiển được game:
Các hàm
0,
1,
2 sẽ được implement sau đó trong bài này. Di chuyển xuốngKhối Tetromino di chuyển xuống sau mỗi game tick (0,8 giây), hoặc khi người dùng đẩy nhanh tiến độ game bằng cách ấn nút mũi tên xuống. Ở hành động này, ta cần phải kiểm tra va chạm giữa khối Tetromino và 2 phần tử: đường biên dưới và các khối đã hạ cánh. Để làm được điều này, mình chọn cách như sau:
Cập nhật lại hàm
3 Hàm
3 từ bài trước của mình cần phải cập nhật thêm như sau:
Ghi chú nhỏ: phương thức
2 giúp mình gọi đến chính xác phương thức khởi tạo của class trực tiếp tạo ra
5. Nhờ vậy dù
5 có là LShape hay ZShape hay gì thì mình cũng sẽ tạo ra được Tetromino khác tương tự thế với code ít dài dòng nhất .Giờ ta cần bắt đầu tiến hành viết những phương thức được dùng trong
3. Kiểm tra vượt đường biên dưới với
6
6 nhận vào một đối tượng thuộc lớp Tetromino và trả về kết quả boolean, cho biết Tetromino đó có bị vượt qua đường biên dưới của game hay chưa. Chẳng phải nói nhiều, hàm này hết sức đơn giản như sau:
Kiểm tra trùng đè vào các ô đã hạ cánh với
8
8 cũng nhận vào một object Tetromino và trả về kết quả boolean. Giá trị true tức là có phát hiện sự trùng nhau giữa landedArray và khối Tetromino. Để phát hiện sự chồng đè, ở đây mình chọn cách kiểm tra mọi khối ô của Tetromino xem liệu có bị trùng vị trí với
9 hay không. Tuy là 2 vòng lặp for, nhưng các khối Tetromino luôn chỉ là tập hợp của 4 khối ô mà thôi, nên hiệu năng ở đây chưa phải là vấn đề. Với những game phức tạp hơn, bạn cần cân nhắc chọn các kỹ thuật khác (như dựa vào hitbox), thay vì kiểm tra hết từng đơn vị diện tích (hay thể tích) của vật thể như này :v.
Gắn lại khối Tetromino vào các khối đã hạ cánh với
1 Khi đã biết rằng khối Tetromino hiện tại đã "va chạm" và không thể đi xuống hơn được nữa, ta cần cho nó dính vào mảng
9. Mỗi loại khối Tetromino đều (sẽ) có màu sắc riêng, nên dù đã trở thành "một khối lớn" với các Tetromino khác, mình muốn màu sắc của khối vừa rơi xuống vẫn được giữ nguyên trong mảng
9. Ta cũng chỉ cần lặp qua
5, và cập nhật giá trị của từng ô nhỏ vào vị trí tương ứng của nó tại
9 là xong.
Đẩy nhanh tiến độ với
2 Hàm này sẽ chạy khi người dùng ấn mũi tên xuống dưới. Ở đây đơn giản mình chỉ chạy tiếp hàm
3 rồi tiến hành vẽ thay đổi ra canvas là xong.
Kết quảXem JSFiddle sau phần vừa rồi tại đây: https://jsfiddle.net/tranxuanthang/3c1fj8os/6/ Di chuyển trái/phảiKiểm tra khối Tetromino vượt ra ngoài biên trái/phảiTương tự với
8, việc kiểm tra xem khối Tetromino có vượt ra ngoài biên trái/phải hay không hết sức đơn giản:
Tiến hành di chuyển khốiGiờ chúng ta tạo các hàm
1 để tiến hành di chuyển khối Tetromino sang trái/phải khi người dùng nhấn phím mũi tên tương ứng. Ta tiếp tục phải tạo một khối Tetromino tạm thời để mô phỏng trạng thái tiếp theo của khối Tetromino. Dù di chuyển sang trái hay phải, bạn đều cần kiểm tra trùng đè với
9 (sử dụng lại
8 chúng ta đã viết ở phần trước) và đồng thời kiểm tra trùng đè ở hai phía trái/phải tương ứng. Không cần thiết kiểm tra trùng đè với cả phía cạnh đối diện hay đường biên dưới nhé.
Kết quảĐỡ hơn rất nhiều rồi. Xem JSFiddle đến bước này tại đây: https://jsfiddle.net/tranxuanthang/4uLw7hn6/4/ Xoay khối TetrominoCũng tương tự như khi chúng ta tiến hành viết các hàm đưa khối Tetromino xuống dưới hay qua trái/phải. Tuy nhiên, xoay khối Tetromino là chuyển động khá phức tạp và bất ngờ do nó thay đổi cả chiều rộng lẫn chiều cao của khối Tetromino khi nằm trong bảng. Để việc xoay hoạt động 100% chính xác, bạn phải kiểm tra đầy đủ va chạm/trùng với mọi phần tử khác (trừ cạnh trái, do cách mà mình chọn làm điểm đặt vị trí khối Tetromino là góc trên bên trái). May thay, các hàm kiểm tra chúng ta đều làm ở phía trên rồi, chỉ cần tái sử dụng/gọi lại ra thôi:
Cuối cùng, chúng ta đã hoàn thiện được tính năng di chuyển và điều khiển của người chơi cho game: Kết quả tại đây, các bạn có thể ấn vào tab Result, bấm vào khung canvas một lần và thử điều khiển bằng 4 phím mũi tên lên/xuống/trái/phải xem sao: Tạm kếtHôm nay chúng ta đã tìm hiểu và làm được kha khá, và game cũng bắt đầu ra hình dáng rồi đấy. Tuy nhiên, game hiện vẫn còn ở xa mức hoàn thiện, và vẫn còn rất nhiều tính năng chúng ta phải phát triển như: |