Cách tiêu chuẩn để đồng bộ hóa hiệu ứng âm thanh với hình ảnh động sprite là gì?


8

Chúng ta hãy xem tình huống bạn có một game nhập vai có phép thuật và mỗi hoạt hình chính tả có số lượng khung hình khác nhau và chúng có các yêu cầu rất khác nhau về hiệu ứng âm thanh. Giả sử rằng mỗi phép thuật chỉ có 1 hình động liên tục được liên kết với nó (trái ngược với nhiều phần mô-đun được sử dụng để tạo thành một hình ảnh động đầy đủ) trong các trò chơi Final Fantasy 16 Bit cũ.

Cách duy nhất tôi có thể nghĩ ra để đảm bảo rằng âm thanh và hình động được đồng bộ hóa là:

  • Lấy số lượng khung hình của một hình ảnh động.
  • Lấy thời gian giữa mỗi khung hình của hình ảnh động. (nếu là 30 khung hình / giây thì đó là 1/30 giây trên mỗi khung hình.)
  • Sau đó tạo một tệp âm thanh có độ dài chính xác như hình động.

Vì vậy, điều này có nghĩa là nếu một hình ảnh động dài 5 giây, chạy ở tốc độ 30 khung hình / giây, với tổng số 150 khung hình, tệp âm thanh cũng sẽ dài 5 giây. Nếu hình động phải có âm thanh "tác động" trên khung thứ 30, điều đó có nghĩa là tệp âm thanh sẽ bao gồm âm thanh tác động ở mốc 1,0 giây.

Cuối cùng, chúng tôi bắt đầu hoạt hình và hiệu ứng âm thanh cùng một lúc và hy vọng rằng các khung và âm thanh được đồng bộ hóa.

Âm thanh này có vẻ như có thể gây ra vấn đề khi các khung hình bị bỏ qua hoặc có điều gì đó xảy ra trong khi hoạt hình và âm thanh được phát hơi quá sớm hoặc quá muộn, và sẽ làm cho âm thanh và hình ảnh động không đồng bộ. Đây có phải là cách tiếp cận tốt nhất hay thường có một cách tốt hơn mà tôi không thấy?

Câu trả lời không nhất thiết phải dành cho Cocos2D cụ thể nếu đó là khái niệm, nhưng nếu có một giải pháp cụ thể cho cocos2d, tôi rất muốn nghe.

EDIT: Tôi cũng nhận ra rằng với phương pháp này, nếu chúng ta tình cờ đi vào và điều chỉnh số lượng khung hình hoặc thời gian của hình ảnh động sau đó, chúng ta cũng phải quay lại và thay đổi tệp âm thanh. Điều này nghe có vẻ là một nguyên nhân khủng khiếp cho lỗi của con người (quên cập nhật các tệp âm thanh sau khi thay đổi hoạt hình.) Tôi hy vọng có những phương pháp tốt hơn ngoài kia.


đây là lý do tại sao các vòng lặp trò chơi thời gian liên tục rất tiện dụng: sau đó bạn không cần lo lắng về việc hoạt hình sẽ không đồng bộ
ratchet freak

@ratchetfreak Tôi tin rằng cocos2d sẽ quản lý thời gian của hình ảnh động một cách chính xác. Nếu tôi tạo một hình động và nói với cocos2d rằng tôi muốn chính xác 1/30 giây giữa các khung, nó sẽ đảm bảo điều này và bỏ qua các khung nếu hiệu suất không đủ tốt. Điều này đảm bảo rằng hình ảnh động được hoàn thành đúng thời điểm (nghĩa là trong thời gian không đổi.) Cho rằng, bạn có nói rằng phương pháp tôi đã nêu ở trên là cách đúng đắn để đi không?
Jamornh

Câu trả lời:


6

Làm điều đó thông qua các sự kiện.

Chính tả bắt đầu là một sự kiện . Bắt đầu phát âm thanh cho sự kiện đó.

Kẻ thù bị tấn công bởi phép thuật cũng là một sự kiện. Ví dụ, nếu kẻ địch ở xa hơn và bạn ném phi tiêu, bạn chỉ phát âm thanh thứ hai (đánh phi tiêu) một khi phi tiêu tiếp cận mục tiêu (nếu bạn coi Ném như một câu thần chú).

Nếu bạn cần buộc nó vào một khung (ví dụ: hãy phát âm thanh "nổ" 30 khung hình từ bây giờ bất kể tốc độ khung hình thời gian thực )), cách dễ nhất để làm như vậy là sử dụng các cuộc gọi lại . Cuộc gọi lại chỉ là "khối mã bạn lên lịch để chạy trong tương lai". Dưới đây là một ví dụ về trình thiết lập tạo cuộc gọi lại của tôi:

- (void) addCallback:(Callback*)callback inHowManyTicks:(unsigned long long)execTicksIntoTheFuture
{
  callbacks.push_back( new TimedCallback( tick + execTicksIntoTheFuture, callback ) ) ;
}

