Old school Swatch Watches
logo

Chatbox|Admin nhận làm wap/web, giá cả thương lượng... Thông tin admin tại mỗi bài viết.
Home · Bang hội ·
* Đăng Nhập hoặc Đăng Kí
để sử dụng hết chức năng của diễn đàn.
Hi, Khách!
HomeBang hội » Thủ thuật » Nokia s40 » Lập trình game j2me by holyeyed
Xuống dưới » Lập trình game j2me by holyeyed
avatar by Pham_loi Pham_loi
Chức vụ:
05:24:03, 29-07-2015

[Lập trình java trên pc công cụ cần thiết và những điều cơ bản
Để bắt đầu xây dựng một java game cho di động bạn cần hai công cụ sau:
- sun java wireless toolkit 2.5.2_01 for cldc
- java se development kit 6u23(sdk)

Cài đặt sdk trước, rồi sau đó mới cài jwt.
Khởi chạy jwt, chọn new project và đặt tên cho ứng dụng (project name) và tên của class chính( midlet class name) của bạn:
Sau đó thì vào ổc:\documents and settings\…\j2mewtk.5.2\appstìm tên folder trùng với tên mà bạn đặt lúc nãy, đây là folder chứa các code và nguồn của ứng dụng. Khuyên bạn nên tạo một shortcut đến đây để sau này tiện tìm đến.
Trong folder đó có 3 thư mục bạn cần quan tâm:
-src: chứa các tập tin mã lệnh
-res: chứa các nguồn như hình ảnh hoặc âm thanh, muốn sử dụng bạn phải cho vào đây
-bin: chứa ứng dụng sau khi đóng gói thành tập tin jar và file manifest.

Sau khi đã biết cách sử dụng chương trình jwt, sau đây tôi sẽ chỉ bạn các hiểu biết cơ bản về các class trong lập trình java, chỉ là một cách hiểu thôi vì khó mà có thể sử dụng ngôn ngữ chuyên nghiệp để nói cho các bạn hiểu được:
- hai công cụ nói trên, jwt giúp các bạn chuyển những mã code thành ngôn ngữ mà di động có thể hiểu được, nhưng cơ bản nó lấy nguồn từ sdk. Sdk cung cấp những class có sẵn mà từ đó chúng ta sử dụng để tạo ra những class mới đa dụng hơn. Điều này cũng tương tự như sử dụng các chức năng cộng trừ nhân chia trên máy tính để thực hiện các bài tóan phức tạp hơn như giải phương trình hay gì gì đó…
- có hai class mà các bạn cần biết rõ đó là midlet và gamecanvas(vì ở đây ta lập trình game). Midlet là nền tảng của mọi tập tin java, ta ví nó như một bức tường và treo lên đó những thứ để ngắm ngía và vẽ vời. Gamecanvas thì như một tờ giấy hoặc một xấp giấy mà ta thực hiện công việc vẽ vời trên đó rồi sau đó thì treo lên tường để ngắm nhìn.
Một class mới được tạo thành như sau (các bạn sau khi copy thì nên bỏ tag <?php và ?> đi nhé):
<?php
import 
[các class có sẵn để sử dụng trong class mới
public class [
tên class mới
extends [
kiểu class
implements [
kiểu thực thi
{
//gán biến ở đây
public [tên class mới(){//lệnh ở đây}
//các chức năng hoặc lệnh ở đây
}
?>

Copy code

Một midlet thì có cấu trúc cơ bản thế này:
<?php
public class [tên class extends MIDlet
{
public [
ten class(){}
public 
void startApp(){}
public 
void pauseApp(){}
public 
void destroyApp(boolean unconditional){notifyDestroyed();//luôn như vậy}
}
?>

Copy code

Một gamecanvas có cấu trúc như sau:
<?php
public class [tên class extends GameCanvas implement Runnalbe
{
public [
tên class(){super(false);//luôn như vậy}
void start()Thread t=new Thread(this);
t.start();//tạo và khởi chạy một tiến trình, sẽ bắt đầu từ function run}
public void run(){}
}
?>

Copy code

thế đấy, bài sau sẽ hướng dẫn cách vẽ lên một canvas và cách để gọi một class gamecanvas từ một midlet hay nói nôm na là treo bức tranh lên tường.


Chỉnh sửa lúc 2016-07-11 02:09 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
05:24:42, 29-07-2015

Vẽ ảnh và liên kết class
Bây giờ ta sẽ bắt đầu vẽ trên class gamecanvas và liên kết nó với class midlet. Ta sẽ tạo một project mới tên vd và midlet class name cũng tên vd luôn
Tạo file vd.java(tên midlet là gì thì tên này như vậy) với nội dung sau:
<?php
import javax
.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
vd extends MIDlet
{
public 
vd(){}
public 
void startApp(){}
public 
void pauseApp(){}
public 
void destroyApp(boolean unconditional){notifyDestroyed();}
}

Copy code

Và bây giờ là bức hình gamecanvas, tạo một file a.java có nội dung như sau:
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
extends GameCanvas implements Runnable
{
private 
Graphics g=getGraphics();
int w,h;
public 
a(){super(false);}
void start(){
w=getWidth();//chieu rong man hinh
h=getHeight();//chieu cao man hinh
Thread t=new Thread(this);
t.start();}
public 
void run()
{
boolean play=true;
while(
play){
g.setColor(0x000000);
g.fillRect(0,0,w,h);
g.setColor(0xffffff);
g.drawRect(w/2,h/2,w/4,h/4);
flushGraphics();//hien thi len man  hinh
try{Thread.sleep(30);}catch(Exception e){}//cho ngung mot thoi gian
}
}
}
?>

Copy code

Sau đó ta sẽ cho liên kết 2 class này lại như sau:
Trong file vd.java ta thêm:
<?php
import javax
.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
vd extends MIDlet
{
private 
a hcn;
public 
vd(){}
public 
void startApp(){
hcn=new a(this);
hcn.start();
Display.getDisplay(this).setCurrent(hcn);
}
public 
void pauseApp(){}
public 
void destroyApp(boolean unconditional){notifyDestroyed();}
}
?>

Copy code

Và trong a.java ta thêm:
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
extends GameCanvas implements Runnable
{
private 
vd main;
private 
Graphics g=getGraphics();
int w,h;
public 
a(vd main){
super(false);
this.main=main;}
void start(){
w=getWidth();//chieu rong man hinh
h=getHeight();//chieu cao man hinh
Thread t=new Thread(this);
t.start();}
public 
void run()
{
boolean play=true;
while(
play){
g.setColor(0x000000);
g.fillRect(0,0,w,h);
g.setColor(0xffffff);
g.drawRect(w/2,h/2,w/4,h/4);
flushGraphics();
try{
Thread.sleep(30);}catch(Exception e){}//cho ngung mot thoi gian
}
}
}
?>

Copy code

Sau đó ta nhấn nút built trên trình JWT và nếu không báo lỗi ta nhấn run sẽ thấy kết quả:
HIỂU THÊM MỘT CHÚT VỀ LIÊN KẾT CLASS
mỗi class viết ra của ta cũng như là một công thức được lưu lại và có thể sử dụng cho nhiều class khác mà không cần phải viết lại, mặc dù bạn cũng có thể viết luôn trong củng một class tất cả những gì bạn muốn, nhưng như thế thật là rối và lúc nào cũng phải viết đi viết lại những thứ thường hay sử dụng. vì vậy liên kết class giúp cho việc sử dụng nhửng gì cần sử dụng mọi lúc mọi nơi mà không phải viết lại nữa.
cũng giống như những biến khác, mỗi class đã viết hoàn thành của chúng ta là một kiểu biến
chẳng hạn ta đã viết class draw.java như sau:
<?php
public class draw
{
boolean ds(){ return false;} //tra ve gia tri dung sai
void fillrect(Graphics g){};//lenh ve hinh chu nhat
void drawstring(String t,Graphics g){};//lenh ve chuoi
}
?>

Copy code

và bây giờ trong một class khác như display.java chẳng hạn, ta muốn vẽ hàng loạt hình chữ nhật hoặc đơn giản là một chuỗi gì đó mà không muốn rối mắt ta thực hiện liên kết với draw.java để vẽ ngay vào trong display.java mà không cần phải viết lại mất thời gian, ta có thể làm như sau:
trong display.java ta gọi biến a với kiểu là draw, tức là tạo một biến mới với kiểu là class draw mà chúng ta đã tạo ra:
<?php
public class display{
draw a;
Graphics g=getGraphics();
String str="holyeyed";
}

Copy code

bây giờ muốn dùng function vẽ hình chữ nhật trong draw ta chỉ việc sử dụng biến a như sau:
<?php
public class display{
draw a;
Graphics g=getGraphics();
String str="holyeyed";
a.fillrect(g) ;
}
?>

Copy code

công thức là tên biến, rồi đến dấu chấm, rồi đến tên function. cứ mỗi lần vào trong một dấu ngoặc thì sử dụng một dấu chấm rồi lấy tên phần tử mà ta muốn lấy.
như tronga.fillrect(g);gồm có:
a: đại diện cho class draw vì ta tạo ra a từ draw
fillrect : là tên function có trong draw và a tạo ra từ draw nên nó cũng thừa kế
g: là đối tượng, theo như trong function fillrect có đối tượng Graphics . với function drawstring nó nhận 2 đối tượng 1 kiểu string. 1 kiểu Graphics

vd: để sử dụng function drawstring ta viết:
a.drawstring(str,g);
một số cách để liên kết class:
ta có thể tạo biến như trên:
[tên class [biến sử dụng;
[tên class [biến sử dụng=new [ten class();
hoặc gọi trực tiếp luôn mà không cần gán biến
[tên class.[tên đối tượng sử dụng;

VỀ VIỆC VẼ HÌNH ẢNH LÊN CANVAS
- Trong class canvas ta có thể vẽ hình, vẽ nhiều lệnh vẽ lên một graphics, sau mỗi lần vẽ xong ta gọi lệnh flushGraphics() để quét tất cả những hình ta đã vẽ ra màn hình. Và nếu muốn xóa tất cả để vẽ mới ta phải gọi lệnh fillrect(0,0,w.h) để làm cho toàn màn hình thành một màu trơn. Mặc định hệ tọa độ bắt đầu từ vị trí 0,0 ở góc trên bên trái màn hình, x sẽ tăng dần từ trái sang phải, và y sẽ tăng dần từ trên xuống dưới :D


Chỉnh sửa lúc 2016-07-11 05:45 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
05:25:23, 29-07-2015

Sự điều khiển: keyPressed() và getKeyStates()
Bây giờ thì ta sẽ học cách để đưa lệnh vào cho một trò chơi thông qua các nút bấm. lấy ví dụ của bài học trước, ta sẽ cho di chuyển hình chữ nhật khi các nút được nhấn:
File vd.java vẫn như cũ, file a.java thêm và chỉnh sửa như sau:
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
extends GameCanvas implements Runnable
{
private 
vd main;
private 
Graphics g=getGraphics();
int w,h;
public 
a(vd main){
super(false);
this.main=main;}
void start(){
w=getWidth();//chieu rong man hinh
h=getHeight();//chieu cao man hinh
Thread t=new Thread(this);
t.start();}
public 
void run()
{
boolean play=true;
while(
play){
g.setColor(0x000000);
g.fillRect(0,0,w,h);
g.setColor(0xffffff);
g.drawRect(w/2,h/2,w/4,h/4);
flushGraphics();
try{
Thread.sleep(30);}catch(Exception e){}//cho ngung mot thoi gian
}
}
protected 
void keyPressed(int key){
if(
key==KEY_NUM2){h-=3;}
if(
key==KEY_NUM4){w-=3;}
if(
key==KEY_NUM6){w+=3;}
if(
key==KEY_NUM8){h+=3;}
}
void input(){
int k=getKeyStates();
if(
k==UP_PRESSED){h--;}
if(
k==LEFT_PRESSED){w--;}
if(
k==RIGHT_PRESSED){w++;}
if(
k==DOWN_PRESSED){h++;}
}
}
?>

Copy code

Ta thấy trong khi sử dụng protected void keyPressed(int key){} mỗi lần nhấn nút chỉ có tác dụng một lần, còn đối với getKeyStates() thì lại có tác dụng khi nhấn giữ. Đó là do getKeyStates() đựơc sử dụng trong một function tự tạo và được gọi vào vòng lặp liên tục mỗi khi vòng lặp lại.
keyPressed(int key) nhận các giá trị theo nút bấm: KEY_NUM0 ->KEY_NUM9 và 48-> 57 (từ 0->9), KEY_STAR (phím *), KEY_POUND (phím #), -6(phím chọn trái), -7(phím chọn phải), -1(phím chuyển lên),-2(phím chuyển xuống), -3(phím chuyển trái), -4(phím chuyển phải), -5(FIRE, phím OK)
và getKeyStates() nhận các giá trị: UP_PRESSED (lên), DOWN_PRESSED (xuống), LEFT_ PRESSED (trái), RIGHT_ PRESSED (phải), FIRE_ PRESSED (phím OK)


Chỉnh sửa lúc 2016-07-11 05:52 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
05:30:23, 29-07-2015

off-Screen và Plash
Sau hai bài mở đầu chắc các bạn cũng đã hiểu khá về việc vẽ hình ảnh từ những class có sẵn của java rồi. Hôm nay tôi sẽ trỉnh bày cách vẽ hình ảnh lên canvas và vẽ chuyển cảnh, giống như kéo màn trên các sân khấu hay chuyển tiếp giữa các khung hình.
sau đây tôi sẽ vẽ hình sau(nhớ hình ảnh thì cho vào thư mục res nhé) và cho kéo màn qua lại hai bên:
Vẫn lấy ví dụ cũ là file vd.java nhưng bây giờ thay file a.java bằng file plash.java như sau:
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
plash extends GameCanvas implements Runnable
{
private 
vd main;
private 
Graphics g=getGraphics();
private 
Image im;
int w=getWidth();
int h=getHeight();
public 
plash(vd main){
super(false);
this.main=main;}
void start(){
Thread t=new Thread(this);
t.start();}
public 
void run()
{
try{
im=Image.createImage("/im.png");}catch(Exception e){}
boolean play=true;
while(
play){
plashopen();//mo ra
plashclose();//dong lai
flushGraphics();
try{
Thread.sleep(30);}catch(Exception e){}//cho ngung mot thoi gian
}
}
void plashclose(){
for(
int i=0;i<10;i++){
g.setColor(0x00);
g.drawImage(im,0,0,g.TOP|g.LEFT);
g.fillRect(w-i*(w/20),0,w,h);
g.fillRect(0,0,i*(w/20),h);
flushGraphics();
try{
Thread.sleep(50);}catch(Exception e){}
}
}
void plashopen(){
for(
int j=0;j<10;j++){
g.setColor(0x00);
g.drawImage(im,0,0,g.TOP|g.LEFT);
g.fillRect(0,0,w/2-j*(w/20),h);
g.fillRect(w/2+j*(w/20),0,w,h);
flushGraphics();
try{
Thread.sleep(50);}catch(Exception e){}
}
}
}
?>

Copy code

* trong file vd.java chỉnh sửa để gọi file plash.java tương tự như gọi a.java, chỉ cần thay a thành plash
kết quả thế này:


Chỉnh sửa lúc 2016-07-11 05:37 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
08:44:26, 29-07-2015

Vẽ một phần của hình ảnh- menu game
Vẽ nguyên cả hình ảnh vào trong màn hình thì thật không tiện lợi chút nào, nhất là khi muốn vẽ nhiều hình ảnh mà mỗi hình ảnh lại phải tạo một biến image mới thì thật là mệt. thay vào đó ta chỉ việc dồn tất cả vào một bức ảnh và khi muốn thì chỉ hiển thị phần cần thiết mà thôi.
Để làm được điều đó ta sử dụng công thức setClip(start-x,start-y,w,h) đối với graphics, xem ví dụ sau sẽ rõ:
Ta tạo một file menu.java với nội dung như sau:
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
menu extends GameCanvas implements Runnable
{
private 
vd main;
private 
Graphics g=getGraphics();
private 
Image mn;
int w=getWidth();
int h=getHeight();
private 
int index=0;
private 
boolean play=true;
public 
menu(vd main){
super(false);
this.main=main;}
void start(){
Thread t=new Thread(this);
t.start();}
public 
void run()
{
try{
mn=Image.createImage("/menu.png");}catch(Exception e){}
while(
play){
g.setColor(0x000000);
g.fillRect(0,0,w,h);
g.setClip((w-128)/2,(h-64)/2,128,64);//chỉ vẽ trong khung chu nhat tu diem() voi rong va cao
g.drawImage(mn,(w-128)/2,(h-64)/2-32,g.TOP|g.LEFT);
g.setClip((w-128)/2,(h-64)/2+index*32,128,32);
g.drawImage(mn,(w-128)/2,(h-64)/2+index*32,g.TOP|g.LEFT);
flushGraphics();
try{
Thread.sleep(30);}catch(Exception e){}//cho ngung mot thoi gian
}
}
protected 
void keyPressed(int key){
if(
key==KEY_NUM2){index--;}//len tren
if(key==KEY_NUM8){index++;}//xuong duoi
if(index>1){index=0;}//cho xoay vong
if(index<0){index=1;}//cho xoay vong
if(key==KEY_NUM5){if(index==1){
play=false;
main.destroyApp(true);}}//neu nhan 5 tai exit thi thoat
}
}
?>

Copy code

. trong ví dụ này tôi sử dụng hình ảnh này để thực hiện vịêc vẽ menu
. bức hình sau sẽ giải thích rõ tác dụng của việc setClip như thế nào:
- trên bức ảnh ta có thể thấy khung chữ nhật xanh lá là khung setClip của chứng ta(được xác định từ điểm (1) và có độ rộng w, độ cao h). tất cả những hình ảnh vẽ vào sau đó chỉ có phần nào nẳm trong khung đó thì mới hiện thị ra màn hình. như trong hình, ảnh chứa play và exit được vẽ từ điểm (2), sẽ chỉ hiển thị phần có chứa chữ exit.
• nên nhớ rằng sau mỗi khi setClip và vẽ xong phần cần vẽ phải trả lại toàn màn hình cho graphics như vậy các phần vẽ sau sẽ không bị giới hạn bởi tác dụng của setClip nữa. chúng ta đơn giản là setClip(getWidth(),getHeight()); là được.
• chúng ta thực hiện việc gọi class menu này trong class vd cũng tương tự như các class khác.


Chỉnh sửa lúc 2016-07-11 05:40 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
08:46:32, 29-07-2015

vẽ nền, bản đồ, khung cảnh
Trong game nhân vật của chúng ta không phải chỉ di chuyển trong một không gian nhỏ hẹp, mà đó thật sự là một thế giới rộng lớn. tuy nhiên tất cả chỉ là sự sắp xếp có tính tóan từ trước chỉ bằng vài hình ảnh cơ bản. có thể nói cũng như việc dùng gạch xây nhà, từ những viên gạch giống nhau nhưng cách sắp xếp khác nhau sẽ cho ra nhưng ngôi nhà khác nhau.
Vậy chúng ta hay xem cách xây dựng một thế giới rộng lớn từ những hình ảnh đơn giản như thế nào nhé.
Chúng ta cần chuẩn bị:
- một ảnh bao gồm nhiều ô nhỏ mỗi ô là một viên gạch
- một array chỉ định cách sắp xếp các viên gạch tạo thành map.
* hiểu một chút về TiledLayer:
Công thức
<?php
TiledLayer tl
=new TiledLayer(số cộtsố dòngảnh nguồndài mỗi ô trong ảnh nguồnrộng mỗi ô trong ảnh nguồn);
tl.setCell(col,row,index tile);
tl.setPosition(int xint y);// vẽ từ điểm nào trên màn hình
tl.paint(Graphics); // vẽ tl vào graphics
?>

Copy code

Tôi thì không có năng khiếu cho lắm khi vẽ hình trên máy tính nhưng tạm thời ta sẽ sử dụng tấm hình dưới đây làm gạch
Và map được tạo ra bằng phần mềm tiled map editor, như sau:
<?php
Int
map=={
4,4,4,1,1,4,4,4,4,4,
4,4,1,1,4,4,4,4,4,4,
4,4,1,1,4,4,1,1,4,4,
4,4,1,1,3,1,1,4,4,4,
4,4,1,1,1,1,1,1,4,4,
4,4,4,4,1,1,1,2,4,4,
1,4,4,4,1,1,4,4,4,4,
1,4,4,4,1,1,4,4,4,1,
1,4,4,4,4,4,4,4,4,1,
1,1,4,4,4,4,4,4,1,1
};
?>

Copy code

Xem code hoàn chỉnh dưới đây để thấy nó hoạt động như thế nào:
map.java
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
map extends GameCanvas implements Runnable
{
private 
vd main;
private 
Graphics g=getGraphics();
int w=getWidth();
int h=getHeight();
private 
Image t;
private 
TiledLayer tl;
private 
int x=0,y=0;
private 
boolean play=true;
private 
intmap={
4,4,4,1,1,4,4,4,4,4,
4,4,1,1,4,4,4,4,4,4,
4,4,1,1,4,4,1,1,4,4,
4,4,1,1,3,1,1,4,4,4,
4,4,1,1,1,1,1,1,4,4,
4,4,4,4,1,1,1,2,4,4,
1,4,4,4,1,1,4,4,4,4,
1,4,4,4,1,1,4,4,4,1,
1,4,4,4,4,4,4,4,4,1,
1,1,4,4,4,4,4,4,1,1
}; // dài và rộng là 10 <=> 100 phần tử, 4 và 1 là khung thứ 1 và khung thứ 4 trong ảnh nguồn mà TiledLayer tạo ra ở dưới.
public map(vd main){
super(false);
this.main=main;}
void start(){
Thread t=new Thread(this);
t.start();}
public 
void run()
{
try{
t=Image.createImage("/t.png");}catch(Exception e){}
tl=new TiledLayer(10,10,t,32,32);//tạo tiled layer với 10 cộ, 10 dòng, mỗi ô 10x10
for(int i=0;i<map.length;i++){
int col=i%10;//lay du cua i/10
int row=(i-col)/10;//lay nguyen cua (i-col)/10
tl.setCell(col,row,map[i);}
while(
play){ input();
g.setColor(0x000000);
g.fillRect(0,0,w,h);
tl.setPosition(x,y);
tl.paint(g);
flushGraphics();
try{
Thread.sleep(30);}catch(Exception e){}//cho ngung mot thoi gian
}
}
void input(){
int k=getKeyStates();
if(
k==UP_PRESSED){y++;}
if(
k==LEFT_PRESSED){x++;}
if(
k==RIGHT_PRESSED){x--;}
if(
k==DOWN_PRESSED){y--;}
}
}
?>

Copy code


Chỉnh sửa lúc 2016-07-11 05:55 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
08:47:18, 29-07-2015

nhân vật và Sprite
Bài này sẽ chỉ cho bạn cách tạo ra những nhân vật trong game như thế nào, khác với map là những ô vuông được sắp xếp theo một trật tự cố định, nhân vật thì có nhiều sự chuyển động hơn và class Sprite cho phép chúng ta làm được điều đó:
Công thức
<?php
Sprite s
=new Sprite(ảnh nguồn,dài spritecao sprite); //nếu ảnh nguồn có dài và cao là bội số của dài và cao sprite thì ta tạo được một sprite động (tức là chiều dài và chiều cao ảnh nguồn sẽ chia hết cho chiều dài và chiều cao của ảnh nguồn), khi đó chúng ta có thể cho hiển thị một frame nào đó ra ngoài bằng cách gọi s.setFrame(index frame). Còn về setPosition và paint thì tượng tự như tiledlayer.
?>

Copy code

Bây giờ chúng ta tạo một class mới, class này có tác dụng tạo một Sprite mới từ một ảnh nguồn và cho hiển thị tại frame chỉ định cũng như một điểm xuất hiện trên graphics.
add.java
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
add{
private 
Sprite s;
public 
add(){}
void addsprite(Graphics g,Image im,int f,int x,int y){
s=new Sprite(im,32,32);
s.setFrame(f);
s.setPosition(x,y);
s.paint(g);
}
}
?>

Copy code

Để dùng class này vào trong class map bài trước ta thêm vào map.java như sau( ở đây tôi dùng một ảnh nguồn gồm 4 frame
):
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
map extends GameCanvas implements Runnable
{
private 
vd main;
private 
add sp=new add();
private 
Graphics g=getGraphics();
int w=getWidth();
int h=getHeight();
private 
Image t,ch;
private 
TiledLayer tl;
private 
int x=w/2,y=h/2,f=0;
private 
boolean play=true;
private 
intmap={
4,4,4,1,1,4,4,4,4,4,
4,4,1,1,4,4,4,4,4,4,
4,4,1,1,4,4,1,1,4,4,
4,4,1,1,3,1,1,4,4,4,
4,4,1,1,1,1,1,1,4,4,
4,4,4,4,1,1,1,2,4,4,
1,4,4,4,1,1,4,4,4,4,
1,4,4,4,1,1,4,4,4,1,
1,4,4,4,4,4,4,4,4,1,
1,1,4,4,4,4,4,4,1,1
};
public 
map(vd main){
super(false);
this.main=main;}
void start(){
Thread t=new Thread(this); t.start();}
public 
void run()
{
try{
ch=Image.createImage("/s.png");
t=Image.createImage("/t.png");}catch(Exception e){}
tl=new TiledLayer(10,10,t,32,32);
for(
int i=0;i<map.length;i++){
int col=i%10;
int row=(i-col)/10;
tl.setCell(col,row,map[i);}
while(
play){ input();
g.setColor(0x000000);
g.fillRect(0,0,w,h);
tl.setPosition(x,y);
tl.paint(g);
sp.addsprite(g,ch,f,w/2,h/2);
flushGraphics();
try{
Thread.sleep(30);}catch(Exception e){}//cho ngung mot thoi gian
}
}
void input(){
int k=getKeyStates();
if(
k==UP_PRESSED){y+=3f=1;}
if(
k==LEFT_PRESSED){x+=3f=2;}
if(
k==RIGHT_PRESSED){x-=3f=3;}
if(
k==DOWN_PRESSED){y-=3f=0;}
}
}
?>

Copy code


Chỉnh sửa lúc 2016-07-11 05:59 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
08:48:03, 29-07-2015

phát hiện điểm chạm giữa nhân vật và map
như vậy là ta đã có nhân vật trong trò chơi và cũng đã có thể điều khiển được nhân vật như ta đã đươc biết, thế nhưng khi di chuyển các bạn sẽ thấy rằng nhân vật của bạn có thể di chuyển tự do trên map dù cứ như là ở trên một lớp khác vậy. đúng vậy bởi gì ta vẽ nhân vật và map trên hai lớp khác nhau nên giữa chúng chẳng có liên quan gì. bây giờ ta sẽ tạo ra sự liên hệ giữa chúng để khi nhân vật chạm phải chướng ngại thì không thể đi tiếp nữa.
để làm được như vậy ta gán thêm một tọa độ điểm(px,py) và xét vị trí của toa độ điểm này trên map.
giống như thế này
-khung màu đen là sprite còn khung màu xanh lam là giới hạn mà sprite có thể di chuyển
-khung lớn bên ngoài là map, những ô nhỏ hơn là những tile(viên gạch)
ta sẽ xét bốn điểm góc của sprite so với vị trí các tile nhỏ. từ việc xác định được điểm (px,py)tâm của sprite ta dễ dàng tính được tọa độ bốn góc của nó và từ đó xét vị trí của từng điểm góc so với map, nếu một trong các góc thuộc vào tile là cây hoặc là nhân vật tĩnh thì ta không cho tăng x,y nữa. việc tính xem một góc của sprite đang ở tile nào chỉ cần tìm dòng và cột mà điểm góc đó

<?php
int c
=px/32;//32 là chiều rộng của tile
int r=py/32;//32 là chiều cao của tile
?>

Copy code

hãy xem code map hoàn chỉnh sau để hiểu rõ hơn:
map.java
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
map extends GameCanvas implements Runnable
{
private 
vd main;
private 
add sp=new add();
private 
Graphics g=getGraphics();
int w=getWidth();
int h=getHeight();
private 
Image t,ch;
private 
TiledLayer tl;
private 
int x=w/2,y=h/2,f=0,px,py;
private 
boolean play=true;
private 
intmap={
4,4,4,1,1,4,4,4,4,4,
4,4,1,1,4,4,4,4,4,4,
4,4,1,1,4,4,1,1,4,4,
4,4,1,1,3,1,1,4,4,4,
4,4,1,1,1,1,1,1,4,4,
4,4,4,4,1,1,1,2,4,4,
1,4,4,4,1,1,4,4,4,4,
1,4,4,4,1,1,4,4,4,1,
1,4,4,4,4,4,4,4,4,1,
1,1,4,4,4,4,4,4,1,1
};
public 
map(vd main){
super(false);
this.main=main;}
void start(){
Thread t=new Thread(this);
t.start();
}
public 
void run()
{
try{
ch=Image.createImage("/s.png");
t=Image.createImage("/t.png");}catch(Exception e){}
tl=new TiledLayer(10,10,t,32,32);
for(
int i=0;i<map.length;i++)
{
int col=i%10;
int row=(i-col)/10;
tl.setCell(col,row,map[i);
}
while(
play)
{
input();
g.setColor(0x000000);
g.fillRect(0,0,w,h);
tl.setPosition(x,y);
tl.paint(g);
sp.addsprite(g,ch,f,w/2,h/2);
flushGraphics();
try
{
Thread.sleep(30);}catch(Exception e){}//cho ngưng một thời gian
}
}
void input(){
int k=getKeyStates();
px=-(x-w/2)+16;
py=-(y-h/2)+16;//px,py luôn đối số với x,y và chuyển về tâm nên cộng thêm 16
if(k==UP_PRESSED)
{
f=1;
if(
collide(px,py-4)==0)
{
y+=4;
}}
if(
k==LEFT_PRESSED)
{
f=2;
if(
collide(px-4,py)==0)
{
x+=4;
}}
if(
k==RIGHT_PRESSED)
{
f=3;
if(
collide(px+4,py)==0)
{
x-=4;
}}
if(
k==DOWN_PRESSED)
{
f=0;
if(
collide(px,py+4)==0)
{
y-=4;
}}
}
int collide(int fx,int fy)
{
int collide=0;
for(
int m=-16;m<16;m+=31)
{
for(
int n=-16;n<16;n+=31)
{
int c=(fx+m)/32;
int r=(fy+n)/32;
if(
map[r*10+c!=4)
{
collide++;
}
//chỉ có tile 4 là di chuyển được
}}
return 
collide;
}}
?>

Copy code


Chỉnh sửa lúc 2016-07-11 06:03 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
08:48:44, 29-07-2015

load map từ file nguồn– function class
để có thể dễ dàng hành động và quản lí các máp hơn ta sẽ sử dụng một class tự tạo, va chức năng của nó là tổng hợp một map từ một text file và một hình ảnh nguồn làm gạch.
tôi sử dụng phần mềm tiled-qt để vẽ map cho nên tôi chỉ viết code để chuyển file map mà nó tạo ra thành nguồn mà tôi có thể sử dụng:
các bạn có thể down tiled-qt tại đây
tiled-qt-0.5.1-win32.zip

nội dung của đoạn code như sau:
tomap.java
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;
public class 
tomap
{
TiledLayer totile(String fn,String im)
{
int lw,lh,tw,th;
Image img=null;
InputStream is=getClass().getResourceAsStream(fn);
try{ 
lw=is.read();
lh=(int)is.read();
tw=(int)is.read();
th=(int)is.read();
try{
img=Image.createImage(im);}catch(Exception e){}
TiledLayer tl=new TiledLayer(lw,lh,img,tw,th);
for(
int i=0;i<lw*lh;i++){
int c=i%lw;
int r=(i-c)/lh;
tl.setCell(c,r,is.read());}
img=null;
return 
tl;
}catch(
Exception e){return null;}
}
}
?>

Copy code

khi sử dụng đơn giản ta chỉ cần gọi một biến với kiểu là tên class này(tomap) sau đó cho thực hiện function totile(tên txt file,ten ảnh nguồn)
như ví dụ sau:
<?php
tomap cm
=new tomap();
TiledLayer map=cm.totile("1.txt","/t.png");
?>

Copy code

map.tmx
ví dụ đây là file map do tiled-qt tạo ra:map.tmx
các bạn vào trang http://holyeyed.99k.org/function/tombd.php để chuyển lấy file map cho class trên có thể đọc được
n.mbd
và đây là file sau khi chuyển:n.mbd
ví dụ ta load map trên trong file map.java của vd project như sau:
map.java
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;
public class 
map extends GameCanvas implements Runnable
{
TiledLayer m;
tomap cm=new tomap();
add nv=new add();
private 
vd main;
private 
Graphics g=getGraphics();
private 
boolean play=true,say=false;
private 
int map=0,f=0,x=0,y=0,sx,sy;
Stringmname={"n.mbd"};
int w=getWidth();
int h=getHeight();
public 
map(vd main){
super(false);
this.main=main;
}
void start(){
setFullScreenMode(true);
play=true;
Thread t=new Thread(this);
t.start();}
public 
void run(){
//int i=0,j=0;
switch(map)
{
case 
0:
{
g.setColor(0x0);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0xa09040);
g.drawString("please wait…",w/2,h/2,g.HCENTER|g.BASELINE);
flushGraphics();
m=cm.totile(mname[map,"/t.png");
}
break;
case 
2:
{}
//do something for another map
break;
case 
3:
{}
// do another map
break;
}
while(
play){
g.setColor(0x0);
g.fillRect(0,0,getWidth(),getHeight());
input();
m.setPosition(x,y);
m.paint(g);g.fillRect(0,0,60,40);
g.setColor(0xdd0000);
g.drawString(x+" "+y,0,0,g.TOP|g.LEFT);
nv.addsprite(g,"/s.png",f,(w-32)/2,(h-32)/2,32,32);
flushGraphics();
}
}
void input()
{
int k=getKeyStates();
switch(
k){
case 
64:
y-=4;
break;
case 
2:
y+=4;
break;
case 
32:
x-=4;
break;
case 
4:
x+=4;
break;
case 
256:
{
play=false;
main.destroyApp(true);}
break; }
}
}
?>

Copy code

. trong trường hợp này, nếu bạn muốn xét điểm chạm giữa nhân vật và map thì không dùng cách của bài trước nữa, bởi vì ở đây không tồn tại một array bản đồ cho bạn xét. thế nhưng trên tiledllayer cung cấp một function giúp bạn có thể phát hiện xem một tọa độ điểm đang nằm trên tile nào.
[bint tl.getCell(col, row);[\b
như vậy chỉ cần có tọa độ của nhân vật là bạn có thể dễ dàng xét xem nó đang thuộc tile nào mà xét điểm chạm.
[download
đây là link tilededitor
http://sourceforge.net/projects/tiled/files/tiled-qt/0.7.1/tiled-0.7.1-win32-setup.exe
cách sử dụng:
bạn tạo một file mới điền các thông số của map
vào edit, preference , chọn save data là CSV, bỏ chọn include dtd referens in saved maps
vào map, new tiledset để chọn ảnh làm gạch cho map mới .
sau đó thì upload file map lên trang này để đổi lấy file .mbd


Chỉnh sửa lúc 2016-07-09 14:26 bởi Pham_loi
Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
08:50:18, 29-07-2015

record manager system(rms) và save game
Nếu như không có gì thay đổi thì gần như là bạn có thể hoàn thành một trò chơi đơn giản rồi đó, chỉ có điểu mỗi lần thoát khỏi trò chơi thì đâu lại quay lại từ đầu. tuy nhiên có khi nào các bạn để ý là những ứng dụng java thường hay tăng kích thước sau khi sử dụng không. Đó là vì chúng tạo ra những tập tin ẩn hệ thống để lưu lại những gì cần thiết( các cài đặt, tên người dùng, ngày giờ đăng kí, thông tin…). Java cung cấp một class gọi là record manager system(hệ thống quản lí mẫu tin, gọi tắt là rms) dùng để tạo ra những file lưu lại thông tin của những phiên làm việc trước.
Để sử dụng được class này ta chú ý những điều sau đây:
<?php
import javax
.microedition.rms.*;//class có sẵn cho việc sử dụng rms
?>

Copy code

Những thao tác mà ta cần thực hiện trên recordstore như sau:
<?php
Recordstore rs
=RecordStore.openRecordStore("data",true);//mở 1 recordstore có tên là data nếu đã tồn tại , nếu chưa có thì tạo mới. true ở đây là chỉ việc sẽ tạo mới nếu chưa tồn tại, để false sẽ không tạo mới dù không tồn tại
int rs.addRecord(byte[,offset,length byte);// trả về id của record khi thực hiện lệnh thêm một record mới. Các thông tin cho việc thêm record là một byte array, điểm bắt đầu, số byte tính từ điểm bắt đầu.
void rs.setRocord(ID,byte[,offset,length byte); // tương tự add record, nhưng ở đây nó là một thao tác không trả về ID mà chỉ định sẵn ID sẽ mang thông tin mới này (id record phải tồn tại rồi).
bytedt=rs.getRecord(ID// nhận giá trị của một record thông qua ID của nó, trả về giá trị bytearray. dùng:
String s=new String(dt,0,dt.length); // chuyển giá trị bytearray thành chuỗi và thao tác dễ hơn.
Hoặc:
int getRecord(ID,buffer,offset); // chuyển giá trị vào một buffer và trả về số byte của record. Một buffer có thể là một byte array hoặc là được tạo ra bằng lệnh: StringBuffer sb=new StringBuffer();
void deleteRecord(ID); // tất nhiên là xóa record rồi.
Sau khi sử dụng xong recordStore thì nên đóng nó lại để tiết kiệm bộ nhớvà nếu không cần nó nữa thì xóa luôn nó đi cũng không sao vì ta đã có được các thông tin cần thiết rồi:
void rs.closeRecordStore();
void deleteRecordStrore(tên record);
?>

Copy code

và sau đây là ví dụ minh họa cho dễ hiểu, chúng ta sẽ sử dụng project vd lần nữa. chẳng hạn nhân vật ta di chuyển trên map và ta muốn mỗi lần thóat ra thì vị trí của nhân vật sẽ đựơc lưu lại cho lần sau mở lên. Ta cần làm ở đây là ghi giá trị x,y của nhân vật và trong recordstore. Tôi sẽ sửa lại file map.java để cho đơn giản hơn, nhân vật của ta sẽ di chuyển tự do không bị giới hạn, và khi nhấn phím 5 sẽ thoát game, file map.java như sau:
<?php
import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
map extends GameCanvas implements Runnable
{
private 
vd main;
private 
add sp=new add();
private 
Graphics g=getGraphics();
int w=getWidth();
int h=getHeight();
private 
Image t,ch;
private 
TiledLayer tl;
private 
int x=w/2,y=h/2,f=0;
private 
boolean play=true;
private 
intmap={
4,4,4,1,1,4,4,4,4,4,
4,4,1,1,4,4,4,4,4,4,
4,4,1,1,4,4,1,1,4,4,
4,4,1,1,3,1,1,4,4,4,
4,4,1,1,1,1,1,1,4,4,
4,4,4,4,1,1,1,2,4,4,
1,4,4,4,1,1,4,4,4,4,
1,4,4,4,1,1,4,4,4,1,
1,4,4,4,4,4,4,4,4,1,
1,1,4,4,4,4,4,4,1,1
};
public 
map(vd main){
super(false);
this.main=main;}
void start(){
Thread t=new Thread(this); t.start();}
public 
void run()
{
try{
ch=Image.createImage("/s.png");
t=Image.createImage("/t.png");}catch(Exception e){}
tl=new TiledLayer(10,10,t,32,32);
for(
int i=0;i<map.length;i++){
int col=i%10;
int row=(i-col)/10;
tl.setCell(col,row,map);}
while(
play){ input();
g.setColor(0x000000);
g.fillRect(0,0,w,h);
tl.setPosition(x,y);
tl.paint(g);
sp.addsprite(g,ch,f,w/2,h/2);
flushGraphics();
try{
Thread.sleep(30);}catch(Exception e){}//cho ngung mot thoi gian
}
}
void input(){
int k=getKeyStates();
if(
k==UP_PRESSED){y+=3f=1;}
if(
k==LEFT_PRESSED){x+=3f=2;}
if(
k==RIGHT_PRESSED){x-=3f=3;}
if(
k==DOWN_PRESSED){y-=3f=0;}
if(
k==FIRE_PRESSED){play=falsemain.destroyApp(true);}
}
}
?>

Copy code

Còn bây giờ là một class chức năng, gồm hai chức năng là save và load:
Data.java có nội dung như sau:
<?php
import javax
.microedition.rms.*;
public class 
data
{private RecordStore rs;
public 
data(){}
void save(String name,int id,String info){
try{
rs=RecordStore.openRecordStore("name",true);
int nr=rs.getNumRecords();
if(
nr<id){//nếu chưa tồn tại record tại id cần thêm thì thêm vào record null tại id đó
bytea={};//dữ liệu null
for(int i=0;i<(id-nr);i++){int d=rs.addRecord(a,0,0);}//thêm vào 2 id: 1 và 2
}
bytebdt=info.getBytes();
rs.setRecord(id,bdt,0,bdt.length);
rs.closeRecordStore();
bdt=null;
}
catch(
Exception e){}
}
String load(String name,int id){
String t="";
try{
rs=RecordStore.openRecordStore("name",true);
bytebdt=rs.getRecord(id);
t=new String(bdt,0,bdt.length);
}
catch(
Exception e){}
return 
t;
}
}
?>

Copy code

Sau đó trong map.java ta sử dụng class chức năng data.java cho việc lưu và nhận dữ liệu, map.java sẽ như thế này:
<?php

import javax
.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class 
map extends GameCanvas implements Runnable
{
private 
data dt=new data();
private 
vd main;
private 
add nv=new add();
private 
Graphics g=getGraphics();
int w=getWidth();
int h=getHeight();
private 
Image t;
private 
TiledLayer tl;
private 
int x=0,y=0;
private 
boolean play=true;
private 
intmap={
4,4,4,1,1,4,4,4,4,4,
4,4,1,1,4,4,4,4,4,4,
4,4,1,1,4,4,1,1,4,4,
4,4,1,1,3,1,1,4,4,4,
4,4,1,1,1,1,1,1,4,4,
4,4,4,4,1,1,1,2,4,4,
1,4,4,4,1,1,4,4,4,4,
1,4,4,4,1,1,4,4,4,1,
1,4,4,4,4,4,4,4,4,1,
1,1,4,4,4,4,4,4,1,1
};
public 
map(vd main){
super(false);
this.main=main;}
void start(){
Thread t=new Thread(this); t.start();}
public 
void run()
{try
{
x=Integer.parseInt(dt.load("save",1),10);
y=Integer.parseInt(dt.load("save",2),10);}
catch(
Exception e){}
try{ 
ch=Image.createImage("/s.png");
t=Image.createImage("/t.png");}catch(Exception e){}
tl=new TiledLayer(10,10,t,32,32);
for(
int i=0;i<map.length;i++){
int col=i%10;
int row=(i-col)/10;
tl.setCell(col,row,map);}
while(
play){ input();
g.setColor(0×000000);
g.fillRect(0,0,w,h);
tl.setPosition(x,y);
tl.paint(g);
sp.addsprite(g,ch,f,w/2,h/2);
flushGraphics();
try{
Thread.sleep(30);}catch(Exception e){}//cho ngưng một thời gian
}
}
void input(){
int k=getKeyStates();
if(
k==UP_PRESSED){y++;}
if(
k==LEFT_PRESSED){x++;}
if(
k==RIGHT_PRESSED){x--;}
if(
k==DOWN_PRESSED){y--;}
if(
k==FIRE_PRESSED){
play=false;
dt.save("save",1,x+"");
dt.save("save",2,y+"");
main.destroyApp(true);}
}
}
?>

Copy code

Như vậy là coi như xong những bước cơ bản nhất của một game java cần có rồi đó, nếu như muốn hòan thiện một game thật sự, có thể các bạn cần đau đầu một chút vì đây chỉ là những class cơ bản thôi, các bạn có thể tự tạo ra nhưng class chức năng khác cho công việc của riêng mình, điều quan trọng là trước khi làm mình cần suy nghĩ xem nó sẽ như thế nào trước đã rồi hẳn viết code, cũng như không thể nào đánh caro mà không suy nghĩ hay dựng nhà mà không vẽ thiết kế. mong là các bạn có thể tạo ra những trò chơi hay ho cho mình và cộng đồng game mobile. Còn nếu có thắc mắc gì thì cũng có thể để lại lời nhắn qua địa chỉ mail: holyeyed@ gmail.com, tôi sẽ sẵn sàng giúp đỡ thôi.


Chỉnh sửa lúc 2016-07-09 14:22 bởi Pham_loi
Like: 0
Lên trên  Tổng số: 42
« 1 2 3 4 5 »







Trực Tuyến: Khách: 1
Diễn đàn teen Việt Nam
CopyRight 2014