Khung di chuyển độc lập


11

Tôi đã đọc hai chủ đề khác ở đây về chuyển động: Chuyển động dựa trên thời gian Vs Chuyển động dựa trên tốc độ khung hình? khi nào tôi nên sử dụng bước thời gian cố định hoặc thay đổi?

nhưng tôi nghĩ rằng tôi đang thiếu một sự hiểu biết cơ bản về chuyển động độc lập khung bởi vì tôi không hiểu một trong những chủ đề đó đang nói về cái gì.

Tôi đang theo dõi cùng với các hướng dẫn SDL của lazyfoo và bắt gặp bài học độc lập về khung. http://lazyfoo.net/SDL_tutorials/lesson32/index.php

Tôi không chắc phần chuyển động của mã đang cố nói gì nhưng tôi nghĩ đó là phần này (vui lòng sửa lại cho tôi nếu tôi sai): Để có chuyển động độc lập khung, chúng ta cần tìm hiểu một vật thể cách xa ( ví dụ sprite) di chuyển trong một khung thời gian nhất định, ví dụ 1 giây. Nếu dấu chấm di chuyển với tốc độ 200 pixel mỗi giây, thì tôi cần tính toán nó di chuyển bao nhiêu trong giây đó bằng cách nhân 200 pps với 1/1000 của một giây.

Có đúng không? Bài học nói:

"vận tốc tính bằng pixel trên giây * thời gian kể từ khung hình cuối cùng tính bằng giây. Vì vậy, nếu chương trình chạy ở tốc độ 200 khung hình / giây: 200 pps * 1/200 giây = 1 pixel"

Nhưng ... tôi nghĩ rằng chúng tôi đã nhân 200 pps với 1/1000 giây. Doanh nghiệp này với khung hình mỗi giây là gì?

Tôi đánh giá cao nếu ai đó có thể cho tôi một lời giải thích chi tiết hơn một chút về cách hoạt động của chuyển động độc lập khung.

Cảm ơn bạn.

THÊM VÀO:

SDL_Rect posRect;
posRect.x = 0;
posRect.y = 0;

float y, yVel;
y = 0;
yVel = 0;

Uint32 startTicks = SDL_GetTicks();

bool quit = false;
SDL_Event gEvent;

while ( quit == false )
{
    while ( SDL_PollEvent( &gEvent ) )
    {
        if ( gEvent.type == SDL_QUIT )
            quit = true;
    }

    if ( y <= 580 )
    {
        yVel += DOT_VEL;
        y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
        posRect.y = (int)y;
    }

    startTicks = SDL_GetTicks();
    SDL_BlitSurface( bg, NULL, screen, NULL );
    SDL_BlitSurface( dot, NULL, screen, &posRect );
    SDL_Flip( screen );
}

Đó là mã di chuyển một chấm xuống màn hình. Tôi nghĩ rằng tôi có mọi thứ chính xác cho đến nay. Nó di chuyển xuống màn hình nhưng có một điều kỳ lạ xảy ra mà tôi không thể giải thích. Dấu chấm được cho là ở mức y = 580 khi nó lớn hơn giá trị y đó. Tuy nhiên, mỗi khi tôi chạy chương trình, dấu chấm sẽ kết thúc ở một vị trí khác, nghĩa là từ một chút đến nhiều hơn 580, vì vậy dấu chấm nằm ở nửa màn hình hoặc hơn một nửa màn hình (dấu chấm là 20 pixel, màn hình kích thước 800x600). Nếu tôi làm một cái gì đó như nhấp và giữ thanh tiêu đề của chương trình, sau đó phát hành, dấu chấm sẽ biến mất khỏi màn hình. Làm thế nào mà nó biến mỗi lần? Đối với vấn đề về thanh tiêu đề tôi nghĩ đó là vì khi tôi giữ thanh tiêu đề, bộ hẹn giờ vẫn chạy và thời gian trôi qua ngày càng lớn hơn, dẫn đến một khoảng cách lớn hơn, dấu chấm di chuyển trong khung tiếp theo. Có đúng không?


