Tải bản đầy đủ (.pptx) (66 trang)

Bài giảng Lập trình nâng cao: Danh sách liên kết - Trần Quốc Long

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (249.01 KB, 66 trang )

Snake Game
13&14 - Danh sách liên kết


Nội dung




Trị chơi: Snake
Kỹ thuật





Mảng 2 chiều
Bắt phím với SDL_PollEvent()
Hàng đợi




xử lý hiện tượng rớt phím

Danh sách liên kết



thêm, chèn, xoá trên danh sách hiệu quả



Trị chơi Snake



Sân chơi hình chữ nhật





Rắn lúc đầu






dài 4 ơ (tính cả đầu), ở giữa màn hình, đi xuống

Người chơi điều khiển rắn di chuyển bằng các phím mũi tên
Mỗi lần rắn ăn 1 quả cherry thì dài thêm 1 ô





Trên sân chơi xuất hiện các quả cherry ngẫu nhiên

Thử sức: nhiều loại quả, mỗi loại một tác dụng


Rắn va phải tường hoặc chính nó → thua



/>

Demo - Start Screen


Demo - Midgame screen


Các tác vụ của trị chơi



Hiển thị hình vẽ giới thiệu






Có nút hiển thị bảng xếp hạng các lần chơi

Khởi tạo: sân chơi, con rắn, vị trí quả
Game loop, tại mỗi bước:





Xử lý sự kiện bàn phím để đổi hướng đi bước tiếp theo
Xử lý game logic: di chuyển rắn theo hướng đi hiện tại, va chạm tường, va chạm thân rắn,
ăn quả dài thân và tăng điểm số



Hiển thị màn hình trị chơi


Lộ trình xây dựng trị chơi
Các phiên bản
0.1: vẽ sân chơi và rắn đơn giản (dùng ơ vng hoặc hình tròn), điều khiển được
rắn di chuyển
0.2: thêm quả vào sân chơi, rắn ăn quả dài ra
0.3: xử lý va chạm với cạnh sân và thân rắn
0.4: Vẽ các đốt rắn đẹp bằng ảnh JPG
1.0: Thêm màn hình khởi động, điểm số, bảng xếp hạng


Chuẩn bị






Tạo project Snake
Cài đặt thư viện SDL2, SDL2_image

Đưa main.cpp, painter.h, painter.cpp từ bài giảng về SDL vào project
Sửa main.cpp





Xoá các hàm vẽ
Sửa tiêu đề cửa sổ
Chỉ để lại mã khởi tạo và giải phóng SDL



cửa sổ và bút vẽ


Chuẩn bị
Hàm main()
in t m ain (in t argc,ch ar* argv[])
{
srand(tim e(0));
SD L_W indow * w indow ;
SD L_Renderer* renderer;
initSD L(w indow ,renderer);
Painter painter(w indow , renderer);

// TO D O : gam e code here

quitSD L(w indow ,renderer);
retu rn 0;

}


Mã giả
render splash screen;
initialize play-ground size = (w idth, height)

render play-ground (save tim estam p)
w h ile (gam e is running) {

get user input
update snake direction using user input (turn up, dow n,left, right)

if elapsed tim e > required delay betw een steps
m ove the gam e (snake craw l,generate cherry) to the next step
render play-ground
save new tim estam p
}
render gam e-over screen
update score and ranking table to fi
le


Code C++
renderSplashScreen();
PlayG round p layG rou n d (G R O U N D _W ID TH , G R O U N D _H EIG H T);
SD L_Event e;
renderG am ePlay(painter,playG round);
au to start = C LO C K_N O W ();


au to end = C LO C K_N O W ();

w h ile (playG round.isG am eRunning()) {

Elap sed T im e elapsed = end-start;

w h ile (SD L_PollEvent(& e) != 0 ) {

if (elapsed.count() > STEP_D ELAY) {

U serInput input = interpretEvent(e);

playG round.nextStep();

playG round.processU serInput(input);

renderG am ePlay(painter,

} // non-blocking event detection

playG round);
start = end;

// gam e logic here

SD L_D elay(1); // to prevent high C PU usage because of SD L_PollEvent()
}
renderG am eO ver(painter, playG round);
updateRankingTable(playG round);


}


