0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qiita全国学生対抗戦Advent Calendar 2024

Day 6

【C】winapiでRPGを作る#1

Last updated at Posted at 2024-12-06

「ゲームエンジンを使わずRPGを作りたい」
そん思ったことはありませんか?
では
WINAPI(+α)だけでRPGを作りましょう

引用元と参考元

わかりやすいのでぜひ見に行ってください

かいてい.netさん

とある科学の備忘録さん

viva Cocoaさん

環境とか

・Windows 11
・VSCode V1.95
・windows gcc x64

VisualStudioは使いません.VSCode一本です.

使用ライブラリ

windows.h
stdlib.h
stdio.h

使うかもしれないもの

python3

画像描画

コピペ用

main.c
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

//pixel数
int pixel = 48;

//関数宣言
//呼び出し
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//画像描画
int DrowImage(HDC hdc, char* str, int x, int y, int cx, int cy );

//main関数
int WINAPI WinMain
(
    //引数
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine,
    int nCmdShow
)
{
    //アプリ関数名
    TCHAR szAppName[] = TEXT("TestApp");
    //変数宣言
    WNDCLASS wc;
    HWND hwnd;
    MSG msg;

    wc.style         = CS_HREDRAW | CS_VREDRAW;//スタイル指定
    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 = szAppName;

    if (!RegisterClass(&wc)) return 0;//error吐いた時の処理

    // ウィンドウを作成
    hwnd = CreateWindow
    (
        szAppName, 
        TEXT("Title"),//ウィンドウ名
        WS_OVERLAPPEDWINDOW|WS_MAXIMIZEBOX|WS_MINIMIZEBOX,//ウィンドウスタイル
        CW_USEDEFAULT,//表示位置
        CW_USEDEFAULT,//表示位置
        CW_USEDEFAULT,//x 
        CW_USEDEFAULT,//y
        NULL, 
        NULL,
        hInstance, 
        NULL
    );

    if (!hwnd) return 0;//error排他っと期の処理

    //ウィンドウ作成
    ShowWindow(hwnd, nCmdShow);
    //ウィンドウアップデート
    UpdateWindow(hwnd);

    //mainloop
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        //キー入力メッセージを文字メッセージに変換する。
        TranslateMessage(&msg);
        //メッセージをウィンドウプロシージャへディスパッチする。
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

//メッセージ処理
LRESULT CALLBACK WndProc
(
    //引数
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
    //変数宣言
    int id;
    HDC hdc;
    PAINTSTRUCT ps;
    LPCREATESTRUCT lpcs;

    //メッセージの分岐
    switch (uMsg) 
    {
    case WM_CLOSE:
        //罰ボタン押された時の処理
        id = MessageBox(hwnd, TEXT("exit?"),TEXT("exit"), MB_YESNO | MB_ICONEXCLAMATION );
        if (id == IDYES)
        {
            MessageBox(hwnd, TEXT("OK"), TEXT("OK"), MB_OK);
            DestroyWindow(hwnd);
        }
        return 0;
    //ウィンドウを消す
    case WM_DESTROY:
        //ウィンドウ破壊
        PostQuitMessage(0);
        return 0;
    case WM_CREATE:
        return 0;
    //ペイント
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        //画像表示
        DrowImage(hdc, "ファイル名.bmp",150, 150, 200,300);//ファイル名.bmpを描画
        EndPaint(hwnd, &ps);
        return 0;

    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

//画像描画   HDCobj,アドレス,場所x,場所y,大きさx,大きさy,
int DrowImage(HDC hdc, char* str, int x, int y, int cx, int cy )
{
    HDC hdc_2;
    //画像読み込み用
    HBITMAP image;
    //image
    image = LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    //hdcodj作成
    hdc_2 = CreateCompatibleDC(hdc);
    //select
    SelectObject(hdc_2,image);
    //画像描画
    BitBlt(hdc, x, y, cx, cy, hdc_2, 0, 0, SRCCOPY);
    //hdcobj破壊
    DeleteDC(hdc_2);
    //画像削除
    DeleteObject(image);
    
    //エラーが出れば1を返す
    if (image == NULL){return 1;}
    else{return 0;}
}

かいてい.netさん

をメッセージウィンドウのコードを 参考 引用しています.

このコードではファイル名.bmpを表示しています.

ここではDrowImage関数にhdcファイル名(char*)と場所を入力することで画像を表示させてます.
ただ、WINAPIの仕様でbmpファイルにしか表示できません.
jpgとかは頑張って変換しましょう()

これを改造して動かせるようにします.

キャラを動かす!

グローバル変数にint型x,y,Up,Right,has_runを追加します.

main.c
//x,yの座標
int x=0 ,y=0;
//右左左右キーフラグ
int Up = 0,Right = 0;
//走るフラグ
int has_run = 0;

また、WndProc関数のswitch文に以下のコードを追加します

main.c
case WM_KEYDOWN:
    int vkey = wParam;
    if (vkey == VK_UP){Up = -1;}//上キー
    if (vkey == VK_DOWN){Up = 1;}//上キー
    if (vkey == VK_LEFT){Right = -1;}//上キー
    if (vkey == VK_RIGHT){Right = 1;}//上キー
    //走りフラグ
    if (vkey == VK_SHIFT){has_run = 1 - has_run;}
    //リセット
    if (vkey != VK_UP&&vkey != VK_DOWN){Up = 0;}
    if (vkey != VK_LEFT&&vkey != VK_RIGHT){Right = 0;}
    InvalidateRect(hwnd, NULL, TRUE);  //再描画

何をやってるか

ここではvkeyにキーの入力を代入しています.
ifでキーの番号によってUp,Rightを制御しています.

WndProc関数のswitch文のcase case WM_PAINT:に以下のコードを追加します

main.c
//走るスピード
int run_spped = 10;
//ダッシュする倍率
int run_as = 2;
if (has_run == 1){run_spped = run_spped * run_as;}
        
//座標処理
x += Right*run_spped;
y += Up*   run_spped;

//画像表示
DrowImage(hdc, "プレイヤー.bmp",x-pixel/2, y-pixel/2, 200,300);

プレイヤー.bmpを移動させています.なので適宜他のものに変換してください.

何をやってるか

run_speedhas_runが真ならran_asを掛けるようにしています.

出来たらこんな感じになるはず
Title 2024_12_06 18_20_37.png

おわり

これで動かせるようになりました.
今回はこれで終わりです.

コピペ用
main.c

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

//pixel数
int pixel = 48;

//x,yの座標
int x=0 ,y=0;
//右左左右キーフラグ
int Up = 0,Right = 0;
//走るフラグ
int has_run = 0;

//関数宣言
//呼び出し
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//画像描画
int DrowImage(HDC hdc, char* str, int x, int y, int cx, int cy );

//main関数
int WINAPI WinMain
(
    //引数
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine,
    int nCmdShow
)
{
    //アプリ関数名
    TCHAR szAppName[] = TEXT("TestApp");
    //変数宣言
    WNDCLASS wc;
    HWND hwnd;
    MSG msg;

    wc.style         = CS_HREDRAW | CS_VREDRAW;//スタイル指定
    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 = szAppName;

    if (!RegisterClass(&wc)) return 0;//error吐いた時の処理

    // ウィンドウを作成
    hwnd = CreateWindow
    (
        szAppName, 
        TEXT("Title"),//ウィンドウ名
        WS_OVERLAPPEDWINDOW|WS_MAXIMIZEBOX|WS_MINIMIZEBOX,//ウィンドウスタイル
        CW_USEDEFAULT,//表示位置
        CW_USEDEFAULT,//表示位置
        CW_USEDEFAULT,//x 
        CW_USEDEFAULT,//y
        NULL, 
        NULL,
        hInstance, 
        NULL
    );

    if (!hwnd) return 0;//error排他っと期の処理

    //ウィンドウ作成
    ShowWindow(hwnd, nCmdShow);
    //ウィンドウアップデート
    UpdateWindow(hwnd);

    //mainloop
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        //キー入力メッセージを文字メッセージに変換する。
        TranslateMessage(&msg);
        //メッセージをウィンドウプロシージャへディスパッチする。
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

//メッセージ処理
LRESULT CALLBACK WndProc
(
    //引数
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
    //変数宣言
    int id;
    HDC hdc;
    PAINTSTRUCT ps;
    LPCREATESTRUCT lpcs;

    //メッセージの分岐
    switch (uMsg) 
    {
    case WM_CLOSE:
        //罰ボタン押された時の処理
        id = MessageBox(hwnd, TEXT("exit?"),TEXT("exit"), MB_YESNO | MB_ICONEXCLAMATION );
        if (id == IDYES)
        {
            MessageBox(hwnd, TEXT("OK"), TEXT("OK"), MB_OK);
            DestroyWindow(hwnd);
        }
        return 0;
    //ウィンドウを消す
    case WM_DESTROY:
        //ウィンドウ破壊
        PostQuitMessage(0);
        return 0;
    case WM_KEYDOWN:
        int vkey = wParam;
        if (vkey == VK_UP){Up = -1;}//上キー
        if (vkey == VK_DOWN){Up = 1;}//上キー
        if (vkey == VK_LEFT){Right = -1;}//上キー
        if (vkey == VK_RIGHT){Right = 1;}//上キー
        //走りフラグ
        if (vkey == VK_SHIFT){has_run = 1 - has_run;}
        //リセット
        if (vkey != VK_UP&&vkey != VK_DOWN){Up = 0;}
        if (vkey != VK_LEFT&&vkey != VK_RIGHT){Right = 0;}
        InvalidateRect(hwnd, NULL, TRUE);  //再描画
    case WM_CREATE:
        return 0;
    //ペイント
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        //画像表示
        //走るスピード
        int run_spped = 10;
        //ダッシュする倍率
        int run_as = 2;
        if (has_run == 1){run_spped = run_spped * run_as;}

        //座標処理
        x += Right*run_spped;
        y += Up*   run_spped;       

        //画像表示
        DrowImage(hdc, "プレイヤー.bmp",x-pixel/2, y-pixel/2, 200,300);
        EndPaint(hwnd, &ps);
        return 0;

    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

//画像描画   HDCobj,アドレス,場所x,場所y,大きさx,大きさy,
int DrowImage(HDC hdc, char* str, int x, int y, int cx, int cy )
{
    HDC hdc_2;
    //画像読み込み用
    HBITMAP image;
    //image
    image = LoadImage(NULL, str, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    //hdcodj作成
    hdc_2 = CreateCompatibleDC(hdc);
    //select
    SelectObject(hdc_2,image);
    //画像描画
    BitBlt(hdc, x, y, cx, cy, hdc_2, 0, 0, SRCCOPY);
    //hdcobj破壊
    DeleteDC(hdc_2);
    //画像削除
    DeleteObject(image);
    
    //エラーが出れば1を返す
    if (image == NULL){return 1;}
    else{return 0;}
}


0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?