1. Trang chủ
  2. » Công Nghệ Thông Tin

Hướng dẫn lập trình Game C/C++ cho người mới bắt đầu

45 8,3K 15

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 45
Dung lượng 0,92 MB

Nội dung

Hướng dẫn lập trình Game C/C++ cho người mới bắt đầu

Trang 1

Game C/C++ cho newbie - 01 Lập trình game bắt đầu từ đâu?

bởi Nguyễn Khánh Duy

Game là gì?

Nhìn chung, khi chưa từng biết qua lập trình game, chúng ta thường hay đặt những câu hỏi: lập trình game là như thế nào? Có giống lập trình ứng dụng không? Có khó không? Có đòi hỏi những kỹ thuật gì đặt biệt không ?

Câu trả lời của tôi là: game cũng chỉ là một ứng dụng, và nó cũng như bao ứng dụng khác Khi viết một ứng dụng, bạn có thể bắt đầu từ hàm main, hoặc dùng IDE sinh code tự động để hổ trợ Game cũng vậy Bạn cũng có thể bắt đầu viết game từ hàm main, hoặc dùng các engine hổ trợ

Đứng về khía cạnh lập trình, hay từ chủ quan của tôi, game đơn giản là một vòng lặp vô tận Trong vòng lập đó, bạn vẽ, bạn xử lý các diễn biến của game, xử lý sự kiện tương tác từ người chơi Vậy là đủ cho một game Tuy nhiên, để làm game cho mục đích thương mại, đòi hỏi bạn nhiều hơn thế

Một cách nhìn khác, game là một cuốn phim có tương tác Nếu như một bộ phim cần nhiều thứ như kịch bản tốt, dàn dựng hay, hậu kỳ, kiểm duyệt, quãng bá, thì game cũng vậy Game cũng cần một nội dung hay (kịch bản), coding tốt (dàn dựng, hậu kỳ), kiểm soát chất lượng (kiểm duyệt), quãng bá Nếu một phim thành công được đánh giá qua doanh thu, thì game cũng vậy Tuy nhiên, khi mới bắt đầu, thì doanh thu, lợi nhuận, cần được gạt ra khỏi tư tưởng của mình, để có đủ tỉnh táo tập trung vào chuyên môn

Lập trình game bằng ngôn ngữ nào?

Như mọi ứng dụng khác, bạn có thể lập trình game bằng mọi ngôn ngữ Tùy theo nhu cầu, sở trường mà bạn có thể chọn một ngôn ngữ nào đó để làm game Tuy nhiên, hiện nay có một vài xu thế như sau:

Trang 2

Java: thường dùng để viết game cho Mobile - các dòng phone hổ trợ J2ME, hoặc viết game cho Android

Ít khi dùng để viết game cho PC

C#: khi nhắc tới C#, ta có thể nghĩ ngay đến XNA, và gắn liền với thương hiệu Microsoft Dùng viết game cho windows mobiles hoặc PC

Javascript: dùng cho môi trường web

Objective C: Dùng cho iOS như máy MAC, iPhone, iPad

C/C++: với sự lâu đời cũng như được sự hưởng ứng rộng rãi từ hầu hết các chương trình đào tạo đại học, C/C++ được xem là ngôn ngữ cơ bản của mọi ngôn ngữ lập trình, và có lẽ ít nhất một lần trong đời thì mỗi programmer đều từng đụng đến nó Do đó, C/C++ cũng là một ngôn ngữ khá được ưa chuộng trong lập trình game ngày nay, với khả năng thực thi trên khác nhiều platform: Windows, Linux, MacOS, Android, iphone/iPad, Symbian, Brew, Meegoo,

Xin lưu ý là ta không nên đánh đồng C/C++ với Visual C, hay Turbo C, hay Visual studio VC, TC, VS là những IDE, còn C/C++ là ngôn ngữ lập trình Ta có thể code C/C++ hoàn toàn bằng Nodepad, và dùng các trình biên dịch khác nhau để build

Trong nội dung bài này, tôi cũng dùng C/C++ trên môi trường Visual studio 2010 để minh họa Các bạn

có thể download bản express tại đây Không cần thiết phải crack

Lập trình game cần những kiến thức gì?

Đã là lập trình hiển nhiên cần phải biết lập trình, tư duy lập trình Không nhất thiết bạn phải xuất sắc; biết ít, làm ít, biết nhiều, làm nhiều

Một chút kiến thức kỹ năng về game Hay nói cách khác, biết chơi game, và từng chơi game

Biết một ngôn ngữ lập trình nào đó

Biết một ít kiến thức về toán, vật lý (google it, nếu cần)

