Thứ Bảy, 29 tháng 12, 2012

Chúng ta không chỉ có một mình

Hôm trước đã nói tới chuyện thông qua command mà điểu khiển một biến robot rồi, hôm nay cũng với command và robot này nhưng chúng ta không chỉ điều khiển một mà là nhiều. tức là khi viết lệnh chúng ta viết cho nhiều robot và với phân cách là dấu chấm (.) có bao nhiêu lệnh thì có bấy nhiêu biến robot được vẽ trên màn hình. Hãy xét một lệnh tổng hợp ví dụ như sau: 1 robot: string,x,y Nhiều robot: string1,x1,y1.srting,x2,y2.string3,x3,y3.(string_n,x_n,y_n) Giả sử ta có lệnh tổng hợp sau: Abc,10,50.bcd,30,100.def,120,5 vậy là ta có 3 biến robot được tạo ra và màn hình sẽ thực hiện việc vẽ 3 biến này lên màn hình. Để làm như vậy, bây giờ ta sẽ sử dụng biến rb là một Vector của lớp robot Ta đặt: Vector rb; Chưa vội gán giá trị cho nó bao nhiêu đối tượng mà ta sẽ phân tích từ lệnh. Lớp canvas.java sẽ như thế này: mog.java
C:\Users\WIN7\Documents\NetBeansProjects\mog\src\mog.java
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

public class mog extends MIDlet {
public void startApp(){
Display.getDisplay(this).setCurrent(new canvas());}
public void destroyApp(boolean t){}
public void pauseApp(){}}

class canvas extends Canvas{
textfield tf;
Vector rb=new Vector();
Font f=Font.getFont(0,0,8);
int w,h,k=0,fh;
String command="";
public canvas(){
setFullScreenMode(true);
w=getWidth();
h=getHeight();
fh=f.getHeight();
tf=new textfield("command",0,0,w);
}
public void paint(Graphics g){
g.setFont(f);
g.setColor(0);
g.fillRect(0,0,w,h);
tf.paint(g,k,true);
g.setColor(0xf0f0);
g.setClip(0,0,w,h);
g.drawString(command,0,fh*2,Graphics.TOP|Graphics.LEFT);
if(rb!=null)
for(int i=0;i<rb.size();i++)
((robot)rb.elementAt(i)).paint(g);
k=0;
repaint();
}
public void keyPressed(int k){
this.k=k;
if(k==-5){
command=tf.getString();
String[] acommand=tach(command,".");
for(int i=0;i<acommand.length;i++){
    robot nrb=new robot(w/2,h/2);
    nrb.getcommand(tach(acommand[i],","));
rb.addElement((robot)nrb);}}}
public void keyReleased(int k){this.k=0;}

public String[] tach(String s,String c){
Vector v=new Vector();
if(!s.endsWith(c)){s+=c;}
int st=0,np=s.indexOf(c,st);
while(np!=-1){
v.addElement((String)s.substring(st,np));
st=np+c.length();
np=s.indexOf(c,st);}
String[] rt=new String[v.size()];
v.copyInto((String[])rt);
for(int i=0;i<rt.length;i++){System.out.println(rt[i]+rt[i].length());}
return rt;}
}

class robot{
int x,y,nx,ny;
String say;
long lm=0;
public robot(int x,int y){
this.x=x;
this.y=y;
this.nx=x;
this.ny=y;
}
public void getcommand(String[] s){
say=s[0];
nx=Integer.parseInt(s[1]);
ny=Integer.parseInt(s[2]);
}
public void paint(Graphics g){
if(System.currentTimeMillis()-lm>200)
move();
g.setColor(0xf000f0);
g.fillRect(x,y,16,16);
}

void move(){
x+=x>nx?-1:(x==nx?0:1);
y+=y>ny?-1:(y==ny?0:1);}
}
• Như chúng ta thấy đó, sau khi ta nhấn phím 5, lệnh sẽ được lấy ra từ textfield (tf) và phân tích thành mảng của các lệnh con qua String[] acommand=tach(command,"."); • Và sau đó lại được phân tích và gán vào biến robot bình thường. for(int i=0;i mog.java
C:\Users\WIN7\Documents\NetBeansProjects\mog\src\mog.java
public void keyPressed(int k){
this.k=k;
if(k==-5){
command=tf.getString();
String[] acommand=tach(command,".");
Vector trb=new Vector();
for(int i=0;i<acommand.length;i++){
    String[] info=tach(acommand[i],",");
    robot nrb=new robot(w/2,h/2);
    for(int j=0;j<rb.size();j++){
   if(info[0].equals(((robot)rb.elementAt(j)).say)){nrb=(robot)rb.elementAt(j);
    System.out.println("dectect");}}
    nrb.getcommand(info);
trb.addElement((robot)nrb);}
rb=trb;}}
}
• Lúc này ta cần tạo thêm một biến trb dùng để tạo một vùng thêm các biến robot vào và so sánh với biến rb cũ, nếu không làm như vậy mà thêm trực tiếp vào biến cũ ta sẽ không thể nào kiểm soát được các đối tượng mà ta đã ra lệnh trước đó. • Bài này vậy là xong, nếu đến đây các bạn vẫn chưa hiểu được là ta đang làm cái gì thì bài sau các bạn sẽ rõ. Đây không phải chỉ là chuyện rèn kỹ năng giải thuật mà nó phải có sử dụng thực tế. http://holyeyed.99k.org/function/up/mog-72176.zip

Chủ Nhật, 16 tháng 12, 2012

Đi lệch quỹ đạo

