Bài viết trước mô tả làm thế nào để lưu các cài đặt trò chơi, bao gồm cả âm thanh bật / tắt màn hình, nhưng nó không có bất kỳ âm thanh nào được phát ra. Bài viết này mô tả các Java Mobile Multimedia API (MMAPI) và giải thích làm thế nào để thêm âm thanh vào game.

MMAPI cung cấp một tập các khả năng đa phương tiện cho các thiết bị di động, bao gồm cả phát lại và ghi âm dữ liệu âm thanh và video từ nhiều nguồn khác nhau. Tất nhiên, không phải tất cả thiết bị di động hỗ trợ tất cả các tùy chọn này, nhưng MMAPI được thiết kế để tận dụng những khả năng có sẵn trên thiết bị và bỏ qua những cái mà nó không hỗ trợ.

Thông tin MMAPI

Các MMAPI được xây dựng dựa trên sự trừu tượng cấp cao của tất cả các thiết bị đa phương tiện. Sự trừu tượng này được cài đặt(implement) trong ba lớp  đã hình thành lõi(core) của các hoạt động mà bạn làm với các API này. Những lớp này là 2 interface Player và Control, và lớp Manager. Một lớp khác, lớp trừu tượng DataSource, được sử dụng để xác định vị trí tài nguyên, nhưng nếu bạn định nghĩa một phương pháp mới để đọc dữ liệu, bạn sẽ không cần sử dụng nó một cách trực tiếp.

Tóm lại, lớp Manager được sử dụng để tạo ra các thể hiện Player cho các media khác nhau bằng cách xác định các thể hiện DataSource. Như vậy, các thể hiện Player có thể tạo ra được cấu hình bằng cách sử dụng các thể hiện Control. Ví dụ, hầu hết các thể hiện Player hỗ trợ VolumeControl để điều khiển âm lượng của các Player. Kiểm tra sơ đồ sau đây:

Lớp Manager về cơ bản là một factory của các player được hỗ trợ bởi các phương thức sau đây:

  • createPlayer(DataSource source): tạo một player dựa trên DataSource.
  • createPlayer(InputStream stream, String type): tạo một player sử dụng input stream như là nguồn và giả định rằng các kiểu media đã được cung cấp. Để biết thêm các kiểu media, bạn có thể vào địa chỉ: http://www.iana.org/assignments/media-types/ để kiểm tra.
  • createLayer(String url): tạo một player sử dụng một url để xác định dữ liệu nguồn.

Phương thức cuối cùng cho phép bạn phân bổ các loại media khác nhau, tùy thuộc vào giao thức URL được chọn chọn. Các loại sau được hỗ trợ:

  • Midi Player – “device://midi”: tạo a midi Player.
  • Tone Player – “device://tone”: tạo a tone Player.
  • Capture Audio – “capture://audio”: cho phép capture audio từ thiết bị.
  • Capture Video – “capture://video”: cho phép capture video từ thiết bị.
  • Capture Radio – “capture://radio?f=105.1&st=stereo”: cho phép capture radio.

Để tìm hiểu các kiểu nội dung và giao thức được hỗ trợ trên thiết bị, bạn sử dụng các phương thức của lớp Manager:

  • getSupportedContentTypes(): cung cấp một danh sách các kiểu nội dung sẵn có cho tất cả các giao thức hay một giao thức cụ thể.
  • getSupportedProtocols(): cung cấp một danh sách các giao thức sẵn có cho tất cả các kiểu nội dung hay một kiểu nội dung cụ thể.