Trang 3

Một số kiến thức về đồ họa 2D, 3D

Trong phần này, ta sẽ bắt đầu code game

Chuẩn bị

Bạn cần cài đặt một số tool cần thiết sau:

Visual studio express 2010

Notepad ++

Python 2.7

Java SDK 1.6

Cài đặt "Hello game"

Như đã trình bài trong bài trước, game là một vòng lập vô tận Do đó, với chương trình như nhau, ta cũng có thể tạm gọi là một game (nhưng chưa có tương tác)

Bước một, dùng visual studio, tạo một Empty project, tên gametutor:

Trang 4

Bước 2, tạo file main.cpp,

Add một item mới

Trang 5

Tạo main.cpp từ template

với nội dung:

Trang 7

11 }

Game C/C++ cho newbie - 03 Quản lý vòng đời game

bởi Nguyễn Khánh Duy

Giới thiệu

Với tư tưởng hướng đối tượng, trong bước này, ta sẽ thiết kế những lớp cần thiết cho việc quản lý game

Đối tượng đầu tiên ta thấy chính là game: lớp CGame

Class quản lý game (CGame)

Về cơ bản, ta lớp CGame cần có các phương thức:

Init: thiết lập các tham số cho game

Destroy: hủy game Gọi trước khi kết thúc game, dùng để thu hồi vùng nhớ, giải phóng thiết bị chiếm giữ,

Exit: yêu cầu kết thúc game Làm này được người dùng gọi khi cần kết thúc game

Run: Quản lý vòng lặp chính của game

Pause: tạm dừng game

Resume: khôi phục game sau khi tạm dừng

Trang 8

virtual void Run();

virtual void Exit();

virtual void Pause();

virtual void Resume();

Trang 9

bool IsAlive() {return m_isAlived;}

bool IsPause() {return m_isPaused;}

protected:

virtual void Init() = 0;

virtual void Destroy() = 0;

Trang 10

void CGame::Resume() {

m_isPaused = false; }

void CGame::Exit()

{

m_isAlived = false; }