Bổ sung của bạn thực sự là một câu hỏi khác. Bạn nên làm cho nó một câu hỏi thứ hai thay vì thêm nó vào câu hỏi hiện tại của bạn. Nó có thể được trả lời dễ dàng mặc dù: Chỉ cần tính toán chuyển động y, ví dụ. yMovement = (yVel * (SDL_GetTicks() - startTicks)/1000.f);sau đó làm:if(y + yMovement <= 580){ y += yMovement; } else { y = 580; }
bummzack

Câu trả lời:


10

LƯU Ý: Tất cả các phân số có nghĩa là nổi.

Khung chuyển động độc lập hoạt động bằng cách căn cứ chuyển động của thời gian. Bạn nhận được lượng thời gian dành cho khung hình cuối cùng (vì vậy nếu có 60 khung hình trong một giây, mỗi khung hình sẽ mất 1,0 / 60,0 giây, nếu tất cả các khung hình đều có cùng thời gian) và tìm hiểu xem có bao nhiêu chuyển động dịch sang.

Nếu bạn muốn thực thể của mình di chuyển một lượng không gian nhất định trong một đơn vị thời gian xác định (chúng tôi sẽ nói 100 pixel cho mỗi giây) thì bạn có thể tìm hiểu số lượng pixel bạn nên di chuyển trên mỗi khung hình bằng cách nhân số lượng chuyển động trên mỗi khung hình giây (100 pixel) theo lượng thời gian trôi qua tính bằng giây (1.0 / 60.0) để tìm ra mức độ chuyển động sẽ diễn ra trong khung hình hiện tại.

Nó hoạt động bằng cách tìm ra mức độ chuyển động bạn nên thực hiện trên mỗi khung hình bằng cách sử dụng lượng thời gian đã trôi qua và tốc độ được xác định với một số đơn vị thời gian (tốt nhất là giây hoặc mili giây). Vì vậy, tính toán của bạn có thể trông giống như:movementPerSecond * (timeElapsedInMilliseconds / 1000.0)

Tôi hy vọng điều đó có ý nghĩa với bạn.

Tôi muốn di chuyển anh chàng của tôi 200 pixel sang phải mỗi giây. Nếu khung hiện tại chạy 50 mili giây sau khung trước đó, thì tôi nên di chuyển anh chàng của mình một phần tốc độ được chỉ định trước đó (là 200 pixel). Tôi nên di chuyển anh ta 50/1000 khoảng cách vì chỉ có 1/20 (50/1000 = 1/20) thời gian đã trôi qua. Do đó, sẽ rất hợp lý khi chỉ di chuyển anh ta 10 pixel (nếu có thêm 19 khung hình, cách nhau 50 mili giây, thì tổng lượng chuyển động trong giây đó sẽ là 200 pixel, số lượng chúng tôi muốn).

Cách thức hoạt động của chuyển động độc lập khung là các khung thường xảy ra ở các bước thời gian khác nhau (có một lượng thời gian khác nhau diễn ra giữa các khung tiếp theo). Nếu chúng ta liên tục di chuyển một thực thể một khoảng cách không đổi mỗi khung hình, thì chuyển động dựa trên tốc độ khung hình. Nếu có nhiều thời gian giữa các khung, trò chơi dường như di chuyển quá chậm và nếu không có nhiều thời gian giữa các khung, trò chơi dường như sẽ diễn ra nhanh. (quá ít thời gian giữa các khung = nhiều khung = chuyển động nhiều hơn) Để khắc phục điều này, chúng tôi sử dụng tốc độ về thời gian và theo dõi thời gian giữa các khung. Bằng cách đó, chúng tôi biết đã bao lâu kể từ lần cuối chúng tôi cập nhật vị trí và chúng tôi nên di chuyển thực thể bao xa hơn nữa.

