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ụ:
00:53:42, 04-08-2015

Chỉnh sửa java dùng bytecode
* ĐIỀU KIỆN:
if_acmpeq = bằng nhau (thay bằng ko bằng if_acmpne)
if_acmpne != không bằng nhau (if_acmpeq)
if_icmpeq = bằng nhau (if_icmpne)
if_icmpge >= lớn hơn hoặc bằng(if_icmplt)
if_icmpgt > lớn hơn (if_icmple)
if_icmple <= bé hơn hoặc bằng (if_icmpgt)
if_icmplt < bé hơn (if_icmpge)
if_icmpne != không bằng (if_icmpeq)
ifeq =0 bằng 0 (ifne)
ifge >=0 lớn hơn hoặc bằng 0 (iflt)
ifgt >0 lớn hơn 0 (ifle)
ifle <=0 bé hơn hoặc bằng 0 (ifgt)
iflt < bé hơn 0 (ifge)
ifne !=0 không bằng 0 (ifeq)
ifnonnull !=null không rỗng
ifnull =null nếu rỗng
* mảng array:
------------------
[n phần tử
newarray [loại
dup
iconst_0
[gia tri 0
[store
dup
iconst_1
[gia tri 1
[store
.......
dup
[vitri
[gia tri n
[store
--------------------
gán giá trị vào mảng
[array
[vitri index
[giatri
[xastore
lấy giá trị từ mảng
[array
[vitri index
[xaload
* giá trị chuỗi:
ldc "chuoi 1 bytes index" (2b)
hoặc
ldc_w "chuỗi 2 byte index" (3b)
số byte ở đây có ý nghĩa gì? nó là dùng để chỉ vị trí của chuỗi trong bảng hằng, với ldc thì sau nó chỉ là 1byte để chỉ vị trí (0-255), còn với ldc_w thì nó dùng 2 byte để chỉ vị trí, do đó có nhiều trường hợp chỉnh sửa byte code, thấy ldc "...." và cố tình thay bằng 1 chuỗi khác lại bị lỗi, tại sao, vì những chuỗi ban đầu không bị xóa khỏi vị trí của nó, mà vị trí bảng hằng đã lớn hơn 255, những chuỗi được thêm vào đều phải là ldc_w "....." nhưng lại xảy ra 1 vấn đề, thay ldc thành ldc_w làm tăng lên 1byte, tất cả các code cũng thay đổi vị trí và như vậy xảy ra lỗi.
* các giá trị số:
1 byte:
iconst_m1 (-1),iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5
2 byte:
bipush x
3 byte:
sipush x,ldc_w x,ldc2_w x
* phép toán:
[xadd phép cộng
[xsub phép trừ
[xmul phép nhân
[xdiv phép chia
qui tắc:
->[giá trị 1
[giá trị 2
[phép toán<-
vd:
->iconst_1
bipush 10
iadd<- (thực hiện phép cộng 1 với 10)
* gán giá trị:
->[class
[giatri
putfield [class/tenbien kieu<- (>=5b)
hoac neu la static bien
->[giatri
putstatic [class/tenbien kieu<- (>=4b)
* lấy giá trị:
->[class
getfield [class/tenbien kieu<- (>=4)
hoac neu la static bien
->getstatic [class/tenbien kieu<- (=3b)
* method hàm:
với method thông thường:
->[class
[param cac bien
invokevirtual [class/tenmethod(cac kieu bien)kieumethod <- (>=4b)
với interface method:
->[class
[param cac bien
invokeinterface [class/tenmethod(cac kieu bien)kieumethod [so bien+1 0<- (>=6b)
với static static method:
->[param cac bien
invokestatic [class/tenmethod(cac kieu bien)kieumethod <- (>=3b)
* các loại kiểu biến:
Z đúng sai (iconst_0 sai, iconst_1 đúng)
I biến int, số nguyên
J biến long, số nguyên
C biến char, từ 0-127
D biến double, số thực
F biến float, số thực
L[tên class; biến kiểu class, tạo ra từ các class.
* kiểu truy cập:
final giá trị không thể thay đổi nữa

.
private không thể truy xuất trong class khác
protected không thể truy xuất trong thư mục (package khác)
public tự do truy xuất
static được phép sẵn có, truy xuất trực tiếp qua tên class, không cần phải khởi tạo class để truy xuất.
interface,abstract chỉ chứa các khung method, không mang code, code sẽ được thể hiện trong 1 class khác kế thừa nó.
* trong quá trình chỉnh sửa class, để tránh lỗi phải chú ý tới số byte trước và sau sửa lỗi, để đơn giản nên chỉnh sửa sau cho phần chỉnh sửa và phần sửa có cùng số byte để không phải verify lại mỗi lần sửa, và cũng không thêm bất kể loại kiểu biến nào khác mà hiện đoạn code không dùng tới, ngoại trừ static class không được liệt kê như là 1 kiểu mới nào.
* quá trình verify là gì? là quá trình trình compile chuẩn bị trước các đánh dấu cho máy java đọc sau này, và máy java chỉ đọc khi nó thấy các đánh dấu đó là đúng. mỗi method có phần code cần được verify trước, code bao gồm [bảng code,[bản đồ exception,[bản đồ stack. bản đồ exception là bảng chỉ ra điểm bắt đầu kết thúc, điểm đưa ra và giá trị đưa ra một cách chính xác dựa vào bảng code, nó bao gồm các điểm goto, if_, switchtable, lookuptable, jsr, athrow,... còn bản đồ stack là một bảng chỉ rõ trong từng thời điểm máy java cần những loại biến gì để thực thi, nó cũng liên quan tới các khung trong bảng exception và toàn bộ method nữa, nó liệt kê tất cả các kiểu biến và số biến được sử dụng chính xác trong từng đoạn của code. 2 bảng exception và stack không được hiện ra trong chỉnh sửa, mà chỉ được thêm vào sau khi code đã hoàn thành xong, dựa vào code mà tạo thành, nếu ta sửa 1 class đã được verify, bảng exception và bảng stack là được tạo ra, ta chỉ cần chỉnh dư, hoặc thiếu số byte trong code là các bảng exception và stack lập tức bị lệch và dẫn tới việc java xảy ra lỗi. lỗi còn xảy ra nếu ta thêm những kiểu biến mới mà bảng stack không chỉ định.
* thay đổi kiểu truy xuất có tác dụng:đối với các kiểu truy xuất static nó có thể được thay đổi trực tiếp chỉ cần gọi tên của class chứa nó, đối với các truy xuất final, private, protected làm cho các trường và method không thể được sử dụng bên ngoài class hay trong một package khác, vậy chúng ta nên chú ý khi muốn điều khiển các biến và method này chúng ta nên chuyển chúng sang public hết, như vậy sẽ không còn gặp lỗi nhiều khi sử dụng. chúng ta không được thay một field hay method thông thường sang dạng static vì toàn bộ các class khác đã dùng nó như một cách thông thường chứ không phải static, khi chúng ta thay đổi lập tức bị lỗi.
* những class mang giao diện, đầu tiên là MIDlet nó được thực hiện đầu tiên và giống như là khởi nguồn cho tất cả, ở đó có chứa những thứ cơ bản nhất, muốn chuyển hiện thị phải thông qua nó. Canvas và GameCanvas là đồ họa hiển thị trong phần mềm, mà quan trong trong đó chính là Graphics mà nó mang, các hàm có liên quan tới Graphics chắc chắn là phải vẽ vời gì đó trong phần mềm, mà nó là thứ sẽ hiện lên trên màn hình.
* viết một class mới dùng hàm static sẽ dễ dàng thay thế những hàm thông thường trong các class, vì sao ư? vì nó có thể thêm vào 1 cách phù hợp và nhanh chóng nhất. hãy xem 1 ví dụ:
->ldc "day la 1 chuoi"
invokevirtual java/lang/String/getBytes()[B <-

và thay thế bằng 1 static:
-> ldc "day la 1 chuoi"
invokestatic mmmm/sangbyte(Ljava/lang/String;)[B <-

thấy chưa, bây giờ thì thay vì load class thì tất cả đều biến thành param trong static.
* vấn đề tự do trong chỉnh sửa code, mặc dù verify có qui tắc hết sức chặt chẽ nhưng nó lại chừa phần còn lại của code cho mặc nhiên, điều đó có nghĩa là bạn muốn thêm hay chỉnh sửa gì ở khung cuối cùng của code cũng được, đó là trước [xreturn cuối code.
* chỉ số và thông báo, một vấn đề để quan tâm khi chỉnh game là làm gì? quan sát các thông tin thuôc tính của các chỉ số muốn chỉnh, một người quan sát kĩ và nắm bắt được các logic sẽ nhanh chóng tìm ra được cách tìm ra phim cần chỉnh sửa, đó là lúc không còn giới hạn nào nữa.
ví dụ:
- khi tăng tiền game, có chữ "đạt được tiền", vậy chúng ta sẽ tìm cả cụm từ này hoặc chỉ 1 từ thôi cũng được, đạt được tiền chắc chắn là phải cộng vào biến chứa tiền, ở đâu đó gần đoạn text sẽ có [xadd với cấu trúc mà ta đã biết, ta sẽ dễ dàng nhận ra đâu là biến tiền.
- khi mua đồ, hết tiền và có thông báo "không đủ tiền", tức nhiên là với món đồ mà ta cần mua, như vậy ta cũng tìm kiếm chuỗi này, tới đó, chắc chắn có sự so sánh giữa hai biến, biến tiền của nhân vật và biến tiền món hàng, chúng ta có thể tìm trước đó if[... để tìm ra xem 2 biến nào được so sánh và làm tiếp.
- có những game không có chứa những chuỗi trong class, tìm mãi cũng chẳng ra đâu, chúng ta cần phải quan sát những thuộc tính, mỗi phần mềm và người thiết kế có 1 cách riêng để che giấu những thông tin này, chỉ là người muốn thay đổi có tìm được hay không, nhất là chỉ với những công cụ đơn giản nhất.
* thay thế thế nào? tùy từng trường hợp, mà có thể cho tăng lên, không giảm hoặc qua mặt.
ví dụ: ta tìm được biến mn trong class x là biến tiền, thì hàm trừ tiền có dạng thế này:
->getfield x/mn I
bipush 100
isub
putfield x/mn I<-
. ko cho trừ tiền nữa
->getfield x/mn I
bipush 0
isub
putfield x/mn I<-
. tăng thêm tiền
->getfield x/mn I
bipush 100
iadd
putfield x/mn I<-

ví dụ 2: giả sử ta tìm được hàm so sánh mua hàng thế này:
->iload 3
aload_0
getfield x/mn I
ifle Label10 <-

.qua mặt thế này
->iload 3
aload_0
getfield x/mn I
if_icmpne Label10 <-

còn đối với trường hợp là ldc thì ta phải thay trực tiếp trong bảng hằng constantpool, hoặc nếu code tự do thì xem: nếu bảng hằng nhiều hơn 255 thì dùng ldc_w, ít hơn 255 thì dùng ldc.
end.
.:viết bởi holyeyed:.

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
01:02:36, 04-08-2015

NHỮNG OPCODE CƠ BẢN CẦN PHẢI HIỂU
* các phần của file class:file class gồm có nhiều thông tin, nhưng khi thực hiện trên bytecode chỉ cần biết nó có các phần sau:
- constant pools:
(bảng hằng) cũng không rõ nó dịch ra tiếng Việt là gì thì sẽ chính xác hơn, nhưng rõ ràng nó là những hằng số. thứ tự của mỗi hằng số chính là index của nó, và trong class sẽ sử dụng nó để tạo thành cấu trúc file, có những hằng số được tạo ra bằng cách ghép các hằng số có giá trị khác lại. index bắt đầu từ 1, index 0 không được sử dụng vì nó làm lẫn lộn với opcode null. giống như thế này:
....
0 null
1 a
2 m
3 ()V
4 "day la chuoi"
........
- field:các trường hay biến trong class, được sử dụng trong các hàm, mỗi field này có dạng
[truy xuất [tên [kiểu
phần kiểu này có chủ yếu mấy dạng sau:
B kiểu byte số có giá trị từ -127 đến 127
C kiểu char kí tự, có giá trị 0 đến 127
D kiểu double, số thực
F kiểu float, số thực
I kiểu int, số nguyên lớn hơn byte
J kiểu long, số nguyên lớn hơn int
S kiểu short, số nguyên lớn hơn int, nhỏ hơn long
Z kiểu đúng sai, chỉ mang 2 gí trị, 0, 1
L[x; kiểu load class, [x là tên class, bắt đầu bằng chữ "L" và kết thúc tại ";"
[[kiểu kiểu array, bắt đầu bằng "[", phần kiểu là các kiểu trên.
vd: public a I có nghĩa là field tên a, kiểu int.
private b Lh; có nghĩa là field tên b, được tạo ra từ load class h.
- method:hàm, là nơi chứa các code thực thi chương trình.
[truy xuất [tên ([tham số) [kiểu
phần kiểu ngoài những kiểu như của field thì còn có kiểu void V, kiểu V là kiểu chỉ thực thi mà ko trả lại gì cả.
vd: private meme (ILf;)V có nghĩa là hàm tên meme, cần dùng tham số kiểu int, và tham số kiểu class f, kiểu trả lại là thực thi V.
- code trong method là tập hợp những phần tử bắt đầu bằng opcode và giá trị theo sau của từng opcode, vì có hơn 100 opcode nên sẽ không được nói chi tiết ở đây. chỉ cần biết là mỗi opcode là 1 số có index nhất định và có cấu trúc của nó, có opcode chỉ đứng 1 mình, có opcode cần có giá trị theo sau, giá trị đi trước. những giá trị này được lấy từ bảng hằng constant pool lúc nãy đã nói.
vd:
......
iconst_0 ->là opcode đưa ra số 0, nó ko cần có gì trước sau hết.

ireturn ->là opcode trả về 1 số nguyên, vậy trước nó phải có 1 số nguyên.
ldc "đây là chuỗi" ->ldc là opcode dẫn ra 1 chuỗi hoặc 1 số, nó buộc sau nó phải là 1 index dẫn đến 1 chuỗi trong bảng hằng.
getfield a/f I -> getfield là opcode lấy giá trị từ trường trong class, phía trước nó phải có 1 class, sau nó là "a/f I" chỉ ra tên class, tên biến và kiểu biến được lấy.
invokevirtual a/meme()I -> invokevirtual là opcode thực hiện hàm, trước nó cần có đủ class chứa hàm, các ham số cần thực hiện hàm, phía sau là tên class, tên hàm, tham số và kiểu trả về của hàm.
invokestatic b/bebe(I)V ->invokestatic là opcode thực hiện hàm static, trước nó chỉ cần đủ tham số, không cần class để thực hiện hàm, phía sau vẫn giống như hàm thông thường, gồm tên class, tên hàm, tham số, kiểu trả về.
if_icmplt label10 ->if_icmplt là opcode điều kiện so sánh 2 số nguyên, vì vậy nó cần có 2 giá trị số nguyên phía trước, sau nó là 1 số, chỉ ra nơi sẽ chuyển đến khi điều kiện đúng.
goto label67 ->goto là opcode chuyển đến 1 điểm trong code để tiếp tục thực thi, trước nó chẳng cần gì, sau nó phải là 1 số chỉ ra điểm tiếp tục trong code.
......
* khi chỉnh sửa code bằng bytecode mobile:
nếu bạn chỉnh sửa giá trị trong constant pools thì tất cả các code có lấy giá trị từ nó đều thay đổi theo, vì nó là khởi nguồn của tất cả.
vd: trong bảng hằng có giá trị chuỗi là "con khỉ", giá trị này được sử dụng trong method a và method b, thì khi bạn sửa trong bảng hằng thì cả a và b đều thay đổi.
nếu bạn chỉnh sửa giá trị trong code của hàm thì constant pool sẽ được thêm những giá trị mới, và chỉ có hàm đó được thay giá trị, những hàm khác sử dụng cùng giá trị không bị thay đổi.
vd: như ví dụ trên, nếu bạn mở hàm a ra và chỉnh lại ->ldc "con khỉ" <- thì bảng hằng sẽ thêm vài giá trị mới, và giá trị "con khỉ" trong b không bị thay đổi.
* iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5 là giá trị từ 0 đến 5 sau code này phải có 1 code dùng giá trị nguyên này.
* bipush [x là đưa ra giá trị số nguyên, [x là 1 số nguyên, sau code này phải có 1 code dùng giá trị nguyên này.
* sipush [x cũng đưa ra 1 số nguyên, [x là 1 số nguyên, sau code này phải có 1 code dùng giá trị nguyên này.
* ldc [.... dùng để đưa ra chuỗi hoặc số, sau code này phải có 1 code dùng giá trị này.
* getfield [..., getstatic [.... dùng để lấy 1 giá trị trong một class nào đó, trước getfield phải có giá trị class, sau code này phải có 1 code dùng giá trị này.
* goto [x, goto_w [x dùng để chuyển đến 1 vị trí nào đó trong code, hãy tưởng tượng code là là 1 dãy gồm nhiều ô, ghép lại thành 1 hàng dài, [x là chính là vị trí cần đến.
* if[... [x có nhiều loại if, trước if phải có giá trị để so sánh, nếu là if_[... thì cần 2 giá trị, if[... cần 1 giá trị thôi vì so sánh với 0 hoặc null. [x là điểm cần đi đến nếu điều kiện so sánh đúng, nếu ko đúng thì tiếp tục thực hiện code.
* [xload và [xstore và [xreturn : load tức nhiên là lấy giá trị, store là gán giá trị, và return là trả về, nó mang tính tức thời giống như tải giá trị vào bộ nhớ ram rồi sử dụng, sử dụng xong thì giải phóng. load và store ta thấy suốt trong code, còn return thì là nơi code sẽ kết thúc thực thi. load và store đều có theo sau bởi 1 vị trí, đó là vị trí lưu trữ, mặc định vị trí lưu trữ 0 là class đang thực thi hàm này, trừ static method vị trí 0 vẫn trống. trước khi load phải store, trước store phải có giá trị, sau load phải có code nhận giá trị.
trong đó x có thể là 1 trong số những giá trị này:
llong
sshort
bbyte
cchar
ffloat
ddouble
zboolean, đúng sai
areference, load class
tùy vào kiểu của method mà [xreturn sẽ thuộc vào 1 trong các giá trị sau: nếu là số thì dùng d, i, l, f, nếu là load class, array thì dùng areturn, nếu là boolean đúng sai thì dùng ireturn.
* [xaload và [xastore : cũng giống như ở trên, nhưng đây là dùng cho array, lấy và gán giá trị cho 1 phần tử trong array.
* nop và pop: nop là opcode null, giá trị của nó là 0, nó chẳng làm gì cả, nhưng nếu nó chen ngang những thành phần của opcode khác sẽ gây lỗi, pop là loại bỏ giá trị đưa ra, trước pop phải có 1 giá trị, ví dụ:
-> invokestatic f/h()I
pop <-như vậy giá trị int được trả lại từ method sẽ bị loại bỏ, ko sử dụng nó.
* [xadd, [xsub, [xmul và [xdiv : là các hàm tính toán có sẵn add là cộng, sub là trừ, mul là nhân, div là chia. trước nó phải có 2 giá trị để được thực hiện, sau nó phải có 1 code nhận giá trị này.
->iconts_4
bipush 7
iadd
istore_1 <-cộng 4 với 7 và lưu vào vị trí 1.
một ví dụ:
->
iload_2 //tải số nguyên lưu tại vị trí 2
iload_3 //tải số nguyên lưu tại vị trí 3
ineg //đổi dấu số đằng trước nó, ở đây là số lưu tại 3, trả về số nguyên âm.
invokestatic bk/a(II)I //nhận số lưu tại 2, và số âm lưu tại 3 và thực hiện hàm, trả lại số nguyên.
istore_2 //lưu số nguyên do hàm trả ra vào vị trí 2
iconst_0 //đưa ra 1 số 0
istore_3 //lưu số 0 vào vị trí 3
iload 4 //tải số lưu tại 4
ifeq 50 //nếu số 4 mà bằng 0 thì đi tới vị trí code 50.
<-
end.
.:viết bởi holyeyed:.

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
18:22:51, 31-05-2016

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 đủ.

img


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.

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
18:31:07, 31-05-2016

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:

<?php
//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) {}
}
?>

Copy code

tạo một class mới đặt tên là game, có nội dung như sau:
<?php
//game.java

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

Stringsmenu={"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(00wh);
g.setColor(0xf0f0f0);
switch(
mode){
case 
0//vẽ menu
//vẽ thanh index
g.fillRect(0, (h-fh*3)/2+mindex*fhwfh);
//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/,( h-fh*3)/2+i*fhGraphics.HCENTER|Graphics.TOP);
}
break;
case 
1//vẽ game play
g.drawString(smenu[0w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;
case 
2//vẽ help
g.drawString(smenu[1w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;
case 
3//vẽ about
g.drawString(smenu[2w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;}
//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit"0hGraphics.LEFT|Graphics.BOTTOM);
g.drawString("back"whGraphics.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<0mindex=smenu.length-1;
if(
mindex==smenu.lengthmindex=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();}
}
?>

Copy code


img

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
18:34:46, 31-05-2016

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:

<?php
import javax
.microedition.lcdui.*;

public class 
{

//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 -
1f=0y-=16; break;
case -
2f=1y+=16; break;
case -
3f=2x-=16; break;
case -
4f=3x+=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);}
}
}
?>

Copy code


img
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:
img
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:
<?php
import javax
.microedition.lcdui.*;

public class 
game extends Canvas {
Stringsmenu={"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(00wh);
g.setColor(0xf0f0f0);
switch(
mode){
case 
0//vẽ menu
//vẽ thanh index
g.fillRect(0, (h-fh*3)/2+mindex*fhwfh);
//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/,( h-fh*3)/2+i*fhGraphics.HCENTER|Graphics.TOP);
}
break;
case 
1//vẽ game play
g.drawString(smenu[0w/2h/2Graphics.BASELINE|Graphics.HCENTER);
t.paint(gk);
x.paint(gk);
break;
case 
2//vẽ help
g.drawString(smenu[1w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;
case 
3//vẽ about
g.drawString(smenu[2w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;}
//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit"0hGraphics.LEFT|Graphics.BOTTOM);
g.drawString("back"whGraphics.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<)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;}
}
?>

Copy code

Bây giờ thì viết thêm class F nữa, đây sẽ là đạn bắn ra từ các xe.
<?php
//F.java
import javax.microedition.lcdui.*;
public class 
{
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=xthis.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 
0this.y-=16; break;
case 
1this.y+=16; break;
case 
2this.x-=16; break;
case 
3this.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;}
}
}
?>

Copy code

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.

<?php
//T.java
import javax.microedition.lcdui.*;

public class 
{
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 -
1f=0; if(check()){y-=16lm=System.currentTimeMillis();} break;
case -
2f=1; if(check()){y+=16lm=System.currentTimeMillis();} break;
case -
3f=2; if(check()){x-=16lm=System.currentTimeMillis();} break;
case -
4f=3; if(check()){x+=16lm=System.currentTimeMillis();}break;
case -
5d.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);
}
}
?>

Copy code

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

img

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
18:35:05, 31-05-2016

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.

<?php
//game.java

import javax.microedition.lcdui.*;

public class 
game extends Canvas {
Stringsmenu={"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(00wh);
g.setColor(0xf0f0f0);
switch(
mode){
case 
0//vẽ menu
//vẽ thanh index
g.fillRect(0, (h-fh*3)/2+mindex*fhwfh);
//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/,( h-fh*3)/2+i*fhGraphics.HCENTER|Graphics.TOP);
}
break;
case 
1//vẽ game play
g.drawString(smenu[0w/2h/2Graphics.BASELINE|Graphics.HCENTER);
t.paint(gk);
x.paint(g0);

//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[1w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;
case 
3//vẽ about
g.drawString(smenu[2w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;}
//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit"0hGraphics.LEFT|Graphics.BOTTOM);
g.drawString("back"whGraphics.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 aT 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;}
}
?>

Copy code

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

img

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
18:36:01, 31-05-2016

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.

<?php
//game.java

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

public class 
game extends Canvas {
Stringsmenu={"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(00wh);
g.setColor(0xf0f0f0);
switch(
mode){
case 
0//vẽ menu
//vẽ thanh index

g.fillRect(0, (h-fh*3)/2+mindex*fhwfh);
//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/,( h-fh*3)/2+i*fhGraphics.HCENTER|Graphics.TOP);
}
break;
case 
1//vẽ game play
g.drawString(smenu[0w/2h/2Graphics.BASELINE|Graphics.HCENTER);
t.paint(gk);
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[1w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;
case 
3//vẽ about
g.drawString(smenu[2w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;}
//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit"0hGraphics.LEFT|Graphics.BOTTOM);
g.drawString("back"whGraphics.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 aT 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;}

}

?>

Copy code

Kết quả của ta sẽ là xe tự động di chuyển

img
Và sửa lại một chút cho khả năng tự nhả đạn:
<?php
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;}
?>

Copy code

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
18:36:18, 31-05-2016

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

<?php
import javax
.microedition.lcdui.*;

public class 
{
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 wint 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 -
1f=0; if(check()){y-=16; if(y<0)y=0lm=System.currentTimeMillis();} break;
case -
2f=1; if(check()){y+=16; if(y>h-16*3)y=h-16*3lm=System.currentTimeMillis();} break;
case -
3f=2; if(check()){x-=16; if(x<0)x=0lm=System.currentTimeMillis();} break;
case -
4f=3; if(check()){x+=16; if(x>w-16*3x=w-16*3lm=System.currentTimeMillis();}break;
case -
5d.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);
}
}
?>

Copy code

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 t và x
<?php
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);}
?>

Copy code

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

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
18:36:35, 31-05-2016

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

<?php
import javax
.microedition.lcdui.*;

public class 
{
T x;
boolean die;
int k;
public 
E(int xint yint colorint 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 {
Stringsmenu={"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;
Ee;
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(00wh);
g.setColor(0xf0f0f0);
switch(
mode){
case 
0//vẽ menu
//vẽ thanh index
g.fillRect(0, (h-fh*3)/2+mindex*fhwfh);
//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/,( h-fh*3)/2+i*fhGraphics.HCENTER|Graphics.TOP);
}
break;
case 
1//vẽ game play
g.drawString(smenu[0w/2h/2Graphics.BASELINE|Graphics.HCENTER);
t.paint(gk);
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[1w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;
case 
3//vẽ about
g.drawString(smenu[2w/2h/2Graphics.BASELINE|Graphics.HCENTER);
break;}

//vẽ nút lệnh
g.setColor(0xf0f0f0);
g.drawString("exit"0hGraphics.LEFT|Graphics.BOTTOM);
g.drawString("back"whGraphics.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 aT 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;}
}
?>

Copy code

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...
img


Src: src-32444.zip

Like: 0
avatar by Pham_loi Pham_loi
Chức vụ:
18:36:52, 31-05-2016

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) :
C:\Users\WIN7\Documents\NetBeansProjects\textfield\src\textfield.java

<?php
//textfield.java
 
import javax.microedition.lcdui.*;
 
 public class 
textfield {
 
     
int xywlk 0np 0fhtcolor 0bgcolor 0xf0f0f0;
     
String s ""title;
     
//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
     
Stringac = {" 0"".,1""abc2""def3""ghi4""jkl5""mno6""pqrs7""tuv8""wxyz9"};
     
long lp 0rr 0;
     
boolean focus false;
     
Font f Font.getFont(008);
 
//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)
     
public textfield(String titleint xint yint w) {
         
this.title title;
         
this.x;
         
this.y;
         
this.w;
         
fh f.getHeight();
     }
 
     
String getString() {
         return 
s;
     }
 
//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
     
public void paint(Graphics gint kboolean focus) {
         
g.setFont(f);
         
this.focus focus;
         
//nếu có tác động focus==true thì cho thực hiện vẽ chuỗi theo mã phím
         
if (focus && cr() - lp rr) {
             
add(k);
         }
         
//các hàm vẽ liên quan đến việc vẽ chuỗi s ra màn hình
         
int slen f.stringWidth(s);
         
int kh slen w;
         
g.setColor(bgcolor);
         
g.fillRect(xfhwfh);
         
g.drawString(title ":"xyGraphics.TOP Graphics.LEFT);
         
g.setColor(tcolor);
         
g.setClip(xfhwfh);
         
g.drawString(+ (focus "|" ""), - (kh kh 0), fhGraphics.TOP Graphics.LEFT);
 
 
     }
 
     
void add(int k) {
         
//nếu key là -3(phím qua trái) thì cho xóa kí tự
         
if (== -&& s.length() > 0) {
             
s.substring(0s.length() - 1);
             
lk k;
             
lp cr();
         } else if (
== -6) {//nếu key là -6 thì thôi không tác động đến textfield này nữa
              
focus false;
         } else {
             
//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
             
int sk 48;
            
//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
             
if (sk >= 0) {
                 
//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).
                 
if (cr() - 800 lp && lk == sk) {
                     
np++;
                     if (
np == ac[sk.length()) {
                         
np 0;
                     }
                     
s.substring(0s.length() - 1);
                     
+= ac[sk.charAt(np);
                 } 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ị)
                     
np 0;
                     
+= ac[sk.charAt(np);
                 }
                 
//đặ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)
                 
lk sk;
                 
lp cr();
             }
 
         }
     }
 
//hàm cr() trả lại thời gian hiện thời
     
long cr() {
         return 
System.currentTimeMillis();
     }
 }
 
 class 
canvas extends Canvas {
 
//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
     
textfield tf = new textfield("nhập văn bản"012040);
     
int w getWidth(), getHeight(), 0;
 
     public 
canvas() {
     }
 
    public 
void paint(Graphics g) {
    
g.setColor(0);
    
g.fillRect(00wh);
    
//thực hiện lệnnh vẽ textfield ra màn hình lên Graphics g và với mã phím k
    
tf.paint(gktrue);
    
k=0;
    
repaint();
    }

     public 
void keyPressed(int k) {
    
this.k;
     }

    public 
void keyReleased(int k) {
    
this.0;
     }
    }
?>

Copy code


• ở đâ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.

Source: src-30856.zip

Jar: textfield-62592.jar

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

Polaroid