Điều gì thực sự di chuyển trong một người chạy vô tận?


107

Ví dụ, trò chơi Flappy Bird nổi tiếng, hoặc bất cứ thứ gì thực sự là người chơi (trong trường hợp này là con chim, hoặc máy ảnh mà bạn thích) di chuyển về phía trước hoặc là cả thế giới di chuyển về phía sau (con chim chỉ thay đổi vị trí Y và có một vị trí X không đổi)?


1
Chúng tôi đã xóa nhiều bình luận ngoài chủ đề khỏi câu hỏi này và câu trả lời của nó. Chúng tôi cũng đã chuyển một số cuộc thảo luận hợp lý để trò chuyện, trong một số trường hợp liên tục. Mặc dù vậy, một số người dùng đã cảm thấy cần phải bỏ qua thực tế rằng các bình luận không dành cho các cuộc thảo luận mở rộng và tiếp tục. Như vậy, câu hỏi này đã tạm thời bị khóa.
Josh

Câu trả lời:


146

Tôi hơi không đồng ý với câu trả lời của Philipp ; hoặc ít nhất là với cách anh ấy trình bày nó. Nó mang lại ấn tượng rằng việc di chuyển thế giới xung quanh người chơi có thể là một ý tưởng tốt hơn; khi nó hoàn toàn ngược lại. Vì vậy, đây là câu trả lời của riêng tôi ...


Cả hai tùy chọn đều có thể hoạt động, nhưng nói chung là một ý tưởng tồi để "đảo ngược vật lý" bằng cách di chuyển thế giới xung quanh người chơi thay vì người chơi trên toàn thế giới.


Mất hiệu suất / lãng phí:

Thế giới thường sẽ có rất nhiều đối tượng; nhiều nếu không phải hầu hết, tĩnh hoặc ngủ. Người chơi sẽ có một, hoặc tương đối ít, các đối tượng. Di chuyển toàn bộ thế giới xung quanh người chơi, có nghĩa là di chuyển mọi thứ trong cảnh ngoại trừ người chơi. Các đối tượng tĩnh, các đối tượng động ngủ, các đối tượng động đang hoạt động, các nguồn sáng, các nguồn âm thanh, v.v; tất cả phải được di chuyển.

Điều đó (rõ ràng) đắt hơn đáng kể so với việc chỉ di chuyển những gì thực sự di chuyển (người chơi, và có thể một vài thứ nữa).


Khả năng bảo trì và mở rộng:

Di chuyển thế giới xung quanh người chơi làm cho thế giới (và mọi thứ trong đó) trở thành điểm mà mọi thứ diễn ra tích cực nhất. Bất kỳ lỗi hoặc thay đổi trong hệ thống có nghĩa là, có khả năng, mọi thứ đều thay đổi. Đây không phải là một cách tốt để làm mọi thứ; bạn muốn các lỗi / thay đổi càng tách biệt càng tốt, để bạn không gặp phải những hành vi bất ngờ ở nơi nào đó mà bạn chưa thực hiện thay đổi.

Ngoài ra còn có nhiều vấn đề khác với phương pháp này. Ví dụ, nó phá vỡ nhiều giả định về cách mọi thứ được cho là hoạt động trong động cơ. RigidBodyChẳng hạn, bạn không thể sử dụng động cho bất kỳ thứ gì khác ngoài trình phát; vì một đối tượng có đính kèm RigidBodykhông được đặt thành động học sẽ hoạt động bất ngờ khi cài đặt vị trí / xoay / tỷ lệ (mà bạn đang thực hiện mọi khung hình, cho mọi đối tượng trong cảnh, ngoại trừ người chơi)


Vậy câu trả lời là chỉ di chuyển người chơi rồi!

Chà ... không . Như đã đề cập trong câu trả lời của Philipp, trong một loại trò chơi dành cho người chạy vô hạn (hoặc bất kỳ trò chơi nào có diện tích rộng lớn liền mạch), đi quá xa nguồn gốc cuối cùng sẽ giới thiệu các FPPE đáng chú ý ( Lỗi chính xác nổi ), và cuối cùng, cuối cùng, tràn loại số, hoặc làm cho trò chơi của bạn bị sập, hoặc, về cơ bản, làm cho thế giới khói thuốc bị nứt ... Trên các steroid! 😵 (bởi vì thời điểm này, FPPEs sẽ làm cho trò chơi đã được trên vết nứt "bình thường")


Các thực tế giải pháp:

Làm không và làm cả hai! Bạn nên giữ thế giới tĩnh và di chuyển người chơi xung quanh nó. Nhưng "root lại" cả , người chơi thế giới, khi người chơi bắt đầu đi quá xa gốc (vị trí [0, 0, 0]) của cảnh.

Nếu bạn giữ vị trí tương đối của mọi thứ (người chơi với thế giới xung quanh) và thực hiện quy trình này trong một bản cập nhật khung hình duy nhất, người chơi (thực tế) thậm chí sẽ không nhận thấy!

