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.
Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!
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?)
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.