Làm cách nào để ngăn nhân vật của nền tảng của tôi cắt trên gạch tường?


9

Hiện tại, tôi có một platformer với gạch cho địa hình (đồ họa mượn từ Cave Story). Trò chơi được viết từ đầu bằng XNA, vì vậy tôi không sử dụng động cơ hoặc động cơ vật lý hiện có.

Các va chạm gạch được mô tả khá chính xác như được mô tả trong câu trả lời này (với SAT đơn giản cho hình chữ nhật và hình tròn), và mọi thứ đều hoạt động tốt.

Ngoại trừ khi người chơi chạy vào tường trong khi ngã / nhảy. Trong trường hợp đó, họ sẽ bắt được một viên ngói và bắt đầu nghĩ rằng họ đã chạm sàn hoặc trần nhà không thực sự ở đó.

Hình ảnh bắt nhân vật

Trong ảnh chụp màn hình này, người chơi đang di chuyển sang phải và rơi xuống. Vì vậy, sau khi di chuyển, các va chạm được kiểm tra - và đầu tiên, hóa ra nhân vật người chơi đang va chạm với gạch thứ 3 từ trên sàn và đẩy lên trên. Thứ hai, anh ta phát hiện va chạm với viên gạch bên cạnh và đẩy sang một bên - kết quả cuối cùng là nhân vật người chơi nghĩ rằng anh ta nằm trên mặt đất và không rơi xuống, và 'bắt' trên viên gạch miễn là anh ta chạy vào nó .

Thay vào đó, tôi có thể giải quyết điều này bằng cách xác định các viên gạch từ trên xuống dưới, điều này khiến anh ta rơi xuống một cách trơn tru, nhưng sau đó trường hợp ngược lại xảy ra và anh ta sẽ chạm vào trần nhà không có khi nhảy lên tường.

Làm thế nào tôi nên tiếp cận giải quyết điều này, để nhân vật người chơi có thể rơi dọc theo bức tường như nó cần?


Tương tự với câu hỏi này? gamedev.stackexchange.com/questions/14486/
trộm

@ Byte56 Câu hỏi không giống nhau, nhưng câu trả lời của nó có thể giúp ích.
doppelgreener

Lưu ý: Tôi đã có rất ít thời gian trong vài tuần qua để thử nghiệm các câu trả lời ở đây. Tôi đã thực hiện giải quyết va chạm thế giới như đã trả lời trong câu hỏi @ Byte56 được liên kết, có lỗi riêng biệt với vận tốc cao và chưa thể thử câu trả lời cho câu hỏi này. Tôi sẽ thử những điều đó khi tôi có thể và chấp nhận câu trả lời khi tôi có thể, hoặc tự đăng nếu tôi tự giải quyết.
doppelgreener

Câu trả lời:


8

Cách tiếp cận đơn giản, không chứng minh hơn là đơn giản là không kiểm tra va chạm trên các cạnh ẩn. Nếu bạn có hai gạch ốp tường, một gạch trực tiếp trên gạch kia, thì cạnh dưới của gạch trên và cạnh trên của gạch dưới không nên được kiểm tra xem có va chạm với người chơi không.

Bạn có thể xác định các cạnh nào là hợp lệ trong một lần chuyển đơn giản trên bản đồ ô vuông, lưu trữ các cạnh bên ngoài dưới dạng cờ trên mỗi vị trí ô. Bạn cũng có thể thực hiện việc này khi chạy bằng cách kiểm tra các ô liền kề trong quá trình phát hiện va chạm.

Có nhiều phiên bản nâng cao hơn của kỹ thuật tương tự này giúp cho việc hỗ trợ gạch không vuông cũng dễ dàng và nhanh hơn.

Tôi khuyên bạn nên đọc các bài viết dưới đây. Chúng là những lời giới thiệu đơn giản để thực hiện vật lý cơ bản và phát hiện va chạm trong các nền tảng hiện đại (như Cave Story). Nếu bạn đang cảm thấy Mario ở trường học cũ hơn, sẽ có thêm một vài thủ thuật để lo lắng, nhưng hầu hết trong số chúng liên quan đến việc xử lý nhảy và hoạt hình thay vì va chạm.