Một số tiện ích

// sốốgiây giữa hailâầ
n vẽ
const dou b le STEP_D ELAY = 0.5;

// tên ngắố
n cu
ủa hàm lâố
y thờigian
# defi
ne CLO CK_N O W chrono::system _clock::now

// Kiêủ
u đạidiện cho khoa
ủng thờigian (tính theo giây)
typ edef chrono::duration< dou b le> ElapsedTim e;


Nhập liệu và hiển thị
const in t G RO U N D _W ID TH = 30;
const in t G RO U N D _H EIG H T = 20;

void ren derS p lash S creen ();
void ren derG am eP lay(Painter& , con st PlayG round& playG round);
void ren derG am eO ver(Painter& , const PlayG round& playG round);
U serInput in terp retEven t(SD L_Event e);

void u p dateR an kin gTab le(con st PlayG round& playG round);



PlayGround: lớp biểu diễn sân chơi





Xử lý logic của game

UserInput: các hành động của người chơi

en u m U serInput { N O _IN PU T = 0, KEY_U P, KEY_D O W N ,KEY_LEFT, KEY_RIG H T };


Tạo các hàm rỗng để lấy chỗ
void ren derS p lash S creen ()
{

Đợi 1 phím trước khi bắt đầu

w aitU ntilKeyPressed();
}

void ren derG am eP lay(Painter& , con st PlayG round& playG round) { }

void ren derG am eO ver(Painter& , const PlayG round& playG round) { }


U serInput in terp retEven t(SD L_Event e)
{
retu rn N O _IN PU T;
}

void u p dateR an kin gTab le(con st PlayG round& playG round) { }

chơi


Biểu diễn sân chơi




Tìm cách biểu diễn mỗi đối tượng trong trị chơi bằng Lớp (dữ liệu + hàm)
Sân chơi




Hình chữ nhật các ơ vng
Mỗi ơ có thể trống, vị trí của rắn, vị trí của quả




Có thể mở rộng sau này để có nhiều loại quả

Các chức năng chính (mình có thể nghĩ ra bây giờ)






Khởi tạo (và các Getters đọc trạng thái)
Thêm quả vào chỗ trống
Thay đổi trạng thái các ô


Biểu diễn sân chơi (PlayGround.*)



Enum loại ô trong sân
en u m C ellType { C ELL_EM PTY = 0, CELL_SN AKE, CELL_C H ERRY };



Dữ liệu của lớp PlayGround



Hình chữ nhật → mảng 2 chiều trạng thái
std::vector< std::vector< CellType> > squares;



Con rắn
Snake snake;




Cần tạo lớp Snake






tạo lớp rỗng trong Snake.*
#include trong PlayGround.h để tạm đấy

Điểm số: in t score;


Biểu diễn sân chơi (PlayGround.*)



Trạng thái trò chơi: sử dụng các bít 0, 1, 2, 3
en u m G am eStatus {
G A M E_R U N N IN G = 1 ,
G A M E_STO P = 2,
G A M E_W O N = 4 | G AM E_STO P, // G AM E_W O N tức là G A M E_STO P
G A M E_LO ST = 8 | G A M E_STO P, // tương tự cho G A M E_LO ST
};




Trong lớp PlayGround
Đến đây chương trình dịch được và ta đã lên được
G am eStatus status;
...
p u b lic:
...
b oo l isG am eRunning() con st { retu rn status = = G A M E_R U N N IN G ; }
vo id processU serInput(U serInput input) { }
vo id n extS tep () { }

khung chương trình


Thay đổi trạng thái ơ vng



Có thể khai báo
void ch an g eC ellS tate(in t x, in t y, C ELL_TYPE type);




Một vị trí ln có cả 2 biến x và y
Tạo một struct Position để tiện quản lý



Sẽ có các hàm thay đổi, so sánh, tính tốn vị trí


stru ct Position
{
in t x, y;
};
class P layG rou n d {
...
vo id changeC ellState(Position pos, C ellType type);
};


Khởi tạo sân chơi





Khởi tạo ô vuông: dựa vào số dòng, số cột
Khởi tạo rắn
Thêm 1 quả cherry