Để làm điều đó, bạn có hai tùy chọn chính:

  1. Di chuyển người chơi đến gốc của cảnh và di chuyển thế giới đến vị trí mới so với người chơi.
  2. Hãy nghĩ về thế giới như một tấm lưới; di chuyển một phần của lưới mà người chơi đang ở gốc và di chuyển người chơi đến vị trí mới so với phần đó của lưới.

Dưới đây là một ví dụ về quá trình này đang hoạt động


Nhưng, bao xa là quá xa?

Nếu bạn xem mã nguồn của Unity, họ sử dụng 1e-5( 0.00001) làm cơ sở để xem xét hai giá trị dấu phẩy động "bằng nhau", bên trong Vector2Vector3(các kiểu dữ liệu chịu trách nhiệm về vị trí của các đối tượng, phép quay và tỷ lệ [euler-]). Do mất độ chính xác của dấu phẩy động xảy ra cả hai cách từ 0, nên có thể giả định rằng mọi thứ nằm dưới 1e+5( 100000) từ gốc / gốc của cảnh đều an toàn để làm việc.

Nhưng! Từ...

  1. Nó thích hợp hơn để tạo ra một hệ thống để tự động xử lý các quá trình root lại này.
  2. Dù trò chơi của bạn là gì, không cần phải có một "khu vực" liền kề trên thế giới rộng 100000 đơn vị (mét [?]).

... sau đó có lẽ là một ý tưởng tốt để root lại sớm hơn / thường xuyên hơn 100000 đơn vị đó. Ví dụ, video tôi cung cấp dường như làm điều đó cứ sau 1000 đơn vị.


2
Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện . Vui lòng sử dụng trò chuyện đó thay vì đăng thêm bình luận ở đây.
Alexandre Vaillancourt

> Điều đó (rõ ràng) đắt hơn đáng kể so với việc chỉ di chuyển những gì thực sự di chuyển <Có phải vậy không? Khi kết xuất, dù sao bạn cũng sẽ phải thực hiện phép nhân ma trận với ma trận camera trên tất cả các đối tượng, để camera được cố định tại danh tính sẽ ít tốn kém hơn theo cách này.
Matsemann

Khoảnh khắc đó khi sự phát triển trò chơi trở thành sự phát triển đoàn kết ...
LJ

@Matsemann - Nếu bạn đã đi trò chuyện, bạn sẽ nhận thấy đây không phải là một điểm mới. Như đã giải thích, kết xuất cảnh KHÔNG-THIẾT BỊ; chúng là những đối tượng và đường ống khác nhau và gần như hoàn toàn độc lập. Thực hiện đảo ngược khung tham chiếu theo cách các đối tượng được định vị trong cảnh sẽ có nghĩa là bạn sẽ có một quá trình nặng hơn ở cả hai đầu , thay vì chỉ trong kết xuất. --- Ngoài ra, ngay cả khi hiệu suất được giao dịch như nhau như bạn tranh luận, tất cả các vấn đề khác với đảo ngược vẫn sẽ không được giải quyết, khiến cách tiếp cận đó vẫn còn tồi tệ hơn so với cách khởi động lại.
XenoRo

@LJ Câu hỏi được đặt ra về sự thống nhất một cách cụ thể (xem các thẻ của OP trước các chỉnh sửa [IMHO defifying] của D. Everhard), và vì vậy câu trả lời đã được điều chỉnh để phản ánh điều đó . --- Nhưng đây là phần hay nhất: Có thể là Unity, Unreal, CryEngine, Source, v.v ... Các công cụ tốt nhất và / hoặc phổ biến nhất hoạt động theo cách này (và họ làm điều đó vì một lý do), vì vậy câu trả lời không chỉ hoàn toàn hợp lệ nói chung, nhưng các điểm được thực hiện vẫn đang ở đỉnh cao của sự chính xác . Nói chung, nếu bạn đảo ngược khung tham chiếu của vật lý, bạn có thể gặp phải các sự cố, đặc biệt là trên các đối tượng động.
XenoRo

89

Cả hai tùy chọn đều hoạt động.

Nhưng nếu bạn muốn người chạy vô tận thực sự là vô tận, bạn sẽ phải giữ người chơi đứng yên và di chuyển thế giới. Nếu không, cuối cùng bạn sẽ đạt giới hạn của các biến bạn sử dụng để lưu trữ vị trí X. Một số nguyên cuối cùng sẽ tràn và một biến dấu phẩy động sẽ ngày càng kém chính xác hơn, điều này sẽ khiến cho trò chơi trở nên rối mắt sau một thời gian. Nhưng bạn có thể tránh vấn đề này bằng cách sử dụng loại đủ lớn để không ai gặp phải những vấn đề này trong khoảng thời gian mà người ta có thể hình dung trong một phiên (khi người chơi di chuyển 1000 pixel mỗi giây, số nguyên 32 bit sẽ tràn sau 49 ngày).

Vì vậy, làm bất cứ điều gì cảm thấy khái niệm trực quan hơn với bạn.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Josh

