8Observer8 said:
@rafaelsantana could you build your game from the video above to EXE and attach it in an achieve?
I'll do it this weekend but I have to build a good base map first.
8Observer8 said:
@rafaelsantana could you build your game from the video above to EXE and attach it in an achieve?
I'll do it this weekend but I have to build a good base map first.
Hello Endurion and Airbatz..
I copy source code of this GDI win32 api examples and code compile and run fine .
I am using mingW with Falcon++ IDE.
I have question, i want to add new sprite, and i add it with LoadImage() func and sprite become visible with BitBlt…then i add arrow keys under WM_KEYDOWN ..but when i
pressing keys nothing heappend, i also check key respond with MessageBox and it looks that WM_KEYDOWN is somehow ignored…nothing …any help here ?
this is the code :
case WM_COMMAND:
{
// SHOULD REALLY USE GetAsyncKeyState for game, but simplified here
switch (wParam)
{
case VK_LEFT:
spriteX=spriteX-4;
MessageBox( hwnd, "KEY LEFT PRESSED!", "KEY_LEFT", MB_OK | MB_ICONEXCLAMATION );
break;
case VK_RIGHT:
spriteX=spriteX+4;
break;
case VK_UP:
spriteY=spriteY-4;
break;
case VK_DOWN:
spriteY=spriteY+4;
break;
A) The snippet you pasted shows WM_COMMAND, not WM_KEYDOWN
B) WM_KEYDOWN is posted when the key is pushed down, WM_KEYUP once the key is released. You have to remember the key state somewhere, and check it periodically in your Update code (you do have something like this?)
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
Hi Endurion
Sorry i mix up keydown and wm_command..
Most of time i am using basic compiler called o2 which is also native compiler.
So i don't have much experience with C compilers but all api looking same:
here is whole code:
#define WIN32_LEAN_AND_MEAN
#define TIMER_VELOCITY 1
#define TIMER_ANIMATE 2
#include <windows.h>
#include <stdlib.h>
//#include "resource.h"
HICON hMyIcon;
HBITMAP graphics[4];
HBITMAP g_hbmMask = NULL;
HDC hdcBuffer;
HBITMAP hbmBuffer;
int spriteX = 320, spriteY = 400;
typedef struct SpriteAnimation
{
int xpos;
int ypos;
int frames;
int x_velocity;
int counter;
int direction;
}SAKURA;
SAKURA g_spriteInfo;
HBITMAP CreateBitmapMask( HBITMAP hbmColour, COLORREF crTransparent )
{
HDC hdcMem, hdcMem2;
HBITMAP hbmMask;
BITMAP bm;
GetObject( hbmColour, sizeof( BITMAP ), &bm );
hbmMask = CreateBitmap( bm.bmWidth, bm.bmHeight, 1, 1, NULL );
hdcMem = CreateCompatibleDC( 0 );
hdcMem2 = CreateCompatibleDC( 0 );
SelectObject( hdcMem, hbmColour );
SelectObject( hdcMem2, hbmMask );
SetBkColor( hdcMem, crTransparent );
BitBlt( hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY );
BitBlt( hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT );
DeleteDC( hdcMem );
DeleteDC( hdcMem2 );
return hbmMask;
}
void DrawScene( HDC hdc, RECT* prc )
{
HDC hdcBuffer = CreateCompatibleDC( hdc );
HBITMAP hbmBuffer = CreateCompatibleBitmap( hdc, prc->right, prc->bottom );
HBITMAP hbmOldBuffer = (HBITMAP)SelectObject( hdcBuffer, hbmBuffer );
HDC hdcMem = CreateCompatibleDC( hdc );
BitBlt(hdcBuffer, g_spriteInfo.xpos, g_spriteInfo.ypos, 32, 32, hdcMem, 4*(g_spriteInfo.frames%1), 0, SRCAND); //the sprite G
// BitBlt(hdcBuffer, spriteX, spriteY, 32, 32, hdcMem, 1, 0, SRCAND); //the sprite ship
SelectObject(hdcMem,graphics[1]); // sprG
BitBlt(hdcBuffer, g_spriteInfo.xpos, g_spriteInfo.ypos, 32, 32, hdcMem, 4*(g_spriteInfo.frames%1), 0, SRCPAINT); //spr G
SelectObject(hdcMem,graphics[3]); // ship
BitBlt(hdcBuffer, spriteX, spriteY, 32, 32, hdcMem, 0, 0, SRCPAINT); //ship
SelectObject(hdcMem,graphics[1]);
BitBlt( hdc, 0, 0, prc->right, prc->bottom, hdcBuffer, 0, 0, SRCCOPY );
// SelectObject(hdcMem,graphics[3]); //ship
//BitBlt( hdc, spriteX, spriteY, 32, 32 , hdcBuffer, 0, 0, SRCCOPY ); //ship
SelectObject( hdcMem, hbmBuffer );
DeleteDC( hdcMem );
SelectObject( hdcBuffer, hbmOldBuffer );
DeleteDC( hdcBuffer );
DeleteObject( hbmBuffer );
}
void AnimateSprite( RECT* prc )
{
g_spriteInfo.frames+=TIMER_ANIMATE;
}
void UpdateSpritePosition( RECT* prc )
{
g_spriteInfo.ypos += TIMER_VELOCITY;
g_spriteInfo.counter++;
if(g_spriteInfo.counter == 8)
{
if(g_spriteInfo.direction == 0 )
{
g_spriteInfo.x_velocity = 2;
g_spriteInfo.direction = 1;
}
else if (g_spriteInfo.direction == 1)
{
g_spriteInfo.x_velocity = -2;
g_spriteInfo.direction = 0;
}
g_spriteInfo.counter = 0;
}
g_spriteInfo.xpos += g_spriteInfo.x_velocity;
if ( g_spriteInfo.ypos > 460 ) //when the sprite goes beyond the bottom of the window
{
g_spriteInfo.ypos = -7; //re-set the position of the sprite to be above the top of the window
g_spriteInfo.xpos = abs(rand()*400/RAND_MAX); //randomize the x position of the sprite
}
if (spriteX > 640) // if out pf window
{
spriteX == 0;
}
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch ( msg )
{
case WM_CREATE:
{
BITMAP bm;
SelectObject(hdcBuffer, hbmBuffer);
graphics[1] = LoadImageA( 0, "C:\\man.bmp", 0, 32,32,16 );
graphics[3] = LoadImageA( 0, "C:\\ship.bmp", 0, 32,32,16 );
graphics[0] = CreateBitmapMask( graphics[1], RGB( 0, 0, 0 ) );
graphics[2] = CreateBitmapMask( graphics[3], RGB( 0, 0, 0 ) );
GetObject( graphics, sizeof( bm ), &bm );
ZeroMemory( &g_spriteInfo, sizeof( g_spriteInfo ) );
g_spriteInfo.xpos = abs(rand()*405/RAND_MAX+10); //randomize starting x position
g_spriteInfo.direction = 0;
SetTimer( hwnd, TIMER_VELOCITY, 1, NULL );
SetTimer( hwnd, TIMER_ANIMATE, 2, NULL );
}
return 0;
case WM_COMMAND:
{
// SHOULD REALLY USE GetAsyncKeyState for game, but simplified here
switch (wParam)
{
case 0xCB :
spriteX=spriteX-4;
MessageBox( hwnd, "KEY LEFT PRESSED!", "KEY_LEFT", MB_OK | MB_ICONEXCLAMATION );
break;
case VK_RIGHT:
spriteX=spriteX+4;
break;
case VK_UP:
spriteY=spriteY-4;
break;
case VK_DOWN:
spriteY=spriteY+4;
break;
}
//return 0;--------------------------------------------------------
}
case WM_CLOSE:
DestroyWindow( hwnd );
return 0;
case WM_PAINT:
{
RECT rcClient;
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hwnd, &ps );
GetClientRect( hwnd, &rcClient );
DrawScene( hdc, &rcClient );
EndPaint( hwnd, &ps );
}
return 0;
//--------------------------------------------------------------------------
case WM_TIMER:
{
RECT rcClient;
GetClientRect( hwnd, &rcClient );
switch(wParam)
{
case TIMER_VELOCITY:
UpdateSpritePosition( &rcClient );
//spriteX = spriteX+1;
break;
case TIMER_ANIMATE:
AnimateSprite( &rcClient );
break;
}
InvalidateRect( hwnd, NULL, 0 );
}
return 0;
case WM_ERASEBKGND:
return 1;
case WM_DESTROY:
KillTimer( hwnd, TIMER_VELOCITY );
KillTimer( hwnd, TIMER_ANIMATE );
DeleteObject( graphics );
DeleteObject( g_hbmMask );
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam );
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
hMyIcon = LoadIconW( hInstance, "\myicon.ico");
WNDCLASSEX wc = {0};
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof( WNDCLASSEX );
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = hMyIcon;
wc.hIconSm = NULL;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT( "Buttons" );
RegisterClassEx( &wc );
hwnd = CreateWindowEx( 0, TEXT("Buttons"), "Movin Ghost",
WS_OVERLAPPED | WS_SYSMENU |WS_VISIBLE |WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL );
ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd );
while ( GetMessage( &Msg, NULL, 0, 0 ) > 0 )
{
TranslateMessage( &Msg );
DispatchMessage( &Msg );
}
return Msg.wParam;
}
[quote]HDC hdcBuffer = CreateCompatibleDC(hdc); HBITMAP hbmBuffer = CreateCompatibleBitmap(hdc, prc->right, prc->bottom);
[/quote]
Don't create a new bitmap and new DC everytime you paint. Cache these values and re-use them!
Don't create a new bitmap and new DC everytime you paint. Cache these values and re-use them!
aston2 said:
Don't create a new bitmap and new DC everytime you paint. Cache these values and re-use them!
Didn't I already tell him this? O.o
Make them global. Only create them if they are the INVALID_HANDLE_VALUE.
/*globally*/
HDC hdcBuffer = (HDC)INVALID_HANDLE_VALUE;
HBITMAP hbmBuffer = (HBITMAP)INVALID_HANDLE_VALUE;
void DrawScene(HDC hdc, LPRECT prc)
{
if (hdcBuffer == (HDC)INVALID_HANDLE_VALUE) {
hdcBuffer = CreateCompatibleDC( hdc );
}
if (hbmBuffer == (HBITMAP)INVALID_HANDLE_VALUE) {
hbmBuffer = CreateCompatibleBitmap( hdc, prc->right, prc->bottom );
}
…
}
Note that, if your window changes client rect size, you need to re-create the bitmap. You could, for example, call DeleteObject(hbmBuffer) and set hbmBuffer to INVALID_HANDLE_VALUE in the WM_SIZE message handler.
Finally, it turns out that a better way of running a message pump than using a TIMER is to call InvalidateRect(window, &clientRect) on the window after you call EndPaint(). This will make sure there is always a WM_PAINT message waiting to be drawn, but the rules for message priority is that all other messages have higher priority than WM_PAINT, so user input will still get delivered. Then you want to update simulation right before WM_PAINT if enough time has passed, rather than using WM_TIMER for that.