http://www.metanetsoftware.com/technique/tutorialA.html http://www.metanetsoftware.com/technique/tutorialB.html


Bạn có thể làm rõ làm thế nào để bỏ qua một số cạnh trong khi va chạm? Tôi thường thấy các va chạm được phát hiện là giao điểm của hai hình chữ nhật (giới hạn người chơi và giới hạn gạch). Khi bạn nói không kiểm tra va chạm với các cạnh riêng lẻ, điều đó có nghĩa là thuật toán va chạm không phải là giao điểm hình chữ nhật mà là cái gì khác? Mô tả của bạn có ý nghĩa, nhưng tôi không chắc việc triển khai sẽ như thế nào.
David Gouveia

Vâng, chỉ cần làm một vụ va chạm hình chữ nhật. Chỉ được đơn giản hóa vì dòng luôn được căn trục. Bạn chỉ có thể phân tách kiểm tra hộp của bạn.
Sean Middleditch

5

Đây là thứ tự tôi sẽ làm mọi thứ ....

1) Lưu X, Y hiện tại của ký tự

2) Di chuyển hướng X

3) Kiểm tra tất cả các góc của ký tự bằng cách lấy dữ liệu ô và kiểm tra xem nó có vững không bằng cách thực hiện các bước sau: (X và Y là vị trí ký tự)

  • cho trên cùng bên trái: sàn (X / brickWidth), sàn (Y / brickHeight);
  • cho trên cùng bên phải: sàn ((X + characterWidth) / brickWidth), sàn (Y / brickHeight);
  • cho phía dưới bên trái: sàn (X + / brickWidth), sàn ((Y + characterHeight) / brickHeight);
  • cho phía dưới bên phải: floor ((X + characterWidth) / brickWidth), floor ((Y + characterHeight) / brickHeight);

... để có được dữ liệu gạch chính xác từ dữ liệu bản đồ

4) Nếu bất kỳ ô nào là rắn, thì bạn cần buộc X đến vị trí tốt nhất có thể bằng cách khôi phục X đã lưu và ...

  • nếu bạn di chuyển sang trái: X = floor (X / brickWidth) * brickWidth;
  • nếu bạn di chuyển sang phải: X = ((floor ((X + characterWidth) / brickWidth) + 1) * brickWidth) - characterWidth;

5) Lặp lại 2-4 bằng Y

Nếu nhân vật của bạn cao hơn một ô, bạn cần kiểm tra nhiều ô hơn. Để làm điều này, bạn cần lặp và thêm ô vuông vào vị trí ký tự để lấy ô

int characterBlockHeight = 3;

// check all tiles and intermediate tiles down the character body
for (int y = 0; y < characterBlockHeight - 1; y++) {
    tile = getTile(floor(characterX / tileWidth), floor((characterY + (y * tileHeight)) / tileHeight));
    ... check tile OK....
}

// finally check bottom
tile = getTile(floor(characterX / tileWidth), floor((characterY + characterHeight) / tileHeight);
... check tile OK....

Nếu ký tự rộng hơn 1 khối thì hãy thực hiện tương tự nhưng thay thế ký tựY, characterHeight, brickHeight, v.v. bằng characterX, characterWidth, v.v.


2

Điều gì sẽ xảy ra nếu bạn kiểm tra khả năng va chạm như là một phần của phương pháp di chuyển của người chơi và từ chối chuyển động khiến người chơi trượt vào một vật thể khác? Điều này sẽ ngăn người chơi nhận được 'bên trong' một khối, và do đó anh ta không thể 'ở trên đỉnh' của khối bên dưới nó.


1

Tôi gặp phải vấn đề gần như chính xác trong một trò chơi mà tôi hiện đang làm việc. Cách tôi giải quyết là lưu trữ khu vực của phần chồng chéo khi kiểm tra va chạm và sau đó xử lý các va chạm đó dựa trên mức độ ưu tiên của chúng (khu vực lớn nhất trước), sau đó kiểm tra lại từng va chạm để xem liệu nó đã được giải quyết trước đó chưa sự điều khiển.

Trong ví dụ của bạn, diện tích va chạm trục x sẽ lớn hơn trục y, do đó, nó sẽ được xử lý trước. Sau đó trước khi thử xử lý va chạm trục y, nó sẽ kiểm tra và thấy rằng nó không còn va chạm sau khi được di chuyển trên trục x. :)


