Thứ Năm, 30 tháng 8, 2012

Tổng hợp code một số game Java đơn giản

[Hướng dẫn]Viết một số game bằng Java
Hướng dẫn chạy các project game Java đã viết ở trên:
1. SDK: Eclipse IDE for Java Developers (http://eclipse.org/downloads/)
2. Download Eclipse về, giải nén và cài đặt.
3. Mở Eclipse.
4. File > Import > General > Existing Project into Workspace > Next.
5. Browse tới thư mục chứa project, chọn project muốn thêm (1 hoặc nhiều).
6. Finish.
7. Sau đó build project bạn đã thêm > chạy được chương trình.
8. (Optional) Nếu muốn build ra file jar hay file thực thi trên Windows, cần có tools khác hỗ trợ, về vấn đề này vui lòng tìm hiểu thêm ở Google.

Download toàn bộ code game Java ở dưới :


hoặc:
http://www.fshare.vn/file/UWOH3NSPV19W 

Pass: vuson.tk

Một số hướng dẫn để viết game


[Hướng dẫn]Viết game Ailen bằng Java
I. Giới thiệu
Trong phần hướng dẫn này, chúng ta sẽ tạo ra một phiên bản đơn giản của trò Bắn ruồi - Space Invaders.
Space Invaders là một trò chơi arcade được thiết kế bởi Tomohiro Nishikado. Lần đầu tiên phát hành năm 1978. Người chơi điều khiển một khẩu pháo (phi thuyền, ...). Mục đích là cứu trái đất khỏi cuộc xâm lược của quân xâm lược gian ác từ hành tinh khác.
Trong phiên bản này, chúng ta có 24 quân xâm lược, có thể thay đổi mỗi level là một số lượng hoặc cách bố trí khác nhau. Khi người chơi bắn tên lửa, họ sẽ phải chờ đến khi tên lửa trúng quân xâm lược hoặc phía trên của form. Người chơi bắn bằng phím Space, di chuyển bằng A (trái), D (phải). Quân xâm lược bắn bom ngẫu nhiên, tương tự như người chơi, chúng chỉ có thể bắn quả bom khác khi bom của chúng đụng người chơi (chắc không cần, vì trúng là chết, cần jì trái khác nữa :biggrin
Cười mỉm

 hoặc rơi xuống phía dưới cùng của form.
Game có tất cả 7 tập tin: Aliens.java, Player.java, Board.java, SpaceInvaders.java, Commons.java, Sprite.java, Shot.java được đính kèm ở cuối bài.

II. Hướng dẫn
Aliens.java
Đây là lớp để vẽ nên chuyển động của các aliens (quân xâm lược). Mỗi aliens có một lớp Bomb bên trong nó.

Mã:

public void act (int direction) (
this.x += direction;
)


Hàm act() được gọi từ lớp Board. Nó được sử dụng để di chuyển 1 alien theo hướng ngang.

Mã:

public Bomb getBomb () (
return bomb;
)


Hàm getBomb () được gọi khi 1 alien bắn bom.

Player.java
Đây là lớp vẽ chuyển động của người chơi, chúng ta di chuyển bằng phím A, D và bắn bằng phím Space.

Mã:

private final int START_Y = 280;
private final int START_X = 270;


Đây là các tọa độ ban đầu của người chơi.

Mã:

if (key == KeyEvent.VK_A)
{
dx = -2;
}


Nếu chúng ta bấm phím A, biến dx (độ lệch theo phương ngang) được thiết lập là -2. Lần sau khi hàm act() được gọi, người chơi sẽ được di chuyển về bên trái.

Mã:

if (key == KeyEvent.VK_A)
{
dx = 0;
}
if (key == KeyEvent.VK_D)
{
dx = 0;
}


Khi chúng ta thả phím nhấn ra, khẩu pháo sẽ không di chuyển do dx đã được thiết lập về 0.

Shot.java
Đây là lớp vẽ nên các tên lửa do người chơi bắn ra. Các biến H_SPACE và hằng V_SPACE được sử dụng để định vị các tên lửa một cách thích hợp.
Board.java
Logic chính của trò chơi là nằm ở lớp này.

Mã:

for (int i = 0; i <4; i + +) {
for (int j = 0; j <6; i + +) {
Alien alien = new Alien (alienX + 18 * j, alienY + 18 * i);
alien.setImage (ii.getImage ());
aliens.add (alien);
}
}
player = new player ();
shot = new Shot ();


Trong hàm gameInit () chúng tôi thiết lập 24 alien. Kích cỡ của mỗi alien là 12x12px. Chúng ta đặt 6px trống giữa các alien. Chúng ta cũng tạo ra người chơi và tên lửa.

Mã:

public void drawBombing (Graphics g) {
Iterator i3 = aliens.iterator ();
while (i3.hasNext ()) {
Alien a = (Alien) i3.next ();
Alien.Bomb b = a.getBomb ();
if (! b.isDestroyed ()) {
g.drawImage (b.getImage (), b.getX (), b.getY (), this);
}
}
}


Các hàm drawBombing () dùng để vẽ bom của các alien.

Mã:

if (ingame) {
g.drawLine (0, GROUND, BOARD_WIDTH, GROUND);
drawAliens (g);
drawPlayer (g);
drawShot (g);
drawBombing (g);
}


Bên trong hàm paint(), chúng ta vẽ ra mặt đất, alien, người chơi, tên lửa và bom.
Sau đó, chúng ta sẽ kiểm tra bằng hàm animationCycle().

Mã:

if (deaths == NUMBER_OF_ALIENS_TO_DESTROY) {
ingame = false;
message = "Game won!";
}


Nếu chúng ta tiêu diệt tất cả alien, game sẽ dừng và chúng ta thắng.

Mã:

if (alien.isVisible () & & shot.isVisible ()) {
if (shotX> = (alienX) & &
shotX <= (alienX + ALIEN_WIDTH) & &
shotY> = (alienY) & &
shotY <= (alienY + ALIEN_HEIGHT)) (
ImageIcon ii = new ImageIcon (Expl);
alien.setImage (ii.getImage ());
alien.setDying (true);
deaths + +;
shot.die ();
}
}


Nếu tên lửa bắn bởi người chơi đụng alien, alien đó sẽ mất đi. Chính xác hơn, cờ báo chết được thiết lập. Chúng ta sử dụng nó để hiển thị một vụ nổ. Biến deaths được tăng lên.

Mã:

if (x> = BOARD_WIDTH - BORDER_RIGHT && direction = -1) {
direction = -1;
Iterator i1 = aliens.iterator ();
while (i1.hasNext ())
Alien a2 = (Alien) i1.next ();
a2.setY (a2.getY () + GO_DOWN);
}
}


Nếu alien đến cuối biên phải của form, chúng di chuyển xuống và thay đổi hướng của chúng về hướng ngược lại (theo phương ngang).

Mã:

Iterator it = aliens.iterator ();
while(it.hasNext ()) {
Alien alien = (Alien) it.next ();
if (alien.isVisible ()) {
int y = alien.getY ();
if (y> GROUND - ALIEN_HEIGHT) {
ingame = false;
message = "Invasion!";
}
alien.act (direction);
}
}


Aliens di chuyển. Nếu chúng tiếp cận được đáy, chúng ta thua.

Mã:

int shot = generator.nextInt (15);
Alien a = (Alien) i3.next ();
Alien.Bomb b = a.getBomb ();
if (shot == CHANCE && a.isVisible () & & b.isDestroyed ()) {
b.setDestroyed (false);
b.setX (a.getX ());
b.setY (a.getY ());
}


Đây là mã xác định xem những alien có thả bom hay không. Những alien được thả bom là những alien chưa bị hủy. Dễ hiểu hơn, nó phải nhìn thấy được. Cờ "đã nổ" của bom được thiết lập. Nói cách khác, đó là quả bom đầu tiên của alien nếu quả trước đó đã đụng biên dưới của form. Nếu cả hai điều kiện được thỏa mãn, bom được thả.

Mã:

if (! b.isDestroyed ()) {
b.setY (b.getY () + 1);
if (b.getY ()> = GROUND - BOMB_HEIGHT) {
b.setDestroyed (true);
}
}


Nếu quả bom này là không bị nổ, nó di chuyển 1 px xuống dưới. Nếu đến cuối biên dưới, cờ đã nổ được thiết lập. Những alien đã sẵn sàng để thả một quả bom.

Game khi hoàn thành (minh họa):
[Image: spaceinvaders.png]


File đính kèm



[Hướng dẫn]Viết game Pacman bằng Java


I. Giới thiệu
Trong phần này chúng ta sẽ viết 1 phiên bản đơn giản của trò chơi Pacman.
Pacman là một trò chơi arcade ban đầu được phát triển bởi một công ty Nhật Bản Namco năm 1980. Sau đó, Pacman đã trở thành một trong những trò chơi arcade phổ biến nhất bao giờ hết.
Ví dụ này là một phiên bản đã đơn giản hóa để có thể hiểu dễ dàng hơn.
Mục tiêu của trò chơi là thu thập tất cả các điểm trong mê cung và tránh những bóng ma. Mê cung này bao gồm 15 x 15 ô vuông. Cấu trúc của mê cung là dựa trên một dãy số nguyên đơn giản. Pacman có ba cuộc sống. Chúng tôi cũng tính điểm trong game này.
Trò chơi này bao gồm hai tập tin: Board.java và Pacman.javaII. Hướng dẫn

Mã:

final short leveldata [] = (19, 26, 26, 26, 18, ... );


Những con số này tạo nên mê cung. Chúng cung cấp thông tin mà chúng ta tạo ra các góc và các điểm dựa trên nó. Ví dụ số 19 ở góc trên bên trái chỉ ra đó là ô vuông đó là góc trên, bên trái và có 1 điểm. (16 + 2 + 1)

Mã:

public void doAnimation () {
pacanimcount -;
if (pacanimcount <= 0) {
pacanimcount = pacanimdelay;
pacmananimpos = pacmananimpos + pacanimdir;
if (pacmananimpos == (pacmananimcount - 1) | | pacmananimpos == 0)
pacanimdir =-pacanimdir;
}
}


Hàm doAnimation () dựa trên biến đếm pâcnimcount để quyết định hình ảnh nào của pacman sẽ được vẽ ra. Có bốn hình ảnh pacman. Ngoài ra còn có một biến pacanimdelay, làm cho hình ảnh động chậm hơn một chút. Nếu không pacman sẽ mở miệng quá nhanh.

Mã:

boolean finished = true;
while (i      if ((screendata [i] & 16) != false)
finished = false;
i++;
)


Mã này là một phần của hàm checkMaze (). Nó sẽ kiểm tra, nếu còn điểm nào cho Pacman ăn. Số 16 tượng trưng cho một điểm. Nếu tất cả các điểm đã được ăn hết, chúng ta chuyển tới cấp độ tiếp theo.

Tiếp theo, chúng ta sẽ kiểm tra việc moveGhosts (). Những bóng ma di chuyển một ô và sau đó quyết định, có thay đổi hướng hay không.

Mã:

if (ghostx [i]% blocksize == 0 & & ghosty [i]% blocksize == 0) (


Tiếp tục chỉ khi bạn đã hoàn thành việc di chuyển một ô.

Mã:

pos = ghostx [i] / blocksize + nrofblocks * (int) (ghosty [i] / blocksize);


Dòng này sẽ xác định vị trí của ma. Có 225 vị trí trên lý thuyết. (Ma không thể di chuyển qua tường.)

Mã:

if ((screendata [pos] & 1) == 0 & & ghostdx [i] = 1!) {
dx [count] = -1;
dy [count] = 0;
count + +;
}


Nếu không có vật cản ở bên trái và con ma không phải đã được di chuyển về bên phải, các con ma sẽ di chuyển sang trái. Điều này có ý nghĩa gì? Nếu con ma đi vào một đường hầm, nó sẽ tiếp tục trong cùng một hướng cho đến khi ra khỏi đường hầm. Chuyển động của bóng ma là một phần ngẫu nhiên. Chúng tôi không áp dụng sự ngẫu nhiên này bên trong đường hầm dài. Những con ma có thể mắc kẹt ở đó.

Mã:

if (pacmanx > (ghostx [i] - 12) && pacmanx <(ghostx [i] + 12) &&
pacmany > (ghosty [i] - 12) && pacmany < (ghosty [i] + 12) &&
ingame) {
death = true;
deathcounter = 64;
}


Nếu có va chạm giữa một ghost và pacman => chết.

Tiếp theo chúng ta sẽ thực hiện hàm movePacman(). Biến reqdx và reqdy được xác định trong các lớp bên trong TAdapter. Các biến này được kiểm soát bằng các phím mũi tên.

Mã:

if ((ch & 16) = 0) {
screendata [pos] = (short) (ch & 15);
score++;
}


Nếu pacman di chuyển đến một vị trí, nơi có một điểm, chúng tôi loại điểm đó ra khỏi mê cung và tăng giá trị điểm số.

Mã:

if ((pacmandx == -1 & & == 0 & & ch pacmandy (& 1) = 0!) ||
(pacmandx == 1 & & == 0 & & ch pacmandy (& 4) = 0!) ||
(pacmandx == 0 & & == -1 pacmandy & & ch (& 2) = 0!) ||
(pacmandx == 0 & & == 1 pacmandy & & ch (& 8) = 0!)) {
pacmandx = 0;
pacmandy = 0;
}


Nếu pacman không thể di chuyển tiếp theo hướng hiện nay, chúng ta sẽ vẽ nó đứng tại chỗ.

Mã:

public void drawPacMan (Graphics2D g2d) {
if (viewdx == -1)
drawPacManLeft (g2d);
if (viewdx == 1)
drawPacManRight (g2d);
if (viewdy == -1)
drawPacManUp (g2d);
else
drawPacManDown (g2d);
}


Có bốn hướng có thể cho một pacman. Có bốn hình ảnh cho tất cả các hướng. Các hình ảnh được sử dụng để làm cử động pacman mở miệng, đóng lại.

Hàm drawMaze () vẽ ra mê cung dựa trên các số trong mảng screendata (hiểu đơn giản là các bản đồ trong các game cũng đa số được tạo nên từ 1 ma trận số 2 chiều, trong đó giá trị 1 ô quy định ô đó là đường đi, lề, sông suối, đá.... sau đó người ta sẽ dùng hàm để vẽ lên màn hình thành bản đồ, nhưng di chuyển của nhân vật vẫn dựa trên ma trận này). Ở đây, 1 là biên trái, 2 là biên trên, 4 là biên phải, 8 là biên dưới và 16 là một điểm có thể ăn được. Chúng tôi chỉ đơn giản là đi qua tất cả 255 ô. Ví dụ, ô 9 trong mảng screendata. Chúng ta có bit đầu tiên (1) và bit thứ tư (8) thiết lập. Vì vậy, chúng ta vẽ ra một biên dưới và một biên trái trên ô này nói riêng.

Mã:

if ((screendata [i] & 1) != false) / / vẽ trái
{
g2d.drawLine (x, y, x, y + blocksize - 1);
}


Vẽ biên trái nếu bit đầu tiên của số được thiết lập. 

Game hoàn chỉnh:
[Image: pacman.png]


File đính kèm



[Hướng dẫn]Viết game Gỡ mìn (Minesweeper) bằng Java


Giới thiệu
Dò mìn (Minesweeper) là một trò chơi phổ biến dần phát triển thành game mặc định trên nhiều hệ điều hành. Mục tiêu của trò chơi là đánh dấu tất cả các trái mìn trong game từ một vùng mở. Nếu người chơi nhấp chuột vào ô chứa mìn, mìn sẽ nổ và game kết thúc. Một ô không phải mìn có thể là 1 số hoặc để trống. Số này cho biết số mìn có thể có trong 8 ô xung quanh ô số này. Chúng ta đặt cờ đánh dấu 1 ô có mìn (hoặc chúng ta tin rằng có mìn) bằng cách nhấp phải vào nó
Đây là phiên bản đã được chỉnh sửa là đơn giản hóa từ phiên bản applet tôi tìm thấy trên javaside.
Game có 2 lớp, được liệt kê ở cuối bài.

[Image: minesweeper.png]


Hướng dẫn code
Đầu tiên chúng ta khai báo các hằng sẽ sử dụng trong game. 

Mã:

private final int NUM_IMAGES = 13;
private final int CELL_SIZE = 15;


Có 13 hình được dùng trong game này. Một ô có thể có xung quanh cao nhất 8 trái mìn nên chúng ta có các con số từ 1 đến 8. Chúng ta cần hình ảnh của 8 con số này, ô trống, ô mìn, ô được phủ (khi khởi đầu game, tất cả ô đều đc phủ hay nói cách khác là bị che), ô đánh dấu và cuối cùng là ô bị đánh dấu sai. Kích thước mỗi hình ảnh là 15x15. 

Mã:

private final int COVER_FOR_CELL = 10;
private final int MARK_FOR_CELL = 10;
private final int EMPTY_CELL = 0;
...


Một vùng mìn là một mảng các con số. Ví dụ, 0 chỉ 1 ô trống. Số 10 chỉ ra 1 ô đã được đánh dấu hay phủ. Dùng các hằng số như vậy sẽ phát huy tính dễ đọc của mã.

Mã:

private int[] field;


Mỗi ô trong vùng có 1 con số riêng. Như ô có mìn sẽ là số 9, ô có số 2 tức là xung quanh nó sẽ có 2 trái mìn. Hơi rắc rối chút nhưng có lẽ các bạn sẽ hiểu nếu theo dõi mã nguồn. 

Mã:

private int mines = 40;
private int rows = 16;
private int cols = 16;


Vùng mìn của chúng ta có 40 trái, có 16 hàng và 16 cột, như vậy ngoài ra có them 256 ô khác không phải mìn. 

Mã:

for (int i = 0; i < NUM_IMAGES; i++) {
img[i] =
(new ImageIcon(Integer.toString(i) + ".png").getImage();
}


Bậy giờ chúng ta nạp các hình ảnh của game vào, chúng được đặt tên theo thứ tự liệt kê ở trên, từ 0 đến 12.

Hàm newGame() khởi tạo game của chúng ta.

Mã:

all_cells = rows * cols;
field = new int[all_cells];
for (i = 0; i < all_cells; i++)
field[i] = COVER_FOR_CELL;


Những dòng này sẽ khởi tạo vùng mìn. Mọi ô đều được phú như mặc định. 

Mã:

while (i < mines) {
position = (int) (all_cells * random.nextDouble());
if ((position < all_cells) &&
(field[position] != COVERED_MINE_CELL)) {
current_col = position % cols;
field[position] = COVERED_MINE_CELL;
...


Trong vòng lặp ta khởi tạo ngẫu nhiên vị trí của mìn trong vùng. 

Mã:

cell = position - cols;
if (cell >= 0)
if (field[cell] != COVERED_MINE_CELL)
field[cell] += 1;


Mỗi ô có thể được bao quanh lên đến 8 ô (điều này không áp dụng cho các ô vùng biên). Chúng ta tăng biến đếm mìn cho các ô lân cận cho từng trái mìn được đặt xuống ngẫu nhiên.

Trong hàm find_empty_cells(), chúng ta sẽ tìm những ô trống. Nếu người chơi nhấn vào 6o có mìn, game sẽ kết thúc. Nếu họ nhấn vào ô kề mìn, ô này sẽ đc bỏ phủ và hiện ra con số có bao nhiêu trái mìn gần đó. Nhấn vào 1 ô trống sẽ mở ra 1 vùng bao gồm nhiều ô trống khác cùng những ô khác có số bao quanh vùng trống vừa tạo (những ô có số trở thành biên cho vùng trống). Chúng ta dung giải thuật đệ quy để tìm các ô trống đó.

Mã:

cell = j - 1;
if (cell >= 0)
if (field[cell] > MINE_CELL) {
field[cell] -= COVER_FOR_CELL;
if (field[cell] == EMPTY_CELL)
find_empty_cells(cell);
}


Trong đoạn mã này, chúng ta kiểm tra 1 ô bên trái 1 ô trống hay không, nếu nó không trống, mở nó ra. Nếu nó trống, lặp lại tiến trình.

Hàm paint() chuyển số của ô thành hình ảnh 

Mã:

if (!inGame) {
if (cell == COVERED_MINE_CELL) {
cell = DRAW_MINE;
} else if (cell == MARKED_MINE_CELL) {
cell = DRAW_MARK;
} else if (cell > COVERED_MINE_CELL) {
cell = DRAW_WRONG_MARK;
} else if (cell > MINE_CELL) {
cell = DRAW_COVER;
}
}


Nếu trò chơi kết thúc, chúng ta sẽ mở toàn bộ vùng mìn còn lại và những ô bị đánh dấu sai nếu có.

Mã:

g.drawImage(img[cell], (j * CELL_SIZE),
(i * CELL_SIZE), this);


Dòng code này vẽ tất cả ô.

Trong hàm mousePressed chúng ta ghi nhận và thực hiện tương ứng với mỗi cú nhấn. Game dò mìn chỉ thực hiện hoàn toàn bằng chuột. 

Mã:

field[(cRow * cols) + cCol] += MARK_FOR_CELL;
mines_left--;


Nếu người chơi click phải lên 1 ô chưa đánh dấu, chúng ta ghi nhận giá trị ô là MARK_FOR_CELL để sau đó nó sẽ được vẽ lên bằng hàm paint(). (lưu ý nó vẫn còn bị phú/ che và chỉ thêm vào là đã đc đánh dấu)

Mã:

if (field[(cRow * cols) + cCol] > COVERED_MINE_CELL) {
return;
}


Không có jì xảy ra nếu ta nhấn lên 1 ô đã đc đánh dấu. Nó phải đc bỏ đánh dấu bằng 1 cái nhấn chuột phải nữa trước khi có thể nhận them sự kiện nhấn chuột nào. 

Mã:

field[(cRow * cols) + cCol] -= COVER_FOR_CELL;


Nhấn chuột trái sẽ mở ô ra. 

Mã:

if (field[(cRow * cols) + cCol] == MINE_CELL)
inGame = false;
if (field[(cRow * cols) + cCol] == EMPTY_CELL)
find_empty_cells((cRow * cols) + cCol);


Trong trường hợp nhấn phải mìn, game sẽ kết thúc, chúng ta gọi hàm find_empty_cells(), để hiển thị các ô khác. 

Dịch: Shin
Ngoài source nguồn ra, có 2 bộ hình cho game, các bạn có thể lựa theo ý thích của mình 
Happy

 hình tự làm nên hơi xấu
Biggrin

 sau khi giải nén thì import vào project là dùng đc.



File đính kèm




[Hướng dẫn]Viết game Rắn săn mồi bằng Java


Giới thiệu
Con rắn là một game cổ điển. Lần đầu tiên xuất hiện trong thập niên 70, sau đó nó đã được đưa lên máy tính. Trong trò chơi này người chơi điều khiển một con rắn. Mục tiêu là để ăn táo nhiều càng tốt. Khi con rắn ăn một quả táo, số đốt thân của nó tăng lên. Con rắn phải tránh những bức tường và cơ thể của chính mình. Game này đôi khi được gọi là Nibbles.
Kích thước của mỗi của các đốt thân của một con rắn là 10px. Con rắn này được điều khiển bằng phím mũi tên. Ban đầu con rắn có ba khớp. Trò chơi được bắt đầu bằng cách bấm một trong các phím mũi tên. Nếu trò chơi kết thúc, chúng ta sẽ hiển thị thông báo Game Over ở giữa của Form.
Game có 2 lớp, được liệt kê ở cuối bài.Hướng dẫn code
Đầu tiên chúng ta sẽ khai báo những hằng (constant) sử dụng trong game:

Mã:

private final int WIDTH = 300;
private final int HEIGHT = 300;
private final int DOT_SIZE = 10;
private final int ALL_DOTS = 900;
private final int RAND_POS = 29;
private final int DELAY = 140;


WIDTH và HEIGHT xác định kích thước của Ban. DOT_SIZE là kích thước của táo và các đốt thân của con rắn. ALL_DOTS xác định số lượng chấm tối đa có thể có trên Board (900 = 300 * 300/10 * 10). RAND_POS liên tục được sử dụng để tính toán vị trí ngẫu nhiên của một trái táo. Hằng số DELAY xác định tốc độ của trò chơi.

Mã:

private int x[] = new int[ALL_DOTS];
private int y[] = new int[ALL_DOTS];


Hai mảng x, y lưu tọa độ của tất cả các khớp xương của con rắn.

Trong hàm move() là các thuật giải chính của trò chơi. Để hiểu nó, hãy nhìn con rắn chuyển động như thế nào. Bạn kiểm soát đầu của con rắn, có thể thay đổi hướng của nó với các phím mũi tên. Phần còn lại của các khớp di chuyển lên một vị trí trong mảng. Khớp thứ 2 di chuyển đến vị trí vừa rồi của khớp thứ nhất, khớp thứ 3 di chuyển đến vị trí vừa rồi của khớp thứ 2...

Mã:

for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}


Đoạn code này di chuyển các khớp tuần tự lên.

Mã:

if (left) {
x[0] -= DOT_SIZE;
}


Đoạn code này di chuyển đầu con rắn qua trái.

Hàm checkCollision () dùng để xác định xem con rắn đã đụng chính nó hoặc những bức tường.

Mã:

for (int z = dots; z > 0; z--) {
if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {
inGame = false;
}
}


Đoạn code này kết thúc trò chơi khi con rắn đụng 1 trong những khớp thân của nó bằng đầu (đương nhiên ^^).

Mã:

if (y [0]> HEIGHT) {
inGame = false;
}


Kết thúc trò chơi khi con rắn đạt tới độ dài cho phép (gọi là về nước ah 
Cười nhe răng

).

[Image: snake.png]


Trên đây là hướng dẫn viết game rắn săn mồi đơn giản nhất. Các bạn có thể thêm vào táo độc hay táo lớn, hoặc các bức tường giữa đường...Việc phát triển như thế nào là do bạn, chứ chơi 1 game đơn giản như zầy thì chán lắm ^^
Dịch: Shin


File đính kèm



[Hướng dẫn]Viết game Xếp hình bằng Java


Giới thiệu:
Chúng ta có hình của nhân vật Sid trong phim Ice Age. Nó được cắt thành 12 miếng. Bạn có thể tải hình ảnh tại đây (click phải chọn Save Image)

[Image: icesid.jpg]


Đây là hình ảnh sau khi hoàn thành game:

[Image: puzzle.png]


Game Puzzle chỉ có 1 lớp Puzzle duy nhất được liệt kê ở cuối bài.
Mục đích của trò chơi nhỏ này là xếp thành hình ảnh ban đầu. Chúng ta di chuyển các hình ảnh bằng cách clik vào chúng. Chỉ có những hình ảnh kề Label (ô trống) thì mới được di chuyển.

Hướng dẫn code:

Mã:

pos = new int[][] {
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
{9, 10, 11}
};


Đây là mảng vị trí các hình trong game.

Mã:

ImageIcon sid = new ImageIcon(Puzzle.class.getResource("icesid.jpg"));
source = sid.getImage();


Chúng ta sử dụng lớp ImageIcon để nạp hình.

Mã:

for ( int i = 0; i < 4; i++) {
for ( int j = 0; j < 3; j++) {
if ( j == 2 && i == 3) {
label = new JLabel("");
centerPanel.add(label);
} else {
button = new JButton();
button.addActionListener(this);
centerPanel.add(button);
image = createImage(new FilteredImageSource(source.getSource(),
new CropImageFilter(j*width/3, i*height/4, (width/3)+1, height/4)));
button.setIcon(new ImageIcon(image));
}
}
}


Đoạn mã này tạo ra 11 nút nhấn (để nhận sự kiện nhất và di chuyển hình) và 1 nhãn (ô trống không có hình). Sau đó ta cắt hình lớn ra thành 12 phần và đặt vào 11 button (1 hình bị lược bỏ theo đúng như nguyên mẫu trò chơi).

Mã:

int labelX = label.getX();
int labelY = label.getY();
int buttonX = button.getX();
int buttonY = button.getY();


Chúng ta lấy tọa độ của nút được nhấn và tọa độ của label, những cặp tọa độ x, y này rất quan trọng với logic của trò chơi.

Mã:

int buttonPosX = buttonX / size.width;
int buttonPosY = buttonY / size.height;
int buttonIndex = pos[buttonPosY][buttonPosX];


Bây giờ chúng ta đã có được vị trí của nút đc nhấn trong mảng 2 chiều.

Mã:

if (labelX == buttonX && (labelY - buttonY) == size.height ) {
int labelIndex = buttonIndex + 3;
centerPanel.remove(buttonIndex);
centerPanel.add(label, buttonIndex);
centerPanel.add(button,labelIndex);
centerPanel.validate();
}


Trong trường hợp này, chúng ta nhận khi 1 nút được nhấn và nó ở ngay trên label. Nếu đúng, chúng có cùng x. Nếu nút nhấn bên phải label, thì hàm (labelY - buttonY) == size.height trả về true.


File đính kèm



[Hướng dẫn]Viết game Xếp gạch bằng Java


Giới thiệu
Tetris là một trong những trò chơi máy tính phổ biến nhất từng được tạo ra. Trò chơi gốc đã được thiết kế và lập trình bởi một lập trình viên Nga Alexey Pajitnov năm 1985. Kể từ đó, Tetris có trên hầu hết mọi nền tảng máy tính trong rất nhiều biến thể. Ngay cả điện thoại di động của tôi có một phiên bản sửa đổi của trò chơi Tetris.
Tetris còn được gọi là gaem xếp gạch hay câu đố dạng xếp khối. Trong trò chơi này, chúng ta có bảy hình dạng khác nhau được gọi là tetrominoes: S, Z, T, L, I, L đối xứng ngược và hình vuông. Mỗi hình dạng được hình thành với bốn hình vuông. Các hình dạng đang rơi xuống theo thời gian. Các đối tượng của trò chơi Tetris có thể di chuyển và xoay hình dạng, để chúng kết hợp với nhau càng nhiều càng tốt. Nếu chúng ta xoay sở tạo thành được một hàng, hàng đó bị phá hủy và chúng ta ghi điểm. Tetris cứ được chơi mãi cho đến khi chúng ta thoát hoặc thua.

[Image: tetrominoes.png]


Chúng ta không dùng hình ảnh cho trò chơi Tetris, chúng ta sử dụng API trong Swing để vẽ các tetrominoes. Đằng sau mỗi trò chơi, hình thành mô hình toán học. Vì vậy, nó được gọi là Tetris.
Một số ý tưởng của trò chơi.
* Chúng ta sử dụng một lớp Timer để tạo ra chu kỳ trò chơi.
* Các tetrominoes được vẽ lên (không dùng Image để tránh làm tăng dung lượng game, thích hợp cho các hệ máy di động).
* Các hình di chuyển tmột hình vuông bằng khối vuông cơ sở(không dùng bằng pixel)
* Một cách toán học thì game khi đang chơi là 1 danh sách các con số (sẽ nói rõ hơn ở phần sau nhưng sẽ hay hơn nếu bạn tự tìm hiểu và tưởng tượng ra ^^).
Tôi đã đơn giản hóa trò chơi một chút, để nó dễ dàng hơn để hiểu. Trò chơi bắt đầu ngay lập tức, sau khi được chạy (lược bỏ màn hình mở đầu). Chúng ta có thể tạm dừng trò chơi bằng cách bấm phím p. Phím Space sẽ thả mảnh Tetris ngay lập tức xuống phía dưới (tăng tốc rơi cực đại). Phím d sẽ thả mảnh xuống một dòng (nó có thể được sử dụng để tăng tốc độ rơi xuống một chút) Các trò chơi. Tốc độ trò chơi là 1 hằng số không đổi, không thể thực hiện tăng tốc. Điểm số là số dòng mà chúng ta đã phá được.
Trò chơi có 3 lớp, được liệt kê ở cuối bài.

Hướng dẫn code lớp Tetris và lớp Shape
Trong lớp Tetris, chúng ta cài đặt các thành phần như vùng hiển thị và trạng thái của trò chơi.

Mã:

board.start();


Hàm start() bắt đầu game ngay lập tức!

Lớp Shape chứa thông tin về một mảnh Tetris được tạo ra bất kỳ.

Mã:

enum Tetrominoes (NoShape, ZShape, SShape, LineShape,
TShape, SquareShape, LShape, MirroredLShape);


Các liệt kê Tetrominoes giữ tất cả bảy dạng Tetris. Cộng với hình dạng đặc biệt gọi là NoShape.

Mã:

public Shape () (
coords = new int [4] [2];
setShape (Tetrominoes.NoShape);
)


Đây là phương thúc khởi tạo của lớp Shape. Các mảng coords giữ tọa độ thực tế của một mảnh Tetris.

Mã:

coordsTable = new int [][][] (
((0, 0), (0, 0), (0, 0), (0, 0)),
((0, -1), (0, 0), (-1, 0), (-1, 1)),
((0, -1), (0, 0), (1, 0), (1, 1)),
((0, -1), (0, 0), (0, 1), (0, 2)),
((-1, 0), (0, 0), (1, 0), (0, 1)),
((0, 0), (1, 0), (0, 1), (1, 1)),
((-1, -1), (0, -1), (0, 0), (0, 1)),
((1, -1), (0, -1), (0, 0), (0, 1))
);


Mảng coordsTable giữ tất cả giá trị có thể có để phối hợp hiển thị của miếng Tetris của chúng ta (cần phải suy nghĩ kỹ chỗ này nha, tương tự như bài toán con mã đi tuần). Đây là một mẫu mà từ đó tất cả các mảnh coordiate lấy giá trị của chúng.

Mã:

for (int i = 0; i <4; i + +) {
for (int j = 0; j <2; + + j) {
coords [i] [j] = coordsTable [shape.ordinal ()] [i] [j];
}
}


Ở đây chúng ta đặt một dãy các giá trị coordiate từ coordsTable đến một mảng coords của một mảnh Tetris. Lưu ý việc sử dụng hàm ordinal(). Trong C ++, kiểu liệt kê mặc định như là một số nguyên. Không giống như trong C++, kiểu liệt kê của Java là hỗ trợ đầy đủ các lớp. Và hàm ordinal() trả về vị trí hiện tại của biến enum trong đối tượng liệt kê.

Các hình ảnh sau đây sẽ giúp hiểu được sự phối hợp các giá trị hơn một chút. Các mảng coords lưu toạ độ của các mảnh Tetris. Ví dụ, các số (0, -1), (0, 0), (1, 0), (1, 1), đại diện cho các kiểu xoay của một hình chữ S. Sơ đồ dưới đây minh hoạ:

[Image: coordinates.png]



Mã:

public Shape rotateLeft()
{
if (pieceShape == Tetrominoes.SquareShape)
return this;
Shape result = new Shape();
result.pieceShape = pieceShape;
for (int i = 0; i < 4; ++i) {
result.setX(i, y(i));
result.setY(i, -x(i));
}
return result;
}


Đoạn mã này xoay các mảnh qua trái. Các hình vuông không phải xoay, đó là lý do tại sao chúng tôi chỉ đơn giản tra lại tham chiếu đến đối tượng hiện hành. Nhìn vào hình ảnh trước đó sẽ giúp hiểu được chúng xoay thế nào.




Hướng dẫn code cho lớp Board:

Mã:

...
isFallingFinished = false;
isStarted = false;
isPaused = false;
numLinesRemoved = 0;
curX = 0;
curY = 0;
...


Chúng ta khởi tạo một số biến quan trọng. Biến isFallingFinished xác định nếu hình dạng Tetris hoàn thành việc rơi xuống thì sau đó chúng ta cần phải tạo một hình mới. NumLinesRemoved đếm số dòng chúng ta đã loại bỏ (ăn điểm) cho đến nay. curX và curY xác định vị trí thực tế của hình Tetris đang rơi.

Mã:

setFocusable (true);


Chúng ta dứt khoát phải gọi phương thức setFocusable() để phần hiển thị của chúng ta có thể nhận được các phím nhấn.

Mã:

timer = new Timer (400, this);
timer.start ();


Đối tượng Timer thực hiện một hoặc nhiều sự kiện sau khi một thời gian trễ chỉ định (Interval). Trong trường hợp của chúng ta, là gọi phương thức actionPerformed() mỗi 400 ms.

Mã:

public void actionPerformed (ActionEvent e) {
if (isFallingFinished) {
isFallingFinished = false;
newPiece ();
} else {
oneLineDown ();
}
}


Hàm actionPerformed() kiểm tra nếu việc rơi xuống đã hoàn tất. Nếu đúng, một mảnh mới sẽ được tạo ra. Nếu không, những mảnh Tetris rơi xuống một dòng.

Bên trong hàm paint(), chúng ta vẽ ra tất cả các đối tượng ở trên bảng hiển thị (về sau sẽ gọi là board).

Mã:

for (int i = 0; i <boardheight; i="" +="" +)="" {<br="">     for (int j = 0; j <boardwidth; +="" j)="" {<br="">         Tetrominoes shape = shapeAt (j, BoardHeight - i - 1);
if (shape! = Tetrominoes.NoShape)
drawSquare (g, 0 + j * squareWidth (),
boardTop + i * squareHeight (), shape);
}
}


Trong bước đầu tiên chúng ta vẽ tất cả các hình dạng, hay những phần còn sót lại của 1 hình dạng đã rơi xuống tới dưới cùng. Tất cả các khối vuông đã được ghi nhớ trong mảng board. Chúng ta truy cập nó bằng cách sử dụng shapeAt().

Mã:

if (curPiece.getShape () = Tetrominoes.NoShape!) {
for (int i = 0; i <4; i + +) {
int x = curX + curPiece.x (i);
int y = curY - curPiece.y (i);
drawSquare (g, 0 + x * squareWidth (),
boardTop + (BoardHeight - y - 1) * squareHeight (),
curPiece.getShape ());
}
}


Trong bước thứ hai, chúng ta vẽ mảnh thực sự đang rơi.

Mã:

private void dropDown()
{
int newY = curY;
while (newY > 0) {
if (!tryMove(curPiece, curX, newY - 1))
break;
--newY;
}
pieceDropped();
}


Nếu chúng ta bấm phím Space, mảnh rơi ngay xuống dưới. Chúng ta chỉ đơn giản là cố gắng thả 1 mảnh xuống từng dòng cho đến khi nó đạt đến đáy hoặc trên một mảnh Tetris trước đó.

Mã:

private void clearBoard ()
{
for (int i = 0; i          board [i] = Tetrominoes.NoShape;
}


Hàm clearBoard() lấp đầy board bằng những hình NoShapes. Việc này sau đó được sử dụng để phát hiện va chạm.

Mã:

private void pieceDropped ()
{
for (int i = 0; i <4; i + +) {
int x = curX + curPiece.x (i);
int y = curY - curPiece.y (i);
board [(y * BoardWidth) + x] = curPiece.getShape ();
}
removeFullLines ();
if (! isFallingFinished)
newPiece ();
}


Hàm pieceDropped() đặt các mảnh rơi vào mảng board. Một lần nữa, board lưu giữ tất cả các khối vuông của mảnh và những phần còn sót lại của những mảnh đã rơi xuống trước đó. Khi đã hoàn tất rơi xuống, đó là thời gian để kiểm tra, nếu chúng ta có thể loại bỏ một số đường thẳng trên board. Đây là công việc của hàm removeFullLines (). Sau đó, chúng ta tạo ra một mảnh mới. Chính xác hơn, chúng ta cố gắng tạo ra một mảnh mới.





Mã:

private void newPiece ()
{
curPiece.setRandomShape ();
curX = BoardWidth / 2 + 1;
curY = BoardHeight - 1 + curPiece.minY ();
if (tryMove (curPiece, curX, curY!)) {
curPiece.setShape (Tetrominoes.NoShape);
timer.stop ();
isStarted = false;
statusbar.setText ( "Game over");
}
}


Hàm newPiece() tạo ra một mảnh Tetris mới. Các mảnh được tạo hình ngẫu nhiên dựa trên những hình cơ bản. Sau đó chúng ta tính toán curX ban đầu và curY. Nếu chúng ta không thể di chuyển đến vị trí ban đầu, trò chơi kết thúc. Giờ được ngừng lại. Chúng ta đặt lại chuỗi trên thanh statusbar.

Mã:

private boolean tryMove (Shape newPiece, int newX, int newY)
{
for (int i = 0; i <4; i + +) {
int x = newX + newPiece.x (i);
int y = newY - newPiece.y (i);
if (x <0 | | x> = BoardWidth | | y <0 | | y> = BoardHeight)
return false;
if (shapeAt (x, y) = Tetrominoes.NoShape!)
return false;
}
curPiece = newPiece;
curX = newX;
curY = newY;
repaint ();
return true;
}


Hàm tryMove () cố gắng di chuyển các mảnh Tetris. Trả về false, nếu nó đụng biên của board hay những mảnh đã rơi xuống trước đó.

Mã:

for (int i = BoardHeight - 1; i> = 0; - i) {
boolean lineIsFull = true;
for (int j = 0; j <boardwidth; +="" j)="" {<br="">         if (shapeAt (j, i) == Tetrominoes.NoShape) (
lineIsFull = false;
break;
}
}
if (lineIsFull) {
++numFullLines;
for (int k = i; k < BoardHeight - 1; ++k) {
for (int j = 0; j < BoardWidth; ++j)
board [(k * BoardWidth) + j] = shapeAt (j, k + 1);
}
}
}


Bên trong hàm removeFullLines (), chúng ta kiểm tra nếu có bất kỳ hàng nào đủ điều kiện để ghi điểm trong số tất cả các hàng của board. Nếu có ít nhất một dòng đầy đủ, nó được loại bỏ. Sau khi tìm thấy một dòng đầy đủ, chúng ta tăng biến đếm. Chúng tôi di chuyển tất cả các dòng ở trên dòng đó xuóng một dòng. Bằng cách này chúng ta tiêu diệt 1 dòng đầy đủ.

Mỗi mảnh Tetris có bốn hình vuông. Mỗi ô vuông được vẽ bằng hàm drawSquare (). Mỗi mảnh Tetris có màu sắc khác nhau.

Mã:

g.setColor (color.brighter ());
g.drawLine (x, y + squareHeight () - 1, x, y);
g.drawLine (x, y, x + squareWidth () - 1, y);


Bên trái và trên của một hình vuông được vẽ ra với một màu sáng hơn. Tương tự, phía dưới và bên phải được vẽ ra với các màu sắc tối hơn. Điều này mô phỏng một cạnh 3D.

Chúng ta điều khiển game với bàn phím. Các cơ chế kiểm soát được thực hiện với một KeyAdapter. Đây là một lớp bên trong đó sẽ nạp chồng hàm keyPressed().

Mã:

case KeyEvent.VK_RIGHT:
tryMove (curPiece, curX + 1, curY);
break;


Nếu chúng ta nhấn phím mũi tên trái, chúng ta sẽ cố gắng để di chuyển các mảnh rơi xuống một khối vuông bên trái.

[Image: tetris.png]


=================================================
Như vậy, còn những phần như combo, hiển thị trước mảnh tiếp theo, ghi điểm hay thêm các mảnh mới là do bạn quyết định! Hãy thử đi!
Do lỗi chuyển dữ liệu nên diễn đàn đã mất source bản gốc, hiện tại chỉ có bản đã upgrade của mình, nếu bạn nào quan tâm thì down về dùng thử (có thể có lỗi ngớ ngẩn nào đó ^^)
Dịch: Shin



File đính kèm




[Hướng dẫn]Viết game Phá gạch bằn Java


Giới thiệu
Breakout là một trò chơi arcade ban đầu được phát triển bởi công ty Atari Inc. thành lập năm 1976. Trong trò chơi này, người chơi di chuyển một thanh trượt trên màn hình và đánh trả lại một quả bóng. Mục tiêu là để tiêu diệt các viên gạch ở trên cùng của cửa sổ.
Trong trò chơi của chúng ta, chúng ta có một thanh trược, bóng và 30 viên gạch. Chúng ta cần hình ảnh cho một quả bóng, thanh trượt và gạch (có lẽ bạn cần phải tự chuẩn bị). Chúng ta dùng một Timer để tạo ra một chu trình trò chơi. Chúng tôi không làm việc với góc, chúng tôi chỉ cần thay đổi hướng: trên, dưới, trái và phải. Tôi đã lấy cảm hứng từ trò chơi pybreakout. Nó được phát triển trong thư viện PyGame của Nathan Dawson.
Trò chơi được cố ý làm cho đơn giản (việc phúc tạp nó lên là của chúng ta :biggrin
Cười mỉm

. Không có tiền thưởng, cấp độ, điểm số. Vì vậy, mà nó được dễ dàng hơn để hiểu.
Trò chơi này bao gồm bảy tập tin: 6 lớp và 1 giao diện.

Hướng dẫn code
Đầu tiên là giao diện Common chứa những hằng chung nhất.
Sau đó là lớp Sprite là một lớp cơ sở cho tất cả các đối tượng. Chúng tôi đặt ở đây tất cả các hàm và các biến có ở bóng, gạch và thanh trượt như getImage() hoặc getX().
Lớp Brick dành cho các viên gạch, chú ý, biến destroyed để đánh dấu trạng thái của viên gạch.
Lớp Ball để hiển thị và tương tác với bóng. Hàm move() dùng để di chuyển bóng, khi nó đụng vào đối tượng khác thì sẽ tự tính toán hướng dội lại ngay lập tức.
Tiếp theo là lớp Paddle dành cho thanh trượt, nó đóng gói đối tượng thanh trượt trong trò Breakout. Thanh trượt này được kiểm soát bằng các phím mũi tên trái và phải. Bằng cách bắt sự kiện khi người dùng nhấn phím mũi tên, chúng tôi đặt biến điều hướng. Bằng cách bắt sự kiện khi thả phím mũi tên, chúng tôi đặt biến dx = 0. Bằng cách này thanh trượt ngừng di chuyển.
Như thông lệ, đây là lớp Board. Hàm gameInit() khởi tạo 1 bóng, 1 thanh trượt và 30 viên gạch. Trong khi trò chơi diễn ra, hàm paint sẽ liên tục update và vẽ các đối tượng lên màn hình. Lớp ScheduleTask nhảy mỗi 10 ms. Trong khi hàm chạy, chúng ta di chuyển bóng và thanh trượt này. Chúng tôi kiểm tra sự va chạm nếu có và chúng ta repaint(). Chúng ta kiểm tra liên tục xem có bao nhiêu viên gạch đã bị phá hủy, nếu hết 30 viên, ta thắng, nếu bóng đụng phía dưới, ta thua. Hàm autoMove() được gọi trong mỗi chu kỳ của trò chơi để di chuyển bóng trên màn hình. Nếu nó đụng các biên thì sẽ thay đổi hướng bóng.
Và cuối cùng, lớp chính của trò chơi - Breakout.

[Image: breakout.png]


-----------------------------------------------------------------------------------------------------
Sau đây ta có thể viết các hàm up level lên, cho số gạch tăng dần, hay thay đổi tốc độ di chuyển của bóng, thêm phần tính điểm...nói chung, làm thề nào là tùy thuộc vào bạn, đừng gọi đây là thành phẩm, vì nó chỉ là gợi ý cho game bạn thôi.
Ngoài các lớp dùng trong game, còn có 3 hình với kích thước chuẩn để bạn sử dụng trong game của mình, nếu muốn có thể thay đổi lại theo ý thích 
Biggrin

 chỉ cần import vào project là xong.
Dịch: Shin



File đính kèm




 [Hướng dẫn]Viết một số game bằng Java


Giới thiệu
Là một trò chơi cổ điển, được viết ra từ 1980 bởi Hiỏyuki Imabayashi. Sokoban nghĩa là người giữ chuồng ngựa (Bật mã ôn chắc 
Cười nhe răng

) trong tiếng Nhật. Người chơi đẩy các khối hộp vào 1 khu vực đã định trong 1 mê cung nào đó.
Source game được đính kèm ở cuối bài, sau đây là phần hướng dẫn.

Hướng dẫn
Chúng ta điều khiển player (sokoban) bằng các phím mũi tên, phím R dùng để khởi động lại. Khi tất cả hộp đều đc xếp vào khu vực đích, trò chơi hoàn thành. Khi đó chúng ta chỉ đơn giản vẽ ra chuỗi "Completed" ở góc trên bên trái của cửa sổ.
Trò chơi này đã được đơn giản hoá rất nhiều, chỉ chứa những chức năng chính, để chúng ta có thể dễ dàng làm quen và nâng cấp lên với nhiều chức năng khác. Ở đây chỉ có 1 level duy nhất.

Mã:

private final int OFFSET = 30;
private final int SPACE = 20;
private final int LEFT_COLLISION = 1;
private final int RIGHT_COLLISION = 2;
private final int TOP_COLLISION = 3;
private final int BOTTOM_COLLISION = 4;


Các hình ảnh trong chương trình đều có kích cỡ 20x20, được thể hiện bằng hằng SPACE. Hằng OFSET là khoảng cách giữa lề của sổ và không gian game. Có 4 loại va chạm được thể hiện bằng các hằng còn lại.

Mã:

private ArrayList walls = new ArrayList();
private ArrayList baggs = new ArrayList();
private ArrayList areas = new ArrayList();


Tường, hộp và khu vực hoàn thành là những đối tượng đặc biệt trong game.

Mã:

private String level =
"    ######\n"
+ "    ##   #\n"
+ "    ##$  #\n"
+ "  ####  $##\n"
+ "  ##  $ $ #\n"
+ "#### # ## #   ######\n"
+ "##   # ## #####  ..#\n"
+ "## $  $          ..#\n"
+ "###### ### #@##  ..#\n"
+ "    ##     #########\n"
+ "    ########\n";


Có lẽ không cần giải thích cũng có thể hiểu được đây là gì. Trừ khoảng trắng ra thì còn lại 5 loại ký tự khác nhau:
- ( # ): tường
- ( $ ): hộp
- ( . ): khu vực hoàn thành (địa điểm hoàn thành nếu nằm rải rác)
- ( @ ): người chơi (sokoban)
- ( \n ): bắt đầu 1 dòng mới trong bản đồ

Mã:

public final void initWorld() {
int x = OFFSET;
int y = OFFSET;
...


Hàm initWorld() khởi tạo thế giới của game, nó sẽ đọc chuỗi bản đồ phía trên và lấp đầy các đối tượng đặc biệt.

Mã:

} else if (item == '$') {
b = new Baggage(x, y);
baggs.add(b);
x += SPACE;


Trong trường hợp $, chúng ta tạo ra các hộp, đối tượng này sẽ được thêm vào danh sách hộp, biến x được tăng lên theo sau đó.

Mã:

public void buildWorld(Graphics g) {
...


Hàm buildWorld() vẽ trò chơi lên cửa sổ.

Mã:

ArrayList world = new ArrayList();
world.addAll(walls);
world.addAll(areas);
world.addAll(baggs);
world.add(soko);


Chúng ta tạo ra các đối tượng trong thề giới trò chơi vừa được vẽ lên.

Mã:

for (int i = 0; i < world.size(); i++) {
Actor item = (Actor) world.get(i);
if ((item instanceof Player)
|| (item instanceof Baggage)) {
g.drawImage(item.getImage(), item.x(), item.y(), this);
} else {
g.drawImage(item.getImage(), item.x(), item.y(), this);
}
...


Ta sẽ đi dọc theo bản đồ, và vẽ lên từng đối tượng.

Mã:

if (completed) {
g.setColor(new Color(0, 0, 0));
g.drawString("Completed", 25, 20);
}


Nếu cấp độ hoàn thành, chúng ta vẽ “Completed” ở góc trên bên trái cửa sổ.

Mã:

if (key == KeyEvent.VK_LEFT) {
if (checkWallCollision(soko,
LEFT_COLLISION)) {
return;
}
if (checkBagCollision(LEFT_COLLISION)) {
return;
}
soko.move(-SPACE, 0);
...


Trong hàm keyPressed(), chúng ta sẽ kiểm tra các phím được nhấn, điều khiển đối tượng sokoban với các phím mũi tên, nếu không ‘chạm’ tường hay hộp, thì sokoban sẽ dịch chuyển về hướng được nhấn.

Mã:

} else if (key == KeyEvent.VK_R) {
restartLevel();
}


Khởi động lại game khi R được nhấn.

Mã:

if (type == LEFT_COLLISION) {
for (int i = 0; i < walls.size(); i++) {
Wall wall = (Wall) walls.get(i);
if (actor.isLeftCollision(wall)) {
return true;
}
}
return false;
...


Hàm checkWallCollision() được tạo ra để bảo đảm sokoban và hộp ko vượt qua tường được. Có 4 loại va chạm cần được test, ở trên chỉ là test bên trái.

Mã:

private boolean checkBagCollision(int type) {}


Rắc rối hơn chút, hàm checkBagCollision kiểm tra va chạm và chỉ khi nó đụng vào sokoban thì mới di chuyển, và phải không được chạm vào tường hay hộp khác, sau khi hộp được di chuyển thì ta lại kiểm tra xem game đã hoàn hành chưa bằng hàm isCompleted().

Mã:

for (int i = 0; i < num; i++) {
Baggage bag = (Baggage) baggs.get(i);
for (int j = 0; j < num; j++) {
Area area = (Area) areas.get(j);
if (bag.x() == area.x()
&& bag.y() == area.y()) {
compl += 1;
}
}
}


isCompleted() kiểm tra đã hoàn thành game hay chưa. Chúng ta lấy số lượng hộp rồi kiểm tra toạ độ từng hộp với các toạ độ đích.

Mã:

if (compl == num) {
completed = true;
repaint();
}


Kiểm tra biến compl và num để xác định game hoàn thành hay chưa.

Mã:

public void restartLevel() {
areas.clear();
baggs.clear();
walls.clear();
initWorld();
if (completed) {
completed = false;
}
}


Nếu di chuyển sai thì cần phải reset lại game. Chúng ta xoá tất cả đối tượng trong list và khởi tạo lại từ đầu, kể cả các biến.

--------------------------------------------------------------------------------------------------------------------------------
Lớp Actor: lớp cơ bản cho các đối tượng có trong game, đóng gói những chức năng cơ bản của 1 đối tượng.

Mã:

public boolean isLeftCollision(Actor actor) {
if (((this.x() - SPACE) == actor.x()) &&
(this.y() == actor.y())) {
return true;
} else {
return false;
}
}


Hàm này kiểm tra xem object này có va chạm với object khác ở bên trái nó không.

Lớp Wall: kế thừa từ lớp Actor, trong quá trình khởi tạo, nó sẽ vẽ ra hình bức tường từ tập tin hệ thống.
Lớp Player: lớp khởi tạo đối tượng sokoban.

Mã:

public void move(int x, int y) {
int nx = this.x() + x;
int ny = this.y() + y;
this.setX(nx);
this.setY(ny);
}


Lớp này có hàm move() dùng để di chuyển trong game.

Lớp Baggage: có thể di chuyển được nên cũng có hàm move().
Lớp Area: khu vực mà chúng ta sẽ đặt các hộp vào.
Lớp Sokoban: lớp chứa hàm main() của chương trình.
Game sau khi hoàn thành (minh hoạ)

[Image: sokoban.png]


Dịch: Shin


File đính kèm


15 nhận xét:

  1. anh ơi,anh có code về game đua xe đơn giản không ạ,anh share mail hunght.thaibinh@gmail.com cho e với ạ
    em cảm ơn nhiêu!!!

    Trả lờiXóa
  2. Anh ơi có code Ô ăn quan không ạ, anh share mail cho e với
    hoangminhquan100395@gmail.com
    e cảm ơn nhiều ạ

    Trả lờiXóa
  3. Anh ơi có code Ô ăn quan không ạ, anh share mail cho e với
    hoangminhquan100395@gmail.com
    e cảm ơn nhiều ạ

    Trả lờiXóa
  4. Ad ơi, có code game đặt boom, phần lớp thả boom ko, giúp em với ạ ! em cám ơn Ad nhiều

    Trả lờiXóa
  5. Ad ơi, có code game đặt boom, phần lớp thả boom ko, giúp em với ạ ! em cám ơn Ad nhiều

    Trả lờiXóa
  6. ad có code game đá bóng luân lưu k ạ? a share mail cho e với lanksnb@gmail.com nha

    Trả lờiXóa
    Trả lời
    1. ad có code về game đua xe đơn giản không ạ,anh share mail thuyduongclover171296@gmail.com cho e với ạ
      em cảm ơn nhiều ạ!!!

      Xóa
  7. Ad ơi, có game tank ko ạ? A share cho e với buihuuthanh95@gmail.com

    Trả lờiXóa
  8. ad có game tìm số không cho mình xin với...doibongnghe02@gmail.com

    Trả lờiXóa
  9. ad có code về game đua xe đơn giản không ạ,anh share mail thuyduongclover171296@gmail.com cho e với ạ
    em cảm ơn nhiều ạ!!!

    Trả lờiXóa
  10. ad có code về game 2048 đơn giản k ạ? share em với caovinh12c11@gmail.com

    Trả lờiXóa
  11. ad có code về game Game Trò chơi tiếng Anh Nghe và chọn ko ak .
    cho e tham khảo vs
    xuantruong408@gmail.com
    e xin cảm ơn ak

    Trả lờiXóa
  12. ak ơi có code về game line không ạ

    Trả lờiXóa
  13. ak có code về game line không ạ sungthang1212@gmail.com

    Trả lờiXóa