Làm thế nào để làm cho một cái gì đó xảy ra mỗi N giây trong trò chơi?


8

Tôi muốn có một cái gì đó xảy ra cứ sau N giây, tôi sẽ làm thế nào? Có thể sử dụng đồng hồ bấm giờ nhưng làm thế nào?


Tôi đã làm cho câu hỏi của bạn chung chung hơn vì tôi nghĩ nó hữu ích hơn với nhiều người hơn theo cách này.
MichaelHouse

Dựa trên các nhận xét về một trong những câu trả lời, tôi không tin rằng người đăng đang tìm kiếm bit hẹn giờ, nhưng làm thế nào để thay đổi khung sprite. Điều đó phụ thuộc nhiều hơn vào nền tảng mà chúng ta đang nói đến. Bất kể, bây giờ câu hỏi đã được chỉnh sửa, nó không đại diện cho những gì anh ấy thực sự hỏi. Java 2D rất quan trọng đối với câu hỏi mà anh ta đang cố hỏi.
nguyên mẫu

Thay đổi sprite và làm cho nó xảy ra cứ sau 5 giây không liên quan và nên được hỏi dưới dạng các câu hỏi khác nhau. Xin hỏi một câu hỏi mới về việc thay đổi sprite. Đảm bảo bao gồm những gì bạn đã thử và những gì về nó không hoạt động.
MichaelHouse

Câu trả lời:


14

Một cách tiếp cận phổ biến cho việc này là sử dụng vòng cập nhật và thời gian delta.

float timerCurrent = 0f;
float timerTotal = 5f;


Update() {
    timerCurrent += deltaTime;
    if(timerCurrent >= timerTotal) {
        //do timer action
        timerCurrent -= timerTotal;
    }
}

Điều này cho rằng bạn có quyền truy cập vào một deltaTimebiến. Thời gian Delta đơn giản là thời gian đã trôi qua kể từ khung cuối cùng. Nhiều động cơ sẽ có sẵn điều này cho bạn hoặc bạn có thể tìm hiểu thêm về cách thiết lập của riêng bạn ở đây .


Đây có phải là ý nghĩa kỹ thuật thích hợp hơn để bắt đầu một bộ đếm thời gian rõ ràng như trong câu trả lời của @ Josh không?
Jack M

@JackM Điều đó sẽ phụ thuộc vào việc thực hiện bộ đếm thời gian. Lý do tôi trả lời như vậy là vì đó là ngôn ngữ bất khả tri và rất đơn giản để thực hiện.
MichaelHouse

1
@JackM: Cũng tốt hơn nếu bạn từng chạy theo trình gỡ lỗi. Thời gian trò chơi tích lũy có thể dừng khi bạn đạt điểm dừng thay vì hết giờ và tiếp tục bắn ngay lập tức.
Ben Jackson

Người ta phải cẩn thận, vì trò chơi có thể đóng băng chẳng hạn và bọ ve có thể bị mất. Do đó, người ta phải gọi hành động của bộ đếm thời gian cho mỗi tích tắc với đồng bằng đã chỉ định đã qua và không chỉ một lần, v.v.
Christian Ivicevic

Phương pháp này không phụ thuộc vào việc đếm bọ ve, nó dựa vào thời gian delta. Nếu có thêm một khung dài, thời gian delta cũng quá dài. Tuy nhiên, trong nhiều trường hợp, tốt hơn là giới hạn thời gian delta, các khung hình dài thêm có thể gây ra các vấn đề với vật lý và như vậy. Phương pháp này sau đó tốt hơn so với việc chỉ sử dụng thời gian hiện tại trừ đi thời gian bắt đầu vì nó sẽ đồng bộ hóa tốt hơn với các tính toán khác trong trò chơi khi giới hạn khoảng thời gian delta.
MichaelHouse

3

Trong hầu hết các ngôn ngữ, bạn cần khởi động đồng hồ với một số loại chức năng gọi dọc theo các dòng clock.startTimer()trước khi bạn vào vòng lặp chính. Sau đó, bạn phải lưu trữ giá trị thời gian của đồng hồ trước khi bạn nhập vòng lặp chính vào một biến có chức năng như thế nào time = clock.getTime(). Lưu trữ thời gian bước của bạn vào biến n.

Trong vòng lặp chính của bạn, kiểm tra bạn muốn thực hiện là một cái gì đó dọc theo dòng

if(time + n <= clock.getTime())
     //do stuff
     time = clock.getTime() //important to assign new time value here

Lưu ý: Tôi không chắc bạn đang xem ngôn ngữ / thư viện nào vì vậy đây chỉ là một thuật toán chung mà tôi nghĩ ra khỏi đỉnh đầu. Nó có thể không phù hợp với nhu cầu của bạn chính xác. Một số ngôn ngữ / thư viện yêu cầu bạn tạo một đối tượng đồng hồ trong khi những ngôn ngữ khác bạn có thể chỉ cần thực hiện một cuộc gọi hàm trực tiếp.

Theo các bình luận dưới đây, bạn phải cẩn thận với các vấn đề luồng tùy thuộc vào ngôn ngữ bạn đang sử dụng. Bạn cũng nên sử dụng một phao đôi để lưu trữ time.


