掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.28941

背景の横スクロール
投稿者---るる(2006/11/18 14:44:50)


#include<stdio.h>
#include<windows.h>
#include<sys/stat.h>
#include<io.h>
#include<fcntl.h>

unsigned char *buf;//背景用
unsigned char *chr;//キャラクタ用
int n;
int xPos = 0, yPos = 0;//キャラクタの座標

HDC hdc;
HDC memDC;
HBITMAP memBM;
void *vramAdr;

void bufBlt(HDC hdc, int dx, int dy, int w, int h, char *buf, int sx, int sy, int colorlKey){
    int *c = (int *)vramAdr;
    BITMAPINFOHEADER *bh = (BITMAPINFOHEADER*)(buf+14);
    for(int y = 0; y < h; y++){
        int srcY = bh->biHeight-1-(sy+y);
        if(srcY < 0 || 480 <= srcY){
            continue;
        }
        int disY = dy+y;
        if(disY < 0 || 480 <= disY){
            continue;
        }
        for(int x = 0; x < w; x++){
            int srcX = sx+x;
            if(srcX < 0 || 640 <= srcX){
                continue;   
            }
            int disX = dx+x;
            if(disX < 0 || 640 <= disX){
                continue;
            }
            // 描画
            int srcOffset = 54 + srcY*bh->biWidth*3 + srcX*3;
            int color = RGB(buf[srcOffset+2], buf[srcOffset+1], buf[srcOffset]);
            if(color != colorlKey) SetPixel(hdc, disX, disY, color);
//      if(color != colorlKey) c[disY*640 + disX] = RGB(buf[srcOffset], buf[srcOffset+1], buf[srcOffset+2]);
        }
    }
    
}



//OSから来るメッセージを処理するコールバック
LRESULT CALLBACK winFunc(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam)
{
    struct stat st;
    int fd;
    
    //メッセージ処理
    switch(message){
        case WM_CREATE:{
            hdc = GetDC(hwnd);
            memDC = CreateCompatibleDC(hdc);
            
            BITMAPINFO bi;  memset( &bi, 0, sizeof(bi)); 
            bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
            bi.bmiHeader.biWidth = 640;
            bi.bmiHeader.biHeight = -480;
            bi.bmiHeader.biPlanes = 1;
            bi.bmiHeader.biBitCount = 32;
            memBM = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &vramAdr, NULL, 0);
            
            SelectObject(memDC, memBM);
            ReleaseDC(hwnd, hdc);
            
            //背景
            fd = open("sample.bmp", O_BINARY | O_RDONLY);
            fstat(fd, &st);
            st.st_size = 921654;
            buf = (unsigned char*)malloc(st.st_size);
            read(fd, buf, st.st_size);
            close(fd);
            
            //キャラクタ
            fd = open("走りサンプル.bmp", O_BINARY | O_RDONLY);
            fstat(fd, &st);
            st.st_size = 73782;
            chr = (unsigned char*)malloc(st.st_size);
            read(fd, chr, st.st_size);
            close(fd);
            
            SetTimer(hwnd, 0, 1, NULL);
            SetTimer(hwnd, 1, 100, NULL);
            break;
        }
        
        case WM_PAINT:{
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &ps);
            
            //バックバッファの内容を一括コピー
            BitBlt(ps.hdc, 0, 0, 640, 480, memDC, 0, 0, SRCCOPY);
            
            EndPaint(hwnd, &ps);
            break;
        }
        case WM_KEYDOWN:{
        if(wParam == VK_SPACE){
        }
        break;
        }
    
        
        // 終了処理
        case WM_DESTROY:{
            free(buf);
            free(chr);
            KillTimer(hwnd, 0);
            KillTimer(hwnd, 1);
            DeleteDC(memDC);
            DeleteObject(memBM);
            PostQuitMessage(0);
            break;
        }
        
        //タイマー
        case WM_TIMER:{
            if(wParam == 0){
                if(GetAsyncKeyState(VK_RIGHT)&0x8000){
                    xPos+=10;
                }
                if(GetAsyncKeyState(VK_LEFT)&0x8000){
                    xPos-=10;
                }
                if(GetAsyncKeyState(VK_UP)&0x8000){
                    yPos-=10;
                }
                if(GetAsyncKeyState(VK_DOWN)&0x8000){
                    yPos+=10;
                }
                InvalidateRect(hwnd, NULL, NULL);
                UpdateWindow(hwnd);
            }
            if(wParam == 1){
                n = (n+1)%6;
            }
            
            
            bufBlt(memDC, 0, 0, 640, 480, buf, 0, 0, -1);//背景
            bufBlt(memDC, xPos, yPos, 48, 64, chr, n*48, 0, RGB(0, 255, 0));//キャラ
            
            break;
        }    
    }
    
    //終了処理
    return DefWindowProc(hwnd, message, wParam, lParam);
}

