Tại sao vật lý không hành xử nhất quán trong Unity?


7

Tôi đang làm một trò chơi trong đó người chơi AI ném bóng.

Ảnh chụp màn hình

Trong ảnh chụp màn hình, bạn có thể thấy đấu trường được ngăn cách bởi một mạng ở giữa. Mỗi bên của đấu trường có 6 người chơi thuộc một trong 2 đội. Ngay bây giờ, một trong những cầu thủ ở phía bên phải có bóng (cầu thủ phía trên bên phải). Anh ấy sẽ ném bóng sang bên trái.

Theo mã của tôi, quả bóng phải luôn hạ cánh trên cùng một vị trí, bởi vì người chơi luôn áp dụng cùng một lực cho quả bóng. Tuy nhiên, tôi đã nhận thấy rằng quả bóng không phải lúc nào cũng hạ cánh ở cùng một nơi. Tôi đã đánh dấu nơi tôi đã nhìn thấy đất bóng với một vài vòng tròn màu đỏ.

Thật thú vị, trên PC chính của tôi, quả bóng hầu như luôn rơi vào vòng tròn bên phải nhất. Nó hiếm khi rơi vào các vòng tròn khác, mặc dù điều đó xảy ra. Tuy nhiên, trên 3 PC khác, tôi đã thử trò chơi này, quả bóng thường rơi vào chân của cầu thủ trên cùng bên trái, đôi khi trên đầu hoặc phía sau anh ta, nhưng không bao giờ ở vòng tròn bên phải nhất (trước mặt anh ta ).

Trò chơi của tôi phụ thuộc rất nhiều vào vật lý. AI có nhiệm vụ tính toán cách ném bóng để đưa nó hạ cánh xuống một vị trí rất cụ thể, cũng như đoán xem nó sẽ hạ cánh ở đâu tùy thuộc vào vị trí và chuyển động của quả bóng. Nếu vật lý không hoạt động nhất quán trên tất cả các máy mọi lúc, làm thế nào AI có thể tính toán chính xác tất cả những điều này?

Đây là mã phụ trách ném:

private IEnumerator Serve()
{
    var ball = GameObject.Find("Ball").GetComponent<BallController>();
    if (ball.ServingPlayer != this)
        yield break;

    yield return new WaitForSeconds(3);

    Vector3 shootDirection = transform.forward.normalized;
    var q = Quaternion.AngleAxis(-45, transform.right);

    ball.RigidBody.AddForce(q * shootDirection * 20f, ForceMode.VelocityChange);
}

Như bạn có thể thấy, quả bóng luôn được ném "về phía trước" (hướng về phía lưới) ở góc lên 45 °, sử dụng một vectơ chuẩn hóa và tốc độ không đổi ( 20f).

Trước mỗi lần ném, vị trí của các cầu thủ được đặt lại về cùng một vị trí (và xoay) mà họ nhìn thấy trên ảnh chụp màn hình.

player.transform.localEulerAngles = new Vector3(0, playerRotation, 0);
player.transform.position = startingposition + posOffset;

Trong trường hợp này, playerRotationmột trong hai 90fhoặc -90ftùy thuộc vào phía người chơi đang ở trên, startingpositionlà vị trí "nằm ngang" của họ (so với mạng) và posOffsetlà vị trí "dọc" của họ.

Quả bóng có tốc độ thiết lập lại vận tốc và góc, nhưng không phải là quả cầu (vì nó là một quả cầu, nên vòng quay của nó không ảnh hưởng gì). Vị trí của nó cũng được đặt ở một vị trí cố định liên quan đến bất kỳ cầu thủ nào phải giao bóng.

rb.velocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
transform.position = ServingPlayer.ServingPosition;

Đây rblà quả bóng RigidBody.

Cuối cùng, tôi không ảnh hưởng đến chuyển động của quả bóng theo bất kỳ cách nào. Tôi chỉ đơn giản là áp dụng một lực cho nó khi phục vụ, điều này chỉ xảy ra một lần. 3 giây sau khi bóng hạ cánh, trận đấu được đặt lại và mọi thứ lặp lại.

Luồng về cơ bản là như thế này (mã giả):

Start()

ResetCourt()
StartCoroutine(Players[0].Serve())
event BallLanded()
wait for 3 seconds

// repeat starting with ResetCourt()

Tôi thực sự cần quỹ đạo của quả bóng để có thể tái tạo mỗi lần trên mọi máy có thể. Rõ ràng là tôi đang làm gì đó sai ở đây, nhưng những gì?


2
Tôi đoán; công cụ vật lý không có bước thời gian cố định dẫn đến hành vi hơi khác nhau tùy thuộc vào tốc độ cpu của bạn đang chạy. Bước thời gian vật lý của bạn có thể được liên kết với bước thời gian kết xuất của bạn không?
Richard Tingle

@RichardTingle. Tôi nghĩ rằng bạn đang ở một cái gì đó. Tôi đã xem các cài đặt Thời gian trong dự án của mình và quyết định chơi xung quanh với Dấu thời gian cố định. Việc tăng từ 0,02 (50 cập nhật mỗi giây) lên 0,04 khiến PC chính của tôi hoạt động giống như 3 máy tính xách tay mà tôi đã thử nghiệm. Đặt nó thành 0,01 làm cho đất bóng sớm hơn nhiều. Không chắc chắn làm thế nào để đối phó với nó, nhưng nó chắc chắn là một sự khởi đầu.
Nolonar

2
@Nolonar: bạn hiện đang tham gia vào lĩnh vực thú vị của sự khác biệt tích hợp số. :) Các bước tích hợp lớn hơn tạo ra sự thiếu chính xác lớn hơn. Các bước tích hợp nhỏ đòi hỏi nhiều bước hơn và do đó có nhiều khả năng xử lý hơn để tính kết quả cuối cùng. Một động cơ vật lý có thể nhanh, chính xác hoặc mục đích chung: chọn hai. :)
Sean Middleditch

Câu trả lời:


7

Tôi không nghĩ bạn đang làm gì sai, lý do kết quả khác nhau là do công cụ vật lý Unity đang gọi FixedUpdate ở một tốc độ khác nhau tùy thuộc vào tải phần cứng và hệ thống. Nhiều tính toán vật lý sử dụng bước thời gian trên mỗi cuộc gọi quá trơn tru kết quả. Xem câu trả lời tại đây: http://answers.unity3d.com/questions/11839/making-fixedupdate-fixed-timestep-indep khu.html


3
Vâng, vấn đề thực sự là Unity đã không cập nhật với cùng tốc độ. Để khắc phục điều này, tôi đã đi đến Chỉnh sửa > Cài đặt dự án > Thời gian . Ở đó, tôi phải đặt " Dấu thời gian tối đa được phép " thành cùng giá trị với " Dấu thời gian cố định " để đảm bảo dấu thời gian sẽ luôn giống nhau, bất kể tải hệ thống. Bây giờ, tất cả các máy móc của tôi thể hiện cùng một hành vi mọi lúc. Cảm ơn.
Nolonar
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.