Qua bốn tháng thực tập em đã tìm hiểu được những kiến thức cơ bản của Java, công nghệ J2ME, và cách xây dựng một ứng dụng trên điện thoại di động . Qua đó dần áp dụng công nghệ mới vào trong cuộc sống. Dưới đây là một số kiến thức đã đạt được:
• Hiểu chi tiết về J2ME và ứng dụng của nó để lập trình trên thiết bị di động.
• Nắm được các kỹ thuật xử lý âm thanh, hình ảnh, lưu trữ trên điện thoại di động.
• Ứng dụng các kết quả nghiên cứu được xây dựng Game đơn giản khai thác các điểm mạnh về âm thanh, hình ảnh, đồ họa
• Áp dụng thành công trên một số hang điện thoại hỗ trợ java như SonyEricson
59 trang |
Chia sẻ: aloso | Lượt xem: 2267 | Lượt tải: 1
Bạn đang xem trước 20 trang tài liệu Đồ án J2ME và lập trình Game trên điện thoại di động, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
hép nhập số điện thoại
• URL: Chỉ cho phép nhập các ký tự hợp lệ bên trong URL
• PASSWORD: che tất cả các ký tự nhập vào
2.2.5 ChoiceGroup
Thành phần ChoiceGroup cho phép người dùng chọn từ một danh sách đầu vào đã được định nghĩa trước. ChoiceGroup có 2 loại:
multi-selection(cho phép chọn nhiều mục): nhóm này có liên quan đến các checkbox.
exclusive-selection(chỉ được chọn một mục): nhóm này liên quan đến nhóm các radio button.
2.2.6 Image and ImageItem
Hai lớp được dùng để hiển thị hình ảnh là: Image và ImageItem. Image được dùng để tạo ra một đối tượng hình ảnh và giữ thông tin như là chiều cao và chiều rộng, và dù ảnh có biến đổi hay không. Lớp ImageItem mô tả một tấm ảnh sẽ được hiển thị như thế nào, ví dụ tấm ảnh sẽ được đặt ở trung tâm, hay đặt về phía bên trái, hay bên trên của màn hình.
MIDP đưa ra 2 loại hình ảnh là loại ảnh không biến đổi và ảnh biến đổi. Một tấm ảnh không biến đổi thì không thể bị thay đổi kể từ lúc nó được tạo ra. Đặc trưng của loại ảnh này là được đọc từ một tập tin. Một tấm ảnh biến đổi về cơ bản là một vùng nhớ. Điều này tùy thuộc vào việc bạn tạo nội dung của tấm ảnh bằng cách ghi nó lên vùng nhớ. Các phương thức dựng cho lớp Image và ImageItem.
Image createImage(String name);
Image createImage(Image source);
Image createImage(byte[] imageDate, int imageOffset, int imageLength);
Image createImage(int width, int height);
Image createImage(Image image, int x, int y, int width, int height, int transform);
Image createImage(InputStream stream);
Image createRGBImage(int[] rgb, int width, int height, boolean processAlpha);
ImageItem(String label, Image img, int layout, String altText);
2.3 List
Một List chứa một dãy các lựa chọn được thể hiện một trong ba dạng. Chúng ta đã thấy loại cho phép nhiều lựa chọn và loại chỉ được phép chọn một khi làm việc với ChoiceGroup. Dạng thứ 3 là là dạng không tường minh. Các List không tường minh đuợc dùng để thể hiện một thực đơn các chọn lựa
2.4 TextBox
TextBox được dùng để cho phép nhập nhiều dòng. Thành phần TextBox và TextField có những ràng buộc giống nhau trong việc chỉ định loại nội dung được phép nhâp vào.Ví dụ ANY, EMAIL, URI…
Dưới đây là phương thức dựng của một TextBox:
TextBox(String title, String text, int maxSize, int constraints);
2.5 Alert và AlertType
Một Alert đơn giản là một hộp thoại rất nhỏ. Có 2 loại Alert:
•Modal: là loại hộp thoại thông báo được trình bày cho đến khi người dùng ấn nút đồng ý
•Non-modal: là loại hộp thoại thông báo chỉ được trình bày trong một số giây nhất định
Các phương thức dựng của Alert:
Alert(String title);
Alert(String title,String alertText, Image alertImage,AlertType alertType);
Thành phần AlertType sử dụng âm thanh để thông báo cho người dùng biết có một sự kiện xảy ra. Ví dụ bạn có thể sử dụng AlertType để mở một đoạn âm thanh nào đó báo hiệu cho người dùng biết khi có lỗi xảy ra
Thành phần AlertType bao gồm 5 loại âm thanh định sẵn là: thông báo, xác nhận, báo lỗi, thông báo và cảnh báo
Ta thấy các phương thức dựng của Alert cho biết là Alert có thể bao gồm 1 tham chiếu đến một đối tượng AlertType
2.6. Ticker
Thành phần Ticker đuợc dùng để thể hiện một đoạn chuỗi chạy theo chiều ngang. Tham số duy nhất của thành phần Ticker là đoạn văn bản được trình bày. Tốc độ và chiều cuốn được xác định bởi việc cài đặt trên thiết bị nào.
Phương thức dựng của Ticker : Ticker(String str)
Từ cây phân cấp các thành phần thể hiện trên thiết bị, ta thấy là thành phần Ticker không là lớp con của lớp Screen mà Ticker là một biến của lớp Screen. Điều này có nghĩa là một Ticker có thể được gắn vào bất cứ lớp con của lớp Screen bao gồm cả Alert.
2.7 Xử lý sự kiện
Xử lý sự kiện hầu như rất quan trọng với đa số MIDlet. Một ứng dụng không thể thiếu sự tương tác giữa người dùng và chương trình. Xử lý sự kiện không khác gì hơn là đoán nhận một sự kiện khi nào xuất hiện và thực hiện một yêu cầu nào đó dựa vào sự kiện phát sinh. Cần có ba bước để quản lý thành công một sự kiện:
Phần cứng (thiết bị vật lý) phải đoán nhận được điều gì đã xuất hiện: một phím được nhấn, hay một phím được nhả ra, nắp điện thoại được mở ra hay đóng lại…
Phần mềm trên thiết bị (bộ quản lý ứng dụng) cần được thông báo về sự kiện này.
Khi một thông báo được gửi đến MIDlet từ bộ quản lý ứng dụng, thông báo sẽ chứa thông tin về sự kiện để ta có thể đưa ra những quyết định để xử lý.
Trước khi một MIDlet có thể đoán nhận được thông báo từ bộ quản lý ứng dụng là một sự kiện, nó phải thiết lập bộ lắng nghe sự kiện Listener. Có hai giao diện chính cho mỗi MIDlet là: CommandListener và ItemStateListener.
2.7.1 Đối tượng Command
Khi một hành động xảy ra trên thiết bị di động, một đối tượng Command giữ thông tin về sự kiện đó. Thông tin này bao gồm loại hành động thực thi, nhãn của mệnh lệnh và độ ưu tiên của chính nó. Trong J2ME, các hành động nói chung được thể hiện dưới dạng các nút trên thiết bị
Nếu có quá nhiều hành động được hiển thị trên thiết bị, thiết bị sẽ tạo ra một thực đơn để chứa các hành động
Chỉ có các thành phần MIDP sau đây mới có thể chứa các đối tượng Command là: Form, TextBox, List và Canvas.
Các bước cơ bản để xử lý các sự kiện với một đối tượng Command:
Tạo một đối tượng Command
Đặt đối tượng Command lên trên một đối tượng Form, TextBox, List, hay Canvas
Tạo một bộ lắng nghe
Khi có một sự kiện xảy ra, bộ lắng nghe sẽ phát sinh một lời gọi đến phương thức commandAction(). Trong thân phương thức này bạn có thể xác định đối tượng nào phát sinh ra sự kiện và tạo ra các xử lý tương ứng
Dưới đây là đoạn mã minh họa việc tạo ra sự kiện Command và xử lý sự kiện:
private Form fmMain;
private Command cmExit;
... fmMain = new Form("Core J2ME");
cmExit = new Command("Exit", Command.EXIT, 1);
...fmMain.addCommand(cmExit); fmMain.setCommandListener(this); ...public void commandAction(Command c, Displayable s)
{ if (c == cmExit)
{ destroyApp(true); notifyDestroyed(); }}
2.7.2 Đối tượng Item
Ngoài việc xử lý sự kiện bằng đối tượng Command ta có thể xử lý sự kiện bằng đối tượng Item. Nhiều đối tượng trong MIDP đã được định nghĩa trước cho việc xử lý các sự kiện cụ thể nào đó. Ví dụ đối tượng DateField cho phép người sử dụng chọn lựa ngày và giờ trên màn hình, đối tượng TextField cho phép người dùng nhập vào một chuỗi các ký tự, số và các ký tự đặc biệt
Tương tự như việc xử lý sự kiện bằng đối tượng Command, thì khi có một thay đổi xảy ra đối với bất kỳ thành phần Item nào thì phương thức itemStateChanged() sẽ được gọi. Và chúng ta sẽ thực hiện các xử lý bên trong phương thức này
Dưới đây là đoạn mã minh họa việc tạo ra sự kiện Command và xử lý sự kiện:
private Form fmMain;
private DateField dfToday;
fmMain = new Form("Core J2ME");
dfToday = new DateField("Today:", DateField.DATE);
fmMain.append(dfToday);
fmMain.setItemStateListener(this); public void itemStateChanged(Item item)
{if (item == dfToday)
Chương 3
CÁC THÀNH PHẦN GIAO DIỆN Ở MỨC THẤP
3.1 Các hàm API ở mức thấp
Mặc dù các hàm API cấp cao cung cấp một tập đầy đủ các thành phần để xây dựng giao diện ứng dụng người dùng. Tuy nhiên các thành phần cấp cao không cung cấp phương tiện để vẽ trực tiếp lên thiết bị thể hiện. Vì thiếu khả năng này nên các ứng dụng được tạo ra sẽ gặp nhiều giới hạn. Ví dụ hầu hết các nhà phát triển Game di động dựa trên khả năng vẽ các đường thẳng và các hình dạng như là một phần tích hợp quá trình phát triển.
Nếu các hàm API cấp cao cho phép chúng ta tạo ra giao diện cho các ứng dụng theo chuẩn, thì các hàm API cấp thấp cho phép chúng ta có thể thể hiện các ý tưởng của mình.
3.2 Lớp Canvas
Lớp Canvas cung cấp một khung vẽ cho phép tạo ra giao diện tùy biến người dùng. Một số lượng lớn các phương thức trong lớp này được dùng để xử lý sự kiện, vẽ ảnh và chuỗi lên thiết bị hiển thị. Hai lớp chính sử dụng ở mức API cấp thấp là Canvas và lớp đối tượng đồ họa Graphics.
Canvas là nơi để vẽ, được hình dung là một tấm vải có chiều rộng và chiều cao, với những gì vẽ lên đó đều sẽ hiển thị ra bên ngoài. Lớp Canvas cũng cung cấp những phương thức để xử lý sự kiện mức thấp.
Ta dùng đối tượng Graphics (được gọi là ngữ cảnh đồ họa Graphics) để vẽ lên Canvas. Lớp này có những phương thức để vẽ đường thẳng, hình cung, hình chữ nhật, văn bản…
3.2.1 Hệ thống trục tọa độ
Hệ thống tọa độ cho lớp Canvas có tâm tọa độ là điểm trái trên của thiết bị trình bày. Giá trị x tăng dần về phía phải, giá trị y tăng dần khi đi xuống phía dưới.
3.2.2 Tạo một đối tượng Canvas
Bước đầu tiên để làm việc với một lớp Canvas là tạo ra một lớp thừa kế từ lớp Canvas
class TestCanvas extends Canvas implements CommandListener{private Command cmdExit;
...display = Display.getDisplay(this);
cmdExit = new Command("Exit", Command.EXIT, 1);
addCommand(cmdExit);setCommandListener(this);...protected void paint(Graphics g)
{// Draw onto the canvas
}
3.3 Sự kiện hành động
Cũng như các thành phần Form, List, và TextBox, một Canvas có thể xử lý các sự Command. Chúng ta có thể xử lý các sự kiện Command trên thành phần Canvas cung cách như các thành phần khác
Đoạn mã sau minh họa việc xử lý sự kiện Command trên thành phần Canvas
class TestCanvas extends Canvas implements CommandListener{private Command cmdExit;
...display = Display.getDisplay(this);
cmdExit = new Command("Exit", Command.EXIT, 1);
addCommand(cmdExit);setCommandListener(this);...protected void paint(Graphics g)
{// Draw onto the canvas
...}public void commandAction(Command c, Displayable d)
{if (c == cmdExit)
... }
3.4 Mã phím
Trong trường hợp xử lý các hành động của các phím mềm, một Canvas có thể truy cập đến 12 mã phím. Những mã này được đảm bảo luôn luôn có trên bất kỳ các thiết bị MIDP nào
KEY_NUM0KEY_NUM1KEY_NUM2KEY_NUM3KEY_NUM4KEY_NUM5KEY_NUM6KEY_NUM7KEY_NUM8KEY_NUM9KEY_STARKEY_POUND
Bốn phương thức để xử lý các mã phím là:
void keyPressed(int keyCode): Gọi khi một phím bị nhấn lần đầu.
void keyReleased(int keyCode): Gọi khi một phím được thả.
void keyRepeated(int keyCode): Gọi khi một phím bị giữ.
String getKeyName(int keyCode): Lấy một chuỗi phím mang thông tin cho phím.
3.5 Lớp Graphics
Một đối tượng đồ họa Graphics (còn được gọi là ngữ cảnh đồ họa Graphics) là một dụng cụ để vẽ lên Canvas.
Có hai cách để tham chiếu đến đối tượng này:
Cách đầu tiên là viết phương thức paint() trong lớp Canvas
protected void paint(Graphics g)
{
…..
}
Cách thứ hai là thông qua đối tượng hình ảnh Mutable:
Image im=Image.createImage(80,20);
Graphics g=im.getGraphics();
3.5.1 Hỗ trợ màu
Một ứng dụng MIDP chỉ có một đối tượng Display. Đối tượng này đuợc dùng để lấy thông tin của màn hình hiển thị hiện tại, ví dụ như số màu hỗ trợ và các phương thức để yêu cầu các đối tượng được hiển thị. Đối tượng Display đơn giản là một bộ quản lý sự hiển thị của thiết bị và điều khiển những gì sẽ được hiển thị ra trên thiết bị.
boolean isColor()
int numColors()
Phương thức đầu tiên cho biết thiết bị có hỗ trợ hiển thị màu hay không. Nếu có thì phương thức thứ 2 sẽ được gọi để xác định số màu được hỗ trợ. Các phương thức tiếp theo dưới đây để lấy về màu và thiết lập màu .
void setColor(int RGB);
void setColor(int red, int green, int blue);
int getColor();
int getBlueComponent();
int getGreenComponent();
int getRedComponent();
void setGrayScale(int value);
int getGrayScale();
Chú ý có thể xác định màu bằng 2 cách. Cách 1: xác định một số nguyên đại diện cho 3 giá trị của màu là đỏ, xanh lá cây và xanh dương với 8 bit cho mỗi màu. Hay cách 2 có thể dùng từng tham số riêng biệt để xác định mỗi màu. Khi sử dụng một giá trị để lưu giữ màu, thì màu đỏ sẽ chiếm 8 bit đầu kể từ bên trái, tiếp theo là 8 bit dành cho màu xanh lá cây, sau cùng là màu xanh dương.
Dưới đây là cách thiết lập màu chỉ sử dụng một số nguyên:
int red = 0,
green = 128,
blue = 255;
...
g.setColor((red << 16) | (green << 8) | blue);
…..
Còn có thể xác định màu bằng cách thiết lập giá trị cho 3 tham số:g.setColor(red, green, blue);
3.5.2 Loại nét vẽ
Có thể chọn nét khi vẽ đường thẳng, cung và hình chữ nhật trên thiết bị hiển thị. Dưới đây là các phương thức dùng để thiết lập loại nét vẽ
int getStrokeStyle();
void setStrokeStyle(int style);
Hai kiểu nét vẽ được định nghĩa trong lớp Graphics là nét chấm, và nét liền
g.setStrokeStyle(Graphics.DOTTED);
g.setStrokeStyle(Graphics.SOLID);
3.5.3 Vẽ đường thẳng
Để vẽ đường thẳng, dùng phương thức: Graphics.drawline(). Nó chấp nhận 4 tham số: x1,x2,y1,y2. Các tham số thiết lập trên màn hình 2 điểm (x1,y1), (x2,y2), và một đường thẳng được vẽ giữa chúng.
3.5.4 Vẽ hình chữ nhật
Cũng giống như cung thì hình chữ nhật có thể chỉ được vẽ viền bao quanh hoặc tô bên trong. Bên cạnh đó có thể vẽ hình chữ nhật đó có 4 góc là tròn hoặc là vuông. Dưới đây là một số phương thức để vẽ hình chữ nhật:
void drawRect(int x, int y, int width, int height);
void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight);
void fillRect(int x, int y, int width, int height);
void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight);
Khi vẽ hình chữ nhật có 4 góc là tròn thì bạn phải xác định đường kính theo chiều ngang(arcWidth) và đường kính theo chiều dọc(arcHeight). Những tham số này được định nghĩa độ sắc nét của cung theo mỗi chiều. Giá trị càng lớn thể hiện một cung tăng dần, ngược lại là một đường cong hẹp.
3.5.5 Vẽ cung
Khi vẽ một cung, có thể vẽ nó chỉ có đường bao xung quanh hay yêu cầu nó được tô bên trong. Cũng có thể bắt đầu bằng cách chỉ định chiều bao quanh bên ngoài của một hình hộp chữ nhật tưởng tượng. Góc bắt đầu xác định vị trí bắt đầu vẽ khung, với giá trị 0 được xác định tại thời điểm 3 giờ. Giá trị dương tính theo ngược chiều kim đồng hồ. Góc của cung chỉ ra rằng có bao nhiêu độ được vẽ tính từ góc ban đầu, đi theo ngược chiều kim đồng hồ.
Một số các phương thức dùng để vẽ cung
void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle).
3.5.6 Font chữ
Phần sau đây cũng quan trọng không kém là cách sử dụng font chữ được hỗ trợ bởi giao diện cấp thấp của ứng dụng MIDP. Một số các phương thức dựng của lớp Font:
Font getFont(int face, int style, int size)
Font getFont(int fontSpecifier)
Font getDefaultFont()
Một số thuộc tính của lớp Font
FACE_SYSTEMFACE_MONOSPACEFACE_PROPORTIONALSTYLE_PLAINSTYLE_BOLDSTYLE_ITALICSTYLE_UNDERLINEDSIZE_SMALLSIZE_MEDIUMSIZE_LARGE
Các tham số kiểu dáng có thể được kết hợp thông qua toán tử hay. Ví dụFont font = Font.getFont(Font.FACE_PROPORTIONAL,
Font.STYLE_BOLD | Font.STYLE_ITALIC, Font.SIZE_MEDIUM);
Sau khi bạn có một tham chiếu đến một đối tượng Font, bạn có thể truy vấn nó để xác định thông tin của các thuộc tich của nó.
int getFace();
int getStyle();
int getSize();
boolean isPlain();
boolean isBold();
boolean isItalic();
boolean isUnderlined();
Kích thước của các font chữ được xác định bởi chiều cao của font chữ, bề dài tính bằng điểm ảnh của một chuỗi ký tự trong một font xác định. Một số các phương thức sau hỗ trợ khi tương tác với một đối tương font
int getHeight();
int getBaselinePosition();
int charWidth(char ch);
int charsWidth(char[] ch, int offset, int length);
int stringWidth(String str);
int substringWidth(String str, int offset, int length);
3.5.7 Vẽ các chuỗi ký tự
Có thể vẽ chuỗi ký tự ra màn hình thông qua một số các phương thức:
void drawChar(char character, int x, int y, int anchor);
void drawChars(char[] data, int offset, int length, int x, int y, int
anchor);void drawString(String str, int x, int y, int anchor);
void drawSubstring(String str, int offset, int len, int x, int y, int anchor);
3.5.8 Vẽ ảnh
Lớp Graphics cung cấp 1 phương thức dùng để vẽ ảnh:drawImage(Image img, int x, int y, int anchor);
Tham số đầu tiên tham chiếu tới một đối tượng hình ảnh. Chúng ta cần phải tạo ra đối tượng image trước khi gọi drawImage
- Đối với hình ảnh không thay đổi:
Image image=Image.createImage(/” image source”);
- Đối với hình ảnh thay đổi:
Image image=Image.createImage(imagewidth, imageheight);
3.5.9 Vùng cắt (Clipping Regions)
Đối với mỗi lời gọi đến hàm paint(), toàn bộ màn hình sẽ được vẽ lại. Vùng cắt có thể giới hạn những gì được vẽ trên màn hình. Một lợi ích quan trọng là giảm thời gian để làm mới màn hình.
Các phương thức của vùng cắt:
void setClip(int x, int y, int width, int height): đặt hình chữ nhật khoanh vùng cắt.
void clipRect(int x, int y, int width, int height): giao hình chữ nhật này với hình chữ nhật của vùng cắt hiện thời để tạo ra vùng cắt mới.
int getClipX(): lấy tọa độ X của vùng cắt hiện thời.
int getClipY(): lấy tọa độ Y của vùng cắt hiện thời.
int getClipHeight() : lấy chiều cao của vùng cắt hiện thời.
int getClipHeight() : lấy chiều rộng của vùng cắt hiện thời.
Chương 4
CƠ CHẾ LƯU TRỮ DỮ LIỆU RMS
(Record Management System)
4.1 Giới thiệu hệ thống lưu trữ dữ liệu RMS
Việc lưu trữ thông tin cho việc khởi tạo của các ứng dụng là cần thiết và quan trọng. Thông tin mà các ứng dụng có thể lưu trữ như các thông tin cấu hình ứng dụng, thông tin quá trình sử dụng các ứng dụng,…Đối với máy PC thì việc này tương dối dễ dàng khi chúng ta có trong tay nhiều thiết bị lưu trữ như HDD, CD- ROM, USB DISK,…nhưng việc này tương đối khó khăn đối với các ứng dụng trên điện thoại di động. MIDP cung cấp cho chúng ta một đối tượng là Record Management System cho phép chúng ta lưu trữ dữ liệu dưới dạng Record.Các API của đối tuợng này được cung cấp trong gói javax.microedition.rms. Một vùng nhớ trên các thiết bị sử dụng MIDP sẽ được dành riêng cho việc lưu trữ các dữ liệu của ứng dụng MIDlet. Vị trí và kích thước của vùng lưu trữ này đuợc xác định tùy thuộc vào những thiết bị cụ thể.
RMS cho phép lưu trữ dữ liệu khi ứng dụng thoát, khởi động lại và khi thiết bị di động tắt hay thay pin. Dữ liệu của ứng dụng sẽ tồn tại trên thiết bị di động cho đến khi ứng dụng thật sự được xóa khỏi thiết bị di động. Khi một MIDlet bị xóa, tất cả các record mà nó lưu trữ cũng bị xóa.
Luu trữ
bản ghi 1
Luu trữ
bản ghi 2
Luu trữ
bản ghi 3
MIDlet 1
MIDlet 2
MIDlet 3
Hình 4.1. Lưu trữ dữ liệu
Như trong hình vẽ, các MIDlet có thể có nhiều hơn một tập hợp các record và chúng có thể truy xuất đến tập hợp dữ liệu lưu trong bộ MIDlet mà chúng lưu trữ. Do đó, MIDlet 1 và MIDlet 2 có thể truy truy xuất đến Record Store 1 và Record Store 2 nhưng chúng không thể truy xuất đến Record Store 3. Ngược lại, MIDlet 3 chỉ có thể truy xuất Record Store 3 mà không thể truy xuất đến Record Store 1 và Record Store 2. Tên của bộ lưu trữ dữ liệu phải là duy nhất trong một bộ MIDlet nhưng trong các bộ MIDlet khác nhau có thể trùng tên.
Hệ thống RMS lưu trữ các bản ghi theo một mảng các byte. Các mảng byte có chiều dài khác nhau và mỗi mảng byte được gán một số ID bản ghi. Các bản ghi được định danh bằng một số ID duy nhất. Các số ID duợc đánh số bắt dầu từ 1. Các số ID sẽ tăng dần và không đuợc dùng lại cho dù bản ghi dó có bị xoá nên sẽ tồn tại một số khoảng trống trong các ID bản ghi. MIDP không kiểm soát việc ghi quá số bản ghi tối đa, diều này phụ thuộc vào ứng dụng.
4.2 Định dạng, thêm, xóa các record
Thêm record gồm 2 buớc: buớc đầu tiên là dịnh dạng record theo các yêu cầu và buớc hai là thêm các record đã được định dạng vào RMS. RMS không hỗ trợ sự tuần tự hoá do đó ta phải định dạng các mảng byte dể lưu trữ bản ghi.
Sau dây là ví dụ của việc dịnh dạng lưu trữ bản ghi, mở một RMS và sau đó là thêm dữ liệu bản ghi vào RMS.
ByteArrayOutputStream baos=new ByteArrayOutputStream(); DataOutoutStream outputStream=new DataOutputStream(baos); outputStream.writeByte(‘T’);
outputStream.writeInt(score); outputStream.writeUTF(name);
byte[] theRecord=baos.toByteArray(); recordStore rs=null;
rs=RecordStore.openRecordStore(“RecordStoreName”,CreateIfNotEx ist);
int RecordID=rs.addRecord(theRecord,0,theRecord.length);
4.2.1 Định dạng dữ liệu bản ghi
Trong ví dụ trên hai dòng đầu tạo một luồng xuất để ghi dữ liệu bản ghi. Sử dụng đối tuợng DataOutputStream cho phép các bản ghi dễ dàng được định dạng theo các kiểu chuẩn của Java (long, int ,string,…) mà không phải quan tâm dến việc tách nó thành dữ liệu dạng byte. Phương thức writeInt(), writeByte(), writeUTF() định dạng dữ liệu như hình vẽ (tag, score, name). Sử dụng thẻ tag làm có ích để xác định loại record sau này. Phương thức toByteArray() chép dữ liệu trong một luồng xuất thành một mảng byte chứa các bản ghi dể lưu trữ. Biến theRecord tham chiếu đến dữ liệu động dã được định dạng.
4.2.2 Thêm record và RMS
Khi dữ liệu dã được định dạng, nó có thể được thêm vào RMS. Phương thức openRecordStore() tạo và mở một RMS với tên là RecordStoreName. Phương thức addRecord dùng để thêm record bắt dầu từ byte 0 của theRecord và trả về ID của bản ghi gắn với record này.
4.2.3 Xóa bản ghi
Bản ghi được xóa bằng cách chuyển số ID bản ghi cho phương thức deleteRecord() của đối tượng RecordStore. Khi bản ghi có ID 7 đuợc xóa, thêm mới bản ghi thì bản ghi đó có ID là 8, ID 7 không được dùng lại.
4.3 Lọc bản ghi với RecordFilter
Giao diện RecordFilter cung cấp một cách thuận tiện dể lọc các bản ghi theo tiêu chuẩn nhất định, RecordEnumeration có thể duợc dùng để duyệt qua các bản ghi và chỉ trả về các record phù hợp với tiêu chuẩn xác định. Giao diện RecordFilter có phương thức matches() dùng để xác định các tiêu chuẩn phù hợp. Phương thức matches() có tham số đầu vào là mảng byte biểu diễn một bản ghi. Phương thức trả về true nếu bản ghi này phù hợp với tiêu chuẩn đã định nghĩa.
4.4 Duyệt Record với RecordEnumeration
Lớp RecordEnumeration cung cấp các phương thức để duyệt các
record trong RecordStore một cách nhanh chóng
RecordEnumeration re = rs.enumerateRecords(null,null,false);
while (re.hasNextElement())
{
// Get the next record into a String
String str = new String(re.nextRecord());
... do something ...
}
RecordEnumeration API
int numRecords(): Số lượng record trong enumeration
byte[] nextRecord(): Record tiếp theo
int nextRecordId(): Record ID của record tiếp theo
byte[] previousRecord() : Record trước đó
int previousRecordId() : Record ID của record trước đó
boolean hasNextElement() : Kiểm tra enumeration có record kế tiếp
boolean hasPreviousElement() : Kiểm tra enumeration có record trước đó
void keepUpdated(boolean keepUpdated): Đặt enumeration reindex sau khi có sự thay đổi
boolean isKeptUpdated(): Kiểm tra enumeration có tự động reindex()
void rebuild() :Tạo lại index
void reset() : Đưa enumeration về record đầu tiên
void destroy() : Giải phóng tài nguyên được sử dụng bởi enumeration.
4.5 Sắp xếp các record với interface RecordComparator
Interface này giúp người lập trình so sánh hai Record theo một tiêu chí nào đó. Interface này định nghĩa phương thức compare với trị đầu vào là hai mảng các byte thể hiện hai Record cần so sánh. Phương thức này trả về các trị sau được định nghĩa trong interface:
•EQUIVALENT: Nếu hai Record bằng nhau
•FOLLOWS: Nếu Record thứ 1 đứng sau Record thứ 2
•PRECEDES: Nếu Record thứ 1 đứng trước Record thứ 2.
4.6 Thông báo những thay đổi với RecordListener
Chúng ta cần được thông báo khi được xóa, thêm, hay cập nhật lai. Ví dụ một MIDlet có thể cất giữ những tùy chọn của ứng dụng vào vùng lưu trữ. Khi người dùng thay đổi những thiết lập của họ cho ứng dụng, chương trình cần nhận ra những thay đổi này để MIDlet có thể thực hiện những điều chỉnh cần thiết ngay khi đang chạy. Hoặc chúng ta có một MIDlet quản lý danh sách các thông tin quan hệ (họ tên, ngày sinh, email…). Danh sách có thể được sử dụng bất kỳ lúc nào bởi MIDlet, ví dụ: khi người dùng đang nghi email, họ có thể tìm kiếm bất kỳ một email nào đó trên Server từ xa chứa danh sách các địa chỉ này. Khi một thay đổi xảy ra trên MIDlet, chúng ta phải có khả năng nhận biết những thay đổi này.
Chúng ta sử dụng bộ Listener RecordListener để phát hiện các thay đổi trên vùng bản ghi. RecordListener hoạt động như bất kỳ một Listener nào khác trong Java. Nếu đăng ký một Listener, thì khi một sự kiện xuất hiện, phương thức thông báo sẽ được gọi để cho bạn biết sự thay đổi.
Có ba phương thức được dùng để báo hiệu sự thay đổi của bản ghi:
Void recordAdded ( RecordStore rs, int recorded): Thông báo bản ghi đã được thêm.
Void recordChanged ( RecordStore rs, int recorded): Thông báo bản ghi đã bị thay đổi.
Void recordDeleted ( RecordStore rs, int recorded): Thông báo bản ghi đã bị xóa.
4.7 Xử lý ngoại lệ
Có năm ngoại lệ (Exception) dành riêng cho RMS. Chúng đều được kế thừa từ lớp java.lang.Throwable.
InvalidRecordIDException: Cho biết số bản ghi sai.
RecordStoreException: Một ngoại lệ chung cho biết lỗi vùng bản ghi.
RecordStoreFullEception: Cho biết bản ghi đầy.
RecordStoreNotFoundException: Cho biết vùng bản ghi không tồn tại.
RecordStoreNotOpenException: Cho biết vùng bản ghi chưa được mở.
Chương 5
KHUNG KẾT NỐI CHUNG
(GENERIC CONNECTION FRAMEWORK)
Mặc dù hạn chế về bộ nhớ và khả năng xử lý nhưng thiết bị di động vẫn hỗ trợ hệ thống xử lý file và các giao thức kết nối mạng. Với kích thước hơn 200 kb và hơn 100 class và interfaces trong gói java.io, java.net của J2SE sẽ chiếm hầu hết bộ nhớ nhỏ bé của những thiết bị đi động. Do đó Sun không thể kế thừa những gói này vào trong J2ME, mà đã xây dựng một chuẩn là Generic Connection Framework (GCF). GCF sẽ giúp cho các thiết bị di động có thể truy xuất được các tài nguyên mạng, cũng như các tài nguyên khác mà địa chỉ của chúng được xác định bằng URL.
Generic Connection Framework bao gồm một tập hợp các interfaces được khai báo trong package javax.microedition.io.
5.1 Phân cấp kết nối
Ý tưởng cơ bản là dùng một lớp duy nhất, Connector có thể tạo ra bất kỳ kiểu kết nối nào, file, http, datagram…Phương thức mở kết nối có dạng sau:
Connector.Open(“ protocol : address ; parameters);
Ví dụ:
Connector.Open(“”);
Connector.Open(“socket://www.some_adress.com”);
Connector.Open(“file://www.some_adress.com”);
Cách những giao thức này được xử lý chính là tính linh hoạt và vai trò chính của GCF. Khi thực thi Connector sẽ tìm kiếm lớp thích hợp cài đặt giao thức được yêu cầu kết nối. Nó sử dụng Class.forName() để nạp lớp. Một yêu cầu mở kết nối HTTP trong J2ME:
Class.forName(“ com.sun.midp.io.j2me.http.Protocol ”);
Nếu lớp này được tìm thấy, thì một đối tượng được trả về và đối tượng này được cài đặt giao diện kết nối của connector. Giao diện lớp của Connector và Connection được định nghĩa trong CLDC.
Hình bên dưới cho thấy các lớp tạo nên phân cấp kết nối Connection, mỗi lớp được định nghĩa như một giao diện.
Connection
(Interface)
InputConnection
(Interface)
OutputConnection
(Interface)
DatagramConnection
(Interface)
StreamConnection
(Interface)
Hình 5.1. Phân cấp Connection
Các lớp và các phương thức và các phương thức trong GCF:
Connection (public abstract interface Connection)
public void close()
InputConnection( public abstract interface InputConnection extend Connection)
public InputStream openInputStream()
public DataInputStream openDataInputStream();
OutputConnection(public abstract interface InputConnectin extends Connection)
public OutputStream openOutputStream()
public DataOutputStream openDataOutputStream()
StreamConnection ( public abstract interface StreamConnection extends InputConnection, OutputConnection)
ContentConnection (public abstract interface ContentConnection extends StreamConnection)
public long getLength()
public String getEncoding()
public String getType()
HttpConnection ( public interface HttpConnection extends ContentConnection).
5.2 Kết nối HTTP
Trong MIDP 1.0, giao thức luôn đảm bảo được cài đặt là HTTP. Thông qua lớp HttpConnection, bạn có thể giao tiếp với một máy chủ Server trên mạng, hoặc bất kỳ thiết bị từ xa nào hỗ trợ HTTP. Nếu một thiết bị không trực tiếp hỗ trợ HTTP, ta cần một cổng chuyển tiếp dùng chuyển đổi giao thức thiết sang HTTP trước khi giao tiếp với Server.
5.2.1 Tính khả chuyển
Giao diện kết nối Connection duy nhất được MIDP 1.0 hỗ trợ là HttpConnection. Nếu tính khả chuyển là một yêu cầu của chương trình thì chỉ nên sử dụng duy nhất một giao diện này. Các cài đặt khac có thể hỗ trợ những giao thức như gói dữ liệu Datagram hoặc Socket nhưng không bảo đảm rằng những giao thức này sẽ sẵn sang trên mọi thiết bị khác chạy MIDP 1.0. HTTP được xem như giao thức hoạt động theo cớ chế Yêu cầu/Phản hồi (Request/Response). Máy khách Client chuẩn bị một yêu cầu, gửi nó cho một Server với địa chỉ được định dạng theo URL và sau đó là một phản hồi được trả lại từ máy chủ Server.
5.2.2 Tạo kết nối
Lớp Connector có bảy phương thức để tạo ra một kết nối tới một máy chủ Server. Có 3 dạng phương thức open(). Phương thức đầu tiên yêu cầu duy nhất địa chỉ Server. Phương thức thứ hai chấp nhận kiểu cho đọc/ghi truyền vào tham số. Phương thức thứ ba có thêm một cờ cho biết người gọi phương thức muốn quản lý các ngoại lệ timeout.
public static Connection open ( String name)
public static Connection open ( String name, int mode)
public static Connection open ( String name, int mode, boolean timeout)
pulic static DataInputStream openDataInputStream ( String name)
pulic static DataOutputStream openDataOutputStream ( String name)
pulic static OutputStream openOutputStream ( String name).
5.2.3 Yêu cầu (Request) của máy khách Client
Một yêu cầu máy khách Client, được gọi là yêu cầu thực thể gồm có ba mục: phương thức yêu cầu (Request), header và phần thân. Có ba phương thức yêu cầu có thể sử dụng trong lớp HttpConnection.
GET: Gửi yêu cầu bằng chuỗi dữ liệu.
POST: Gửi yêu cầu bằng luồng dữ liệu.
HEAD: Yêu cầu nhận thông tin mô tả của dữ liệu.
Tất cả ba phương thức này đều thong báo cho máy chủ rằng một máy khách đang yêu cầu kiểu thong tin nào đó. GET và POST chỉ khác nhau cách đóng gói dữ liệu gửi đi.
HttpConnection http=null;
http = (HttpConnection) Connector.open(url);
http.setRequestMethod( HttpConnection.GET);
Thông tin header : Bộ phận thứ hai của một yêu cầu (Request) máy khách Client cần gửi là thong tin header. Giao thức HTTP định nghĩa hơn 40 trường header như: Accept, Cache-Control, Content-Type, Exprires, If-Modified-Since and User- Agent. Header. Được thiết lập bằng cách gọi setRequestProperty().
Phần thân body: Đoạn dữ liệu được chuyển từ Client đến Server gọi là phần thân của yêu cầu Request. GET gửi phần thân dữ liệu trên địa chỉ URL, trong khi POST gửi thông qua một stream riêng biệt.
5.3 Phản hồi từ Server
Khi một máy khách Client đã đóng gói phương thức yêu cầu, header và phần thân dữ liệu, sau đó gửi nó qua mạng, bây giờ tùy vào máy chủ Server tiếp nhận và trả lời yêu cầu. Khi máy chủ phát sinh một phản hồi thì nội dung của nó được gọi là Response. Như với yêu cầu máy khách, phản hồi từ Server gồm 3 mục: tình trạng, header và phần thân.
5.3.1 Dòng tình trạng
Dòng tình trạng cho biết kết quả của yêu cầu máy khách Client. Với HttpConnection, có hơn 35 mã tình trạng. HTTP chia mã tình trạng ra thành từng nhóm.
xx- Thông tin.
xx- Thành công.
xx- Chuyển hướng.
xx- Máy khách Client lỗi.
xx- Máy chủ Server lỗi.
Ví dụ , HTTP_OK (mã tình trạng 200) cho biết yêu cầu của máy khach Client được xử lý thành công. Kho gửi phản hồi, Server kèm theo phiên bản giao thức với mã tình trạng. Ví dụ:
HTTP/1.1 200 OK
HTTP/1.1 400 Bad Request
HTTP/1.1 500 Internal Server error.
5.3.2 Header
Tương tự như máy khách Client, máy chủ Server có thể gửi thông tin thông qua một Header. Các thông tin này lưu ở dạng khóa- giá trị theo nhiều dạng và có thể lấy ra thông qua các phương thức sau:
String getHeaderField (int n): lấy giá trị trường header bằng chỉ số.
String getHeaderField (String name): lấy giá trị trường header bằng chỉ tên.
Long getHeaderFieldDate( String name, long def): Lấy về trường int theo tên.
String getHeaderFieldKey (int n): Lấy về khóa của trường sử dụng chỉ số.
Long getExpiration(): Lấy thời gian hết hạn.
Long getLastModified(): Lấy thời gian cập nhật sau cùng.
5.3.3 Phần thân (Body)
Phần thân là dữ liệu gửi từ máy chủ Server đến máy khách Client. Không có phương thức trong HTTP để đọc phần thân. Cách chung nhất để đọc được phần thân là thông qua Stream.
Chương 6
CÁC KỸ THUẬT CƠ BẢN TRONG LẬP TRÌNH GAME MOBILE
6.1 Lịch sử Game
Từ các thế kỷ trước con người đã biết đến Game như những Game thể thao, Game trên giấy, chơi cờ, đánh bài….Từ khi có sự xuất hiện của máy tính, Game đã bước vào một kỷ nguyên mới. Game đã trở thành một trong nguyên nhân chính giải thích vì sao có nhiều người mang về những chiếc hộp gọi là máy vi tính.
Vào cuối những năm 90 và đầu những năm 2000, với những Game như Everquest , Ultima Online và Age of Emprise…, đó là còn chưa kể đến vô số các Game nhỏ trên các Web như Yahoo, MSN Zone, Pogo…nó trở nên rõ ràng điều mà làm bận tâm rất nhiều Game thủ không chỉ là hình ảnh đẹp, hay chi tiết bạo lực đẫm máu mà đó chính là những con người thực. Game nhiều người chơi mà từ lâu đã phổ biến đối với những chuyên viên máy tính đã giữ xu thế chủ đạo.
Ở một khía cạnh nào đó, Game đã đáp ứng được nhu cầu xã hội và là một cách để 2 hay nhiều người cùng bước vào một thế giới khác. Game vi tính đã thâm nhập vào cuộc sống con người một cách thực sự, khi chơi Game người chơi dường như ở một thế giới khác mà chính họ là nhân vật chính.
Trong khi những Game truyền thống trên PC, hay các hệ thống Console ngày càng phát triển thì giờ đây một loại hình Game mới xuất hiện : Game Mobile. Ngày nay hiếm thấy người nào đi đâu mà không đem theo những thiết bị cầm tay như máy nhắn tin, PDA, điện thoại di động…Những thiết bị này không chỉ giúp con người liên lạc với nhau mọi luc mọi nơi mà nó còn đem lại nhiều tiện ích giải trí khác như nghe nhạc, xem phim, chơi Game…Tuy Game mobile chạy trên những dòng máy có cấu hình thấp về vi xử lý cũng như về bộ nhớ và khả năng hỗ trợ về hình ảnh và âm thanh kém, mặc dù vậy không vì thế mà nó trở nên kém hấp dẫn người chơi.
6.2 Lập trình Game Mobile
6.2.1 Đối tượng và thuộc tính của đối tượng.
Đối tượng là một trong những thành phần quan trọng nhất của bất kỳ một Game đồ họa nào. Mỗi đối tượng là bất kỳ hình dạng đồ họa nào xuất hiện trên màn hình. Các đối tượng sẽ di chuyển và tương tác với những đối tượng khác.
Những thuôc tính cơ bản của một đối tượng Game chuẩn:
X position( vị trí x): tượng trưng cho hoành độ của đối tượng đo bằng pixel.
Y position( vị trí y): tượng trưng cho tung độ của đối tượng đo bằng pixel.
Vx (vận tốc Vx): Tượng trưng cho tốc độ ngang của đối tượng. Nếu Vx dương đối tượng sẽ di chuyển sang phải, nếu Vx âm đối tượng di chuyển sang trái.
Vy ( vận tốc Vy): Tượng trưng cho tốc độ dọc của đối tượng. Nếu Vx dương đối tượng di chuyển xuống dưới, nếu Vx âm đối tượng di chuyển lên trên. Khi cả Vx và Vy bằng 0 đối tương sẽ đứng yên.
Width (chiều rộng): Tượng trưng cho độ rộng hình ảnh của đối tượng. Cùng với vị trí x, nó xác định cạnh phải của đối tượng trên tọa độ x.
Height (chiều cao): Tượng trưng cho độ cao hình ảnh của đối tượng. Cùng với vị trí y, nó xác định cạnh dưới của đối tượng trên tọa độ y.
Image (hình ảnh): Các điểm đồ họa tượng trưng của đối tượng được mã hóa theo định dạng PNG.
Frame (Khung): Nếu một đối tượng cử động nó sẽ có nhiều hơn một khung hình.
Visibility ( Tính chất khả biến): Việc điều khiển tính khả biến sẽ làm hiển thị hoặc che dấu đối tượng.
6.2.2 Vẽ các đối tượng
Mỗi đối tượng vô nghĩa cho đến khi chúng được vẽ ra màn hình. Đoạn mã sau mô tả cách vẽ một đối tượng:
public void paint(Graphics g)
{
g.setClip((int)Float.getInteger(x), (int)Float.getInteger(y), width, height); g.drawImage(image, (int)Float.getInteger(x) - frame * width, (int)Float.getInteger(y) , Graphics.TOP | Graphics.LEFT); g.setClip(0, 0, Cache.width, Cache.height);
}
Hình chữ nhật cắt được tai vị trí x, y và với chiều cao và chiều rộng hiện hành. Nó đảm bảo rằng chỉ có một khung hình được vẽ tại một thời điểm. Hình ảnh sau đó sẽ được vẽ nên khung hình phù hợp với với góc trái phía trên cao hơn của hình chữ nhật được cắt.
6.2.3 Sự nhận biết va chạm giữa các đối tượng
Sự nhận biết va chạm đối tượng là tính chất thiết yếu nhất của bất kỳ một Game nào. Sư nhận biết va chạm cho biết đến khi nào 2 đối tượng chạm vào nhau
Dạng cơ bản nhất của sự nhận biết va chạm là coi mỗi đối tượng như một hình chữ nhật. Để thực hiện nhận biết này, bạn cần phải chọn vị trí x, y , độ rộng và chiều cao của đối tượng :
public boolean collide(Sprite sprite)
{
if ((Float.getInteger(x) + width) > Float.getInteger(sprite.getX()) &&
Float.getInteger(x) Float.getInteger(sprite.getY()) &&
Float.getInteger(y) < Float.getInteger(sprite.getY()) + sprite.getHeight())
return true;
return false;
6.2.4 Quản lý các đối tượng đồ họa
Công việc của phần quản lý đồ họa là quản lý một mục các phần đồ họa khác nhau và cung cấp những khả năng để có thể thực hiện một cách khéo léo các phần đồ họa khác.
Các công việc cần làm:
addSprite ( Sprite sprite) : Thêm một phần đồ họa mới.
insertSprite ( Sprite sprite, int post) : Chèn một phần đồ họa mới vào vị trí post.
getSpritePosition ( Sprite sprite) : Trả về dữ liệu số của phần đồ họa ( Sprite) ngay tại nơi đồ họa được dẫn vào. Giá trị khởi đầu của đồ họa tại vị trí đó là 0. Trả về -1 nếu phần đồ họa không tìm thấy.
getSprite (int index) : Trả lại phần đồ họa để kết hợp với phần index được nêu ra.
deleteSprite ( Sprite sprite): Xóa một phần đồ họa từ bộ quản lý.
deleteSprite ( int post) : Xóa một phần đồ họa tại vị trí xác định.
Paint ( Graphics g): Vẽ tất cả các phần đồ họa lên Graphics.
Size() : Trả về số các phần tử đồ họa.
6.2.5 Lập trình Game đa luồng
Khi các Game chạy trên điện thoại, nhiều đoạn mã phải được thực thi một cách mô phỏng. Nó bao gồm các hoạt động như kiểm tra bàn phím, di chuyển các đối tượng, kiểm tra va chạm giữa các đối tương, tái vẽ...Nếu đặt hết các nhiệm vụ vào stack và thực hiện lần lượt thì chỉ cần nhấn một phím mới là có thể dừng Game. Một cách tốt hơn là đặt nhiệm vụ vào các danh sách khác nhau và thực thi cùng lúc. Ví dụ một nhiệm vụ thực thi bàn phím trong khi một nhiệm vụ khác thực thi việc vẽ các đối tượng…Khả năng làm việc đa nhiệm này có thể thực hiện đơn giản bằng việc sử dụng những khả năng đa luồng ( multithreading ) của java.
Có hai cách để tạo luồng là kế thừa đối tượng Thread hoặc thực thi giao diện runable.
Những phương thức quan trọng cho lớp Thread:
currentThread(): Trả lại luồng đang thực thi.
yield(): Ngừng luồng thực thi hiện hành và cho phép luồng khác thực thi.
sleep ( milis ): Ngừng luồng đang thực thi trong thời gian mili giây xác định.
start(): Làm cho luồng bắt đầu được thực thi.
run(): đây là phương thức quan trọng nhất, tất cả mọi hành động đều được thực thi tại đây.
activeCount(): Trả về số lượng hiện hành các luồng trong máy ảo Java.
Sử dụng Thread để tạo hoạt hình
Thread được lớp java.lang.Thread cung cấp. Trong các kỹ thuật tạo hoạt hình ta có thể sử dụng Thread để định thời gian.
public class GameCanvas{
private final int DELAY=100;
private GameThread thread;
private boolean running;
pulic GameCanvas()
{
}
public void start(){
running=true;
Thread=new GameThread();
Thread.start();
public void stop()
{
running=flase;
}
public class GameThread extends Thread
{
public void run()
{
while(running)
{
// Cập nhật màn hình;
// Kiểm tra
// Vẽ lại
Try
{
thread.sleep(DELAY);
}catch (Exception e){
}
}
}
Biến running cho biết Tread đang thực thi hay không. Thead dừng khi biến running bằng false khi gọi phương thức stop(). DELAY cho biết thời gian lặp lại hành động của Thread.
Sử dụng giao diện Runable để tạo hoạt hình
Cách khác để tạo hoạt hình là thực hiện giao diện Runable của lớp java.lang.Runable:
public class GameCanvas implements java.lang.RunnableƠ
private final int DELAY=100;
private Thread thread;
private boolean running;
public GameCanvas()
{
}
public void start()
{
running=true;
thread=new Thread(this);
thread.start();
}
public void stop()
{
running=false;
}
public void run(){
while(running){
// Cập nhật màn hình;
// Kiểm tra
// Vẽ lại
Try
{
thead.sleep(DELAY);
}catch (Exception e){
}
}
}
Do được kế thừa từ lớp Thread nên cũng có cờ running chi biết giao diện có được thực thi hay không. Nó sẽ ngừng khi running được gán bằng false khi gọi phương thức stop().
Chương 7
XÂY DỰNG GAME ĐUA XE
7.1 Môi trường thực hiện ứng dụng
Hệ điều hành Windows XP.
JDK 1.5
Netbeans IDE 5.0
Samsung JaUmi Wireless Tookit 2.0
J2ME Wireless Toolkit 2.2
7.1.1 Giới thiệu về NetBeans
Download NetBeans IDE: Bạn có thể tải về từ Internet, hãy vào địa chỉ sau: . Hiện tại phiển mới nhất của NetBeans là 5.5 nhưng trong nội dung đề tài tôi sử dụng phiên bản 5.0. trước tiên cần download NetBeans IDE 5.0, sau đó tải NetBeans IDE Add-ons Mobility Pack 5.0.
Sau khi cài đặt chạy file NetBeans.exe, giao diện chính của NetBeans như hình bên dưới:
Hình 7.1 Khởi động Netbeans
Để tạo một dự án J2ME mới chọn menu File chọn New Project cửa sổ như hình bên dưới sẽ xuất hiện:
Hình 7.2 Tạo project J2ME
Nhập tên dự án và chọn finish. Như vậy một dự án J2ME mới đã được tạo, cửa sổ như hình bên dưới sẽ xuất hiện
Hình 7.3 Thêm các file cho project
Từ đây chọn new file, chọn loại file mà bạn cần tạo và bắt đầu thực hiện dự án.
Để chạy, Debug hay Complie các file click mắt phải chuột vào dự án và chọn lệnh cần thực hiện:
Hình 7.4 Chạy chương trình
7.1.2 Các phương pháp tải ứng dụng vào điện thoại di động
Sau khi đóng gói project bạn có thể tải vào điện thoại theo các cách sau:
- Truyền qua cổng hồng ngoại, với các modem điện thoại cũ.
- Truyền qua cổng bluetooth: tốc độ nhanh hơn và khoảng cách truyền xa hơn hồng ngoại
- Sửng dụng cable dữ liệu kết nối trực tiếp với máy tính.
- Tải từ Internet với những loại điện thoại hỗ trợ GPRS.
7.2 Thiết kế ứng dụng
7.2.1 Những khó khăn trong việc lập trình trên điện thoại di động
Bộ xử lý ít ỏi: Khi lập trình Game, Game phải di chuyển các nhân vật tính toán các vị trí mới, kiểm tra va chạm và tô màu mọi thứ. Tất cả những chức năng này được hỗ trợ bởi đa luồng, khi nhiều hành động được thực thi cùng một lúc. Tuy nhiên trong thực tế chỉ có một luồng thực thi tại một thời điểm, thời gian thực thi của bộ vi xử lý sẽ bị chia nhỏ. Do mắt người quan sát chậm nên có vẻ mọi hành động xảy ra cùng một lúc. Khi tất cả đã hoàn tất, thời gian thực thi của các luồng phải ở dưới mức cực đại. Mức cực đại này được xác định bởi tốc độ khung hình của Game. Đa số bộ xử lý của các thiết bị nhỏ đều không đáp ứng được tốc độ khung hình cần thiết 16 hình/s), điều này phát sinh rất nhiều khó khăn cho các lập trình viên trong quá trình xây dựng ứng dụng.
Bộ nhớ bị giới hạn: Ngay cả khi bộ xử lý đủ mạnh, bộ nhớ sẽ quyết định một ứng dụng nào đó có thể chạy trên thiết bị đó hay không.
Kiểu bộ nhớ trong J2ME được chia làm ba vùng:
Vùng nhớ làm việc: Nơi thiết bị lưu trữ những dữ liệu cần thiết trong thời gian hoạt động của ứng dụng. Ví dụ như các file ảnh, âm thanh trong Game…
Vùng nhớ lưu trữ: Nơi thiết bị lưu trữ dữ liệu RMS.
Vùng nhớ ứng dụng: Nơi chứa Game và các ứng dụng được cài đặt.
Độ phân giải của màn hình: Những thiết bị khác nhau thì cũng có độ phân giải màn hình khác nhau. Một ứng dung có thể chạy trên thiết bị này nhưng chưa chắc đã chạy tốt trên thiết bị khác. Mặc dù ngày càng có nhiều loại màn hình được tung ra nhưng đa số các màn hình đều có độ phân giải, cũng như khả năng hỗ trợ màu kém.
7.2.2 Bài toán: Mô phỏng Game đua xe
Người chơi sử dụng các phím 4(sang trái), phím 6 (sang phải), phím 2 (lên trên) , phím 8( xuống dưới) để điều khiển chiếc xe. Bạn điều khiển chiếc xe sao cho xe của bạn không đụng vào xe đi ngược chiều. Nếu đụng xe, xe của bạn sẽ bị mất năng lượng, khi năng lượng xe bạn bằng 0 trò chơi kết thúc và bạn là người thua cuộc. Trong quá trình đua bạn có thể sử dụng phím 5 để bắn đạn.
Trò chơi có 3 cấp độ:
Cấp độ 1: Đây là cấp độ dễ nhất, giành cho những người mới chơi.
Cấp độ 2: Độ khó sẽ được tăng lên so với cấp độ 1.
Cấp độ 3: Cấp độ khó nhất của trò chơi, đường đua dài nhất, lượng xe cản đường nhiều nhất, tốc độ di chuyển nhanh nhất. Nếu hoàn thành cấp độ này bạn sẽ được nhi danh vào “Bảng xếp hạng”.
7.2.3 Xây dựng các thành phần chính của Game
Dựa vào những kiến thức cơ bản về J2ME và lập trình Game cho mobile để xây dựng giao diện và các đối tượng chính của một Game đua xe đơn giản.
Các thành phần chính của Game đua xe:
Giao diện người dùng.
Đồ họa cấp thấp: Các đối tượng nhân vật, cách hiển thị nhân vật, xử lý các hành động chính của Game, xử lý va chạm…
Vùng lưu trữ dữ liệu : Lưu lại danh sách những người chơi có thành thích tốt.
7.2.4 Các lớp và các phương thức chính trong Game
Lớp StartForm.java : Hiển thị menu chính của Game cho phép người dùng lựa chọn các mục chính trong Game.
Lớp Track.java : Hiển thị 3 cấp độ chơi của Game.
Lớp Cache.java: Lớp này có nhiệm vụ chính là lưu dữ toàn bộ tài nguyên của hệ thống. Bao gồm hình ảnh các nhân vật.
try
{
carImage = Image.createImage("/car.png");
enemyImage = Image.createImage("/enemy.png");
flameImage = Image.createImage("/flame.png");
powerupImage = Image.createImage("/power.png");
} catch (Exception ex) {}
Lớp Sprite.java : Đây là đối tượng nhân vật tổng quát nhất trong Game. Lớp này có 2 phương thức quan trọng : Vẽ nhân vật ra Graphics và phát hiện va chạm với các đối tượng khác.
Hàm xử lý va chạm:
public boolean collide(Sprite sprite)
{
if ((Float.getInteger(x) + width) >
Float.getInteger(sprite.getX()) &&
Float.getInteger(x) < Float.getInteger(sprite.getX()) +
sprite.getWidth() && (Float.getInteger(y) + height) >
Float.getInteger(sprite.getY()) &&
Float.getInteger(y) <
Float.getInteger(sprite.getY()+sprite.getHeight())
return true;
return false;
}
Hàm vẽ Sprite:
public void paint(Graphics g)
{
g.setClip((int)Float.getInteger(x), (int)Float.getInteger(y),
width, height);
g.drawImage(image, (int)Float.getInteger(x) - frame * width, (int)Float.getInteger(y), Graphics.TOP | Graphics.LEFT); g.setClip(0, 0, Cache.width, Cache.height);
}
Lớp Player.java : Lớp nhân vật thể hiện chiếc xe, kế thừa từ lớp Sprite.
Lớp GameCanvas.java : Đây là lớp quan trọng nhất, taaij đây tất cả những hành động, sự kiện chính của Game sẽ được vẽ. Lớp này kế thừa lớp Canvas:
Phương thức khởi tạo đối tượng:
try{
Sprite sprite = new Sprite(Cache.enemyImage,
Cache.enemyImage.getWidth(), Cache.enemyImage.getHeight(), 1);
int x = rnd.nextInt() % (ROAD_WIDTH -
Cache.enemyImage.getWidth());
x = (x < 0 ? -x : x);
sprite.setX(Float.createFloat(Cache.width - ROAD_WIDTH) / 2 + x);
sprite.setY(Float.createFloat(- i * Cache.height / 4));
x = rnd.nextInt() % 1000;
long veer = Float.createFloat(0,x);
long newspeed = Float.add(veer,enemyspeed);
sprite.setVy(newspeed);
x = rnd.nextInt() % 2;
long sidemove = Float.createFloat(x);
sprite.setVx(sidemove);
enemyList.addSprite(sprite);
} catch (Exception ex) {}
Phương thức di chuyển đối tượng:
switch (key)
{
case Canvas.LEFT:
if (Float.getInteger(player.getX()) >
(Cache.width - ROAD_WIDTH) / 2)
player.setX(Float.sub(player.getX(),
Float.createFloat(2)));
break;
case Canvas.RIGHT:
if (Float.getInteger(player.getX()) + player.getWidth() <
(Cache.width + ROAD_WIDTH) / 2)
player.setX(Float.add(player.getX(),
Float.createFloat(2)));
break;
case Canvas.UP:
if (Float.getInteger(player.getY())>0){
player.setY(Float.sub(player.getY(),
Float.createFloat(2)));
theweapon.setY(Float.sub( theweapon.getY(),
Float.createFloat(2)));
Lớp RMS : Nơi lưu trữ những người chơi có điếm số cao nhất. Lớp sẽ tạo ra một vùng RecordStore
7.2.5 Một số hình ảnh khi chơi Game
KẾT LUẬN
Qua bốn tháng thực tập em đã tìm hiểu được những kiến thức cơ bản của Java, công nghệ J2ME, và cách xây dựng một ứng dụng trên điện thoại di động . Qua đó dần áp dụng công nghệ mới vào trong cuộc sống. Dưới đây là một số kiến thức đã đạt được:
Hiểu chi tiết về J2ME và ứng dụng của nó để lập trình trên thiết bị di động.
Nắm được các kỹ thuật xử lý âm thanh, hình ảnh, lưu trữ trên điện thoại di động.
Ứng dụng các kết quả nghiên cứu được xây dựng Game đơn giản khai thác các điểm mạnh về âm thanh, hình ảnh, đồ họa…
Áp dụng thành công trên một số hang điện thoại hỗ trợ java như SonyEricson…
Game đua xe đã áp dụng những kiến thức lý thuyết mà em đã trình bày. Chương trình ứng dụng những kỹ thuật về xây dựng giao diện, kỹ thuật đồ họa, xử lý va chạm giữa các đối tượng, cơ chế lưu trữ dữ liệu… Tuy nhiên do mới làm quen với công nghệ mới và kiến thức có hạn nên chương trình chỉ dừng ở mức độ mô phỏng, không có tính thực tiễn…
Nếu có điều kiện em tin rằng mình có thể làm cho ứng dụng trở lên hoàn thiện, có đầy đủ tính năng của một Game đua xe: có âm thanh và hình ảnh tốt hơn, có thể chạy trên mọi loại điện thoại, có thể chơi qua mạng hồng ngoại hoặc bluetooth…..
Cuối cùng em xin chân thành cảm ơn cô giáo Ngô Thị Lan đã giúp đỡ
em hoàn thành đề tài này.
Sinh viên
Trấn Đức Nam
TÀI LIỆU THAM KHẢO
[1] Nguyễn Phương Lan- JAVA tập 3- NXB Lao Động Xã Hội.
[2] Đỗ Quang Thái -Tự học Ngôn Ngữ Java- NXB Thống Kê.
[3] Trần Tiến Dũng -Giáo trình lý thuyết và bài tập Java- NXB Giáo Dục.
[4] IT-GROUP -Lập trình Game cho DTDD- NXB Giao Thông Vận Tải
[5] MARTIN J. WELLS-J2ME.Game.Programming
[6] www.javavietnam.org
NHẬN XÉT CỦA GIÁO VIÊN
……………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………
Các file đính kèm theo tài liệu này:
- 32055.doc