Làm thế nào để di chuyển người chơi trong khi cũng cho phép các lực tác động đến nó


7

Hiện tại, đó là cách tôi di chuyển người chơi:

rb.velocity = Vector2.right * input.x;

Và tôi ảnh hưởng đến anh ta một lực trong khi anh ta bị hư hại bởi một thực thể:

rb.AddForce(Vector2.right * force);

Nó hoạt động tốt, cho đến khi tôi cố gắng di chuyển trong khi tôi bị hư hỏng bởi một thực thể. Vì vận tốc của tôi = input.x trong khi tôi di chuyển, tôi không thể tác động đến bất kỳ lực nào đối với nó. Tôi đã cố gắng tóm tắt vận tốc:

rb.velocity+=Vector2.right * input.x;

Nhưng sau đó tôi cần phải kẹp tốc độ và nếu tôi kẹp nó, lực của tôi bị ảnh hưởng đến người chơi cũng bị kẹp.

Làm thế nào tôi có thể giải quyết vấn đề này?

Câu trả lời:


5

Bạn đang đi đúng hướng! Đây là một cái gì đó mà thường bộ điều khiển chịu trách nhiệm. Khi bạn nhảy vào một platformer, bạn sử dụng biến "isGrounded" để thay đổi cách các điều khiển hoạt động khi ở trên không? Bạn cần một trạng thái tương tự cho isKnockback. Trong hầu hết các trò chơi khi người chơi bị đánh bật trở lại, họ có quyền kiểm soát sọc từ họ trong một khoảng thời gian nhất định. Điều đó hoặc bạn coi nó như là không khí, thay vì đặt vận tốc, nó sẽ chỉ dùng một lực để điều chỉnh vận tốc. Làm thế nào bạn muốn thực hiện điều khiển đó là một lựa chọn thiết kế, nhưng không có câu trả lời dựa trên vật lý thực sự. Câu trả lời dựa trên vật lý thực sự là triển khai sự vận động ở chân của nhân vật và điều đó không thực sự hữu ích cho vật lý trò chơi. Một giải pháp khác có thể là thay vì áp dụng một lực, là để làm việc với gõ cửa ở mức vận tốc như chuyển động của bạn. Áp dụng một vận tốc và giảm nó một lượng mỗi lần cập nhật cố định để mô phỏng hiệu ứng giống như gõ lại. Đây là một giải pháp phổ biến khác trong ngành.

Chỉnh sửa: Chỉ cần ghi có các câu trả lời khác ở đây, họ đề cập đến việc tăng tốc / lực di chuyển của bạn dựa trên. Đây cũng là một tùy chọn, tùy thuộc vào loại chuyển động bạn muốn. Cách tiếp cận này trực quan hơn nhiều nhưng cung cấp cho bạn mức độ kiểm soát thấp hơn. Tất cả phụ thuộc vào những gì bạn muốn và điều quan trọng là bạn sớm đưa ra quyết định đó (hoặc thử nghiệm nếu bạn không chắc chắn) vì nó sẽ tác động đến các quyết định tiếp theo. Nếu bạn muốn xem một số mã nền tảng có thể nhận được điên rồ như thế nào, Matt đã phát hành mã cho Madeline từ Celeste. Họ sử dụng một công cụ khác (khung thực tế) nhưng bạn có thể nhận được ý chính về việc có bao nhiêu biến và vật lý giả được sử dụng để đạt được cảm giác đó. https://github.com/NoelFB/Celeste/blob/master/Source/Player/Player.cs


Cảm ơn bạn, nó được thực hiện bằng cách kiểm tra đúng isKnockback khi lực được áp dụng và kiểm tra sai khi người chơi sẽ va chạm với mặt đất vào lần tới, nó hoạt động rất tốt
Basea Basilia

Vui mừng khi nghe nó. Nói chung đừng sợ vật lý giả trong các trò chơi của bạn. Rất nhiều động cơ có những vật lý thực tế tuyệt vời này, nhưng trong nhiều kịch bản trò chơi, mọi người cuối cùng chỉ giả mạo phần lớn :)
gjh33

9

Tôi đã tạo ra một trò chơi demo nhỏ vài ngày trước, thể hiện những cách khác nhau để di chuyển một nhân vật người chơi. Nó có thể giúp bạn hiểu rõ hơn cách di chuyển nào là phù hợp với trò chơi cụ thể của bạn.

Nói chung, bạn nên sử dụng rigidbody.AddForcebất cứ khi nào khả thi. Nó tự động đảm nhiệm việc quản lý nhiều lực chồng chéo và đảm bảo rằng việc truyền động lượng trên các va chạm là chính xác về mặt vật lý.