//メイン関数
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE plnst, char *cmdLine, int cmdShow){
    srand(GetTickCount());
    
    // ウィンドウクラスの定義
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(wcex);
    wcex.cbClsExtra = NULL;
    wcex.cbWndExtra = NULL;
    wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
    wcex.hIcon = LoadIcon(NULL,IDI_APPLICATION);
    wcex.hIconSm = NULL;
    wcex.hInstance = hInst;
    wcex.lpfnWndProc = winFunc;
    wcex.lpszClassName = "(.;:'盆')";
    wcex.lpszMenuName = NULL;
    wcex.style = NULL;
    
    HRESULT hr = RegisterClassEx(&wcex);
    
    // ウィンドウの作成
    unsigned int style = WS_OVERLAPPEDWINDOW;
    RECT rect = {0, 0, 640, 480};
    AdjustWindowRect(&rect, style, false);
    HWND hwnd = CreateWindow(wcex.lpszClassName, wcex.lpszClassName, style, 
                    CW_USEDEFAULT, /* x座標 */ CW_USEDEFAULT, /* y座標 */ 
                    rect.right-rect.left, rect.bottom-rect.top, NULL, NULL, hInst,NULL);
    
    // 作成したウィンドウの表示
    ShowWindow(hwnd, cmdShow);
    UpdateWindow(hwnd);
    
    // メッセージループ
    MSG msg;
    while(GetMessage(&msg, NULL, NULL, NULL)){//xボタンが押されるまで
        DispatchMessage(&msg);
    }
    
    return 0;
}





この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:背景の横スクロール 28942 るる 2006/11/18 14:45:08


No.28942

Re:背景の横スクロール
投稿者---るる(2006/11/18 14:45:08)




初めまして、るるというものです。(字数の問題で次レスにてのご挨拶失礼します)

C++,Win32API,WindowsXP,BorlandC++で前レスのプログラムを作成したのですが、背景を横スクロールするやり方がわかりません…
よければご教授を戴きたいです



この投稿にコメントする

削除パスワード

No.28946

Re:背景の横スクロール
投稿者---pseudo(2006/11/19 11:56:43)


えーっと、基本的なことはもう随分できてらっしゃるみたいですね。

あとは、SetPixelなんか使わずに、コメントアウトされている
if(color != colorlKey) c[disY*640 + disX] =〜 の方を使っちゃえ、とか
スクロールして左(右?)にはみ出ちゃった背景は、もちろん右(左?)に描画したいだろうから
その処理を追加しなきゃね、とか
WM_TIMERの処理の最後にInvalidRectとUpdateWindowのコンボを忘れずに、とか。


この投稿にコメントする

削除パスワード

No.28947

Re:背景の横スクロール
投稿者---るる(2006/11/19 21:07:55)


pseudo様、ご指摘ありがとうございました。
プログラムを手直ししたところ、アニメーションがすんなりと動いてくれるようになりました(かなり感動しました!)

スクロールですが、考えた結果下のプログラムになったのですが、これではうまく動いてはくれません。

1,背景を表示し、その隣(画面外)にもう一枚配置
2,スクロールさせ、背景(一枚目)が画面外にでたら二枚目の隣に配置

という処理を考えているのですが…;
#include<stdio.h>
#include<windows.h>
#include<sys/stat.h>
#include<io.h>
#include<fcntl.h>

unsigned char *buf;//背景用
unsigned char *chr;//キャラクタ用
int n;
int xPos = 0, yPos = 0;//キャラクタの座標

HDC hdc;
HDC memDC;
HBITMAP memBM;
void *vramAdr;

void bufBlt(HDC hdc, int dx, int dy, int w, int h, char *buf, int sx, int sy, int colorlKey){
    //親レスと同じなので省略

            if(color != colorlKey) c[disY*640 + disX] = RGB(buf[srcOffset], buf[srcOffset+1], buf[srcOffset+2]);
        }
    }
    
}

