Làm thế nào để tôi làm cho một vật thể chuyển động dừng lại trơn tru ở cuối con đường?


8

Có hàng tá cách tôi có thể diễn đạt câu hỏi này, nhưng để giữ cho suy nghĩ của tôi phù hợp, tôi đang đặt câu hỏi phù hợp với vấn đề của mình.

Vì vậy, tôi đang tạo ra một nền tảng nổi mà tôi muốn có thể chỉ cần di chuyển từ điểm được chỉ định đến điểm khác, sau đó quay trở lại điểm đầu tiên và chỉ cần đi qua giữa hai đường thẳng. Tuy nhiên, chỉ để làm cho nó thú vị hơn một chút, tôi muốn thêm một vài quy tắc vào nền tảng.

  1. Tôi đang mã hóa nó để di chuyển bội số của toàn bộ giá trị của dữ liệu thế giới. Vì vậy, nếu nền tảng không đứng yên, thì nó sẽ di chuyển ít nhất một chiều rộng toàn bộ hoặc chiều cao của gạch.
  2. Trong một chiều dài gạch, tôi muốn nó tăng tốc từ điểm dừng đến tốc độ tối đa nhất định.
  3. Khi đạt đến khoảng cách một chiều dài của ô, tôi muốn nó dừng chậm lại ở tọa độ ô đã cho và sau đó lặp lại quy trình theo chiều ngược lại.

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

Hai phần đầu không quá khó, về cơ bản tôi gặp rắc rối với phần thứ ba. Tôi muốn nền tảng dừng chính xác ở tọa độ ô, nhưng vì tôi đang làm việc với khả năng tăng tốc, có vẻ dễ dàng bắt đầu áp dụng gia tốc theo hướng ngược lại với giá trị lưu trữ tốc độ hiện tại của nền tảng khi nó đạt đến một chiều dài của ô về khoảng cách (giả sử rằng ô đang di chuyển nhiều hơn một chiều dài của ô, nhưng để đơn giản hóa mọi thứ, hãy giả sử là như vậy) - nhưng câu hỏi đặt ra là giá trị chính xác của gia tốc sẽ tăng lên từ đâu để tạo ra hiệu ứng này? Làm thế nào tôi tìm thấy giá trị đó?


1
Hiện tại tôi không có thời gian cho câu trả lời đầy đủ, nhưng hãy xem điều này: red3d.com/cwr/steer/gdc99 , đặc biệt là phần "Đến". Bắt chước hành vi đó để làm chậm lại điểm dừng và đảo ngược nó để tăng tốc từ điểm dừng.
MichaelHouse

Đánh dấu trang. Đó là vô số thông tin quý giá mà bạn vừa khai sáng cho tôi, thưa ngài.
TheBroodian

Kiểu "mong muốn_velocity = (clipped_speed / distance) * target_offset" này có ý nghĩa, nhưng không chính xác. Khi tôi tìm thấy mong muốn_velocity, để tôi trừ nó khỏi tốc độ hiện tại của đối tượng?
TheBroodian

Tôi sử dụng nó để cập nhật giá trị gia tốc: acceleration = desired_velocity - currentVelocitySau đó áp dụng gia tốc đó như bình thường. Tôi sẽ tạo ra một câu trả lời trong một chút nữa cho thấy những gì tôi làm.
MichaelHouse

Câu trả lời:


5

Sử dụng các hành vi chỉ đạo như một hướng dẫn. Nhìn vào hành vi đến:

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

Hành vi đến giống hệt như tìm kiếm trong khi nhân vật ở xa mục tiêu của nó. Nhưng thay vì di chuyển qua mục tiêu ở tốc độ tối đa, hành vi này khiến nhân vật chậm lại khi tiếp cận mục tiêu, cuối cùng chậm lại để dừng trùng khớp với mục tiêu.

Chúng ta có thể tạo một chức năng "đến tại" giống như một cái gì đó tương tự như thế này:

arriveAtPoint(Vector2f position, Vector2f target) {
    float slowing_distance = 1;
    Vector2f target_offset = target - position;
    float distance = target_offset.length();
    float ramped_speed = currentVelocity * (distance / slowing_distance);
    float clipped_speed = Math.min(ramped_speed, currentVelocity);
    targetLinearVelocity = target_offset.scale(clipped_speed / distance);
    acceleration = targetLinearVelocity -linearVelocity;
}

Điều này sẽ cập nhật gia tốc mà chúng ta cần sử dụng để áp dụng cho đối tượng đang chuyển động.


Và chỉ để làm rõ, linearVelocity sẽ là vận tốc mà đối tượng của chúng ta hiện đang di chuyển sau khi cập nhật trước?
TheBroodian

Phrasing của bạn là khá lạ. Nhưng, linearVelocity == currentVelocity.
MichaelHouse

3
Tôi không đồng ý với cách tiếp cận này trên cơ sở rằng nó quá phức tạp. Có thể thực hiện điều này với một tween đơn giản bằng cách sử dụng các phương trình chuyển động ( công thức SUVAT ). Một đại số nhỏ và bạn có thể tính toán các đầu vào cần thiết để đạt được mục tiêu mong muốn một cách chính xác.
Andrew Russell