1

Một cách khắc phục đơn giản nhưng không hoàn hảo là thay đổi hình dạng của hộp va chạm của người chơi để nó không phải là hình vuông. Cắt bỏ các góc để làm cho anh ta giống như hình bát giác hoặc một cái gì đó tương tự. Bằng cách này, khi anh ta va chạm với một viên gạch giống như những cái trên tường, anh ta sẽ trượt khỏi nó và không bị bắt. Điều này không hoàn hảo bởi vì bạn vẫn có thể nhận thấy anh ta bắt được các góc một chút, nhưng anh ta sẽ không bị mắc kẹt và nó rất dễ thực hiện.


1

Một vấn đề rất giống đã được đề cập trong hướng dẫn này: Giới thiệu về Phát triển trò chơi . Phần có liên quan của video là lúc 1:44 , giải thích bằng sơ đồ và đoạn mã.

Lưu ý 14-tilemap.py thể hiện sự cố cắt, nhưng nó đã được sửa trong 15-blocker-sides.py

Tôi không thể giải thích chính xác lý do tại sao ví dụ hướng dẫn cuối cùng không có clip trong khi mã của bạn thì có, nhưng tôi nghĩ nó có liên quan đến:

  • Phản ứng va chạm có điều kiện dựa trên loại gạch (cạnh nào thực sự hoạt động.)
  • Người chơi luôn luôn 'rơi.' Mặc dù người chơi dường như đang nghỉ ngơi trên một ô, nhưng người chơi thực sự liên tục rơi qua ô đó, sau đó bị đẩy trở lại đỉnh. (Thành self.restingviên trong mã chỉ được sử dụng để kiểm tra xem người chơi có thể nhảy hay không. Mặc dù vậy, tôi không thể khiến người chơi thực hiện cú nhảy 'nhân đôi' từ tường. Tuy nhiên, về mặt lý thuyết có thể là có thể)

0

Một phương pháp khác (mà tôi đã trả lời câu hỏi Byte56 liên kết đến) sẽ là kiểm tra xem độ phân giải va chạm có đặt nhân vật vào chỗ trống hay không. Vì vậy, trong vấn đề của bạn, bạn có một vụ va chạm từ trần của hình chữ nhật bên trong để di chuyển nó lên, điều này là bất hợp pháp (vì bạn vẫn đang va chạm với một ô khác). Thay vào đó, bạn chỉ di chuyển nó nếu bạn di chuyển vào một không gian trống (chẳng hạn như cách va chạm từ ô trên sẽ di chuyển bạn sang bên trái) và khi bạn tìm thấy va chạm đó, bạn đã hoàn tất.

Câu trả lời tôi đưa ra có mã, nhưng nó trở nên quá phức tạp. Tôi sẽ theo dõi tất cả các va chạm trong khung thời gian đó và chỉ lấy một xung đột dẫn đến một không gian trống. Tuy nhiên nếu không có ai, tôi nghĩ rằng tôi đã dùng đến việc đặt lại vị trí của nhân vật về vị trí cuối cùng, tuy nhiên điều đó thực sự xấu xí và có lẽ bạn nên thử thực hiện một cái gì đó giống như Mario ban đầu khi anh ta chỉ di chuyển theo một hướng hoặc một cái gì đó khi không có độ phân giải không gian trống có khả năng. Ngoài ra, bạn có thể sắp xếp danh sách các độ phân giải va chạm đó và chỉ di chuyển đến vùng tự do với khoảng cách ngắn nhất (tôi nghĩ rằng giải pháp đó sẽ là thích hợp nhất, mặc dù tôi không mã hóa cho điều đó).


0

Tôi mới chỉ thực hiện 3 SAT ở chế độ 3D nên có lẽ tôi không hiểu điều này. Nếu tôi hiểu vấn đề của bạn thì đó có thể là do việc liên lạc với trục tiếp xúc không thể thực hiện được, dẫn đến việc người chơi hành động như có một tầng. Một cách giải quyết khác có thể là sử dụng hình dạng vòng tròn cho caracter của bạn, sau đó bạn sẽ chỉ nhận được các trục tiếp xúc theo hướng trục x khi va vào tường.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.