Tạo autobot chơi T-rex game (xử lí hình ảnh)

 

Chào mọi người, hôm nay rảnh được buổi tối vì thầy gia hạn deadline bài tập á. Học online môn nào cũng một đống bài tập, sợ thật. Không biết khi nào mới được quay lại trường, một số dự án của mình đang dở dang mình cũng mong được quay lại lab để hoàn thành. Tuy bài tập chiếm thời gian gần như cả ngày nhưng có thời gian rảnh mình vẫn học lập trình chăm chỉ. Cách mình học là nghĩ ra các dự án nhỏ nhỏ xong lập trình và tìm hiểu dần dần đến khi hoàn thành nó, như vậy mình sẽ học thêm nhiều kiến thức mới và kỹ năng giải quyết vấn đề.

Mấy hôm trước mình thấy có bạn làm mạch chơi game T - REX này bằng arduino và quang trở. Giống như tiêu đề, hôm nay mình sẽ thử tạo một chương trình để chơi game T - REX huyền thoại cũng với cấu trúc một sensor và lệnh nhảy nhưng viết bằng ngôn ngữ python. Game T - REX là cái game mà khi mất intermet thì trình duyệt chrome nó cho mình chơi ấy, nếu không mất internet mà muốn chơi thì vào đây: http://www.trex-game.skipser.com/

Phân tích đề bài một xíu, game này khá đơn giản, có một con khủng long chạy trên trục x và người chơi phải nhấn phím space để khủng long nhảy tránh các chướng ngại vật. Vậy chúng ta cần giải quyết 3 vấn đề là: khởi động, hành động nhảy và khi nào thì nhảy.

Ở chương trình này mình sử dụng các thư viện sau: pillow, numpy, pyautogui, time... Tiến hành cài đặt các thư viện cần thiết.

from PIL import ImageGrab, ImageOps
from numpy import *
import pyautogui
import time

Bây giờ thì chúng ta chuẩn bị giải quyết vấn đề thứ nhất: khởi động trò chơi. Mình chia thành 2 màn hình để tiện test code.



Đầu tiên chúng ta sẽ đi xác định vị trí nút Start trên màn hình game T - REX bằng cách screen shot và thả ảnh vào Paint. Tại tab View, tích vào Gridlines và tìm đến nút Start với độ phóng to 100%.



Dựa vào Rulers ở chúng ta xác định vị trí nút Start (chấm đỏ) đơn vị điểm ảnh, ta có vị trí (480, 390). Mình thực hiện tương tự với nhân vật T - REX luôn để lát khỏi nhắc lại, ta được vị trí mũi T - REX là (246, 395). Tiến hành khai báo Restart_button và Trex

Trex = (246, 395)
restart_button = (480, 390)

Tiếp theo tiến hành khởi tạo hàm restart để khởi động trò chơi:

def restart():
    pyautogui.click(restart_button)

Lệnh phía trên khi được gọi sẽ thực hiện thao tác Click vào vị trí restart_button mà chúng ta đã khai báo bên trên, thư viên pyautogui sẽ hỗ trợ điều này. Chạy thử chương trình bằng cách gọi chương trình restart(), xem thử đã có thể tự khởi động trò chơi hay chưa. Thành công. Chúng ta đến vấn đề tiếp theo, làm thế nào để con khủng long nhảy lên. Chắc chắn là một chương trình con khác.

def jump():
    pyautogui.keyDown('space')
    time.sleep(0.05)
    pyautogui.keyUp('space')

Chương trình jum() thực hiện hành động nhấn phím space và giữ trong 0.05s trước khi nhả phím.  Kiểm tra lại chương trình bằng cách gọi hàm jump() ngay phía dưới hàm start() ta sẽ thấy con khủng long nhảy một cái sau khi khởi động.

Đã giải quyết được 2/3 rồi, vấn đề còn lại là khi nào nhảy. Để giải quyết vấn đề này ta nhận thấy khủng long cần nhảy lên khi sắp đến bụi cây, vậy cần một cảm biến đặt phía trước khủng long để xác định bụi cây. Tôi sẽ tạo một hộp quét màu sắc phía trước T - REX, khi phát hiện màu sắc thay đổi sẽ gọi lệnh jump().

def sensor():
    global a
    box = (250, 395, 360, 420)
    image = ImageGrab.sensor(box)
    grayscale = ImageOps.grayscale(image)
    a = array(grayscale.getcolors())
    print(a.sum())

Chúng ta khai báo biến a như một biến toàn cục, sử dụng xuyên suốt chương trình. Box sẽ có dạng hình chữ nhật, chiều dài đặt gần T - REX kéo dài đến điểm phát hiện bụi cây. Đừng quên in ra giá trị a.sum() để sử dụng về sau nhé. Tại main(), chúng ta tạo một vòng lặp vô hạn, gọi chương trình sensor() và đặt điều kiện nếu a.sum() khác x thì thực hiện nhảy. Vậy x ở đâu?

Khi sensor quét đi theo phương ngang, mặc định giá trị sẽ đo trên nền trắng. Nghĩa là nếu không có bụi cây nào được sensor quét qua thì giá trị x không thay đổi, nếu x thay đổi sẽ gọi chương trình jump(). Trước khi đặt điều kiện, chúng ta hãy chạy thử chương trình để lấy giá trị này, chính là giá trị a.sum() mà tôi nhắc đến phía trên. Sau khi đã có giá trị x, chúng ta tiến hành viết điều kiện:

def main():
    while True:
        grab()
        if a.sum() != 2997:
            jump()

Xong rồi, cuối cùng là chạy chương trình restart() và main().

restart()
main()


Mình sẽ đính kèm toàn bộ chương trình ở phía dưới, các bạn có thể tải về bằng cách nhấn vào Download.




Độ chính xác của autobot phụ thuộc vào vị trí đặt box sensor và thời gian giữ phím space. Chúc các bạn tự tạo được cho mình một con autobot chuẩn.