Hướng dẫn C++ cơ bản cho người mới - Zubachi biên soạn

Thảo luận trong 'Game Development' bắt đầu bởi Alone Beast, 9/2/06.

  1. Alone Beast

    Alone Beast C O N T R A

    Tham gia ngày:
    14/1/04
    Bài viết:
    1,607
    Nơi ở:
    ...
    Nhập môn C++ dành cho người chưa biết gì
    (c) 2005 by zubachi

    Tài liệu sau sẽ dạy những vấn đề căn bản nhất trong lập trình C++ cơ bản. Chương trình biên dịch được dùng là Microsoft Visual C++ 6.0 (MSVC6). Chỉ yêu cầu biết dùng... Windows.

    1 - Tạo một workspace:
    Trong MSVC6, bất kỳ một đề án lập trình nào cũng phải có một workspace, chứ không chỉ đơn giản là một file duy nhất, thì mới có thể hoạt động được. Tạo ra workspace thực ra rất đơn giản. Trong tài liệu này, chúng ta sẽ lập những chương trình căn bản nhất, gọi là các chương trình console (Console Application). Các chương trình console chỉ có thể hiện ra chữ trên một console nền đen tương tự như môi trường DOS.

    [​IMG]
    Một chương trình console

    Chương trình console quả thật là không có nhiều tác dụng. Người ta thường tạo ra những chương trình này nhằm mục đích kiểm tra thuật toán, hay thực hiện các công việc không cần dùng đến hình ảnh như là format đĩa, convert dữ liệu, v.v... Ở đây, chúng ta lập chương trình console để học một cách dễ dàng vì lập ra các chương trình có hình ảnh là việc tương đối khó khăn cho người mới bắt đầu.

    Các bước tạo ra một workspace cho chương trình console:
    + Bấm vào menu File. Chọn New. Một dialog hiện ra.

    [​IMG]

    Lưu ý những vị trí khoanh đỏ

    + Bấm vào tab Projects. Chọn mục Win32 Console Application. Chọn Create new workspace. Gõ tên đề án vào.
    + Bấm OK. Một dialog hiện ra.

    [​IMG]

    Đây là Wizard hỗ trợ việc tạo workspace. Bạn có thể nhờ Wizard tạo ra một workspace được làm sẵn. Ở đây, chúng ta chọn An empty project, nghĩa là chúng ta không cần một workspace có sẵn, mà sẽ tự tạo ra.

    + Bấm Finish, workspace mới sẽ được tạo ra.

    Sau đây là hình ảnh một workspace của một chương trình console đơn giản.

    [​IMG]


    Chỗ khoanh đỏ cửa sổ workspace explorer, hiện ra các thành phần của workspace. Chỗ khoanh xanh là phần gõ chương trình.

    Nếu bạn không thấy được phần khoanh đỏ (phần workspace explorer), thì bấm menu View -> Workspace (hoặc bấm Alt - 0).

    Lúc này, bên dưới khung workspace explorer có 2 cái tab là ClassView và FileView. Trong tài liệu này, chúng ta không dùng đến tab ClassView, mà chỉ dùng tab FileView. Hãy bấm vào tab FileView nếu như bạn đang ở tab ClassView.

    Như vậy, bạn có thể thấy là một workspace sẽ có thể có nhiều thành phần khác nhau. Sau khi lập trình xong, các phần này sẽ được nối lại với nhau, tạo ra file EXE. Tuy nhiên, trong tài liệu này, chúng ta sẽ chỉ tạo ra một thành phần duy nhất mà thôi.

    2 - Chương trình Hello World:

    Hầu hết các tài liệu dạy lập trình đều dùng chương trình Hello World làm mẫu đầu tiên. Tài liệu này cũng không ngoại lệ.

    Để có thể bắt đầu, với bài học phần trước, bạn cần tạo một workspace cho chương trình console.

    Đầu tiên chúng ta cần cho vào workspace một thành phần. Thành phần này sẽ là một đoạn chương trình C++. Bạn cần biết là một thành phần của workspace không nhất thiết phải là một đoạn chương trình, mà còn có thể là một hình ảnh, âm thanh, v.v...

    Các bước để thêm một đoạn chương trình C++ vào workspace:
    + Bấm vào tab FileView trên khung workspace explorer.
    + Bấm nút phải vào phần Source Files (khoanh xanh), rồi chọn Add Files to Folder (khoanh đỏ)
    [​IMG]
    + Tiếp theo, bạn chỉ việc gõ tên file vào. Bất kỳ tên gì cũng được.
    [​IMG]

    + Một dialog như sau sẽ hiện ra thì bạn chỉ việc chọn Yes để tạo ra file mới. Nếu bạn chọn No thì MSVC6 sẽ không tạo ra file mới và workspace sẽ không có thêm đoạn chương trình nào hết.

    [​IMG]

    Bấm Cancel để gõ lại tên file.

    Như vậy trên khung workspace explorer sẽ xuất hiện một thành phần mới. Ở đây là đoạn chương trình có tên file là main.cpp.
    [​IMG]

    Bạn sẽ bắt đầu viết chương trình bằng cách double-click vào tên file main.cpp, nếu tên file này không hiện ra thì có thể do bạn chưa bấm nút expand (khoanh xanh trong hình trên) cho phần Source Files.

    Phần gõ chương trình sẽ hiện ra, bạn chỉ việc gõ vào đoạn chương trình sau:
    //***************************************************************
    #include <iostream>
    #include <conio.h>

    int main() {
    std::cout << "Hello World!";

    while (!_kbhit());

    return 0;
    }
    //***************************************************************

    Tạm thời bạn chưa cần hiểu rõ đoạn chương trình trên làm cái gì. Thay vì vậy, bạn sẽ cho chương trình hoạt động.

    Để có thể cho một chương trình hoạt động, bạn cần biên dịch (compile) chương trình. Biên dịch là quá trình chuyển đổi chương trình viết bằng ngôn ngữ C++ thành một ngôn ngữ đặc biệt, gọi là mã máy (machine code), mà máy vi tính có thể hiểu được. Tất nhiên, trước mắt thì bạn không cần phải học cái ngôn ngữ đặc biệt đó làm gì. Sau khi mã máy được tạo ra, nó sẽ được ghi lại thành file EXE, để sau này bạn có thể cho chương trình hoạt động mà không cần thực hiện lại quá trình biên dịch.

    Tiếp theo, để có thể thấy được chương trình hoạt động, bạn chỉ việc cho chạy (run) file EXE đã được tạo ra trong quá trình biên dịch.

    Các bước biên dịch và chạy chương trình:
    + Bấm vào menu Build, chọn Build <tên đề án>.exe (hoặc bấm F7), MSVC6 sẽ biên dịch chương trình và tạo ra file EXE.
    [​IMG]

    Trong quá trình biên dịch có thể xảy ra lỗi. Có khả năng bạn đã gõ đoạn chương trình chưa thật chính xác. Cách tốt nhất là bạn nên Copy và Paste lại đoạn mã để tránh rủi ro này. Ngoài ra, cũng có khả năng bạn thực hiện quá trình tạo workspace chưa đúng theo trình tự đã nêu ở phần 1. Nếu vậy, bạn sẽ phải thực hiện các bước lại từ đầu.

    + Sau đó, bạn bấm F5 để chạy chương trình.

    [​IMG]


    Chương trình sẽ hiện ra kết quả như vậy. Bạn cần bấm một nút nào đó trên bàn phím để close.
     
  2. Alone Beast

    Alone Beast C O N T R A

    Tham gia ngày:
    14/1/04
    Bài viết:
    1,607
    Nơi ở:
    ...
    Còn dưới đây là hướng dẫn sử dụng C và C++ để lập trình game đơn giản. Zubachi viết, chia thành nhiều document, nhưng do bản tính không thích nổi trội hay le lói :p nên anh đã không post lên, mà chỉ để link down cho mọi người.
    Phần này (tập 1 ) Zubachi cũng chưa hoàn thành, nên hi vọng mọi người cổ vũ để ảnh thực hiện được trọn vẹn. ^^

    ==================


    Lập trình trò chơi với DirectX 7 và MSVC++ 6


    Tập 1 - Trò chơi Arcade


    Lời nói đầu

    Tài liệu này được viết nhằm mục đích hướng dẫn lập trình trò chơi một cách nghiêm túc. Công cụ lập trình là Microsoft Visual C++ 6 và Microsoft DirectX 7 SDK. Tập 1 của tài liệu sẽ dừng lại ở mức độ căn bản, và bỏ qua phần nâng cao là lập trình 3D, trí tuệ nhân tạo, và chơi qua mạng. Tài liệu sẽ được chia thành các phần:
    • Sơ lược về lập trình C trong Windows
    • Lập trình DirectX 7 (bỏ qua 3D, Direct Play)
    • Xây dựng engine DirectX 7 đơn giản (bỏ qua 3D, Direct Play)
    • Phát triển một trò chơi Arcade

    Yêu cầu hệ thống:
    • Hệ điều hành Microsoft Windows 98 trở lên
    • Microsoft DirectX run-time library
    • Microsoft DirectX 7.0a SDK
    • Microsoft Visual C++ 6.0

    DirectX run-time library không nhất thiết phải là của DirectX 7. Run-time library có thể dễ dàng download trên trang web của Microsoft (http://www.microsoft.com). Ngoài ra, hầu hết các CD trò chơi được lập trình với DirectX đều có phần run-time.

    Hiện nay DirectX 7 SDK không được lưu trữ trên trang web của Microsoft nữa. Tuy nhiên, chúng ta không cần cả một bộ SDK hơn 100MB để lập trình DirectX 7 với MSVC++ 6. Tác giả đã nén các phần chính yếu, bao gồm các header và library, và đưa lên mạng theo các địa chỉ:
    http://zubachi.topcities.com/include.zip (209kb)
    http://zubachi.topcities.com/lib1.zip (200kb)
    http://zubachi.topcities.com/lib2.zip (870kb)
    * Phần library đã được tách làm hai file zip, lib1.zip và lib2.zip . Các file trong hai file nén này cần được chứa trong cùng một folder.


    Phần 1 - Sơ lược về lập trình C trong Windows

    Hãy khảo sát chương trình Hello World viết bằng C trong DOS (hay Windows Console):

    *********************************************************************************************************************************************************
    #include <stdio.h>

    void main() {
    printf("Hello World\n);
    }
    *********************************************************************************************************************************************************

    Ai cũng biết chương trình sẽ in ra dòng chữ Hello World trên nền màn hình đen sì của DOS. Nhưng liệu chương trình ngắn ngủi trên có thể in chữ ra một cửa sổ nền trắng của Windows không? Sự thật là lập trình trong Windows không có sự giản đơn như vậy. Trong DOS, lệnh printf sẽ in chữ ra màn hình, nhưng trong môi trường Windows, chúng ta cần xây dựng một màn hình, hay đúng hơn là một cửa sổ, để in chữ. Do đó, chương trình căn bản nhất về lập trình trong Windows là xây dựng một cửa sổ.

    1 - Giới thiệu

    Hệ điều hành Windows chiếm rất nhiều diện tích lưu trữ, trong khi DOS chỉ cần vài chục kilobytes, hay tối đa là vài megabytes là đủ. Thật ra, phần core (phần sườn) của Windows cũng không lớn hơn DOS bao nhiêu. Phần chiếm nhiều diện tích lưu trữ chính là các driver và API dll. Các driver dùng đề điều khiển phần cứng, còn các API dll là phần run-time cho các chương trình.

    DLL (Dynamic Link Library) có thể gọi là thư viện liên kết động. Một library (thư viện) là một tập hợp các function (hàm) thường dùng trong một chương trình. Trong quá trình biên dịch, Chương trình C sẽ được link (liên kết) với các library để có thể tiếp cận các function cần thiết. File EXE của chương trình sẽ gộp chung cả library vào, kích thước file EXE có thể sẽ rất lớn nếu gặp một thư viện phức tạp. Nhưng DLL có tính dynamic (động), sẽ không được link như library thông thường. Thay vào đó, nó được lưu trữ trong bộ nhớ trong quá trình chạy chương trình và sẽ thi hành phần việc của nó một cách độc lập. Nhờ sự độc lập như vậy mà xử dụng DLL sẽ nhanh hơn. Và đây cũng là một yếu tố cần thiết về lập trình trong Windows.

    Có thể nói bất kỳ một chương trình nào chạy trong Windows cũng đều cần các run-time dll. Nói cách khác là chúng không thể tự hoạt động một mình như các chương trình DOS. Các run-time dll cung cấp các hàm chức năng cho một chương trình, ví dụ: Một chương trình cần vẽ một dòng chữ lên cửa sổ. Để thực hiện điều này, nó phải gọi đến hàm DrawText trong dll GDI32. Như vậy, công việc vẽ dòng chữ là của GDI32 chứ không phải của chính chương trình. Do đó, chương trình này luôn cần dll GDI32.

    GDI32 trong ví dụ trên luôn có mặt trong bất kỳ một máy computer cài Windows nào, vì nó đã được cài đặt sẵn cùng với hệ điều hành. Các DLL được cài đặt sẵn như GDI32 được gọi là các API (Application Programming Interface) DLL, hỗ trợ làm đơn giản hoá việc lập trình trong Windows.

    Các phần tiếp theo sẽ hướng dẫn bạn đọc từng bước xây dựng một chương trình đơn giản. Tuy nhiên, tài liệu sẽ hạn chế ở việc xây dựng một cửa sổ với một menu bar, đủ phục vụ cho mục đích lập trình game.

    2 - Nhập môn


    Chúng ta sẽ xây dựng một chương trình Hello World cơ bản nhất trong phần này. Chương trình sẽ hiển thị dòng chữ Hello World trong một Message Box.

    Đầu tiên, chúng ta cần tạo phần shell (khung sường) cho chương trình bằng Wizard của Visual C++ 6. Các bạn có thể tự gõ lấy phần shell, nhưng điều này là không cần thiết.

    Các bước tạo phần shell cho chương trình đầu tiên:
    • Click vào menu File, chọn New
    • Chọn tab Projects, chọn Win32 Application
    • Trong ô Project name, gõ vào tên chương trình
    • Trong ô Location, chọn folder chứa chương trình
    • Các lựa chọn khác để giống như hình minh họa
    • Tất nhiên là click OK

    [​IMG]

    Trong Dialog Win32 Application Wizard xuất hiện sau khi click OK, chọn A simple Win32 application.

    Shell của chương trình bao gồm các file (giả sử tên chương trình là temp2):
    StdAfx.cpp
    temp2.cpp
    StdAfx.h
    readme.txt
    basetsd.h

    Trước mắt bạn không cần biết StdAfx.cpp, StdAfx.h hay basetsd.h là cái gì cả.

    Bạn nên để màn hình MSVC giống như trong hình minh họa, nghĩa là gồm khung Workspace (bên mé tay trái) và khung Output (bên dưới cùng), bằng cách bấm vào nút Workspace (hay bấm Alt-0) và nút Output (hay bấm Alt-2) trên thanh Toolbar.

    Trong khung Workspace, chọn tab File View (ở bên dưới của khung), chọn file .cpp của chương trình (ví dụ: temp2.cpp).

    Đoạn mã sau đây là do Wizard tạo ra sẵn:

    *********************************************************************************************************************************************************
    // temp2.cpp : Defines the entry point for the application.
    //

    #include "stdafx.h"

    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    // TODO: Place code here.

    return 0;
    }
    *********************************************************************************************************************************************************

    Bạn xoá dòng lệnh có chữ TODO và thay thế bằng dòng lệnh:

    *********************************************************************************************************************************************************
    ...
    MessageBox(NULL, "Hello World", "My Application", 0);
    ...
    *********************************************************************************************************************************************************

    Sau đó bấm F7 để biên dịch chương trình, rồi bấm Ctrl-F5 để chạy. Chương trình sẽ hiện ra một Message Box có tiêu đề My Application và dòng chữ Hello World với nút OK.

    Tất nhiên khả năng đồ họa của DirectX 7 không thể nào hoạt động trên một Message Box được. Cái chúng ta thật sự cần là một cửa sổ. Phần tiếp theo sẽ xây dựng một cửa sổ và hiển thị dòng chữ Hello World lên đó.
     
  3. Alone Beast

    Alone Beast C O N T R A

    Tham gia ngày:
    14/1/04
    Bài viết:
    1,607
    Nơi ở:
    ...
    3 - Đôi nét về lập trình hướng đối tượng

    Cho đến lúc này, nếu bạn thật sự không hiểu gì hết thì nên từ giả tài liệu này, và tìm một tài liệu về lập trình C căn bản trong DOS (hay Visual Basic cũng được).

    Gõ chương trình có thể hiểu là gõ những dòng lệnh mà máy vi tính có thể hiểu và sẽ thi hành theo từng dòng một. Giống như hướng dẫn làm một việc nào đó từng bước vậy. Và như vậy, một chương trình là một bảng hướng dẫn cho máy vi tính để thi hành một công việc nào đó.

    Trong kỹ thuật lập trình cũ, người ta thường phân chương trình thành các module (đoạn chương trình), bao gồm có module chính (chứa function main) và các module phụ (chứa các function cần thiết khác). Các dữ liệu sẽ được lưu trữ riêng lẻ so với các function. Kiểu lập trình như vậy chính là kiểu lập trình trong ngôn ngữ C (không phải là C++). Với tư tưởng lập trình như vậy, lập trình trong Windows sẽ rất khó khăn.

    Trong C++, ngôn ngữ rất thiên về lập trình hướng đối tượng, thì chương trình còn được phân ra làm nhiều class (lớp đối tượng hay loại đối tượng). Mỗi class tượng trưng cho một kiểu đối tượng. Để dùng class vào mục đích thực tiễn, chương trình sẽ phải tạo các instance của các class. Một instance chính là một đối tượng được xây dựng dựa trên một class. Tóm lại, class là kiểu, còn instance được tạo ra theo kiểu đó.

    Để lập trình game, bạn chỉ cần hiểu đại khái là được, không cần phải đi sâu.


    4 - Xây dựng một cửa sổ

    Chúng ta hãy khảo sát dòng lệnh:

    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

    Dòng lệnh này bắt đầu function WinMain, function này tương đương với main so với lập trình trong DOS, hay với Form_Load() hoặc Sub Main() trong Visual Basic. Chương trình của chúng ta sẽ được bắt đầu từ ngay sau dòng lệnh này. Các tham số trong function là do hệ thống cung cấp để chúng ta dùng:

    • HINSTANCE hInstance Handle (địa chỉ) đến vùng bộ nhớ chứa file .exe chương trình.
    • HINSTANCE hPrevInstance Không dùng trong chương trình Windows 32-bit (chỉ dùng với hệ điều hành 16-bit cũ)
    • LPSTR lpCmdLine Command Line (tham số của chương trình).
    • int nCmdShow Một giá trị cần dùng cho function ShowWindow().

    Bây giờ chúng ta sẽ bắt đầu xây dựng một cửa sổ. Bạn sẽ cần phải tạo một shell mới, tương tự như chương 1.

    Sau đó copy đoạn mã sau vào chương trình.

    *********************************************************************************************************************************************************
    #include "stdafx.h"
    #include <windows.h>

    // Bước 4
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    switch(msg)
    {
    case WM_CLOSE:
    DestroyWindow(hwnd);
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
    }

    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
    {
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Bước 1
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "myWindowClass";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
    MessageBox(NULL, "Window Registration Failed!", "Error!",
    MB_ICONEXCLAMATION | MB_OK);
    return 0;
    }

    // Bước 2
    hwnd = CreateWindowEx(
    WS_EX_CLIENTEDGE,
    "myWindowClass",
    "The title of my window",
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
    NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
    MessageBox(NULL, "Window Creation Failed!", "Error!",
    MB_ICONEXCLAMATION | MB_OK);
    return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Bước 3
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
    }
    return Msg.wParam;
    }
    *********************************************************************************************************************************************************

    Chương trình sẽ hiện ra một cửa sổ như sau:


    Bây giờ, chúng ta sẽ khảo sát các bước để xây dựng một cửa sổ (lưu ý các dòng chú giải đã đánh dấu vị trí của từng bước):

    Bước 1: Đăng ký class cửa sổ với hệ điều hành:
    Trước khi ra lệnh cho hệ điều hành tạo một cửa sổ, chúng ta cần thông báo các chi tiết của cửa sổ trước. Một class cửa sổ chứa các thông tin chi tiết cần được đăng ký, và một hay nhiều cửa sổ sẽ được tạo theo mẫu class này. Điều này gồm ba bước:
    • Khai báo class cửa sổ (khai báo biến) WNDCLASSEX wc;
    • Khai báo các chi tiết của instance
    • Ra lệnh đăng ký RegisterClassEx(&wc);
    Các chi tiết của cửa sổ bao gồm (bạn chưa cần hiểu hết):
    • cbSize Kích thước của cấu trúc cửa sổ, thường gán giá trị : sizeof(WNDCLASSEX)
    • style Kiểu class, thường đặt : 0
    • cbClsExtra Dung lượng bộ nhớ cần thêm cho class này, thường đặt : 0
    • cbWndExtra Dung lượng bộ nhớ mà mỗi cửa sổ đặt theo class này cần thêm, thường đặt : 0
    • hInstance Handle đến phần bộ nhớ của chương trình, tất nhiên là đặt : hInstance
    • hIcon Biểu tượng lớn của cửa sổ, được xếp đặt qua function LoadIcon
    • hCursor Hình ảnh của con trỏ chuột, được xếp đặt qua function LoadCursor
    • hbrBackGround Màu nền cửa sổ
    • lpszMenuName Tên của thanh menu trong resource (tài nguyên) của chương trình
    • lpszClassName Tên của class cửa sổ sẽ đăng ký
    • hIconSm Biểu tượng nhỏ của cửa sổ
    • lpfnWndProc Function điều khiển cửa sổ

    Bước 2: Ra lệnh tạo cửa sổ
    Bạn cần ghi nhớ tên của class cửa sổ (lpszClassName). Cái tên này có thể được lưu trữ dưới dạng hằng (như trong ví dụ này) hoặc biến. Các bước tạo cửa sổ:
    • Khai báo một biến để lưu trữ pointer (vị trí trong bộ nhớ) đến cửa sổ
    • Ra lệnh tạo cửa sổ (lệnh CreateWindowEx)
    Cấu trúc của lệnh CreateWindowEx
    HWND CreateWindowEx(
    DWORD dwExStyle,
    LPCTSTR lpClassName,
    LPCTSTR lpWindowName,
    DWORD dwStyle,
    int x,
    int y,
    int nWidth,
    int nHeight,
    HWND hWndParent,
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam
    );

    • dxExStyle Kiểu cửa sổ mở rộng. Có nhiều rất kiểu mở rộng, nhưng trước mắt chúng ta chỉ biết kiểu WS_EX_CLIENTEDGE cho viền đậm bao quanh và có thể thay đổi kích thước.
    • lpClassName Tên của class cửa sổ. Class cửa sổ có tên này sẽ được tham khảo khi tạo cửa sổ.
    • lpWindowName Tên của cửa sổ, sẽ được hiện lên trên thanh tiêu đề.
    • dwStyle Kiểu cửa sổ. Với sự phối hợp các kiểu khác nhau sẽ cho ra nhiều kiểu cửa sổ. Ví dụ: WS_OVERLAPPED | WS_HSCROLL sẽ cho một cửa sổ có thanh tiêu đề, viền xung quanh với một thanh cuộn ngang.
    • x Vị trí xuất hiện của cửa sổ (tính theo pixel).
    • y
    • nWidth Bề ngang của cửa sổ (tính theo pixel).
    • nHeight Bề dọc của cửa sổ (tính theo pixel).
    • nWndParent Handle đến cửa sổ cha (trong lập trình game, dĩ nhiên ta để NULL cho giá trị này).
    • hMenu Handle đến thanh menu.
    • hInstance Handle đến chương trình.
    • lpParam Ít khi dùng đến, nhất là trong lập trình game.

    Bước 3: Vòng lặp
    Đối với một chương trình không có cửa sổ, vòng lặp có thể không cần thiết vì nó chỉ thực thi một lượt rồi tự thoát. Nhưng một chương trình có cửa sổ thì không như vậy. Bạn cần một vòng lặp để bảo tồn chương trình trong bộ nhớ. Vòng lặp này thực hiện các bước:
    • Chờ và nhận message (thông báo) từ cửa sổ
    • Thông dịch và chuyển message đến function điều khiển cửa sổ

    Function GetMessage sẽ nhận message từ cửa sổ. Cấu trúc của GetMessage gồm:
    BOOL GetMessage(
    LPMSG lpMsg,
    HWND hWnd,
    UINT wMsgFilterMin,
    UINT wMsgFilterMax
    );

    • lpMsg Pointer đến vùng nhớ chứa message. Bạn cần khai báo pointer này (ví dụ: MSG msg;).
    • hWnd Handle đến cửa sổ lấy message. Bạn có thể nghĩ ngay đến cửa sổ vừa tạo, và có thể dùng biến hWnd, nhưng mà tốt nhất là bạn để NULL. Khi để NULL, function GetMessage sẽ lấy các message từ tất cả các cửa sổ tạo bởi chương trình.
    • wMsgFilterMin Các giá trị lọc message. Nếu cả hai cùng là 0 thì sẽ không lọc message.
    • wMsgFilterMax

    Hai dòng lệnh sau sẽ thực hiện bước còn lại:
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);

    Bước 4: Tạo function điều khiển cửa sổ
    Khi đăng ký class cửa sổ, chúng ta phải khai báo phần lpfnWndProc có giá trị bằng chính tên một function nào đó (ví dụ: wc.lpfnWndProc = MyWndProc;). Function này có tác dụng điều khiển cửa sổ.

    Function này sẽ phải được khai báo như sau:
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

    Các tham số của function là do hệ thống tự động cung cấp:
    • hwnd Handle đến cửa sổ.
    • msg Message của cửa sổ đã được thông dịch

    • wParam Các tham số của chương trình (ít dùng)
    • lParam

    Bạn sẽ phải kiểm tra xem message từ cửa sổ là message nào bằng cấu trúc switch. Trong ví dụ trên, ta chỉ điều khiển cửa sổ qua hai message WM_CLOSE và WM_DESTROY. Message WM_CLOSE khi có lệnh đóng cửa sổ (bấm vào nút close), và cửa để đóng cửa sổ, ta cần thi hành lệnh DestroyWindow. Còn message WM_DESTROY là khi có lệnh thoát chương trình, và khi thoát chương trình, ta cần phải thi hành lệnh PostQuitMessage.

    Tóm tắt:
    WinMain là function chính, tương đương với main trong lập trình DOS. Tham số cần thiết nhất do WinMain cung cấp là hInstance, là handle trỏ đến vùng bộ nhớ của chương trình.

    Tạo một cửa sổ cần 4 bước:
    • Đăng ký một class window
    • Ra lệnh tạo cửa sổ
    • Thi hành vòng lặp để bảo tồn chương trình trong bộ nhớ
    • Tạo function điều khiển cửa sổ
     
  4. Alone Beast

    Alone Beast C O N T R A

    Tham gia ngày:
    14/1/04
    Bài viết:
    1,607
    Nơi ở:
    ...
    5 - Dùng resource

    Resource là tài nguyên của chương trình. Đó là các menu, bitmap (hình ảnh), cursor (hình ảnh con trỏ chuột), v.v... . Lập trình API trong Windows đòi hỏi việc dùng resource. Tuy nhiên, trong lập trình game, chúng ta không cần dùng đến resource Việc hướng dẫn dùng resource trong tài liệu này nhằm mục đích giúp cho bạn hiểu biết sâu thêm một bước Ngoài ra, bạn có thể bỏ qua phần này.

    Đầu tiên bạn cần tạo một chương trình hiện lên cửa sổ đơn giản như phần trước. Đây sẽ là phần shell của chúng ta để tạo một chương trình có thể hiện một menu bar.

    Để bắt đầu dùng resource, ta cần làm các bước sau:
    • Mở workspace của chương trình căn bản.
    • Chọn File -> New, chọn tab Files, chọn để thêm file Resource Script. Trong khung File name, gõ vào tên của resource script. Các phần khác nên để giống hình minh họa.
    • Sau khi click OK, để ý tab Resource trong khung Workspace.

    [​IMG]


    Chúng ta cần thêm một menu bar vào resource script. Các bước để thêm một resource vào resource script (để ý resource script là tập hợp các resource):
    • Chọn Insert -> Resource (hoặc bấm Ctrl-R)
    • Trong dialog Insert resource, chọn Menu
    • Click New

    [​IMG]
     
  5. Alone Beast

    Alone Beast C O N T R A

    Tham gia ngày:
    14/1/04
    Bài viết:
    1,607
    Nơi ở:
    ...
    Cửa sổ chỉnh sửa resource Menu sẽ hiện lên. Để điều chỉnh và xem xét các resource, bạn chọn tab Resource trong khung Workspace. Khi đó, danh sách các resource sẽ hiện lên. Double click vào tên một resource để chỉnh sửa, hoặc right click để thay đổi thuộc tính (như đổi tên).

    [​IMG]

    Trong cửa sổ chỉnh sửa resource menu, double click vào khung chữ nhật đứt nét để thêm một menu item. Right click để sửa thuộc tính hay đổi tên.

    [​IMG]

    Lưu ý một menu item gồm phần caption (xem như tên của item được thể hiện trên màn hành) và ID. Phần ID là tên của menu item dùng để viết chương trình.

    Chương trình trong ví dụ sau cần:
    • Một menu có ID là IDR_MENU
    • Một menu item File
    • Trong File, cần một menu item Exit có ID là ID_FILE_EXIT

    * Khi tạo một resource, một file header resource.h sẽ tự động được tạo ra. File này sẽ tự động được chỉnh sửa bởi MSVC khi có một resource nào đó được điều chỉnh.

    Như vậy, resource menu có ID là IDR_MENU đã được tạo ra. Tiếp theo chúng ta sẽ làm cho nó xuất hiện trên chương trình. Trong phần trước, các bạn có thể để ý đến thành phần lpszMenuName trong cấu trúc của class cửa sổ (WNDCLASSEX). Đây là pointer đến resource menu. Nếu bạn để pointer này NULL thì chương trình không có menu. Bây giờ, thay vì để NULL, bạn thế vào giá trị:

    wc.lpszMenuName = (LPCSTR) IDR_MENU;

    Cho đến lúc này, bạn không cần phải biết ý nghĩa của (LPCSTR) làm gì. Nhưng tác giả cũng giải thích sơ qua : LPCSTR là viết tắt của Long Pointer Constant String, hay đúng hơn là Long Pointer to a String Constant (pointer 32-bit đến một hằng chuỗi). Khi để trong dấu ngoặc đơn thì có ý nghĩa chuyển đổi giá trị của IDR_MENU thành một chuỗi. Nếu bạn mở file resource.h ra xem, thì sẽ thấy dòng: #define IDR_MENU 101; . Nghĩa là IDR_MENU có giá trị số 101. Khi chuyển thành chuỗi không có nghĩa chuỗi đó có giá trị "101", mà có giá trị là ký tự thứ 101 trong bảng mã ASCII (vì pointer chuỗi này không có thuộc tính Unicode nên dùng bảng mã ASCII).

    Khi biên dịch và chạy chương trình, bạn sẽ thấy xuất hiện menu bar. Nhưng menu item Exit chưa thật sự làm cái gì hết. Để cho nó có tác dụng là thoát chương trình như mong đợi chúng ta cần sửa lại function WndProc như sau:

    *********************************************************************************************************************************************************
    ...
    LRESULT CALLBACK WndProc2(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    // Khai báo biến mới
    int wmId, wmEvent;

    switch(msg)
    {
    // Đoạn mã mới
    case WM_COMMAND:
    wmId = LOWORD(wParam);
    wmEvent = HIWORD(wParam); //Có thể bỏ qua dòng lệnh này
    switch (wmId)
    {
    case ID_FILE_EXIT:
    DestroyWindow(hwnd);
    break;
    }
    break;
    //Hết
    case WM_CLOSE:
    DestroyWindow(hwnd);
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
    }
    ...
    *********************************************************************************************************************************************************

    Chúng ta khai báo đến hai biến wmId và wmEvent, mà thật ra chỉ dùng có wmID. Giá trị của wmId là 2 byte thấp của tham số wParam (wParam có 4 byte, và đây là một số nguyên 32-bit). Nó dùng để chứa thông tin về các sự kiện của thanh menu. Nghĩa là sẽ trả về giá trị là menu item nào vừa được kích hoạt. Còn wmEvent ở trong đoạn mã này không có ý nghĩa gì hết, chỉ để cho có màu mè vậy thôi.

    Trong phần trước chúng ta đã biết về message WM_CLOSE, và WM_DESTROY. Trong đoạn mã trên, lại có thêm message WM_COMMAND. Message này được post (gởi đến hệ điều hành) khi có sự kiện về menu bar.

    Đoạn mã không có gì khó hiểu, có thể không cần giải thích gì thêm. Và như vậy, chúng ta đã thêm được một thanh menu vào chương trình. Phần sau sẽ hướng dẫn in một dòng chữ lên cửa sổ.
     
  6. Alone Beast

    Alone Beast C O N T R A

    Tham gia ngày:
    14/1/04
    Bài viết:
    1,607
    Nơi ở:
    ...
    (tiếp)
    6 - In chữ lên cửa sổ

    Chúng ta lại bắt đầu bằng chương trình tạo một cửa sổ. Chỉnh sửa function WndProc như sau:

    *********************************************************************************************************************************************************
    ...
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    //Khai báo biến mới
    HDC hdc;
    PAINTSTRUCT ps;

    switch(msg)
    {
    //Đoạn mã mới
    case WM_PAINT:
    hdc = BeginPaint(hwnd, &ps);
    char *temp;
    temp = "Hello world";
    RECT rt;
    GetClientRect(hwnd, &rt);
    DrawText(hdc, temp, lstrlen(temp), &rt, DT_CENTER);
    EndPaint(hwnd, &ps);
    break;
    //Hết
    case WM_CLOSE:
    DestroyWindow(hwnd);
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
    }
    ...
    *********************************************************************************************************************************************************

    Lần này, chúng ta lại xử lý thêm message mới là WM_PAINT. Message này được post khi có sự kiện vẽ cửa sổ. Đoạn mã điều khiển message này sẽ giúp chúng ta vẽ cửa sổ theo ý muốn.

    Để vẽ cửa sổ, chúng ta cần một pointer đến Device Context và một Paint Brush (cọ vẽ). Bạn không cần biết nhiều về Device Context và Paint Brush làm gì khi sắp tới đây, chúng ta sẽ dùng Direct Draw. Device Context là một cấu trúc chứa những chi tiết về vùng độ hoạ, và ở đây là cửa sổ, còn Paint Brush chứa chi tiết về cọ vẽ (mà không phải là các chi tiết kiểu như màu sắc).

    Trong chương trình chúng ta đã khai báo 2 biến hdc và ps. HDC là handle đến Device Context, còn ps là cọ vẽ. Function BeginPaint sẽ khởi tạo cọ vẽ và trả về Device Context của cửa sổ. Còn có một số function khác cũng trả về Device Context nhưng ở đây ta chỉ dùng BeginPaint. Khi kết thúc vẽ cửa sổ, chúng ta cần phải dùng function EndPaint.

    Function DrawText dùng để in chữ. Function này cần 5 tham số:

    DrawText(hdc, temp, lstrlen(temp), &rt, DT_CENTER);

    Tham số đầu tiên là pointer đến Device Context của cửa sổ. Tham số thứ hai có dạng LPCSTR, là một long pointer đến chuỗi cần in, LPCSTR thực ra cũng có cấu trúc tương đương với char *, bạn dùng cái nào cũng được. Tham số thứ ba là độ dài của chuỗi cần in, tất nhiên bạn muốn thay đổi cho in chuỗi ngắn hơn cũng được. Ba tham số này không có gì phải giải thích nhiều.

    Tham số thứ tư là chứa chi tiết về vùng sẽ in. Có thể nói là vị trí in chuỗi cũng được. Tham số này có kiểu RECT là pointer đến cấu trúc của một hình chữ nhật. Cấu trúc này có dạng như sau:
    • int left;
    • int top;
    • int right;
    • int bottom;
    Đây là bốn vị trí chỉ ra tọa độ của hai góc trên và dưới của một hình chữ nhật.

    Nếu bạn dùng chương trình Paint Brush, khi dùng công cụ vẽ chữ, bạn cũng phải vẽ một hình chữ nhật trước để làm khung rồi mới gõ chữ vào khung đó. Ở đây, phương pháp vẽ chữ của function DrawText cũng tương tự như thế.

    Tham số thứ năm là kiểu vẽ chữ. DT_CENTER nghĩa là căn cho dòng chữ ở giữa hình chữ nhật.

    Việc in chữ lên cửa sổ trong Window rõ ràng có sự phức tạp hơn DOS. Nguyên nhân là vì chữ đã in ra trên cửa sổ không còn được xem là các ký tự nữa mà là các hình ảnh. Xét như vậy thì rõ ràng là đơn giản lắm rồi vì đồ hoạ trong DOS còn có phần phức tạp hơn.
     
  7. Alone Beast

    Alone Beast C O N T R A

    Tham gia ngày:
    14/1/04
    Bài viết:
    1,607
    Nơi ở:
    ...
    7 - Nâng cao với Common Dialog

    Trong phần này, chúng ta sẽ dùng Common Dialog dll để mở dialog Open File. Dialog này thường dùng khi save hoặc load một file.

    [​IMG]

    Chúng ta sẽ xây dựng một chương trình đơn giản. Gồm menu File với 2 item là Load và Exit. Chức năng Load sẽ mở dialog Open File, cho phép người dùng chương trình chọn một file nào đó. Cửa sổ chương trình sẽ in ra đường dẫn đến file đã chọn.

    Gởi kèm với phần tài liệu này là project đã được viết sẵn. Tác giả chỉ giải thích sơ qua cách dùng dialog open file.

    Để dùng dialog này, ta cần khai báo biến có dạng OPENFILENAME:

    OPENFILENAME ofn;

    Kiểu OPENFILENAME là một cấu trúc chứa chi tiết về dialog. Các sắp xếp các chi tiết được thể hiện trong chương trình ví dụ.

    Function OpenFileName sẽ làm xuất hiện dialog. Function sẽ trả về FALSE nếu bấm nút Cancel.

    Để vẽ lại toàn bộ cửa sổ, ta thêm vào dòng lệnh:

    RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);

    * Phần này chấm dứt chương sơ lược về lập trình trong Windows. Tác giả không có ý định đào sâu vào lập trình API và GDI vì sẽ đi ra ngoài nội dung của tài liệu. Việc đi thẳng vào lập trình DirectX mà không đi sâu vào lập trình Windows như vậy thật ra không gây trở ngại lớn nào vì phương pháp hướng dẫn của tài liệu này là: không cần hiểu sâu, chỉ cần biết là như vậy sẽ làm như vậy. Chúng ta chỉ cần biết điều cần phải biết.
     
  8. Alone Beast

    Alone Beast C O N T R A

    Tham gia ngày:
    14/1/04
    Bài viết:
    1,607
    Nơi ở:
    ...
    Giới thiệu DirectX và công nghệ COM

    Trong những ngày đầu của hệ điều hành Windows 32 bits, Microsoft đã chú ý tới tiềm năng của ngành sản xuất game. Họ đã tung ra một bộ hỗ trợ lập trình (Software Development Kit) gọi là WinG. Tuy nhiên, WinG còn quá chậm so với DOS32. Nhờ đó, trong thế giới game, DOS vẫn sống.

    Nếu bạn đã từng chơi những game trong DOS như DOOM hay Warcraft 2, bạn có thể để ý thấy dòng chữ giới thiệu DOS4GW. DOS4GW là một hệ điều hành DOS 32 bits - thay vì Windows 32 bits - được dùng nhiều trong lập trình game lúc đó.

    Vấn đề quan trọng trong lập trình game là sự tương thích với máy. Bởi vì có quá nhiều card màn hình, card sound, card mạng, và thậm chí là bàn phím trên thị trường. Mỗi một loại lại có kiểu lập trình khác nhau, mà người lập trình không thể nào cứ mỗi một loại lại cho ra một phiên bản game.

    Đối với những game dùng chế độ VGA 256 màu (độ phân giải 320x200, 8-bit màu), thì sự tương thích với card màn hình không đáng kể, do dùng chuẩn VGA. Chuẩn VGA là sự thống nhất giữa những nhà sản xuất card màn hình. Về sau có chuẩn VESA cho phép độ phân giải và độ sâu màu cao hơn, nhưng lại không đạt được sự thống nhất đáng kể.

    Lúc đó, DOS4GW cũng gần giải quyết vấn đề bằng cách đưa ra một bộ hỗ trợ lập trình. Lúc cài đặt trò chơi, người chơi game sẽ phải lựa chọn đúng loại card màn hình và card sound trên máy vi tính. Chương trình game sẽ theo đó lựa chọn bộ điều khiển (driver) phù hợp để có thể hoạt động. Các driver này được lưu trữ trong cùng folder của trò chơi (folder này thường có tên là "drivers").

    Thế nhưng, lúc độ chỉ có mấy chục chuẩn card màn hình và card sound, nên kích thước của bộ driver không quá lớn. Càng về sau, với sự ra đời của card 3D, lại càng có nhiều chuẩn khác nhau. Nếu lưu trử toàn bộ các driver của toàn bộ các chuẩn thì kích thước folder driver còn lớn hơn rất nhiều lần so với game. Vả lại lúc đó, với những game nhỏ, mà dùng cách trên, như Sim City 2000 thì folder drivers cũng chiếm 1/4 kích thước trò chơi rồi. Rõ ràng, đây là một việc không mấy hiệu quả.

    Dù vậy, cách giải quyết thật ra không khó. Có điều, trước khi người ta giải quyết vấn đề đối với DOS4GW thì DirectX và Windows 98 đã ra đời.

    Đến phiên bản 5, DirectX đã nhanh tương đương so với DOS4GW, mà kỹ thuật lại có sự hiệu quả hơn. Người lập trình game có thể tiếp cận trực tiếp phần cứng mà không phải lo lắng đến sự tương thích. Và như vậy, trong thế giới game, DOS đã chết.

    Để có thể giúp cho người lập trình không phải lo lắng đến sự tương thích, DirectX đã dùng đến công nghệ COM.


    ==========================

    Đến đây thì tài liệu của Zubachi dừng lại, hy vọng huynh sớm cập nhật. Cám ơn nhiều ^^
     
  9. zubachi

    zubachi Donkey Kong

    Tham gia ngày:
    5/11/04
    Bài viết:
    301
    Nơi ở:
    Tây phương
    :D Rất tiếc là anh sẽ không hòan tất cái tài liệu nhảm nhí này, thay vì đi tiếp DirectDraw cổ lỗ sĩ, anh sẽ viết một tài liệu khác về DirectX Graphics. Nhưng xin chờ một thời gian 2-3 tháng nữa để hòan tất một game nho nhỏ.
     
  10. tutukun

    tutukun Mario & Luigi

    Tham gia ngày:
    15/2/05
    Bài viết:
    749
    Nơi ở:
    Singapore
    cái này có vẻ là dạy về VC++ thì đúng hơn, còn những cái còn lại thì quá ngắn ngọn và kô thể gọi là hướng dẫn cơ bản cho người mới đc. Dù sao cũng thx vì đã có ý tốt :D
     
  11. >VoDich<

    >VoDich< Legend of Zelda

    Tham gia ngày:
    26/1/05
    Bài viết:
    919
    Nơi ở:
    Can Tho
    {@: thế có chỗ nào down Microsoft Visual C++ 6.0 ko :@}
     
  12. motorolan

    motorolan T.E.T.Я.I.S

    Tham gia ngày:
    7/3/05
    Bài viết:
    600
    Nơi ở:
    Hà Nội
    Ra hàng mà mua đĩa hà, cái này chỉ cần một đĩa thôi . Thanks nhé, bài hướng dẫn của bác hay we' , tui cũng đã bắt đầu với VC++ được một thời gian rồi nhưng chưa biết bước vào việc làm game như thế nào
     
  13. >VoDich<

    >VoDich< Legend of Zelda

    Tham gia ngày:
    26/1/05
    Bài viết:
    919
    Nơi ở:
    Can Tho
    {@: 1 đĩa à hả, sao có lần có người chỗ tui nói 5,6 đĩa gì lận ????????????????????? , thanks :@}
     
  14. SVS

    SVS Mario & Luigi

    Tham gia ngày:
    27/6/03
    Bài viết:
    899
    Nơi ở:
    Graveyard of rusted uses
    Làm gì có ngôn ngữ nào cần 5-6 đĩa lận! Tới VS.Net mà cũng chỉ có 3 đĩa! + MSDN là 4.
     
  15. tutukun

    tutukun Mario & Luigi

    Tham gia ngày:
    15/2/05
    Bài viết:
    749
    Nơi ở:
    Singapore
    down VC++2005 trên trang web của Microsoft về mà dùng thử, hay hơn Vc6 nhiều. Được free một năm :P, nhưng dùng ai thấy thích thì ra hàng mà mua đĩa chắc cũng có đầy
     
  16. motorolan

    motorolan T.E.T.Я.I.S

    Tham gia ngày:
    7/3/05
    Bài viết:
    600
    Nơi ở:
    Hà Nội
    Tui cũng ko rõ nữa , có thể là có một bộ 2,3 đĩa đầy đủ nhưng mà mua vesion 1 đĩa là đủ rồi , tui cũng vậy nè , từ khi mua về thực hành có thấy thiếu cái gì đâu :D
     

Chia sẻ trang này