キャラ移動制限

画像を表示させ動き回るとウィンドウからはみ出してしまう。
なので、移動制限を設ける。
これ以外にも方法はあるので、考えてみる事をお勧めします。
実行サンプル
プログラム
▽ 全体表示
#include <windows.h>
#include <windowsx.h>
#pragma comment(lib,"msimg32.lib")// TransparentBltに必要
#include <wingdi.h>
#include <string>
HWND g_hwnd;
const int WINX = 320;
const int WINY = 240;
const char TITLE[] = "Win08";
const int nFramesPerSecond = 30;
//----- Graphic Class -----//
class Graphic{
private:
HDC m_graphichdc;
HDC m_hdc;
HANDLE m_hbmp;
BITMAP m_bitmap;
public:
Graphic();
Graphic(HDC hdc,std::string filename);
~Graphic();
void Create(HDC hdc,std::string filename);
bool TrDraw(HDC hdc,int x,int y,int width = 0,int height = 0,int px = 0,int py = 0,UINT color = RGB(255,255,255));
bool TrDraw(int x,int y,int width = 0,int height = 0,int px = 0,int py = 0,UINT color = RGB(255,255,255));
bool Draw(HDC hdc,int x,int y,int width = 0,int height = 0,int px = 0,int py = 0);
bool Draw(int x,int y,int width = 0,int height = 0,int px = 0,int py = 0);
void SetHDC(HDC hdc){ m_hdc = hdc;}
HDC GetGraphicHDC(){ return m_graphichdc;}
BITMAP GetBitmap(){ return m_bitmap;}
};
Graphic::Graphic(){}
Graphic::Graphic(HDC hdc,std::string filename){
Create(hdc,filename);
}
Graphic::~Graphic(){
ReleaseDC(g_hwnd,m_graphichdc);
ReleaseDC(g_hwnd,m_hdc);
DeleteObject(m_hbmp);
}
void Graphic::Create(HDC hdc,std::string filename){
m_hdc = hdc;
m_hbmp = LoadImage(GetModuleHandle(NULL),filename.c_str(),IMAGE_BITMAP,0,0,LR_LOADFROMFILE | LR_CREATEDIBSECTION);
m_graphichdc = CreateCompatibleDC(m_hdc);
SelectObject(m_graphichdc,m_hbmp);
GetObject(m_hbmp,sizeof(HBITMAP),&m_bitmap);
}
bool Graphic::TrDraw(HDC hdc,int x,int y,int width,int height,int px,int py,UINT color){
if(width == 0){
TransparentBlt(hdc,x,y,m_bitmap.bmWidth,m_bitmap.bmHeight,m_graphichdc,px,py,m_bitmap.bmWidth,m_bitmap.bmHeight,color);
}else{
TransparentBlt(hdc,x,y,width,height,m_graphichdc,px,py,width,height,color);
}
return true;
}
bool Graphic::TrDraw(int x,int y,int width,int height,int px,int py,UINT color){
TrDraw(m_hdc,x,y,width,height,px,py,color);
return true;
}
bool Graphic::Draw(HDC hdc,int x,int y,int width,int height,int px,int py){
if(width == 0){
BitBlt(hdc,x,y,m_bitmap.bmWidth,m_bitmap.bmHeight,m_graphichdc,px,py,SRCCOPY);
}else{
BitBlt(hdc,x,y,width,height,m_graphichdc,px,py,SRCCOPY);
}
return true;
}
bool Graphic::Draw(int x,int y,int width,int height,int px,int py){
Draw(m_hdc,x,y,width,height,px,py);
return true;
}
//----- Graphic Class E -----//
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
bool Query(LONGLONG&,DWORD&);
void Release(HDC&,HWND&,char*);
void Mainloop(HDC hdc,const int frame);
bool Start(HDC hdc);
bool End(HDC hdc);
HDC Back_Init_Surface(HWND hwnd)
{
HDC hdc,BackDC;
HBITMAP hBackBMP;
hdc=GetDC(hwnd);
BackDC=CreateCompatibleDC(hdc);
hBackBMP=CreateCompatibleBitmap(hdc,WINX,WINY);
SelectObject(BackDC,hBackBMP);
PatBlt(BackDC,0,0,WINX,WINY,WHITENESS);
DeleteObject(hBackBMP);
ReleaseDC(hwnd,hdc);
return BackDC;
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR lpCmdLine,int nCmdShow)
{
MSG msg;
WNDCLASSEX wc;
HWND hwnd;
ZeroMemory(&wc,sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.lpszMenuName = NULL;
wc.hInstance = hInstance;
wc.hIcon = (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_APPLICATION),IMAGE_ICON,0,0,LR_SHARED);
wc.hIconSm = (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_APPLICATION),IMAGE_ICON,0,0,LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(IDC_ARROW),IMAGE_CURSOR,0,0,LR_DEFAULTCOLOR | LR_SHARED);
wc.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszClassName= TITLE;
if(!RegisterClassEx(&wc))return FALSE;
// ウィンドウのスタイル
// WS_OVERLAPPEDWINDOW = 大抵のやつを有効にしろ
// & ~WS_THICKFRAME = WS_OVERLAPPEDWINDOWからサイズ変更を無効に
// & ~WS_MAXIMIZEBOX = WS_OVERLAPPEDWINDOWから最大化を無効に
const DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX;
// ウィンドウを作る!
hwnd = CreateWindowEx(0,TITLE,TITLE,dwStyle,
GetSystemMetrics(SM_CXSCREEN)/2 - WINX/2, // 真ん中に表示
GetSystemMetrics(SM_CYSCREEN)/2 - WINY/2, // 真ん中に表示
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
if(!hwnd)return FALSE;
g_hwnd = hwnd;
//----- ウィンドウサイズをWINX WINY の大きさに。------
RECT window_rect;
SetRect(&window_rect,0,0,WINX,WINY);
AdjustWindowRectEx(&window_rect,GetWindowLong(hwnd,GWL_STYLE),GetMenu(hwnd) != NULL,GetWindowLong(hwnd,GWL_EXSTYLE));
const int nWidth = window_rect.right - window_rect.left;
const int nHeight = window_rect.bottom - window_rect.top;
SetWindowPos(hwnd,NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
//----- WINX WINY の大きさに。E -----
// ちらつきが起こるのでダブルバッファ
HDC BackDC = Back_Init_Surface(hwnd);
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
HDC hdc=GetDC(hwnd);
//----- QueryPerformance準備 -----//
LONGLONG llCurrentTime,llNextTime;
DWORD dwTimeCount;
if(!Query(llNextTime,dwTimeCount))
Release(hdc,hwnd,"QueryPerformanceの失敗");
//----- QueryPerformance準備 E -----//
int frame = 0; // 開始時からの合計フレーム数
bool active; // ウィンドウはアクティブ?
// ループ前の準備
Start(BackDC);
for(;;){
active = (hwnd == GetActiveWindow()) ? (IsIconic(hwnd)? true : false) : true;
if(active || PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){
if(!GetMessage(&msg,(HWND)NULL,0,0))break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}else{
// nFramesPerSecondで決められたFPSに固定
QueryPerformanceCounter((LARGE_INTEGER *)&llCurrentTime);
if (llCurrentTime > llNextTime){
// 白で塗りつぶし
PatBlt(BackDC,0,0,WINX,WINY,WHITENESS);
if(!active){Mainloop(BackDC,frame);}
// メインの画面に描画
BitBlt(hdc,0,0,WINX,WINY,BackDC,0,0,SRCCOPY);
llNextTime += dwTimeCount;
if(llNextTime < llCurrentTime)llNextTime = llCurrentTime + dwTimeCount;
}
}
frame++;
}
// 破棄などの処理
End(BackDC);
ReleaseDC(hwnd,hdc);
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
switch(msg){
case WM_KEYDOWN:
if(wParam != VK_ESCAPE){return 0;}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
break;
}
return (DefWindowProc(hwnd,msg,wParam,lParam));
}
void Release(HDC &hdc,HWND &hwnd,char *str)
{
MessageBox(hwnd,str,"失敗",MB_OK | MB_ICONSTOP);
if(!hdc)ReleaseDC(hwnd,hdc);
PostQuitMessage(0);
}
bool Query(LONGLONG &llNextTime,DWORD &dwTimeCount){
LONGLONG llPerformanceCounter;
if(!QueryPerformanceFrequency((LARGE_INTEGER *)&llPerformanceCounter))return false;
dwTimeCount = (DWORD)(llPerformanceCounter / nFramesPerSecond);
if(!QueryPerformanceCounter((LARGE_INTEGER *)&llNextTime))return false;
return true;
}
void FPS_Show(HDC hdc,int x,int y)
{
static DWORD dwTime = GetTickCount();
static int count = 0;
static char str[50] = "0FPS";
count++;
// 一秒間を測る
if(GetTickCount() - dwTime >= 1000){
wsprintf(str,"%dFPS",count);
count = 0;
dwTime = GetTickCount();
}
TextOut(hdc,x,y,str,lstrlen(str));
}
static int x=20,y=50;
static const int width = 48; // sekitoriの幅
static const int height= 48; // sekitoriの高さ
static const int speed = 5;
static Graphic sekitori,background;
bool Start(HDC hdc){
// 画像を読み込む
sekitori.Create(hdc,"Graphic/sekitori1.bmp");
background.Create(hdc,"Graphic/back.bmp");
return true;
}
// メインループ
void Mainloop(HDC hdc,const int frame){
if(GetKeyState(VK_UP ) & 0x80){
y -= speed;
if(y < 0)y = 0;
}else
if(GetKeyState(VK_DOWN ) & 0x80){
y += speed;
if(y+height > WINY)y = WINY - height;
}
if(GetKeyState(VK_RIGHT) & 0x80){
x += speed;
if(x+width > WINX)x = WINX - width;
}else
if(GetKeyState(VK_LEFT ) & 0x80){
x -= speed;
if(x < 0)x = 0;
}
background.Draw(hdc,0,0,320,240);
// RGB(255,255,255)を透明にして描画
sekitori.TrDraw(hdc,x,y,width,height,0,0,RGB(255,255,255));
// FPSを表示
FPS_Show(hdc,0,0);
}
bool End(HDC hdc){
return true;
}