void CGame::Run() {

this->Init();

while (m_isAlived) {

if (m_isPaused) {

printf("paused\n"); }

else

{

printf("running\n"); }

Sleep(80);

Trang 11

Đảm bảo khả năng sử dụng lại của CGame ở nhiều game khác nhau

Tách biệt giữ lớp thư viện và lớp ứng dụng, thuận tiện trong việc phát triển và bảo trì

Khi này, ta thiết kế 1 lớp mới có tên là CExample, thừa kế từ CGame:

Trang 13

Hàm main được thiết kế đơn giản như sau:

Game C/C++ cho newbie - 04.Chia để trị

bởi Nguyễn Khánh Duy

Phương pháp chung

Ở phần 3, ta đã thiết kế một lớp để quản lý vòng đời của game Tuy nhiên, khó khăn dễ thấy là game thường rất lớn Nếu tất cả mọi cập nhật game đều để trong hàm Run(), thì việc quản lý trở nên rất khó khăn Để giải quyết vấn đề này, ta có thể áp dụng một phương pháp cũ nhưng hiệu quả: chia để trị

Phương pháp chia để trị này được áp dụng trong tất cả các ứng dụng, thông qua việc áp dụng lượt

đồ State diagram:

Trang 14

Source: http://upload.wikimedia.org/wikipedia/commons/c/cf

Áp dụng mô hình trên, game sẽ được chia thành nhiều state Vấn đề nãy sinh là state trong game là gì,

và chia như thế nào?

State và cách chia state trong game

State trong game, có thể hiểu là một giai đoạn của game, hay một màn hình/ 1 cảnh / 1 scene (tùy theo cách gọi, cách hiểu)

Khi chơi một game, lấy vị dụ như game Angry Birds trên trình duyệt Chrome:

Logo nhà sản xuất

Màn hình giới thiệu game (poster)

Menu chính (gồm các nút play, option )

Trang 15

State vs sub-State

Với một state quá lớn, ta lại nghĩ đến trường hợp chia nhỏ state thành các sub-state Tuy nhiên, nên thận trọng trong việc chia sub-state Việc chia thành các sub-state bên trong state đòi hỏi chi phí quản lý cao hơn Do đó, không nên nếu không thật sự cần thiết

Thiết kế State như thế nào ?

Nhìn chung, State cũng giống như một ứng dụng thu nhỏ, do đó cũng có các bước cơ bản sau:

Init

Update

Render

Exit

Trang 16

virtual void Init() = 0;

virtual void Update() = 0;

virtual void Render() = 0;

Trang 17

Quản lý các State như thế nào?

Sau khi đã chia nhỏ các state, nhiệm vụ tiếp theo là làm sao đảm bảo việc chuyển đổi giữa các state được trơn tru

Việc quản lý các state nhìn chung là do vòng lặp chính điều khiển Tuy nhiên để thuận tiên, ta có thể định nghĩa 1 lớp chuyển quản lý các state, tạm gọi là lớp CStateManagement

Để đơn giản, việc quản lý state tuân theo nguyên tắc sau:

Tại một thời điểm, chỉ có 1 state được phép "hoạt động" (Update/Render)

Khi chuyển từ một state (A) sang một state khác (B), A phải được hủy (Exit) và B phải được tạo (Init) sau

Trang 18

CState* m_pCurrentState;

CState* m_pNextState;

public:

void Update(bool isPause);

void SwitchState(CState* nextState);

};

Trang 21

Trong ví dụ trên, hàm Update mới là hàm quản lý chính việc chuyển state SwitchState chỉ đóng vai trò

"đánh dấu" Điều này đảm bảo CStateManagement hoạt động đúng theo 3 tiêu chí đã nêu ở trên

Kết nối State và Game

Do việc quản lý State lúc này được trao cho CStateManagement Ta chỉ việc kết nối CStateManagement

virtual void Run();

virtual void Exit();

virtual void Pause();

virtual void Resume();

bool IsAlive() {return m_isAlived;}

bool IsPause() {return m_isPaused;}

protected:

CGame();

Trang 22

static CGame* s_pInstance;

virtual void Init() = 0;

virtual void Destroy() = 0;

Trang 23

else

{

CStateManagement::GetInstance()->Update(false);

Trang 27

Để việc quản lý được đơn giản, ta cần chia chương trình (game) thành các state nhỏ

Để thuận tiện, trước khi bắt đầu code game, ta nên vẽ trước state diagram, phác họa các state cần thiết, cũng như "đường đi" giữa các state

Đến thời điểm này, thư viện ta đã xây dựng được 3 lớp cơ bản:

Trang 28

CGame

CState

CStateManagement

Game C/C++ cho newbie - 05 Game đa nền tảng

bởi Nguyễn Khánh Duy

Một ví dụ khác, hàmprintfdùng cho debug có thể dùng cho console win32, tuy nhiên với Android thì không thể, mà phải được thay bằng android_log_print

Cách thức cấu hình

Để làm được như đã nêu, trước tiên, ta cần cấu hình cho từng platform khác nhau khi compile Ta định nghĩa 1 số file header:

Trang 29

Header.h: chứa những thông tin header cần cho chương trình

Config.h: chứa các thông tin cấu hình

Macros.h: chứa các macro thông dụng

Trang 32

Trong ví dụ trên, ta dùng 1 hàmwrapper là Log, thay cho printf của win32 console và

android_log_print của Android log Đồng thời thay thế tất cả các hàmprintf bằng Log, và khai báo

#include "header.h" ở tất cả các lớp

Xây dựng lớp đại diện / cầu nối

Tuy nhiên, không phải trong trường hợp nào ta cũng có thể sử dụng macro Với những trường hợp phức tạp, ta thay thế bằng hàm Ta định nghĩa một lớp gọi là CDevice chứa các tập hàm này (Trong ví dụ này,

ta giả sử Sleep là một trường hợp ví dụ)

Trong trường hợp cần can thiệp sang một môi trường khác C/C++ (Obj-C hoặc Android Java), lớp device làm nhiệm vụ như một wrapper, đóng vai trò cầu nối, giúp thư viện game tương đối độc lập với platform

Trang 35

Trong ví dụ trên, hàm SleepEx được thay đổi tùy theo platform

Lúc này, lớp CGame được hiệu chỉnh:

Trang 36

else

{

CStateManagement::GetInstance()->Update(false); }

Trang 37

28

Game C/C++ cho newbie - 06 Frame-rate

bởi Nguyễn Khánh Duy

FrameDt: khoảng thời gian dùng để thực hiện xong một frame

Limit framerate: là kỹ thuật giới hạn số lượng frame trong 1 giây Kỹ thuật này giúp:

+ Ổn định framerate chung cho cả game

+ Giảm tình trạng game lúc nhanh lúc chậm

+ Giúp đồng bộ hóa framerate của game trên các device khác nhau

+ Giảm năng lượng tiêu tốn không cần thiết Fps càng cao, đồng nghĩa với việc CPU/GPU làm việc trong khoảng thời gian dài với công suất cao, gây hao phí không cần thiết Limit framerate giữ fps ở mức độ vừa phải, tạo ra khoảng thời gian "nghĩ ngơi" cho CPU/GPU

Kỹ thuật Limit framerate

Như đã trình bày ở trên, Limit framerate đảm bảo fps được duy trì ổn định quanh một giá trị qui ước Giả sử mong muốn tốc độ game ổn định ở khoảng 25 fps

25 fps40ms/frame

Như vậy, mỗi lần update & render trung bình khoảng 80 ms Trong trường hợp tổng thời gian update + render nhỏ hơn 80ms, game được phép "ngủ" trong khoảng thời gian còn lại

Trang 38

Trong hình minh họa trên:

Frame 1: tổng thời gian update + render là 20ms Do đó, game được sleep trong khoảng 20ms còn lại Frame 2: tổng thời gian update + render là 50ms > 40ms Không cần sleep (hoặc sleep 1)

Frame 3: tổng thời gian update + render là 25ms Do đó, game được sleep trong khoảng 15ms còn lại

Kỹ thuật limit fps không phải là kỹ thuật làm tăng fps Để nâng cao fps cho game, cần kỹ thuật

optimization

Nên limit fps bao nhiêu?

Không có một giá trị cụ thể nào được đưa ra cho câu trả lời này Tùy vào từng game, từng loại game mà người lập trình/nhà sản xuất đưa ra con số qui định cho mình Thông thường, fps = 25 là ổn

Tuy nhiên, việc limit fps sẽ không có tác dụng nếu fps thật sự nhỏ hơn fps cần limit Xem ví dụ trên, frame 2 Trong trường hợp này, limit fps không có vai trò gì khi đặt ở ngưỡng 25fps Tuy nhiên, với ngưỡng 12.5 fps (80 ms/frame), limit fps lại có tác dụng

Implementation

<="" a="" style="margin: 0px; padding: 0px; border: 0px; family: inherit; size: inherit; style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; vertical-align: baseline; color: rgb(3, 119, 186); text-decoration: none; outline: 0px;">Bước 1: Lấy ngày giờ hệ thống

<="" a="" style="margin: 0px; padding: 0px; border: 0px; family: inherit; size: inherit; style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; vertical-align: baseline; color: rgb(3, 119, 186); text-decoration: none; outline: 0px;">Ta cần một hàm lấy giờ hệ thống để tính toán khoảng thời gian dùng cho update + render Để làm được điều này:

Trang 39

<="" a="" style="margin: 0px; padding: 0px; border: 0px; family: inherit; size: inherit; style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; vertical-align: baseline; color: rgb(3, 119, 186); text-decoration: none; outline: 0px;">

<="" a="" style="margin: 0px; padding: 0px; border: 0px; family: inherit; size: inherit; style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; vertical-align: baseline; color: rgb(3, 119, 186); text-decoration: none; outline: 0px;">

<="" a="" style="margin: 0px; padding: 0px; border: 0px; family: inherit; size: inherit; style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; vertical-align: baseline; color: rgb(3, 119, 186); text-decoration: none; outline: 0px;">

<="" a="" style="margin: 0px; padding: 0px; border: 0px; family: inherit; size: inherit; style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; vertical-align: baseline; color: rgb(3, 119, 186); text-decoration: none; outline: 0px;">Khai báo thư viện time.h trong header.h để sử dụng hàm clock() Việc khai báo này được thực hiện với config PLATFORM_WIN32_VS Các platform khác có một chút khác biệt ta sẽ đề cập sau

Trang 40

void SleepEx(unsigned long milisec);

unsigned long GetTimer();

Bước 2: Tạo lớp CFpsManager quản lý fps

Lớp CFpsManager cũng được thiết kế dạng singleton, gồm các phương thức:

SetLimitFps: thiết lập thông số limit fps

BeginCounter: Được gọi khi bắt đầu tình toán fps

EndCounter: Được gọi tại ví trí kết thúc tính đoán fps và thực hiện limit frame rate

GetFrameDt: Lấy FrameDT hiện tại

Trang 41

GetRuntimeFps: Lấy Fps hiện tại (giá trị do đạc thực tế) Kết quả trả về có thể không trùng khớp với giá trị thiết lập bởi SetLimitFps

Trang 43

long Endtime = CDevice::GetInstance()->GetTimer();

int Dt = int(Endtime - m_iStartTime);

Trang 44

Bước 3: Cài đặt chức năng tính toán fps vào vòng lập chính của game

Ta tiến hành hiệu chỉnh CGame

else

{

Ngày đăng: 01/06/2014, 01:19

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w