//OSから来るメッセージを処理するコールバック
LRESULT CALLBACK winFunc(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam)
{
    struct stat st;
    int fd;
    static int w;
    
    //メッセージ処理
    switch(message){
        case WM_CREATE:{
       //親レスと同じなので省略
                        break;
        }
        
        case WM_PAINT:{
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &ps);
            
            //バックバッファの内容を一括コピー
            BitBlt(ps.hdc, w, 0, 640, 480, memDC, 0, 0, SRCCOPY);
            
            EndPaint(hwnd, &ps);
            break;
        }
        case WM_KEYDOWN:{
        if(wParam == VK_SPACE){
        }
        break;
        }
    
        
        // 終了処理
        case WM_DESTROY:{
            free(buf);
            free(chr);
            KillTimer(hwnd, 0);
            KillTimer(hwnd, 1);
            DeleteDC(memDC);
            DeleteObject(memBM);
            PostQuitMessage(0);
            break;
        }
        
        //タイマー
        case WM_TIMER:{
            
            if(wParam == 0){
                if(GetAsyncKeyState(VK_RIGHT)&0x8000){
                    xPos+=10;
                }
                if(GetAsyncKeyState(VK_LEFT)&0x8000){
                    xPos-=10;
                }
                if(GetAsyncKeyState(VK_UP)&0x8000){
                    yPos-=10;
                }
                if(GetAsyncKeyState(VK_DOWN)&0x8000){
                    yPos+=10;
                }
                InvalidateRect(hwnd, NULL, NULL);
                UpdateWindow(hwnd);
            }
            if(wParam == 1){
                n = (n+1)%6;
            }
            
            w--;
            bufBlt(memDC, w, 0, 640, 480, buf, 0, 0, -1);//背景
            bufBlt(memDC, w+641, 0, 640, 480, buf, 0, 0, -1);
            if(w == -640){
                bufBlt(memDC, w+, 0, 640, 480, buf, 0, 0, -1);
            }
            bufBlt(memDC, xPos, yPos, 48, 64, chr, n*48, 0, RGB(0, 255, 0));//キャラ
            
            InvalidateRect(hwnd, NULL, NULL);
            UpdateWindow(hwnd);
            
            break;
        }
        case WM_CLOSE:{
            int id;
            id = MessageBox(hwnd, "終了しても良いですか?", "確認", MB_OKCANCEL | MB_ICONQUESTION);
            if(id == IDYES){
                DestroyWindow(hwnd);
            }
            break;
        }
            
    }
    
    //終了処理
    return DefWindowProc(hwnd, message, wParam, lParam);
}

//メイン関数
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE plnst, char *cmdLine, int cmdShow){
    
      //親レスと同じなので省略

    return 0;
}



この投稿にコメントする

削除パスワード

No.28958

Re:背景の横スクロール
投稿者---pseudo(2006/11/21 00:46:43)


そこまで出来ていながら! そこまで出来ていながら!
もうゴールは目の前なのに!

いいヒントが思いつきません。
もう答えを書いてしまいます。

ここ:
            if(w == -640){
                bufBlt(memDC, w+, 0, 640, 480, buf, 0, 0, -1);
            }


これにかえます:
            if(w == -640){
                w = 0;
            }


ところで、今るるさんが知りたい情報とはあまり関係ないかも知れませんが、
       SetTimer(hwnd, 0, 1, NULL);

がちょっと疑問です。1000分の1秒毎の処理を期待しているみたいですけども。

MSDN で SetTimer を調べると、
Windows 2000/XP: If uElapse is less than 10, the timeout is set to 10.

と書かれてあると思います。つまり Win2kやXPでは、uElapse に 10 未満の値が入力されると
10 にしちゃいますよと。

10でも辛いんじゃないかな。。。妙なところがボトルネックになって、
なんだか不自然な画面の動き方に見えるかも知れません。
20や30あたりも試してみるとよいと思います。

# ちなみに私「WM_TIMERの処理の最後にInvalid〜とUpdate〜を」とか書いちゃいましたが、
# とりあえずWM_TIMERの処理の途中にInvalid〜とUpdate〜があったんですね。
# うーん、ちょっと失敗。。。


この投稿にコメントする

削除パスワード