một lập trình viên thường không thể nào kiểm soát hết mọi trường hợp có thể xảy ra trong thực tế, dù rằng đó là ứng dụng do chính họ tạo ra. một thế giới nhỏ bé cũng có những sự cố của chính nó, tôi cũng gặp nhiều những sự cố như vậy, tôi cố gắng sửa chữa chúng nhưng dường như cứ để như vậy thì lại hay hơn. mình có thề sửa cái này vì nó ngay trước mặt mình nhưng còn những thứ không bao giờ hiện ra ngay trước mắt. tôi không biết mình có đi lệch quỹ đạo hay không và thật sự đâu là quĩ đạo của chính tôi. dù sao thì tôi cũng sống cho chính bản thân mình và không chịu sự điều khiển của ai cả, nếu như tôi không còn là tôi của những ngày ban đầu thì tôi vẫn đi trong chính con đường của mình chứ không ai khác. trong những gì mà ta đầu tư cũng có thể bỏ đi hết, nếu tự nhiên có thứ gì đó thu hút ta hơn. tôi thường xem việc lập trình hoặc là viết bài hướng dẫn như là một sự giải thoát khỏi sự chán nản của cuộc sống nhưng thỉnh thoảng cái cô độc vẫn ám ảnh tôi nhiều hơn. và bây giờ tôi muốn nói gì đó cho nó khuây khỏa, muốn quên đi những thứ mà tôi chưa kịp hoàn thành. bế tắc trong bất cứ chuyện gì cũng không có nghĩa lí gì hết nếu như có một cái gì đó cho ta nhìn ra ngoài. hãy thử tưởng tượng khi bạn đang cố gắng suy nghĩ về cuộc đời mình rồi sẽ ra sao và có một người đến nói với bạn rằng hãy đi chơi với họ thì bạn sẽ nghĩ sao. tự nhiên ta sẽ quên hết mọi thứ đang dang dở và hào hứng đến với họ hơn là việc ta đang làm. tôi không biết, thường thì tôi sẽ làm vậy, và ngay cả trong việc viết hướng dẫn như thế này tôi cũng không muốn bó buộc vào điều gì hết, đừng phiền lòng nếu như bài biết này làm phí thời gian của bạn, vì nó là những gì mà tôi thấy là có ý nghĩa với một vài người và ít nhất là đối với tôi. nhiều khi nằm trên giường và nhìn ra ngoài cửa sổ tôi lại thấy nó như hấp dẫn tôi rất nhiều, tôi thích nhìn chỉ một góc như vậy và suy nghĩ xem những phần còn lại của thế giới đang diễn ra như thế nào. hay chuyện vào một thời gian nào đó bạn nghĩ về một người bạn của mình hiện giờ đang làm gì và như thế nào, có những chuyện gì làm cho họ buồn hay vui và họ có nhớ tới bạn không. thật sự là ta có thể nghĩ đến hàng vô số những chuyện xảy ra trên thế giới này và mọi thứ điều tuyệt diệu.
"hãy thử nhìn xung quanh và nghĩ xem điều gì đang diễn ra ở đó"

điều khiển nhân vật thông qua lệnh

Bài trước đã hướng dẫn cách viết một class textfield hiển thị và nhập trên Canvas, bài này sẽ sử dụng đến textfield đó để làm vài thứ: Đầu tiên chúng ta sẽ tạo một class nhận giá trị là một chuổi và sau đó là phân tích chuỗi đó để thực hiện những lệnh mà ta muốn, lệnh ở đây bao gồm (chuỗi,tọa độ x, tọa độ y) và sau khi nhận chuỗi này nó sẽ tự cập nhật thông tin vào trong các biến của nó, ta viết như sau: NewClass.java
C:\Users\WIN7\Documents\NetBeansProjects\textfield\src\NewClass.java
import javax.microedition.lcdui.*;
import java.util.*;

class canvas extends Canvas{
textfield tf;
//robot là một đối tượng nhận lệnh và điều khiển bởi lệnh
robot rb;
Font f=Font.getFont(0,0,8);
int w,h,k=0,fh;
String command="";
public canvas(){
setFullScreenMode(true);
w=getWidth();
h=getHeight();
fh=f.getHeight();
tf=new textfield("command",0,0,w);
rb=new robot(w/2,h/2);
}
public void paint(Graphics g){
g.setFont(f);
g.setColor(0);
g.fillRect(0,0,w,h);
//vẽ hộp nhập văn bản lên canvas
tf.paint(g,k,true);
g.setColor(0xf0f0);
g.setClip(0,0,w,h);
//vẽ chuỗi lệnh ra màn hình
g.drawString(command,0,fh*2,Graphics.TOP|Graphics.LEFT);
//vẽ đối tượng nhận lệnh ra màn hình
rb.paint(g);
k=0;
repaint();
}
public void keyPressed(int k){
this.k=k;
//nếu nhấn mã -5 (phím ok) thì cho command nhận giá trị của textfield (tf), 
if(k==-5){
command=tf.getString();
//sau đó truyền tham số vào trong đối tượng hoạt động robot(rb), trước đó ta cho nó tách thành từng phần qua method tach trước, cách nhau bởi dấu phẩy (có dạng: say,x,y)
rb.getcommand(tach(command,","));}}
public void keyReleased(int k){this.k=0;}
//chức năng tách chuỗi ra thành từng phần
public String[] tach(String s,String c){
Vector v=new Vector();
if(!s.endsWith(c)){s+=c;}
int st=0,np=s.indexOf(c,st);
while(np!=-1){
v.addElement((String)s.substring(st,np));
st=np+c.length();
np=s.indexOf(c,st);}
String[] rt=new String[v.size()];
v.copyInto((String[])rt);
for(int i=0;i<rt.length;i++){System.out.println(rt[i]+rt[i].length());}
return rt;}
}


Lớp robot là một dạng như sau, nó sẽ nhận các giá trị lệnh và xử lí để hoạt động theo lệnh đó: NewClass.java
C:\Users\WIN7\Documents\NetBeansProjects\textfield\src\NewClass.java