Sau khi bạn đã tạo ra một player, bạn có thể bắt đầu sử dụng nó bằng cách đơn giản gọi phương thức start (). Khi đạt đến sự kết thúc của media thì nó stop một cách tự động. Đây là một cái nhìn đơn giản của lớp Player. Trên thực tế lớp có năm tiểu trạng thái:

  • UNREALIZED: đây là trạng thái đầu tiên của Player thu được từ lớp Manager.
  • REALIZED: Khi phương thức realized() được gọi, Player chuyển sang trạng thái này để thu nhận thông tin cần thiết để có được các nguồn media.Quá tình realized một Player có thể là một tài nguyên và quá trình tiêu tốn thời gian. Player có thể phải giao tiếp với server, đọc một file hay tương tác với một tập các đối tượng.
  • PREFETCHED: Sau khi một player được realized, nó có thể vẫn cần các tài nguyên khan hiếm hay độc quyền, fill bộ đệm với dữ liệu media hay thực hiện các tiến trình start-up khác. Và điều này được thực hiện bằng cách gọi phương thức prefetch() để chuyển đổi sang trạng thái này.
  • STARTED: Khi gọi phương thức start(), Player bắt đầu play tài nguyên media cho đến khi nó đạt đến sự kết thúc của media.
  • CLOSED: khi gọi phương thức close(), Player chuyển đổi sang trạng thái này, giải phóng tất cả các tài nguyên nắm giữ. Và nó không thể sử dụng lại lần nữa.

Hình dưới đây cho biết nhiều trạng thái khác nhau và có thể chuyển tiếp giữa chúng:

Nếu ứng dụng của bạn cần thông tin về chuyển đổi trạng thái, bạn cần implements giao diện PlayerListener.

Play a sound

Trong game này, ý tưởng để play một sound mỗi khi Ball di chuyển chạm vào Brick hay Pad. Để làm được điều này, tạo một lớp gọi là Multimedia với phương thức playSound():

//multimedia libraries
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.media.MediaException;
public class Multimedia {
public void playSound(String file, String format) {
try {
InputStream is = getClass().getResourceAsStream(file);
Player p = Manager.createPlayer(is, format);
p.start();
} catch (IOException ioe) {
} catch (MediaException me) {
}
}

Bây giờ chỉ cần sử dụng phương thức bên dưới mỗi khi va chạm giữa Ball và các thực thể khác được phát hiện. Cho mục đích này, tôi đã tạo một sound có tên click.wav và nó phải sẵn có trong tài nguyên của ứng dụng.

public void updateGameState(){

byte colision = ball.colided(pad);
if (colision != Entity.COLLISION_NONE){
if (midlet.soundOn){
midlet.multimedia.playSound(“click.wav”, “audio/X-wav”);
}
}

}

Nếu chạy ứng dụng, bạn sẽ nghe một vài âm thanh khi play game.

Capture Video

Bây giờ, game đã có âm thanh, bạn có thể chụp ảnh của người chơi mỗi khi người đó đạt điểm số cao nhất. Để làm được điều này, bạn cần truy cập vào camera video và show nó vào player. Phương thức dưới sẽ chụp ảnh video và lưu nó vào một item.

Player p;
VideoControl vc;
public Item showVideo(String url){
Item result = null;
try {
p = Manager.createPlayer(url);
p.realize();
// Grab the video control .
vc = (VideoControl)p.getControl(“VideoControl”);
if (vc != null) {
// create the Item with the video image
result =((Item)vc.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null));
// add a label
result.setLabel(“Photo”);
}
// start capture
p.start();
} catch (IOException ioe) {
} catch (MediaException me) { }
return result;
}

VideoControl được sử dụng để tạo Item được sử dụng trong Form:

public Displayable initNewHighScore(int score, int pos) {
  ...
  newHighScoreForm.append(multimedia.showVideo("capture://video"));
  ...
}

Bây giờ, sử dụng VideoControl để chụp một image từ camera.

public Image captureVideo(){
Image result = null;
try {
// grab data
byte[] imageData = vc.getSnapshot(“encoding=png”);
// create image;
result = Image.createImage(imageData, 0, imageData.length);
} catch (MediaException me) {
me.printStackTrace();
}
return result;
}

Sau đó, gọi phương thức này khi high score đã được lưu.

// we added an extra field to Score to store the image
  scores[pos].image = multimedia.captureVideo();

Sau đó, show các image trong màn hình high score.

Chạy ứng dụng để test chức năng mới này. Bài tiếp theo sẽ thảo luận về network trên mobile.

Download Code ở đây

Chúc các bạn thành công.

Các bài liên quan:
Phát triển game đơn giãn trên Mobile(P1)
Phát triển game đơn giãn trên Mobile(P2)
Phát triển game đơn giãn trên Mobile(P3)
Phát triển game đơn giãn trên Mobile(P4)
Phát triển game đơn giãn trên Mobile(P5)
Phát triển game đơn giãn trên Mobile(P7)