Sign in to follow this  

game loop problem

This topic is 2489 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi
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

[code]

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
}
}

[/code]
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


[code]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
}}
[/code]


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


[code]#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()){

[/b][b]//vec2 p = *i * deltatime;[/b]
[b] //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;
}
[/code]




here is my vec2 class :

[code]
#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)
{
}
[/code]

Share this post


Link to post
Share on other sites
You stated the problem yourself! In a game you need to have things updated constantly even if you are not receiving messages. The reason why is that the bullet is only being updated when you receive a message i.e a keypress.

So if you have something like

[code]
while (keepGameRunning == true) {
if (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//gamecodes
}
}
}[/code]


That way the game is always updated but messages are only handled when necessary. Thats only some pseudo code but it should work.

Share this post


Link to post
Share on other sites
You need to use [url="http://msdn.microsoft.com/en-us/library/ms644943(VS.85).aspx"]PeekMessage[/url] instead of GetMessage, as GetMessage will block and wait when there are no messages.
[code]
while(loop) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
No messages, handle a game frame
}
}[/code]

Share this post


Link to post
Share on other sites
thanx m8 that did it !

there is another problem
in my source book there is way to find out if the bullet is out of the screen so i could ereas it from my list
bullet are 2d vector so it goes like that

//get point form
//i is a iterator to my buulet list
POINT P = *I ;
if(!PtInRect(&screenmap , p ){

i=buuletlist.erase(i)

........


but in vs 2008 i GET :Error 1 error C2440: 'initializing' : cannot convert from 'vec2' to 'POINT'

is there a way to convert 2d vector to point ?
i could use my vector.x to locate the bullet but PtInRect wouldn't accept it

Share this post


Link to post
Share on other sites
Looks to me like you have a list of vec2's and are trying to assign its value to a POINT in this line

[code]POINT P = *I ; [/code]

Option A: Write a function that will determine whether the point is on the screen (not hard) and make it accept a vec2
Option B: Declare P as vec2 instead of POINT. ( Which will probably mess up the next line)

Option C: Declare your list as POINTS instead of vec2s.

Option D: Simply declare P as is. Then assign P.x to *i.x and P.y to *i.y

Share this post


Link to post
Share on other sites
Just to tweak your game loop a bit to avoid infrequent problems, you should use [b]while[/b]( PeekMessage(...)) instead of if. Somethig like:
[code]
while( loop )
{
while(PeekMessage(...))
{
if( msg.message==WM_QUIT)
{
// stop your app
}
TranslateMessage(...);
DispatchMessage(...);
}
// game related stuff
}
[/code]

Share this post


Link to post
Share on other sites
Hey check this link for some more details on your loop problem. The main points were mentioned in this thread, but just for the understanding: http://www.directxtutorial.com/Tutorial11/A-A/AA5.aspx

Share this post


Link to post
Share on other sites

This topic is 2489 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this