1
Tôi không nghĩ rằng đó là giải quyết bất cứ điều gì. Thay vì giữ vị trí (và camera) của người chơi, bạn giữ vị trí cuộn của thế giới - nó khác nhau như thế nào?
Đặc vụ_L

1
@Agent_L Nói chung, các thế giới được tạo ra từng phần và mỗi phần có vị trí X / Y của nó. Khi đủ mảnh ghép phía sau người chơi (ví dụ như ngoài màn hình), nó sẽ bị xóa và họ chỉ tạo ra một số tiền nhất định, vì vậy chúng luôn nằm trong một phạm vi tương đối nhỏ - một trò chơi tôi không bao giờ có tọa độ lớn hơn hơn ~ 1000 hoặc ít hơn 0, mặc dù là một người chạy vô hạn, được tạo ngẫu nhiên, vì điều đó - tôi đã theo dõi vị trí của người chơi trong mỗi đoạn và từng chỉ số của từng đoạn trong chuỗi.
Nic Hartley

Tôi không mua khái niệm "biến tràn". Nếu người chơi không di chuyển, thì "nền" sẽ được bù trừ âm bằng chính số tiền mà người chơi sẽ được bù nếu di chuyển. Cả hai trường hợp sẽ gặp chính xác cùng một vấn đề (theo hướng ngược lại) và cả hai sẽ yêu cầu xử lý đặc biệt ở giới hạn tràn.
tiêu

2
ở 1000 pixel mỗi giây, sẽ mất hơn 586 triệu năm để vượt qua số nguyên 64 bit. Đây chỉ thực sự là một vấn đề nếu bạn đang sử dụng các loại thực sự nhỏ như số nguyên 16 bit.
Lyndon White

38

Dựa trên câu trả lời của XenoRo , thay vì phương pháp root lại mà họ mô tả, người ta có thể làm như sau:

Tạo một bộ đệm tròn gồm các phần của bản đồ vô hạn của bạn được tạo, mà nhân vật của bạn di chuyển qua với vị trí được cập nhật với số học modulo (để bạn chỉ cần chạy xung quanh bộ đệm tròn). Bắt đầu thay thế các phần của bộ đệm của bạn ngay khi nhân vật của bạn rời khỏi khối. Phương trình cập nhật của người chơi sẽ giống như:

player.position = (player.position + player.velocity) % worldBuffer.width;

đây là một ví dụ bằng hình ảnh về những gì tôi đang nói về:

nhập mô tả hình ảnh ở đây

Dưới đây là một ví dụ về những gì xảy ra trên gói cuối cùng.

nhập mô tả hình ảnh ở đây

Với phương pháp này, bạn không gặp phải lỗi chính xác bao giờ, nhưng bạn có thể cần tạo một bộ đệm rất lớn nếu bạn có ý định làm điều này trong 3d với khoảng cách rất xa (vì bạn vẫn sẽ cần phải nhìn thấy chính mình ). Nếu con chim nhỏ của nó, kích thước chunk của bạn có thể sẽ chỉ lớn bằng mức cần thiết để giữ một cảnh duy nhất cho một màn hình duy nhất và bộ đệm của bạn có thể rất nhỏ.

Lưu ý rằng bạn sẽ bắt đầu nhận được kết quả lặp lại với BẤT K pr prng nào và số chuỗi không lặp lại tối đa của thế hệ PRNG thường nhỏ hơn độ dài của pow (2, số bit được sử dụng trong nội bộ), với twzen merzenne không phải là phần lớn vấn đề, vì nó sử dụng 2,5k trạng thái bên trong, nhưng nếu bạn sử dụng biến thể nhỏ, bạn có 2 ^ 127-1 lần lặp tối đa trước khi lặp lại (hoặc tệ hơn), tuy nhiên đây vẫn là một con số lớn về mặt thiên văn . Bạn có thể khắc phục các sự cố lặp lại ngay cả khi PRNG của bạn có một khoảng thời gian ngắn thông qua các chức năng trộn tuyết lở tốt cho hạt giống (khi bạn thêm trạng thái ngầm) nhiều lần.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Josh

15

Như đã hỏi và chấp nhận, nó thực sự phụ thuộc vào phạm vi và phong cách trò chơi của bạn, nhưng vì nó không được đề cập: FlappyBird di chuyển chướng ngại vật trên màn hình, thay vì người chơi trên toàn thế giới.

Một người sinh sản đang khởi tạo các vật thể ra khỏi màn hình với tốc độ cố định Vector2.lefttheo hướng.


3
Điều đó hiệu quả với FlappyBird vì đây là một game rất đơn giản. Như đã đề cập trong câu trả lời của tôi, cùng một kỹ thuật, trong khi vẫn có thể , sẽ rất có vấn đề đối với bất kỳ điều gì phức tạp hơn (với nhiều đối tượng / chi tiết thế giới hơn), như Subway Surfer.
XenoRo

15
Tôi đồng ý, và câu trả lời của bạn rất kỹ lưỡng. Tôi chỉ không thấy ai đề cập đến phương pháp vỗ chim thực sự sử dụng, vì vậy tôi đoán tôi sẽ thêm nó.
Stephan
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.