Số khung hình trên giây: Đây là số lượng khung hình diễn ra mỗi giây. Thông thường tốc độ khung hình là số lần trò chơi được vẽ / kết xuất một giây hoặc bao nhiêu lần vòng lặp trò chơi được hoàn thành một giây.

Bước thời gian biến đổi câu cố định: Điều này đề cập đến lượng thời gian giữa các khung. Thông thường, thời gian giữa các khung sẽ không đổi. Một số hệ thống / lõi như vật lý sẽ cần một số đơn vị thời gian để mô phỏng / chạy một cái gì đó. Thông thường, các hệ thống vật lý ổn định hơn / có thể mở rộng nếu bước thời gian được cố định. Sự khác biệt giữa các bước thời gian cố định / biến là trong các tên. Các bước thời gian cố định là những gì chúng nghe giống như: các bước thời gian xảy ra theo một tỷ lệ thời gian cố định. Các bước thời gian thay đổi là các bước thời gian xảy ra ở các mức thời gian khác nhau / khác nhau.


Trong ví dụ bạn đưa ra, 50 mili giây là thời gian cho mỗi khung hình, đúng không? Và điều đó đã được tính bằng 1000 / FPS? Và vì vậy, chuyển động bạn cần để tạo mỗi khung hình là pixel mỗi giây * 50/1000?
Tôm Crackers

hm, tôi nhận ra rằng một phần nghìn giây cho mỗi khung thời gian có thể sẽ thay đổi, phải không? Một cái gì đó như getTicks () - startTicks sẽ luôn khác biệt và không phải là hằng số.
Tôm Crackers

@Omnion: Nếu bạn chỉ định khoảng cách tính bằng "pixel mỗi giây", bạn không thể sử dụng mili giây ... đó sẽ là 1.0 / 60.0 chứ không phải 1000/60, điều này sẽ dẫn đến kết quả hoàn toàn khác.
bummzack

@ShaleighCrackers có, thời gian trôi qua thay đổi. Hãy tưởng tượng một PC cũ không có khả năng hiển thị 60 khung hình / giây. Bạn vẫn muốn trò chơi chạy ở cùng tốc độ (nhưng không phải cùng khung hình / giây) trên một máy như vậy.
bummzack

Vì vậy, trong hướng dẫn lazyfoo, 1000 có nghĩa là gì trong deltaticks / 1000.f? FPS? 1000 mili giây? Tôi hơi bối rối ngay bây giờ. Có vẻ như FPS là cần thiết trong việc xác định thời gian cần thiết cho mỗi khung hình, nhưng nó không thực sự tính toán vào chuyển động.
Tôm Crackers

7

Trong động lực khung, mã của bạn (ví dụ) di chuyển một thực thể sẽ trông như thế này:

x = x + speedPerFrame

Nếu bạn muốn độc lập với khung, nó có thể trông như thế này:

x = x + speedPerSecond * secondsElapsedSinceLastFrame

cảm ơn, điều đó có ý nghĩa Tôi có một câu hỏi khác ở trên.
Tôm Crackers

1

Về câu hỏi bổ sung.

Điểm của bạn dừng tại các vị trí khác nhau mỗi lần vì bạn không kiểm tra ranh giới (y> 580) khi bạn di chuyển nó. Bạn chỉ dừng cập nhật thêm một lần nữa khi nó qua 580.

Ở khung cuối cùng trước khi bạn vượt qua 580, bạn có thể bắt đầu từ 579 hoặc bạn có thể ở mức 570 hoặc bạn có thể ở mức 100. Bạn cũng có thể bước 1 pixel về phía trước hoặc 1000, tùy thuộc vào thời gian khung cuối cùng thực hiện.

Chỉ cần thay đổi điều kiện IF của bạn thành một cái gì đó như thế này và bạn sẽ ổn thôi.

if ( y <= 580 )
{
    yVel += DOT_VEL;
    y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
    if( y > 580 )
    {
        y = 580;
    }
    posRect.y = (int)y;
}
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.