so it's my first 2d game
it's simple tank which can move and fire bullets
my problem is with my game loop
my source book like most of c++4game books is using vs2005 and i'm using vs2008
as u know there are some changes in win32api
so the tank moves fine but when im shooting bullets they move a little and just stop until i press another key and then they start to move again
i know problem is my game loop
which instead of running the game is waiting for new messages
my book says is should change the game loop like this
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow);
{
return run();
}
int run(){
MSG msg;
ZeroMemory(&msg,sizeof(MSG));
while (msg.message !=WM_QUIT)
{
if(PeekMessage(&msg , 0 ,0,0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
game codes
}
}
but my my vs2008 is using int APIENTRY _tWinMain insted of int WINAPI WinMain
which i quite different and seems to have game loop in it's scoop so i didn't know where to put run() function
and when im using it i get a error :The variable 'msg' is being used without being initialized.
so i'm using vs default msg loop
my code now looks like this
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_DUBLE_BUFFERING, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DUBLE_BUFFERING));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
//gamecodes
}}
which is works fine when im pressing keys and thank moves
but it doesn't seems to update the game without receiving new msg so my bullets would stop in the middle of screen until next KEY_DOWN
here is complete code
I'd really appreciate if someone could look into it
#include "stdafx.h"
#include "resource.h"
#include "duble_buffering.h"
#include "backbuffer.h"
#include "vec2.h"
#include <string>
#include <list>
#include <mmsystem.h>
using namespace std;
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
backbuffer* bb =0;
const int cw=800;
const int ch=600;
const POINT cc={cw/2 , ch/2};
RECT maprect = {0,0,800,600};
vec2 tankpos(400.0f , 300.0f);
HPEN gunpen;
vec2 gundirection(0.0f ,-120.0f);
list<vec2> bulletlist;
float lasttime = (float) timeGetTime ();
// Forward declarations of functions included in this code module:
int RUN();
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_DUBLE_BUFFERING, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DUBLE_BUFFERING));
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
float curtime = (float) timeGetTime ();
float deltatime = (curtime-lasttime)*0.001f;
HDC bbdc = bb->getdc();
HBRUSH oldbrush = (HBRUSH) SelectObject(bbdc ,GetStockObject( BLACK_BRUSH));
Rectangle(bbdc ,0,0,800,600);
SelectObject(bbdc , GetStockObject(DKGRAY_BRUSH));
Rectangle(bbdc,(int)tankpos.x-50 ,
(int)tankpos.y-75 ,
(int)tankpos.x+50 ,
(int)tankpos.y+75 );
SelectObject(bbdc , GetStockObject(DKGRAY_BRUSH));
Ellipse(bbdc,(int)tankpos.x-40 ,
(int)tankpos.y-40 ,
(int)tankpos.x+40 ,
(int)tankpos.y+40);
HPEN oldpen = (HPEN)SelectObject(bbdc , gunpen);
MoveToEx(bbdc , (int)tankpos.x ,(int) tankpos.y,0);
LineTo(bbdc , (int)(tankpos.x+gundirection.x) ,
(int) (tankpos.y+gundirection.y));
SelectObject(bbdc , GetStockObject(WHITE_BRUSH));
SelectObject(bbdc , oldpen);
vec2 bulletvel = gundirection + 0.1f;
list<vec2>::iterator i = bulletlist.begin();
while(i != bulletlist.end()){
//vec2 p = *i * deltatime;//it's in my book but when im using it i couldn't see the bullet at all
vec2 p = *i;
*i += bulletvel ;
Ellipse(bbdc ,
p.x-4,
p.y-4,
p.x+4,
p.y+4);
++i;
}
SelectObject(bbdc , oldbrush);
bb->peresent();
float lasttime = curtime;
Sleep(20);
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DUBLE_BUFFERING));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_DUBLE_BUFFERING);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance;
// Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, cw, ch, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
LOGPEN lp;
switch (message)
{
case WM_CREATE:
lp.lopnColor=RGB(150,150,150);
lp.lopnStyle=PS_SOLID;
lp.lopnWidth.x=10;
lp.lopnWidth.y=10;
gunpen = CreatePenIndirect(&lp);
bb = new backbuffer(hWnd , cw , ch );
break;
case WM_KEYDOWN:
switch(wParam){
case 'A' :
tankpos.x -=5.0f;
break;
case 'D' :
tankpos.x +=5.0f;
break;
case 'W' :
tankpos.y -=5.0f;
break;
case 'S':
tankpos.y +=5.0f;
break;
case 'Q' :
gundirection.rotate(-0.1f);
break;
case 'E':
gundirection.rotate (0.1f);
break;
case VK_SPACE:
bulletlist.push_back(tankpos+gundirection);
break;
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
DeleteObject(gunpen);
delete bb;
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
here is my vec2 class :
#include <cmath>
class vec2
{
public:
vec2(void);
vec2(float x0 , float y0);
float x;
float y;
vec2 operator +(vec2& rhs);
vec2 operator +(float a);
vec2& operator +=(vec2& rhs);
vec2 operator *(float s);
vec2& rotate(float r);
~vec2(void);
};
/////////////////////////
#include "StdAfx.h"
#include "vec2.h"
vec2::vec2(){
}
vec2::vec2(float x0,float y0)
{
x = x0 ;
y = y0;
}
vec2 vec2::operator *(float s){
vec2 m;
m.x = x*s;
m.y=y*s;
return m;
}
vec2 vec2::operator +(vec2& rhs){
vec2 add;
add.x = x+rhs.x;
add.y = y+rhs.y;
return add;
}
vec2& vec2::operator +=(vec2& rhs){
x = x+rhs.x;
y = y+rhs.y;
return *this;
}
vec2 vec2::operator +(float a){
vec2 mm;
mm.x=x +a;
mm.y=y +a;
return mm;
}
vec2& vec2::rotate(float r){
x = x*cosf(r) - y* sinf(r);
y = y*cosf(r) + x * sinf(r);
return *this;
}
vec2::~vec2(void)
{
}