No.28983

Re:背景の横スクロール
投稿者---るる(2006/11/22 06:59:35)


pseudo様、アドバイス等ありがとうございました!
無事に横スクロールをすることができました

//OSから来るメッセージを処理するコールバック
LRESULT CALLBACK winFunc(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam)
{
    struct stat st;
    int fd;
    static int w1 = 0, w2;
    
    //メッセージ処理
    switch(message){
        case WM_CREATE:{
            hdc = GetDC(hwnd);
            memDC = CreateCompatibleDC(hdc);
            
            BITMAPINFO bi;  memset( &bi, 0, sizeof(bi)); 
            bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
            bi.bmiHeader.biWidth = Window_sizeX;
            bi.bmiHeader.biHeight = -Window_sizeY;
            bi.bmiHeader.biPlanes = 1;
            bi.bmiHeader.biBitCount = 32;
            memBM = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &vramAdr, NULL, 0);
            
            SelectObject(memDC, memBM);
            ReleaseDC(hwnd, hdc);
            
            //背景
            fd = open("ryusei.bmp", O_BINARY | O_RDONLY);
            fstat(fd, &st);
            st.st_size = 921654;
            buf = (unsigned char*)malloc(st.st_size);
            read(fd, buf, st.st_size);
            close(fd);
            
            //キャラクタ
            fd = open("走りサンプル.bmp", O_BINARY | O_RDONLY);
            fstat(fd, &st);
            st.st_size = 73782;
            chr = (unsigned char*)malloc(st.st_size);
            read(fd, chr, st.st_size);
            close(fd);
            
            SetTimer(hwnd, 0, 1, NULL);
            SetTimer(hwnd, 1, 100, NULL);
            break;
        }
        
        case WM_PAINT:{
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &ps);
            
            //バックバッファの内容を一括コピー
            BitBlt(ps.hdc, 0, 0, Window_sizeX, Window_sizeY, memDC, 0, 0, SRCCOPY);
            
            EndPaint(hwnd, &ps);
            break;
        }
        case WM_KEYDOWN:{
        if(wParam == VK_SPACE){
        }
        break;
        }
    
        
        // 終了処理
        case WM_DESTROY:{
            free(buf);
            free(chr);
            KillTimer(hwnd, 0);
            KillTimer(hwnd, 1);
            DeleteDC(memDC);
            DeleteObject(memBM);
            PostQuitMessage(0);
            break;
        }
        
        //タイマー
        case WM_TIMER:{
            
            if(wParam == 0){
                if(GetAsyncKeyState(VK_RIGHT)&0x8000){
                    xPos+=10;
                }
                if(GetAsyncKeyState(VK_LEFT)&0x8000){
                    xPos-=10;
                }
                if(GetAsyncKeyState(VK_UP)&0x8000){
                    yPos-=10;
                }
                if(GetAsyncKeyState(VK_DOWN)&0x8000){
                    yPos+=10;
                }
                InvalidateRect(hwnd, NULL, NULL);
                UpdateWindow(hwnd);
            }
            if(wParam == 1){
                n = (n+1)%6;
            }
            
            w1--;
            w2 = w1 + 641;
            w2--;
            bufBlt(memDC, w1, 0, Window_sizeX, Window_sizeY, buf, 0, 0, -1);//背景
            bufBlt(memDC, w2, 0, Window_sizeX, Window_sizeY, buf, 0, 0, -1);
            if(w1 == -Window_sizeX){
                w1 = 0;
            }
            if(w2 = -Window_sizeX){
                w2 = 641;
            }
            bufBlt(memDC, xPos, yPos, Charaster_sizeY, Character_sizeX, chr, n*Charaster_sizeY, 0, RGB(0, 255, 0));//キャラ
            
            InvalidateRect(hwnd, NULL, NULL);
            UpdateWindow(hwnd);
            
            break;
        }
        case WM_CLOSE:{
            int id;
            id = MessageBox(hwnd, "終了しても良いですか?", "確認", MB_OKCANCEL | MB_ICONQUESTION);
            if(id == IDYES){
                DestroyWindow(hwnd);
            }
            break;
        }
            
    }
    
    //終了処理
    return DefWindowProc(hwnd, message, wParam, lParam);
}


SetTimerの部分も書き直しました。
ちゃんと正常に動いてくれます。
ありがとうございました!


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