class robot{
int x,y,nx,ny;
String say;
long lm=0;
//hàm khởi tạo robot nhận 2 giá trị x, y là tọa độ đầu tiên của nó
public robot(int x,int y){
this.x=x;
this.y=y;
this.nx=x;
this.ny=y;
}
//hàm getcommand này nhận một mảng chuỗi bao gồm các giá trị truyền vào say, nx, ny 
public void getcommand(String[] s){
say=s[0];
nx=Integer.parseInt(s[1]);
ny=Integer.parseInt(s[2]);
}
//hàm paint sẽ vẽ đối tượng này lên Graphics của canvas, đồng thời cũng di chuyển nó thông qua hàm move
public void paint(Graphics g){
    //cũng cần phải cho nghỉ một khoảng thời gian để nó không di chuyển quá nhanh mà ta không kịp theo dõi
if(System.currentTimeMillis()-lm>200)
move();
g.setColor(0xf000f0);
g.fillRect(x,y,16,16);
}
//hàm move này so sánh giá trị tọa độ x,y với nx,ny để từ đó tính toán và thay đổi giá trị của x,y cho đến khi bằng nx,ny
void move(){
    //so sánh x và nx nếu như x lớn hơn nx thì cho x trừ đi 1, nếu x bằng nx thì không thay đổi x, ngược lại thì cho x tăng lên 1 khi x nhỏ hơn nx
x+=x>nx?-1:(x==nx?0:1);
//tương tự với y và ny
y+=y>ny?-1:(y==ny?0:1);}
}


Xong như vậy là chúng ta đã hoàn thành rồi, chỉ cần ghép nó vào MIDlet nữa là thấy: http://holyeyed.99k.org/function/up/mog-25113.zip http://holyeyed.99k.org/function/up/mog-97485.jar

Thứ Bảy, 15 tháng 12, 2012

nhập văn bản trực tiếp từ Canvas

thường thì muốn nhập chuỗi thì ta thiết kế sử dụng TextBox hoặc là TextField trên Form, nhưng trong game nên hạn chế cho người dùng sử dụng giao diện bậc cao như vậy. Ta sẽ cho nhập văn bản trực tiếp từ bàn phím trên Canvas dựa vào hàm keyPressed(int i) : textfield.java
C:\Users\WIN7\Documents\NetBeansProjects\textfield\src\textfield.java
  1 //textfield.java
  2 import javax.microedition.lcdui.*;
  3 
  4 public class textfield {
  5 
  6     int x, y, w, lk = 0, np = 0, fh, tcolor = 0, bgcolor = 0xf0f0f0;
  7     String s = "", title;
  8     //mảng ac chứa các kí tự cần thiết tương ứng với các phím bấm từ 0 đến 9
  9     String[] ac = {" 0", ".,1", "abc2", "def3", "ghi4", "jkl5", "mno6", "pqrs7", "tuv8", "wxyz9"};
 10     long lp = 0, rr = 0;
 11     boolean focus = false;
 12     Font f = Font.getFont(0, 0, 8);
 13 //hàm khởi tạo textfield nhận các giá trị tiêu đề (title), vị trí đặt hộp text(x, y), và chiều rộng hộp (w)
 14     public textfield(String title, int x, int y, int w) {
 15         this.title = title;
 16         this.x = x;
 17         this.y = y;
 18         this.w = w;
 19         fh = f.getHeight();
 20     }
 21 
 22     String getString() {
 23         return s;
 24     }
 25 //hàm paint này dùng vẽ textfield lên Graphic (g) và được dùng trên Canvas, nó nhận các biến tham số: Graphics g, biến mã phím int k, và biến boolean focus chỉ định là có thực hiện thao tác với textfield này không
 26     public void paint(Graphics g, int k, boolean focus) {
 27         g.setFont(f);
 28         this.focus = focus;
 29         //nếu có tác động focus==true thì cho thực hiện vẽ chuỗi theo mã phím
 30         if (focus && cr() - lp > rr) {
 31             add(k);
 32         }
 33         //các hàm vẽ liên quan đến việc vẽ chuỗi s ra màn hình
 34         int slen = f.stringWidth(s);
 35         int kh = slen - w;
 36         g.setColor(bgcolor);
 37         g.fillRect(x, y + fh, w, fh);
 38         g.drawString(title + ":", x, y, Graphics.TOP | Graphics.LEFT);
 39         g.setColor(tcolor);
 40         g.setClip(x, y + fh, w, fh);
 41         g.drawString(s + (focus ? "|" : ""), x - (kh > 0 ? kh : 0), y + fh, Graphics.TOP | Graphics.LEFT);
 42 
 43 
 44     }
 45 
 46     void add(int k) {
 47         //nếu key là -3(phím qua trái) thì cho xóa kí tự
 48         if (k == -3 && s.length() > 0) {
 49             s = s.substring(0, s.length() - 1);
 50             lk = k;
 51             lp = cr();
 52         } else if (k == -6) {//nếu key là -6 thì thôi không tác động đến textfield này nữa
 53             focus = false;
 54         } else {
 55             //tìm vị trí của phím bấm từ 0 đến 9, do phím 0 có mã phím là 48 nên ta lần lượt trừ cho 48 sẽ tương ứng với vị trí của bảng kí tự trong mảng chuổi ac
 56             int sk = k - 48;
 57             //nếu như sk lớn hơn 0 thì cho thực hiện tiếp, tương đương là bấm các phím từ 0->9
 58             if (sk >= 0) {
 59                 //nếu thời gian hiện tại trừ lp(lần nhấn sau cùng) <800 và phím nhấn lần này giống với phím bấm lần sau cùng thì cho tăng np (index cần lấy của kí tự trong chuỗi).
 60                 if (cr() - 800 < lp && lk == sk) {
 61                     np++;
 62                     if (np == ac[sk].length()) {
 63                         np = 0;
 64                     }
 65                     s = s.substring(0, s.length() - 1);
 66                     s += ac[sk].charAt(np);
 67                 } else {//ngược lại thì cho thêm vào kí tự thích hợp với phím bấm(kí tự đầu tiên tương ứng các mảng giá trị)
 68                     np = 0;
 69                     s += ac[sk].charAt(np);
 70                 }
 71                 //đặt mả phím sau cùng và lk (phím bấm sau cùng) và thời gian bấm sau cùng lp (lần nhấn sau cùng)
 72                 lk = sk;
 73                 lp = cr();
 74             }
 75 
 76         }
 77     }
 78 //hàm cr() trả lại thời gian hiện thời
 79     long cr() {
 80         return System.currentTimeMillis();
 81     }
 82 }
 83 
 84 class canvas extends Canvas {
 85 //tạo một biến textfield mới, với tiêu đề là "nhập văn bản", ở tọa độ (0,120) và chiều rông màn hình
 86     textfield tf = new textfield("nhập văn bản", 0, 120, 40);
 87     int w = getWidth(), h = getHeight(), k = 0;
 88 
 89     public canvas() {
 90     }
 91 
 92     public void paint(Graphics g) {
 93         g.setColor(0);
 94         g.fillRect(0, 0, w, h);
 95         //thực hiện lệnnh vẽ textfield ra màn hình lên Graphics g và với mã phím k
 96         tf.paint(g, k, true);
 97         k=0;
 98         repaint();
 99     }
100 
101     public void keyPressed(int k) {
102         this.k = k;
103     }
104 
105     public void keyReleased(int k) {
106         this.k = 0;
107     }
108 }
• ở đây chúng ta chỉ cần lưu ý là trong textfield.java có các biến đảm nhận thời gian như là lp, để xác định lần nhấn phím sau cùng mà người dùng nhấn. sau đó so sánh với giá trị thời gian hiện tại lấy từ hàm cr(), nếu như mà hai giá trị này chênh nhau quá 800ms thì cho cộng vào chuỗi một kí tự mới tương ứng với index 0 trong giá trị của phím trong mảng chuỗi ac. Còn nếu như mà thấy thời gian chênh nhau giữa lp và cr() trong 800ms trở lại và mã phím cũng là mã phím nhấn sau cùng thì cho tăng index lấy kí tự trong mã phím hiện tại và kết quả là thay đổi kí tự vừa mới ghi lúc nãy chứ không thêm kí tự mới nào. • http://holyeyed.99k.org/function/up/textfield-62592.jarhttp://holyeyed.99k.org/function/up/src-30856.zip