PlayG round::PlayG round(in t w idth, in t height)
: squares(height, vector< CellType> (w idth, CELL_EM PTY)),
snake(this), // rắố
n phụ thuộc vào sân chơi,sưủ
a hàm khơ
ủ itạo Snake
status(G AM E_RU N N IN G ),
score(0)
{
addCherry(); // thêm 1 hàm đặt squ ares[0][0] = C ELL_C H ER RY

// đêủthưủnghiệm
}


Sửa hàm khởi tạo Snake



Cần sửa hàm khởi tạo Snake thành
Snake(PlayG round* playG round);



Như vậy,







trong PlayGround.h có include Snake.h
trong Snake.h lại include PlayGround.h
cái nào trước, cái nào sau ? có lỗi ?

Giải pháp: forward declaration
/>


Khai báo class PlayGround; trước khai báo lớp Snake và #include “PlayGround.h” trong

Snake.cpp


Phiên bản 0.1



Hiển thị đơn giản







Sân chơi: nền tím, ơ vng kẻ màu trắng
Rắn: chỉ có 1 đốt hình trịn màu đỏ
Quả cherry: hình vng nhỏ màu cam

Điều khiển bằng phím




Lúc đầu rắn ở giữa sân chơi, chạy sang phải
Nhận phím mũi tên, chỉnh hướng đi của rắn


renderGamePlay(): vẽ sân chơi
vo id ren d erG am eP lay(Painter& painter, con st PlayG round& playG round)

{
in t top = 0,left = 0;

Vẽ hình tương đối với điểm

in t w idth = playG round.getW idth();

(top, left)

in t height = playG round.getH eight();
painter.clearW ithBgC olor(PU RPLE_C O LO R);
painter.setC olor(W H ITE_C O LO R);
for (in t i= 0;i< = w idth; i+ + ) {
painter.setAngle(-90);

Các đường kẻ dọc

painter.setPosition(left+ i* C ELL_SIZE,top+ 0);
painter.m oveForw ard(height * C ELL_SIZ E);
}
for (in t i= 0;i< = height; i+ + ) {
painter.setAngle(0);
painter.setPosition(left+ 0,top+ i* C ELL_SIZE);
painter.m oveForw ard(w idth * C ELL_SIZ E);
}

Các đường kẻ ngang


renderGamePlay(): continue

co n st vector< vector< C ellType> > & squares = playG round.getSquares();
fo r (in t i= 0; i< height; i+ + ) {

Duyệt mảng 2 chiều

for (in t j= 0 ; j< w idth; j+ + ) {
if (squares[i][j] = = C ELL_C H ER RY) {
painter.setC olor(O RAN G E_C O LO R );

Tìm ơ có cherry

painter.setAngle(-9 0);
painter.setPosition(left+ j*C ELL_SIZE+ 5, top+ i*C ELL_SIZE+ 5 );
painter.createSquare(C ELL_SIZE-1 0 );
} else if (squares[i][j] = = C ELL_SN A KE) {
painter.setC olor(R ED _C O LO R );
painter.setAngle(0 );
painter.setPosition(left+ j*C ELL_SIZE+ 5, top+ i*C ELL_SIZE+ C ELL_SIZE/2);
painter.createC ircle(C ELL_SIZE/2-5 );
}
}
}
SD L_RenderPresent(painter.getRenderer());
}

Tìm các đốt rắn


Biểu diễn con rắn




Dữ liệu của Snake



stru ct Position
{

Position position;

in t x;

PlayG round* playG round;

in t y;
Position(in t x_,in t y_) : x(x_),y(y_) {}



};

Đưa khai báo struct Position sang Position.h





thêm hàm khởi tạo bằng 2 toạ độ


#include Position.h trong Snake.h và PlayGround.h


Khởi tạo rắn




Khởi tạo đốt ở giữa sân chơi
Thay đổi trạng thái ở ô này: CELL_SNAKE

Snake::Snake(PlayG round* playG round)
: position(playG round-> getW idth() / 2, playG round-> getH eight() / 2),
th is-> playG round(playG round)
{
playG round-> changeC ellState(position, C ELL_SN AKE);
}

void PlayG round::changeC ellState(Position pos, C ellType type)
{
squares[pos.y][pos.x] = type;
}


×