1
Câu trả lời tốt. Điều này có thể có các vấn đề luồng trong một số ngôn ngữ (ví dụ: .NET) trong đó bộ hẹn giờ được triển khai trong một luồng riêng biệt từ vòng lặp trò chơi của bạn.
tro999

1
Cũng cần lưu ý ở đây rằng nếu timesắp lưu trữ thời gian trò chơi đã trôi qua, thì nên sử dụng định dạng dấu phẩy động có độ chính xác kép.
kevintodisco

Đây là những điểm tốt, tôi sẽ thêm chúng vào câu trả lời.
Josh

2

Như các câu trả lời khác đã chỉ ra, việc thực hiện bộ hẹn giờ có thể được thực hiện bằng cách tăng giá trị được lưu trữ theo từng khung deltaTimevà so sánh nó với thời lượng dự kiến. Để đầy đủ, tôi sẽ bao gồm mã rất giống với các câu trả lời khác:

float elapsed = 0.0f;
float duration = 4.0f;

void update(float deltaTime) {
    elapsed += deltaTime;
    if (elapsed <= duration) {
        // Run code.
        elapsed = 0.0f;
        // Maybe remove from update loop?
    }
}

Làm thế nào bạn muốn xử lý // Run code.phần là tùy thuộc vào bạn. Có thể bạn có một Timerlớp, một thể hiện trong đó lấy một delegate(C #) hoặc callback(C ++) và gọi nó khi hết giờ. Ngoài ra, tạm dừng bộ hẹn giờ là vấn đề loại bỏ nó khỏi vòng cập nhật.

Một cách tiếp cận khác là đánh dấu thời gian bắt đầu của bộ hẹn giờ và thay vào đó là tính toán theo yêu cầu về thời gian đã trôi qua:

double startTime = 0.0; // This is a double for a reason, I'll explain below.
bool running = false;

void start() {
    startTime = getTime(); // This is whatever system time call you want to use.
    running = true;
}

double getElapsed() {
    double elapsed = getTime() - startTime;
    return elapsed;
}

Phong cách này cung cấp thêm một chút kiểm soát cho người sử dụng bộ đếm thời gian. Bản thân cấu trúc không quan tâm đến việc phải làm gì khi thời gian trôi qua đạt đến một điểm nhất định; nó thậm chí không cập nhật. Người dùng có thể chỉ cần truy vấn thời gian đã trôi qua khi cần thiết. Mẫu này có tác dụng phụ đáng tiếc là không thân thiện với trình gỡ lỗi. Thời gian hệ thống tiếp tục khi chương trình của bạn bị dừng trên trình gỡ lỗi, vì vậy các bộ tính giờ như thế này sẽ hoạt động khác đi khi bước qua các chương trình. Một giải pháp tiềm năng cho điều đó là duy trì giá trị thời gian trôi qua dành riêng cho chương trình, được cập nhật mọi khung hình bằng cách sử dụng đồng thời thời gian hệ thống.

Tôi nghĩ quan trọng nhất mặc dù là hai quirks về thời gian trên máy tính, đặc biệt là khi phát triển trò chơi. Đầu tiên là độ chính xác của dấu phẩy động và thứ hai là độ phân giải bộ đếm thời gian gốc.

Bạn sẽ lưu ý rằng trong ví dụ thứ hai, tôi đã sử dụng một doubleloại thay vì một float, như trong ví dụ đầu tiên (kiểu chữ tất nhiên phụ thuộc vào ngôn ngữ bạn đang sử dụng). Lý do cho điều này là ví dụ thứ hai là lưu trữ tổng thời gian trò chơi đã trôi qua . Nếu trò chơi không hoạt động trong một thời gian rất dài, các giá trị định dạng dấu phẩy động có độ chính xác đơn sẽ không đủ độ chính xác để đo chính xác thời gian đã trôi qua , dẫn đến các vấn đề ổn định. Ví dụ đầu tiên là tốt khi sử dụng floatloại miễn là thời lượng lớn không được mong đợi.

Ở đầu kia của quang phổ, nếu thời gian cập nhật bạn mong đợi đủ nhỏ, bạn có thể không thực sự có thể đạt được nó ban đầu, tùy thuộc vào cách bạn có được thời gian hệ thống. Bộ hẹn giờ thường sẽ phụ thuộc vào độ phân giải hẹn giờ của HĐH bạn đang chạy. Ví dụ: độ phân giải hẹn giờ mặc định của Windows 7 trở xuống là 15,6 ms . Điều này có nghĩa là độ chính xác của bộ hẹn giờ thấp nhất bạn có thể đạt được bằng cách sử dụng các chức năng như , timeGetTimehoặc GetTickCountlà 15,6 ms, trừ khi bạn thay đổi độ phân giải của bộ hẹn giờ (cũng có những nguy hiểm liên quan đến điều đó).

Chà, điều đó hóa ra hơi lâu, nhưng đây là những điều quan trọng cần lưu ý khi thực hiện bộ tính giờ.


các bạn cảm ơn nhưng bây giờ tôi làm thế nào để làm điều đó nhưng làm cách nào để thay đổi sprite trở lại và froward
user2957632

@ user2957632 Đó không phải là câu hỏi của bạn lúc này. Hãy làm cho nó rõ ràng hơn.
kevintodisco
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.