Nếu bạn không muốn nhân vật của mình có thể tăng tốc vô thời hạn, hãy tăng giá trị "Kéo tuyến tính" của người cứng nhắc. Lực kéo tăng theo phương trình bậc hai với vận tốc, vì vậy tại một thời điểm nào đó, nó sẽ hủy bỏ gia tốc và hạn chế hiệu quả tốc độ tối đa. Giá trị kéo lớn hơn sẽ dẫn đến thời gian tăng tốc và giảm tốc ngắn hơn, làm cho các điều khiển cảm thấy "chặt chẽ" hơn, nhưng cũng hạn chế rất nhiều ảnh hưởng của va chạm.

Nếu bạn muốn nhân vật có các điều khiển chặt chẽ nhưng cũng bị ảnh hưởng bởi các va chạm, bạn có thể xử lý theo cách mà câu trả lời của gjh33 gợi ý. Có hai trạng thái khác nhau trong trình điều khiển trình phát của bạn. Trạng thái thông thường trong đó người cứng nhắc có lực kéo cao và người chơi có toàn quyền kiểm soát và trạng thái "vừa bị bắn" trong đó bạn giảm lực cản và lực điều khiển tạm thời để khiến nhân vật bay xung quanh trong trạng thái bất lực tạm thời không kiểm soát được .

Tôi mong được chơi trò chơi của bạn.


4

Bản thân tôi, tôi thích giải quyết điều này bằng cách nghĩ tất cả các chuyển động của người chơi là dựa trên gia tốc.

Tôi chọn tốc độ mục tiêu bằng bất kỳ logic điều khiển phức tạp nào tôi thích, sau đó yêu cầu avatar của người chơi tăng tốc về phía mục tiêu đó, đồng thời tôn trọng tốc độ tăng tốc tối đa tôi đặt.

Sau đó, tùy thuộc vào trạng thái của hình đại diện (trên mặt đất, trên băng, trên không, ở trạng thái phản hồi), tôi có thể thay đổi các tốc độ tăng tốc đó để làm cho đầu vào điều khiển có tác động sắc nét hơn hoặc ít rõ rệt hơn.

Rigidbody2D body;

void AccelerateTowards(Vector2 targetVelocity, float maxAccel, float maxDecel) {
    // Compute desired velocity change.
    var velocity = body.velocity;
    var deltaV = targetVelocity - velocity;

    // Convert our velocity change to a desired acceleration,
    // aiming to complete the change in a single time step.

    // (For best consistency, call this in FixedUpdate,
    //  and deltaTime will automatically give fixedDeltaTime)
    var accel = deltaV / Time.deltaTime;

    // Choose an acceleration limit depending on whether we're
    // accelerating further in a similar direction, or braking.
    var limit = Dot(deltaV, velocity) > 0f ? maxAccel : maxDecel;

    // Enforce our acceleration limit, so we never exceed it.    
    var force = body.mass * Vector2.ClampMagnitude(accel, limit);

    // Apply the computed force to our body.
    body.AddForce(force, ForceMode2D.Force);
}

Việc tách tốc độ tăng tốc và giảm tốc như thế này cho phép tôi cho lực phanh sắc nét hơn, điều này có xu hướng giúp các điều khiển cảm thấy chặt chẽ và phản ứng nhanh khi dừng hoặc thay đổi hướng, trong khi vẫn giữ tốc độ mượt mà để tăng tốc. Nó cũng cho phép bạn xử phạt phanh cụ thể khi ở trên băng hoặc bị đẩy lùi.

Chúng ta có thể tạo một đối tượng tham số trạng thái điều khiển để giữ tốc độ tối đa, gia tốc và tốc độ giảm tốc cho các trạng thái không khí, mặt đất, băng, phản hồi, v.v. và sử dụng điều này để điều chỉnh xử lý điều khiển rất linh hoạt:

// Choose our current speed / acceleration parameters based on our state.
var controlState = GetCurrentControlState();

// Compute desired velocity.
var velocity = GetDesiredVelocityFromInput(controlState.maxSpeed);

// Try our best to reach that velocity, with our current parameters.
AccelerateTowards(
     velocity,
     controlState.maxAccel,
     controlState.maxDecel
);

deltatime có tự động cung cấp fixedDeltaTime trong vòng lặp fixedUpdate không? Điều đó thật tuyệt! Tôi biết tôi đã từng phải viết mã xung quanh đó, bạn có biết khi họ thêm nó không?
gjh33

Tôi nhìn vào nó bạn đúng. Điều đó rất hữu ích. Tôi không nhớ rằng là một điều khi tôi bắt đầu làm việc trong sự thống nhất, chắc chắn làm cho việc sử dụng lại các chức năng trong các vòng cập nhật khác nhau trở nên dễ dàng hơn.
gjh33
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.