A TimedCallbackchỉ là một trình bao bọc xung quanh std::function(hoặc bạn có thể sử dụng Objective-C ^{block}. Nó std::functionđược thực thi khi khung của nó lên.

Một cách khác (ít toàn cầu hơn) là đưa các sự kiện vào hoạt hình của bạn . Vì vậy, nếu bạn cần phát nhiều âm thanh cụ thể trên các khung hình động cụ thể rất nhiều, thì hãy lưu trữ map<int,Sound*>trong Animationlớp. Trên mỗi khung hình của hình ảnh động, kiểm tra xem có khung nào tương ứng Sound*để phát cho Khung đó không.

Bạn cũng có thể lưu trữ một map<int, std::function>, trong Animationđối tượng, cho phép bạn gọi lại một functiontrong khi hoạt hình.


Tôi nghĩ rằng bạn có thể đã giải thích sai câu hỏi một chút. Phương pháp của bạn sẽ hoạt động đối với các âm thanh ngắn có nghĩa là loại "đấm", "đánh", "đá", "bắn" kéo dài không quá một giây trong khi đồng bộ hóa không phải là vấn đề (bạn chỉ có thể phát hiệu ứng âm thanh "trên sự kiện "như bạn đề xuất.) Tuy nhiên, với một hình ảnh động + âm thanh dài (ví dụ như armageddon, trong đó 5-6 thiên thạch rơi xuống từ bầu trời và chạm đất ở các khung hình khác nhau, nhưng là một phần của hoạt hình 1 sprite [giống như cách chúng tưởng tượng cuối cùng] sẽ chỉ có 1 sự kiện bắt đầu, không phải một sự kiện trên mỗi thiên thạch) phương pháp này sẽ không đảm bảo đồng bộ phải không?
Jamornh

3
@Jamornh Trong ví dụ về trận mưa sao băng của bạn, bạn bắn một sự kiện: cho mỗi thiên thạch bắt đầu rơi, vì, mỗi thiên thạch rơi xuống đất, có thể là một cho các nhân vật vật lộn với phép thuật. Sử dụng giải pháp này, bạn thậm chí có thể thay đổi số lượng thiên thạch và không gặp vấn đề gì với âm thanh.
akaltar

1
@Jamornh Bạn cũng có thể xếp hàng một sự kiện cho "phát âm thanh nổ 30 khung hình từ bây giờ", cách dễ nhất để làm điều này là sử dụng chức năng gọi lại . Tôi sẽ trình bày chi tiết điều này trong câu trả lời của tôi.
bobobobo

1
@Jamornh Hoạt hình không nhất thiết phải là mô-đun để có thể quay nhiều sự kiện (tại thời điểm xác định trước). Trong trình chỉnh sửa hiệu ứng của bạn, bạn chỉ có thể nói, phát âm thanh bùng nổ ở khung 32.
akaltar

1
Vâng, điều đó sẽ làm việc. Nếu bạn đang sử dụng JSON, tôi sẽ đề xuất một cơ sở hạ tầng như thế nào { 'images':'sprite-%02d.png', 'beginRange':1, 'endRange':32, 'sounds':{ 0 : 'startSpell.wav', 30 : 'impact.wav' } }. Nếu trò chơi của bạn ở giai đoạn rất sớm và thời gian biên dịch vẫn còn thấp, bạn có thể bắt đầu bằng cách mã hóa cấu trúc dữ liệu để xem nó có hoạt động không.
bobobobo

1

Cách tôi làm là làm cho người nghe sự kiện tùy chỉnh cho lớp hoạt hình của tôi và để họ kiểm soát âm thanh của tôi. vì vậy nếu hoạt hình của tôi đã bắt đầu callback.start (); và bắt đầu âm thanh của tôi trong phương pháp đó. nếu hoạt hình của tôi bị tạm dừng, hãy gọi lại. Nguyên nhân (); và tạm dừng âm thanh. khi hoạt ảnh kết thúc, bạn gọi lại.end (); và có kết thúc âm thanh là tốt.

nhưng để đồng bộ hóa hoàn hảo, tôi sẽ đi xa hơn là đếm các khung âm thanh và ngủ (tạm dừng) âm thanh của mình nếu nó ở xa đầu và làm tương tự cho hoạt hình của tôi.

Tôi chưa bao giờ phải làm điều đó cho đến ngày hôm nay bởi vì đề xuất đầu tiên đáp ứng nhu cầu của tôi chỉ tốt cho đến bây giờ.


Bạn có thể giải thích về cách bạn sẽ đếm một "khung" âm thanh? Bạn có nghĩa là đếm số milis giây đã trôi qua kể từ khi âm thanh bắt đầu và thực hiện đếm trên mỗi khoảng thời gian được xác định trước?
Jamornh

không không, tôi hoàn toàn có nghĩa là khung âm thanh được bật. Tôi không biết làm thế nào bạn làm điều đó trong cocos2D nhưng trong âm thanh java có các phương pháp để có được âm thanh khung và "khung" hiện tại, cũng có một cách để đặt khung hiện tại thành nhất định. Tôi chắc chắn nếu bạn nhìn vào nó, bạn có thể tìm thấy các biến tương tự trong giao diện âm thanh của mình, nhưng giống như ai đó đã chỉ ra rằng tốt nhất là để các bản cập nhật của bạn xử lý thời gian hoạt hình. để bạn không thực hiện các hack đồng bộ hóa như vậy.
Jonathan Camarena
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.