TRANG CHỦ
CHUYÊN MỤC
HỌC HỎI
TAG
ABOUT
Tìm kiếm
Lập trình games với Love2D - Chương 13 - Phát hiện va chạm
2023-10-22 07:49:02
Love2D
Học Lập Trình Lua
63 lượt xem
0 bình luận
Giả sử chúng ta đang tạo một trò chơi trong đó bạn có thể bắn hạ quái vật. Một con quái vật sẽ chết khi bị trúng đạn. Vậy điều chúng ta cần kiểm tra là: Con quái vật có va chạm với viên đạn không? Chúng ta sẽ tạo một chức năng kiểm tra va chạm. Chúng ta sẽ kiểm tra va chạm giữa các hình chữ nhật. Điều này được gọi là va chạm AABB. Vậy chúng ta cần biết, khi nào hai hình chữ nhật va chạm nhau? Tôi đã tạo một hình ảnh với ba ví dụ:  Đã đến lúc kích hoạt bộ não lập trình viên rồi. Điều gì đang xảy ra trong ví dụ thứ ba mà không xảy ra trong ví dụ thứ nhất và thứ hai? "Chúng đang va chạm" Đúng, nhưng bạn phải cụ thể hơn. Chúng ta cần thông tin mà máy tính có thể sử dụng. Hãy nhìn vào vị trí của các hình chữ nhật. Trong ví dụ đầu tiên, Đỏ không va chạm với Xanh vì Đỏ ở quá xa về bên trái. Nếu Đỏ ở xa hơn một chút về bên phải, chúng sẽ chạm vào nhau. Chính xác là bao xa? Nếu phía bên phải của Đỏ ở xa hơn phía bên trái của Xanh về bên phải. Đây là điều đúng, ví dụ 3. Nhưng nó cũng đúng với ví dụ 2. Chúng ta cần thêm điều kiện để chắc chắn có va chạm. Ví dụ 2 cho thấy chúng ta không thể đi quá xa về bên phải. Chính xác thì chúng ta có thể đi bao xa? Đỏ sẽ phải di chuyển sang trái bao nhiêu để xảy ra va chạm? Khi bên trái của Đỏ ở xa hơn bên phải của Xanh về bên trái. Vậy chúng ta có hai điều kiện, liệu có đủ để đảm bảo xảy ra va chạm không? Không, hãy nhìn vào hình ảnh sau:  Tình huống này phù hợp với điều kiện trên của chúng ta. Phía bên phải của Đỏ ở xa hơn phía bên trái của Xanh về bên phải. Và phía bên trái của Đỏ ở xa hơn phía bên phải của Xanh về bên trái. Tuy nhiên, không có va chạm. Đó là vì Đỏ quá cao. Nó cần phải di chuyển xuống. Bao xa? Cho đến khi mặt dưới của Đỏ sâu hơn mặt trên của Xanh. Nhưng nếu chúng ta di chuyển nó xuống quá xa thì sẽ không còn va chạm nữa. Đỏ có thể di chuyển xuống bao xa mà vẫn va chạm với Xanh? Miễn là mặt trên của Đỏ cao hơn mặt dưới của Xanh. Bây giờ chúng ta có bốn điều kiện. Có phải tất cả bốn điều kiện đều đúng cho ba ví dụ này?  Bên phải của Đỏ ở xa hơn so với bên trái của Xanh về bên phải. Phía bên trái của Đỏ ở xa hơn so với bên phải của Xanh về bên trái. Mặt dưới của Đỏ nằm sâu hơn mặt trên của Xanh. Mặt trên của Đỏ ở cao hơn mặt dưới của Xanh. Vâng, đúng vậy! Bây giờ chúng ta cần biến thông tin này thành một hàm. Đầu tiên hãy tạo hai hình chữ nhật. ```lua function love.load() --Tạo 2 hình chữ nhật r1 = { x = 10, y = 100, width = 100, height = 100 } r2 = { x = 250, y = 120, width = 150, height = 120 } end function love.update(dt) --Thực hiện di chuyển hình chữ nhật r1.x = r1.x + 100 * dt end function love.draw() love.graphics.rectangle("line", r1.x, r1.y, r1.width, r1.height) love.graphics.rectangle("line", r2.x, r2.y, r2.width, r2.height) end ``` Bây giờ chúng ta tạo một hàm mới gọi là ```checkCollision()```, với 2 hình chữ nhật làm tham số. ```lua function checkCollision(a, b) end ``` Đầu tiên chúng ta cần các cạnh của hình chữ nhật. Bên trái là vị trí ```x```, bên phải là vị trí ```x + width```. Tương tự với ```y``` và chiều cao. ```lua function checkCollision(a, b) --Với biến local người ta thường sử dụng dấu gạch dưới thay vì camelCase local a_left = a.x local a_right = a.x + a.width local a_top = a.y local a_bottom = a.y + a.height local b_left = b.x local b_right = b.x + b.width local b_top = b.y local b_bottom = b.y + b.height end ``` Bây giờ chúng ta có bốn cạnh của mỗi hình chữ nhật, chúng ta có thể sử dụng chúng để đặt các điều kiện vào câu lệnh ```if```. ```lua function checkCollision(a, b) --Với biến local người ta thường sử dụng dấu gạch dưới thay vì camelCase local a_left = a.x local a_right = a.x + a.width local a_top = a.y local a_bottom = a.y + a.height local b_left = b.x local b_right = b.x + b.width local b_top = b.y local b_bottom = b.y + b.height --Nếu bên phải của Đỏ ở xa hơn bên trái của Xanh về bên phải. if a_right > b_left --và phía bên trái của Đỏ ở xa hơn bên phải của Xanh về bên trái. and a_left < b_right --và mặt dưới của Đỏ nằm sâu hơn mặt trên của Xanh. and a_bottom > b_top --và mặt trên của Đỏ ở cao hơn mặt dưới của Xanh.. and a_top < b_bottom then --Có sự va chạm! return true else --Nếu một trong những câu lệnh này sai, hãy trả false. return false end ``` Lưu ý rằng bản thân điều kiện ```if``` là một giá trị ```boolean```. ```checkCollision``` trả về ```true``` khi điều kiện ```if``` trong nó là ```true``` và ngược lại. Do đó ```checkCollision``` có thể đơn giản hóa về dạng sau: ```lua function checkCollision(a, b) --Với biến local người ta thường sử dụng dấu gạch dưới thay vì camelCase local a_left = a.x local a_right = a.x + a.width local a_top = a.y local a_bottom = a.y + a.height local b_left = b.x local b_right = b.x + b.width local b_top = b.y local b_bottom = b.y + b.height --Trả về trực tiếp giá trị boolean này mà không cần sử dụng câu lệnh if return a_right > b_left and a_left < b_right and a_bottom > b_top and a_top < b_bottom end ``` Được rồi, bây giờ chúng ta vẽ các hình chữ nhật theo các điều kiện tô màu sau ```lua function love.draw() --Chúng tôi tạo một biến cục bộ gọi là mode local mode if checkCollision(r1, r2) then --Nếu có va chạm hãy vẽ các hình chữ nhật đầy màu mode = "fill" else --nếu không, hãy vẽ các hình chữ nhật là đường thẳng mode = "line" end --Sử dụng biến làm đối số đầu tiên love.graphics.rectangle(mode, r1.x, r1.y, r1.width, r1.height) love.graphics.rectangle(mode, r2.x, r2.y, r2.width, r2.height) end ``` Mã đầy đủ: ```lua function love.load() --Tạo 2 hình chữ nhật r1 = { x = 10, y = 100, width = 100, height = 100 } r2 = { x = 250, y = 120, width = 150, height = 120 } end function love.update(dt) --Thực hiện di chuyển hình chữ nhật r1.x = r1.x + 100 * dt end function love.draw() --Chúng tôi tạo một biến cục bộ gọi là mode local mode if checkCollision(r1, r2) then --Nếu có va chạm hãy vẽ các hình chữ nhật đầy màu mode = "fill" else --nếu không, hãy vẽ các hình chữ nhật là đường thẳng mode = "line" end --Sử dụng biến làm đối số đầu tiên love.graphics.rectangle(mode, r1.x, r1.y, r1.width, r1.height) love.graphics.rectangle(mode, r2.x, r2.y, r2.width, r2.height) end function checkCollision(a, b) --Với biến local người ta thường sử dụng dấu gạch dưới thay vì camelCase local a_left = a.x local a_right = a.x + a.width local a_top = a.y local a_bottom = a.y + a.height local b_left = b.x local b_right = b.x + b.width local b_top = b.y local b_bottom = b.y + b.height --Trả về trực tiếp giá trị boolean này mà không cần sử dụng câu lệnh if return a_right > b_left and a_left < b_right and a_bottom > b_top and a_top < b_bottom end ``` Nó hoạt động! Bây giờ bạn đã biết cách phát hiện va chạm giữa hai hình chữ nhật. ### Bản tóm tắt Sự va chạm giữa hai hình chữ nhật có thể được kiểm tra bằng bốn điều kiện. Trong đó A và B là hình chữ nhật: Bên phải của A ở xa hơn bên trái của B về bên phải. Bên trái của A ở xa hơn bên phải của B về bên trái. Mặt dưới của A sâu hơn mặt trên của B. Mặt trên của A ở cao hơn mặt dưới của B. ------ [Trước](/learn/detail?learnId=12) | [Mục lục](/learn/search?keyword=Lập%20trình%20games%20với%20Love2D) | [Kế tiếp](/learn/detail?learnId=14)
Gợi ý bài học liên quan
Awesome Love2D
Lập trình games với Love2D - Visual Studio Code
Lập trình games với Love2D - Chương 24
Lập trình games với Love2D - Chương 23
Lập trình games với Love2D - Chương 22