Chủ Nhật, 18 tháng 11, 2012

một đội quân địch, cấp độ khó

trong trò chơi mà chơi với những AI thì lúc nào chúng cũng thua mình thôi, do đó cần tạo ra độ khó bằng cách tăng số lượng của chúng. tôi sẽ tạo ra một đạo quân địch từ những gì mà ta đã có và thêm vào đó một vài thứ khác.
ta sẽ tạo ra một class E, bao gồm một biến xe T và những giá trị như mã key, biến đúng sai die , như sau:
//E.java
import javax.microedition.lcdui.*;

public class E {
T x;
boolean die;
int k;
public E(int x, int y, int color, int w,int h){
die=false;
this.x=new T(x,y,color,w,h);}
void paint(Graphics g,int k){
x.paint(g,k);}
}

. Sau đó trong game.java ta sửa lại như sau:
//game.java

import javax.microedition.lcdui.*;
import java.util.*;

public class game extends Canvas {
String[] smenu={"play game","help","about"};
int w,h,fh,mindex=0,mode=0,k,ak,cx=3;
Midlet m;
Font f=Font.getDefaultFont();
T t,x;
E[] e;
long lai=0;
Random rd=new Random();

public game(Midlet m){
this.m=m;
setFullScreenMode(true);
w=getWidth();
h=getHeight();
fh=f.getHeight();
t=new T(0,0,0xf0f0f0,w,h);
x=new T(w-16*3,h-16*3,0x6060f0,w,h);
//khởi tạo e
e=new E[cx];
for(int i=0;i<e.length;i++){
e[i]=new E(w-16*3,h-16*3,0x6060f0,w,h);}
}

public void paint(Graphics g){
g.setColor(0);
g.fillRect(0, 0, w, h);
g.setColor(0xf0f0f0);
switch(mode){
case 0: //vẽ menu
//vẽ thanh index
g.fillRect(0, (h-fh*3)/2+mindex*fh, w, fh);
//vẽ các menu
for(int i=0;i<smenu.length;i++){
if(i==mindex){g.setColor(0);}else{g.setColor(0xf0f0f0);}
g.drawString(smenu[i],w/2 ,( h-fh*3)/2+i*fh, Graphics.HCENTER|Graphics.TOP);
}
break;
case 1: //vẽ game play
g.drawString(smenu[0], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
t.paint(g, k);
x.paint(g, (ak=ai(x,ak)));
if(check(t,x)){x.color-=0x000010;}
if(check(x,t)){t.color-=0x100000;}

//biến n đếm số xe đã được vẽ trong e
int n=0;
for(int i=0;i<e.length;i++){
//chỉ vẽ ra tới 3 xe tăng, nếu nhiều hơn thì chờ đến lượt
if(n==2)continue;
//nếu chưa trúng đạn thì vẽ ra
if(!e[i].die)
{n++;
e[i].k=ai(e[i].x,e[i].k);
e[i].paint(g,e[i].k);

//check xem có trúng đạn của ta không, nếu có thì cho chết die=true
if(check(t,e[i].x))e[i].die=true;
if(check(e[i].x,t)){
//xe ta bị trúng đạn
//game over, kết thúc trò chơi, hay mất mạng, mất máu gì đó
}}
}
break;
case 2: //vẽ help
g.drawString(smenu[1], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;
case 3: //vẽ about
g.drawString(smenu[2], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;}

//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit", 0, h, Graphics.LEFT|Graphics.BOTTOM);
g.drawString("back", w, h, Graphics.RIGHT|Graphics.BOTTOM);
repaint();}

protected void keyReleased(int k){this.k=0;}

public void keyPressed(int k){
this.k=k;
//cho di chuyển vị trí thanh menu
if(mode==0){
if(k==-1)mindex--;
if(k==-2)mindex++;
if(mindex<0)mindex=smenu.length-1;
if(mindex==smenu.length)mindex=0;
//thay đổi mode khi lựa chọn menu
if(k==-5)mode=mindex+1;
//các lệnh cho menu góc màn hình
if(k==-6)m.notifyDestroyed();}
if(k==-7)mode=0;}

boolean check(T a, T b){
int xc=(a.d.x-b.x)/16/3;
int yc=(a.d.y-b.y)/16/3;
if(xc==0&amp;&amp;yc==0&amp;&amp;a.d.f!=-1){
b.color-=0x100010;
return true;}
return false;}

int ai(T a,int ak){
if(lai<System.currentTimeMillis()-2000){
lai=System.currentTimeMillis();
int k=Math.abs(rd.nextInt())%4;
return -(k+1);}
if(System.currentTimeMillis()%25==0)
return -(1+a.f);
if(rd.nextInt()%3==0&amp;&amp;a.d.f==-1){return -5;}
return 0;}
}

. Kết quả đây, trò chơi gần như hoàn thiện, các bạn có thể thêm phần level cho trò chơi hoặc gì đó hay ho một chút...

source here

giới hạn màn hình

tức nhiên nếu cứ để cho những chiếc xe chạy ra khỏi giới hạn của màn hình thì chẳng biết nó sẽ đi tới đâu, thật sự thì nó không thể nào đi quá giới hạn của biến int nhưng mà ta cũng có thể coi là đó là một nơi vô tận. bây giờ ta sẽ giới hạn khả năng di chuyển của chúng, nhưng chiếc xe khi gặp khung màn hình thì không di chuyển thêm nữa. ta biến đổi T.java như sau:

//T.java

import javax.microedition.lcdui.*;

public class T {
F d;
int x,y,f,color,w,h;
long lm=0;
byte[][] shape={{0,1,0,1,1,1,1,0,1},{1,0,1,1,1,1,0,1,0},{0,1,1,1,1,0,0,1,1},{1,1,0,0,1,1,1,1,0}};

public T(int x,int y,int color,int w, int h){
this.x=x;
this.y=y;
this.color=color;
d=new F(x+16,y+16,0xf00000,50);
this.w=w;
this.h=h;
}

boolean check(){return (lm<System.currentTimeMillis()-60);}

public void paint(Graphics g,int k){
switch(k){
case -1: f=0; if(check()){y-=16; if(y<0)y=0; lm=System.currentTimeMillis();} break;
case -2: f=1; if(check()){y+=16; if(y>h-16*3)y=h-16*3; lm=System.currentTimeMillis();} break;
case -3: f=2; if(check()){x-=16; if(x<0)x=0; lm=System.currentTimeMillis();} break;
case -4: f=3; if(check()){x+=16; if(x>w-16*3) x=w-16*3; lm=System.currentTimeMillis();}break;
case -5: d.f=this.f; break;}
g.setColor(color);
for(int i=0;i<shape[f].length;i++){
int c=i%3,r=(i-c)/3;
g.fillRect(x+c*16,y+r*16,16*shape[f][i],16*shape[f][i]);}
d.fire(g,x+16,y+16);
}
}

. Do hàm khởi tạo trong T.java đã thay đổi nên trong game.java ta cũng thay đổi khởi tạo cho biến tx

public game(Midlet m){
this.m=m;
setFullScreenMode(true);
w=getWidth();
h=getHeight();
fh=f.getHeight();
t=new T(0,0,0xf0f0f0,w,h);
x=new T(w-16*3,h-16*3,0x6060f0,w,h);}

* Kết quả rất mãn nguyện:

AI tự động giải quyết vấn đề.

thật ra không có gì thông minh cho lắm, người lập trình nghĩ sao viết vậy thì các nhân vật tự động cũng làm theo như vậy. nhưng cũng có những Artificial inteligence thật sự làm người ta ngạc nhiên, điều đó phụ thuộc vào người lập trình như thế nào, có khi họ không phải là người truyền cách thức hoạt động vào code mà là một người khác có trí tuệ cao hơn họ, người này có thể không biết gì về lập trình cả.
Ở đây tôi chỉ làm cho xe của địch có khả năng tự di chuyển và nả đạn khi cần thiết, như vậy thì mới thật sự là một trò chơi. trong game.java tôi thêm một hàm mới, hàm này tổng hợp một mã phím theo thời gian.
//game.java

import javax.microedition.lcdui.*;
import java.util.*;

public class game extends Canvas {
String[] smenu={"play game","help","about"};
int w,h,fh,mindex=0,mode=0,k,ak;
Midlet m;
Font f=Font.getDefaultFont();
T t,x;
long lai=0;

public game(Midlet m){
this.m=m;
setFullScreenMode(true);
w=getWidth();
h=getHeight();
fh=f.getHeight();
t=new T(0,0,0xf0f0f0);
x=new T(w-16*3,h-16*3,0x6060f0);}

public void paint(Graphics g){
g.setColor(0);
g.fillRect(0, 0, w, h);
g.setColor(0xf0f0f0);
switch(mode){
case 0: //vẽ menu
//vẽ thanh index

g.fillRect(0, (h-fh*3)/2+mindex*fh, w, fh);
//vẽ các menu
for(int i=0;i<smenu.length;i++){
if(i==mindex){g.setColor(0);}else{g.setColor(0xf0f0f0);}
g.drawString(smenu[i],w/2 ,( h-fh*3)/2+i*fh, Graphics.HCENTER|Graphics.TOP);
}
break;
case 1: //vẽ game play
g.drawString(smenu[0], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
t.paint(g, k);
x.paint(g, (ak=ai(x,ak)));
if(check(t,x)){x.color-=0x000010;}
if(check(x,t))t.color-=0x100000;
break;
case 2: //vẽ help
g.drawString(smenu[1], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;
case 3: //vẽ about
g.drawString(smenu[2], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;}
//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit", 0, h, Graphics.LEFT|Graphics.BOTTOM);
g.drawString("back", w, h, Graphics.RIGHT|Graphics.BOTTOM);
repaint();}

protected void keyReleased(int k){this.k=0;}

public void keyPressed(int k){
this.k=k;
//cho di chuyển vị trí thanh menu
if(mode==0){
if(k==-1)mindex--;
if(k==-2)mindex++;
if(mindex<0)mindex=smenu.length-1;
if(mindex==smenu.length)mindex=0;
//thay đổi mode khi lựa chọn menu
if(k==-5)mode=mindex+1;
//các lệnh cho menu góc màn hình
if(k==-6)m.notifyDestroyed();}
if(k==-7)mode=0;}

boolean check(T a, T b){
int xc=(a.d.x-b.x)/16/3;
int yc=(a.d.y-b.y)/16/3;
if(xc==0&amp;&amp;yc==0&amp;&amp;a.d.f!=-1){return true;}
return false;}

//đây là hàm tổng hợp theo thời gian mã key cho xe tự động
int ai(T a,int ak){
Random rd=new Random();
// điều kiệm để đổi hướng xe là sau 2 giây (2000millis giây)
if(lai<System.currentTimeMillis()-2000){
lai=System.currentTimeMillis();
int k=Math.abs(rd.nextInt())%4;
return -(k+1);}

//nếu như không có gì thay đổi thì cứ sau 25 millis giây cho tiến về trước 1 bước
if(System.currentTimeMillis()%25==0)
return -(1+a.f);

//nếu không thì trả về key không, tức không di chuyển
return 0;}

}


. Kết quả của ta sẽ là xe tự động di chuyển
Và sửa lại một chút cho khả năng tự nhả đạn:
int ai(T a,int ak){
Random rd=new Random();

if(lai<System.currentTimeMillis()-2000){
lai=System.currentTimeMillis();
int k=Math.abs(rd.nextInt())%4;
return -(k+1);}
if(System.currentTimeMillis()%25==0)
return -(1+a.f);
if(rd.nextInt()%3==0&amp;&amp;a.d.f==-1){return -5;}
return 0;}

trúng đạn

bây giờ tôi sẽ thêm một hàm vào trong game.java để phát hiện xem khi nào thì xe ta bị trúng đạn hoặc là xe địch bị ta bắn trúng.

//game.java

import javax.microedition.lcdui.*;

public class game extends Canvas {
String[] smenu={"play game","help","about"};
int w,h,fh,mindex=0,mode=0,k;
Midlet m;
Font f=Font.getDefaultFont();
T t,x;


public game(Midlet m){
this.m=m;
setFullScreenMode(true);
w=getWidth();
h=getHeight();
fh=f.getHeight();
t=new T(0,0,0xf0f0f0);
x=new T(w-16*3,h-16*3,0x6060f0);}

public void paint(Graphics g){
g.setColor(0);
g.fillRect(0, 0, w, h);
g.setColor(0xf0f0f0);
switch(mode){
case 0: //vẽ menu
//vẽ thanh index
g.fillRect(0, (h-fh*3)/2+mindex*fh, w, fh);
//vẽ các menu
for(int i=0;i<smenu.length;i++){
if(i==mindex){g.setColor(0);}else{g.setColor(0xf0f0f0);}
g.drawString(smenu[i],w/2 ,( h-fh*3)/2+i*fh, Graphics.HCENTER|Graphics.TOP);
}
break;
case 1: //vẽ game play
g.drawString(smenu[0], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
t.paint(g, k);
x.paint(g, 0);

//nếu như là kiểm tra thấy đạn của xe này chạm xe kia thì cho xe kia bị đổi màu, tức nhiên là trong thực tế bạn có thể cho nó biến mất

if(check(t,x)){x.color-=0x000010;}
if(check(x,t)){t.color-=0x100000;}

break;
case 2: //vẽ help
g.drawString(smenu[1], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;
case 3: //vẽ about
g.drawString(smenu[2], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;}
//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit", 0, h, Graphics.LEFT|Graphics.BOTTOM);
g.drawString("back", w, h, Graphics.RIGHT|Graphics.BOTTOM);
repaint();}

protected void keyReleased(int k){this.k=0;}

public void keyPressed(int k){
this.k=k;
//cho di chuyển vị trí thanh menu
if(mode==0){
if(k==-1)mindex--;
if(k==-2)mindex++;
if(mindex<0)mindex=smenu.length-1;
if(mindex==smenu.length)mindex=0;
//thay đổi mode khi lựa chọn menu
if(k==-5)mode=mindex+1;
//các lệnh cho menu góc màn hình
if(k==-6)m.notifyDestroyed();}
if(k==-7)mode=0;}


 //hàm check này nhận giá trị là 2 kiểu T và sau đó kiểm tra xem tọa độ đạn của xe đầu và tọa độ của xe sau nếu như mà chạm nhau thì trả lại giá trị true, tương đương với nghĩa là đã bắn trúng.
boolean check(T a, T b){
int xc=(a.d.x-b.x)/16/3;
int yc=(a.d.y-b.y)/16/3;
if(xc==0&&yc==0&&a.d.f!=-1){return true;}
return false;}

}

* kết quả như sau, sau khi trúng đạn xe địch thay đổi màu:

chuẩn bị các nguyên liệu cho game

trong game có các thành phần như là nhân vật, chướng ngại vật, kẻ thù, và những vật dụng khác cũng như ngoại cảnh. tùy theo ý thích của mỗi người mà chúng ta có thể chuẩn bị đủ mọi thứ. cũng như việc lắp ráp một chiếc xe cần phải có những thứ tạo nên chiếc xe đó như khung xe, bánh xe, dây xích, bulong, ốc vít....
bây giờ tôi sẽ làm một game đơn giản thôi và sẽ sử dụng hoàn toàn bằng lệnh, tức là không dung thêm bất cứ file nào ngoài code java. game mà tôi sắp viết nên đây là một trò bắn tăng cổ điển, giống như trò chơi trên các máy bấm hộp nhỏ nhỏ xài pin mà ngoài chợ thường bán.
. Ta cần các hình sau:
- xe tăng của ta gọi là T
- xe tăng chướng vật gọi là X
- đạn bắn ra gọi là F
mỗi một hình như vậy chúng ta sẽ tạo trên một class riêng và chúng phải có những thuộc tính sau:
- tọa độ x
- tọa độ y
1. đầu tiên tôi viết class vẽ T, như sau:
import javax.microedition.lcdui.*;

public class T {

//T này ngoài tọa độ x,y còn có thêm biến frame, và biến màu sắc
int x,y,f,color;

//biến lm ghi lại lần di chuyển cuối cùng của T
long lm=0;

//biến shape là các frame của T, gồm có 4 frame
byte[][] shape={{0,1,0,1,1,1,1,0,1},{1,0,1,1,1,1,0,1,0},{0,1,1,1,1,0,0,1,1},{1,1,0,0,1,1,1,1,0}};

//hàm khởi tạo nhận giá trị tọa độ ban đầu và màu sắc của T
public T(int x,int y,int color){
this.x=x;
this.y=y;
this.color=color;}

//hàm paint dùng để nhận biến Graphics và vẽ trên đó, cùng với biến k là phím nhấn trên bàn phím
public void paint(Graphics g,int k){

//check xem lần cuối cùng di chuyển và khoảng thời gian hiện tại có cách nhau 60 millis giây
if(lm<System.currentTimeMillis()-60){
switch(k){
case -1: f=0; y-=16; break;
case -2: f=1; y+=16; break;
case -3: f=2; x-=16; break;
case -4: f=3; x+=16; break;}
lm=System.currentTimeMillis();}

//đặt màu cho xe tăng này
g.setColor(color);

//vẽ xe tăng theo frame, nếu là 0 thì không vẽ ra được gì, nếu 1 thì vẽ 1 ô vuông, tạo nên hình chiếc xe
for(int i=0;i<shape[f].length;i++){
int c=i%3,r=(i-c)/3;
g.fillRect(x+c*16,y+r*16,16*shape[f][i],16*shape[f][i]);}
}
}

kết quả của ta sẽ như thế này. ta không cần phải thiết kế thêm class X nữa mà chúng ta dùng class T để tạo luôn xe tăng chướng ngại, chỉ cần đổi màu một chút là được, và kết quả ta được như sau:


Tất nhiên trong file game.java chúng ta cũng phải thay đổi một chút để đưa hai đối tượng T này vào:

import javax.microedition.lcdui.*;

public class game extends Canvas {
String[] smenu={"play game","help","about"};
int w,h,fh,mindex=0,mode=0,k;
Midlet m;
Font f=Font.getDefaultFont();
T t,x;

public game(Midlet m){
this.m=m;
setFullScreenMode(true);
w=getWidth();
h=getHeight();
fh=f.getHeight();
t=new T(0,0,0xf0f0f0);
x=new T(w-16*3,h-16*3,0x6060f0);}

public void paint(Graphics g){
g.setColor(0);
g.fillRect(0, 0, w, h);
g.setColor(0xf0f0f0);
switch(mode){
case 0: //vẽ menu
//vẽ thanh index
g.fillRect(0, (h-fh*3)/2+mindex*fh, w, fh);
//vẽ các menu
for(int i=0;i<smenu.length;i++){
if(i==mindex){g.setColor(0);}else{g.setColor(0xf0f0f0);}
g.drawString(smenu[i],w/2 ,( h-fh*3)/2+i*fh, Graphics.HCENTER|Graphics.TOP);
}
break;
case 1: //vẽ game play
g.drawString(smenu[0], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
t.paint(g, k);
x.paint(g, k);
break;
case 2: //vẽ help
g.drawString(smenu[1], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;
case 3: //vẽ about
g.drawString(smenu[2], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;}
//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit", 0, h, Graphics.LEFT|Graphics.BOTTOM);
g.drawString("back", w, h, Graphics.RIGHT|Graphics.BOTTOM);
repaint();}

protected void keyReleased(int k){this.k=0;}

public void keyPressed(int k){
this.k=k;
//cho di chuyển vị trí thanh menu
if(mode==0){
if(k==-1)mindex--;
if(k==-2)mindex++;
if(mindex<0 )mindex=smenu.length-1;
if(mindex==smenu.length)mindex=0;

//thay đổi mode khi lựa chọn menu
if(k==-5)mode=mindex+1;
//các lệnh cho menu góc màn hình
if(k==-6)m.notifyDestroyed();}
if(k==-7)mode=0;}
}

. Bây giờ thì viết thêm class F nữa, đây sẽ là đạn bắn ra từ các xe.
//F.java
import javax.microedition.lcdui.*;
public class F {
int x,y,color,f=-1,speed;
long lm=0;
public F(int x,int y,int color,int speed){
this.x=x;
this.y=y;
this.color=color;
this.speed=speed;}
public void fire(Graphics g,int x,int y){
if(f==-1){this.x=x; this.y=y;}
g.setColor(color);
if(System.currentTimeMillis()%500<250)
g.fillRect(this.x,this.y,16,16);

if(f!=-1&amp;&amp;lm<System.currentTimeMillis()-speed){
switch(f){
case 0: this.y-=16; break;
case 1: this.y+=16; break;
case 2: this.x-=16; break;
case 3: this.x+=16; break;}
lm=System.currentTimeMillis();}
if(f!=-1&amp;&amp;(Math.abs(this.x-x)&gt;240||Math.abs(this.y-y)&gt;320)){f=-1;}
}
}

. cuối cùng thì mỗi xe đều có khả năng nhả đạn, nên trong T class ta chỉnh sửa lại một chút để tạo khả năng bắn đạn cho các xe này.
//T.java
import javax.microedition.lcdui.*;

public class T {
F d;
int x,y,f,color;
long lm=0;
byte[][] shape={{0,1,0,1,1,1,1,0,1},{1,0,1,1,1,1,0,1,0},{0,1,1,1,1,0,0,1,1},{1,1,0,0,1,1,1,1,0}};
public T(int x,int y,int color){
this.x=x;
this.y=y;
this.color=color;
d=new F(x+16,y+16,0xf00000,500);}
boolean check(){return (lm<System.currentTimeMillis()-60);}

public void paint(Graphics g,int k){
switch(k){
case -1: f=0; if(check()){y-=16; lm=System.currentTimeMillis();} break;
case -2: f=1; if(check()){y+=16; lm=System.currentTimeMillis();} break;
case -3: f=2; if(check()){x-=16; lm=System.currentTimeMillis();} break;
case -4: f=3; if(check()){x+=16; lm=System.currentTimeMillis();}break;
case -5: d.f=this.f; break;}
g.setColor(color);
for(int i=0;i<shape[f].length;i++){
int c=i%3,r=(i-c)/3;
g.fillRect(x+c*16,y+r*16,16*shape[f][i],16*shape[f][i]);}
d.fire(g,x+16,y+16);
}
}

kết quả ta được như thế này.

Thứ Bảy, 17 tháng 11, 2012

chia các phần trong một trò chơi

hãy tưởng tượng, khi mở một trò chơi ra bạn sẽ có thể gặp một phần giới thiệu trước, sau đó là menu, mỗi một lựa chọn trong menu lại đưa ra một màn hình khác nhau, như màn chơi, phần hướng dẫn, phần tóm tắt...
bài này sẽ tạo ra một class hiển thị các phần như vậy, và menu của chúng ta chỉ có 3 mục: play game, help, about, với một nút exit ở dưới trái màn hình.
file Midlet của chúng ta sẽ chỉ có thêm một dòng so với ban đầu:
//Midlet.java
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;


public class Midlet extends MIDlet {
public void startApp() {
Display.getDisplay(this).setCurrent(new game(this));
}

public void pauseApp() {}

public void destroyApp(boolean unconditional) {}
}
tạo một class mới đặt tên là game, có nội dung như sau:
//game.java

import javax.microedition.lcdui.*;
public class game extends Canvas {

String[] smenu={"play game","help","about"};
int w,h,fh,mindex=0,mode=0;
Midlet m;
Font f=Font.getDefaultFont();

public game(Midlet m){
this.m=m;
setFullScreenMode(true);
w=getWidth();
h=getHeight();
fh=f.getHeight();}

public void paint(Graphics g){
g.setColor(0);
g.fillRect(0, 0, w, h);
g.setColor(0xf0f0f0);
switch(mode){
case 0: //vẽ menu
//vẽ thanh index
g.fillRect(0, (h-fh*3)/2+mindex*fh, w, fh);
//vẽ các menu
for(int i=0;i<smenu.length;i++){
if(i==mindex){g.setColor(0);}else{g.setColor(0xf0f0f0);}
g.drawString(smenu[i],w/2 ,( h-fh*3)/2+i*fh, Graphics.HCENTER|Graphics.TOP);
}
break;
case 1: //vẽ game play
g.drawString(smenu[0], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;
case 2: //vẽ help
g.drawString(smenu[1], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;
case 3: //vẽ about
g.drawString(smenu[2], w/2, h/2, Graphics.BASELINE|Graphics.HCENTER);
break;}
//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit", 0, h, Graphics.LEFT|Graphics.BOTTOM);
g.drawString("back", w, h, Graphics.RIGHT|Graphics.BOTTOM);
repaint();}

public void keyPressed(int k){

//cho di chuyển vị trí thanh menu
if(k==-1)mindex--;
if(k==-2)mindex++;
if(mindex<0) mindex=smenu.length-1;
if(mindex==smenu.length) mindex=0;

//thay đổi mode khi lựa chọn menu
if(k==-5)mode=mindex+1;

//các lệnh cho menu góc màn hình
if(k==-7)mode=0;
if(k==-6)m.notifyDestroyed();}
}


công cụ sử dụng trong bài viết

. đối với người dùng windows thì netbean hay java wireless toolkit là những phần mềm hỗ trợ lập trình J2ME tốt nhất. ngoài ra các bạn còn cần phải tải gói java hỗ trợ là jdk.
. để tiện lợi, tôi sẽ sử dụng netbean để tiến hành hướng dẫn trong những bài viết này, giao diện và các phần bổ trợ gần như đầy đủ.
netbean download vào trang download và chn download gói all (240Mb)
jdk gói java bổ trợ cung cấp thư viện và môi trường chạy giả lập
. Bạn cài gói JDK trước sau đó cài netBean sau, quá trình khởi động đầu tiên NetBean sẽ kiểm tra phần cứng và cấu hình hơi lâu một chút.
. để tạo một Project mới bạn bấm vào File -> new Project -> (cataloge) Java ME -> (Project) Mobile Application. sau đó nhấn Next
- tiếp theo đặt tên cho Project, bỏ chọn create Hello Midlet, bấm finish
- ở khung bên trái dưới tên project, chọn source package, click phải vào và chọn new -> Midlet, bấm finish, đây là main class của chúng ta.
- để tạo thêm những class phụ chúng ta cũng bấm phải vào source package và chọn new -> class, đặt tên và nhấn finish.
- để mở một file source chỉ cần nhấp đúp vào tên của nó bên khung bên trái.
Đã xảy ra lỗi trong tiện ích này