1
Nó sẽ hữu ích nếu bạn có thể giải thích điều đó với một câu trả lời?
TheBroodian

@AndrewRussell Tôi cũng muốn xem câu trả lời đó.
MichaelHouse

5

Hãy xem trang này: http://sol.gfxile.net/interpolation/index.html

Có vẻ như bạn muốn có một hiệu ứng giống như bước chân:

đồ họa trơn

Nếu bạn có điểm ngoài cùng bên trái, điểm ngoài cùng bên phải nền tảng sẽ đạt được và thời gian nên sử dụng để thực hiện một chuỗi đầy đủ, một cái gì đó như thế này có thể ổn:

khung foreach:

float smoothstep(float t, int level = 1)
{
    float ret = t;
    for(int i = 0; i < level; ++i)
    {
        ret = pow(ret, 2) * (3 - 2 * ret);
    }
    return ret;
}

currentTime += deltaTime;
if(currentTime > fullTime) currentTime -= fullTime;
float halfTime = fullTime / 2.0;
float t = abs(currentTime - halfTime) / halfTime;
t = smoothstep(t, 1);
platformPosition = rightPoint * t + leftPoint * (1 - t);

nếu bạn đang sử dụng một công cụ vật lý, bạn có thể làm cho nó bằng các xung, không nên khó dịch. Nếu bạn muốn một quá trình thậm chí mượt mà hơn, bạn có thể tăng mức độ mượt mà. Nhiều bước


3

Bạn có thể sử dụng XnaTweener cung cấp các hàm nới lỏng nội suy các giá trị từ điểm này sang điểm khác một cách dễ dàng ...

Dưới đây là câu trả lời với một số mã dựa trên dự án Xna Tweener và video cho thấy cách thức hoạt động của nó ...

https://gamedev.stackexchange.com/a/26872/8390

[BIÊN TẬP]

Bạn nên có một chuỗi các khóa xác định chuyển động nền tảng, như sau:

public class MovementKey
{
    public float Time = 0;
    public float Duration;
    public Vector2 Traslation;            // Traslation is relative to previous key
    public TweeningFunction Function;

    internal float GetRatio( float Elapsed )   
    {
        // Always return a value in [0..1] range
        //    0 .. Start position relative to accumulated traslations of previous keys
        //    1 .. Target relative position reached.. then should go to next key if avalaible
        return Function( Elapsed, 0, 1, Duration ); 
    }
}

Và sau đó bạn có thể xử lý chuyển động theo cách này:

public class Movement {

    List<MovementKey> Keys;

    public void Update( float Seconds)
    {

        float ratio;
        if (Playing) Elapsed += Seconds;

        while ( index!= Keys.Count - 1 && Elapsed > Keys[iKey + 1].Time )
        {
            Traslation += Keys[iKey].Traslation;  // Relative
            index++;
        }

       if ( index == Keys.Count - 1 && Elapsed > Keys[iKey].Time + Keys[iKey].Duration )
       {
          ratio = 1;
          if ( DoLoop )
          {
              Elapsed -= (Keys[index].Time + Keys[iKey].Duration);
              Index = 0;
              Traslation = Vector2.zero;
          }
       }
       else {                    
           ratio = Keys[index].GetRatio( Elapsed - Keys[index].Time );
       }

       Position = DefaultPosition + Traslation + ratio * Keys[index].Traslation;        
   }

"DefaultPocation" là vị trí bắt đầu, "Traslation" tích lũy chuyển động của một số khóa và mỗi lần traslation chính đều liên quan đến khóa trước, do đó, khi bạn nhân nó với một hệ số tỷ lệ [0..1], nó sẽ trả về bước traslation tương đối được nội suy để đạt được khóa đó từ khóa trước ...

Tại đây bạn có một video khác cho thấy một chuyển động nền tảng được xác định như được mô tả ở đây ...

http://www.youtube.com/watch?v=ZPHjpB-ErnM&feature=player_detailpage#t=104s

Tôi đã làm lại mã này để cố làm cho dễ hiểu ... có thể nó có một số lỗi ... mã gốc xử lý một số trường hợp của cùng một chuyển động nhưng với một số độ trễ giữa mỗi trường hợp ... Tôi chắc chắn mã này có thể được thiết kế lại để dễ dàng hơn ...


Cảm ơn bạn, điều này rất hữu ích, mặc dù nó được sử dụng trong bối cảnh giống như hoạt hình, tôi đang cố gắng dịch nó trong đầu sang những gì sẽ phù hợp hơn với tình huống của tôi.
TheBroodian

Tôi bị lạc Tôi không thể tìm ra làm thế nào để liên hệ điều này với tình hình hiện tại của tôi cả. oo ;;
TheBroodian

Bạn có một hình ảnh động ... bạn đang cố gắng hoạt hình theo thuật ngữ vị trí ...
Blau

Xin lỗi, lý do tại sao tôi gặp khó khăn, là vì tôi đang cố gắng khởi động ý tưởng này và dịch nó thành một hệ thống hoạt động trên hệ thống thời gian speed = velocity *, trong khi hệ thống này chỉ đơn giản là làm chậm vị trí của đối tượng theo thủ tục (không có gì sai với điều đó, chỉ khó để tìm ra cách thích hợp để liên hệ hai người).
TheBroodian
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.