I'm sort of new to rendering graphics with GDI...
I made a paint program, and it works fine, it's just that it causes a lot of annoying screen flickering. I will admit my paint code is not really optimized (lack of time), but it shouldn't be super inefficient either, so I'm puzzled.
What I'm basically doing is creating a compatible DC on init, then create a compatible bitmap. Then I select it into the compatible DC, and paint to the compatible DC. Then I use BitBlit() to copy it to the window hDC...
Could anyone tell me the possible causes for this screen tearing?
EDIT: btw, screen flickering only occurs during the drawing of a path (before the path gets drawn to the hMemDC, it gets drawn to the hDC of the window)
Code samples:
(EDIT: If you need to see any more code that you think is relevant, comment and I'll edit)
Path::DrawTo(HDC)
bool Path::DrawTo(HDC hDC)
{
if(hDC == NULL || m_PointVector.size() <= 0) {
return false;
}
switch (m_Tool) {
case Tool_Pen:
{
Point2D p = m_PointVector.at(0);
if(m_PointVector.size() > 1) {
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
MoveToEx(hDC, p.x, p.y, nullptr);
for(UINT i = 1; i < m_PointVector.size(); ++i) {
p = m_PointVector.at(i);
LineTo(hDC,p.x,p.y);
}
SelectObject(hDC,oldPen);
break;
} //else
SetPixel(hDC,p.x-1,p.y,m_Col);
SetPixel(hDC,p.x,p.y,m_Col);
SetPixel(hDC,p.x+1,p.y,m_Col);
SetPixel(hDC,p.x,p.y-1,m_Col);
SetPixel(hDC,p.x,p.y+1,m_Col);
break;
}
case Tool_Line:
{
if(m_PointVector.size() > 1) {
Point2D p = m_PointVector.at(0);
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
MoveToEx(hDC, p.x, p.y, nullptr);
for(UINT i = 1; i < m_PointVector.size(); ++i) {
p = m_PointVector.at(i);
LineTo(hDC,p.x,p.y);
}
SelectObject(hDC,oldPen);
}
break;
}
case Tool_Ellipse:
{
if(m_PointVector.size() > 1) {
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
SelectObject(hDC,m_hBrush);
Point2D p1 = m_PointVector.at(0);
Point2D p2 = m_PointVector.at(1);
if(p1.x > p2.x) {
int iTemp = p1.x;
p1.x = p2.x;
p2.x = iTemp;
}
if(p1.y > p2.y) {
int iTemp = p1.y;
p1.y = p2.y;
p2.y = iTemp;
}
Ellipse(hDC,p1.x,p1.y,p2.x,p2.y);
SelectObject(hDC,oldPen);
}
break;
}
case Tool_Rectangle:
{
if(m_PointVector.size() > 1) {
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
SelectObject(hDC,m_hBrush);
Point2D p1 = m_PointVector.at(0);
Point2D p2 = m_PointVector.at(1);
if(p1.x > p2.x) {
int iTemp = p1.x;
p1.x = p2.x;
p2.x = iTemp;
}
if(p1.y > p2.y) {
int iTemp = p1.y;
p1.y = p2.y;
p2.y = iTemp;
}
Rectangle(hDC,p1.x,p1.y,p2.x,p2.y);
SelectObject(hDC,oldPen);
}
break;
}
case Tool_LineTrack:
{
HPEN oldPen = (HPEN)SelectObject(hDC,m_hPen);
SelectObject(hDC,m_hBrush);
int vSize = (int)m_PointVector.size();
Point2D p = m_PointVector.at(0);
if (vSize <= 1) {
Ellipse(hDC,p.x-10,p.y-10,p.x+10,p.y+10);
}
else {
//draw LineTrack
Point2D pTemp = m_PointVector.at(1);
MoveToEx(hDC,p.x,p.y,nullptr);
for (int i = 1; i < vSize; ++i) {
p = m_PointVector.at(i);
pTemp = m_PointVector.at(i-1);
LineTo(hDC,p.x,p.y);
Ellipse(hDC,pTemp.x-10,pTemp.y-10,pTemp.x+10,pTemp.y+10);
}
Ellipse(hDC,p.x-10,p.y-10,p.x+10,p.y+10);
}
SelectObject(hDC,oldPen);
break;
}
}
return true;
}
WndProc(HWND, UINT, WPARAM, LPARAM)
LRESULT MyApp::WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
if(iMsg == WM_CREATE)
{
CREATESTRUCT *pCS = (CREATESTRUCT*)lParam;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)pCS->lpCreateParams);
}
else
{
//retrieve the stored "this" pointer
MyApp* pApp = (MyApp*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch (iMsg)
{
case WM_PAINT:
{
pApp->Paint();
return 0;
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_NEW:
{
////
return 0;
}
return 0;
case IDM_LOAD:
{
//////
return 0;
}
case IDM_SAVE:
{
//////
return 0;
}
case IDM_SAVEAS:
{
//////
return 0;
}
case IDM_COLOURMAIN:
{
COLORREF col;
if(MyWin32Funcs::OnColorPick(col)) {
pApp->m_pPath->SetColor1(col);
}
return 0;
}
case IDM_COLOURSECONDARY:
{
COLORREF col;
if(MyWin32Funcs::OnColorPick(col)) {
pApp->m_pPath->SetColor2(col);
}
return 0;
}
case IDM_PEN:
{
pApp->m_pPath->SetTool(Tool_Pen);
return 0;
}
case IDM_LINE:
{
pApp->m_pPath->SetTool(Tool_Line);
return 0;
}
case IDM_ELLIPSE:
{
pApp->m_pPath->SetTool(Tool_Ellipse);
return 0;
}
case IDM_RECTANGLE:
{
pApp->m_pPath->SetTool(Tool_Rectangle);
return 0;
}
case IDM_LINETRACK:
{
pApp->m_pPath->SetTool(Tool_LineTrack);
return 0;
}
default:
{
//////
return 0;
}
}
}
case WM_LBUTTONUP:
{
//////
Point2D p;
p.x = LOWORD(lParam);
p.y = HIWORD(lParam);
switch(pApp->m_pPath->GetTool()) {
case Tool_Pen:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
case Tool_Ellipse:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
case Tool_Rectangle:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
case Tool_Line:
{
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
case Tool_LineTrack:
{
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
}
return 0;
}
case WM_RBUTTONUP:
{
//////
int x = LOWORD(lParam);
int y = HIWORD(lParam);
switch(pApp->m_pPath->GetTool()) {
case Tool_Line:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
case Tool_LineTrack:
{
pApp->m_bPaintToBitmap = true;
InvalidateRect(pApp->m_hWnd,NULL,true);
break;
}
}
return 0;
}
case WM_LBUTTONDOWN:
{
Point2D p;
p.x = LOWORD(lParam);
p.y = HIWORD(lParam);
switch(pApp->m_pPath->GetTool()) {
case Tool_Pen:
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
}
case WM_MOUSEMOVE:
{
Point2D p;
p.x = LOWORD(lParam);
p.y = HIWORD(lParam);
if (wParam & MK_LBUTTON) {
switch(pApp->m_pPath->GetTool()) {
case Tool_Pen:
{
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
case Tool_Ellipse:
{
if( pApp->m_pPath->GetLen() >= 1) {
pApp->m_pPath->SetPointAt(1,p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
}
else {
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
}
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
case Tool_Rectangle:
{
if( pApp->m_pPath->GetLen() >= 1) {
pApp->m_pPath->SetPointAt(1,p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
}
else {
pApp->m_pPath->AddPoint(p,pApp->m_pBitmapPainter->GetBmpSize(),pApp->m_pBitmapPainter->GetBmpOffset());
}
InvalidateRect(pApp->m_hWnd,NULL,false);
break;
}
}
}
return 0;
}
case WM_CLOSE:
{
//////
return 0;
}
}
PostQuitMessage(0);
return 0;
}
}
}
return DefWindowProc (hWnd, iMsg, wParam, lParam) ;
}
MyApp::Paint()
void MyApp::Paint()
{
BeginPaint(m_hWnd,&m_PaintStruct);
if (m_bPaintToBitmap) {
Point2D p;
p.x = BMPXOFFSET;
p.y = BMPYOFFSET;
m_pPath->Offset(p);
m_pPath->DrawTo(m_pBitmapPainter->GetMemDC());
m_pPath->ClrPath();
m_pBitmapPainter->Paint(); //this is where BitBlt() occurs
m_bPaintToBitmap = false;
if(m_pBitmapPainter->IsAdjusted() == false) {
m_pBitmapPainter->SetbAdjusted(true);
}
}
else {
m_pBitmapPainter->Paint(); //this is where BitBlt() occurs
m_pPath->DrawTo(m_hDC);
}
EndPaint(m_hWnd,&m_PaintStruct);
}
Any help would much be appreciated.
I think what you're seeing is flicker, not tearing. To minimize flicker, your WM_PAINT should write to the window DC exactly once. Typically, this one operation is a BitBlt:
HDC hdc = BeginPaint(m_hwnd, &m_PaintStruct);
... paint to bitmap ...
BitBlt(hdc, ...); // blt from bitmap to screen
EndPaint(m_hwnd, &m_PaintStruct);
If you paint to the window DC in multiple steps, then you open the window for flicker.
Your description of the problem doesn't match the code. In your description, you say that you're blitting from the compatible DC to the window hDC. But in your code, your BitBlt is followed by a m_pPath->DrawTo(m_hDC). If a refresh occurs during the DrawTo, then the screen will refresh with a partially-drawn view, resulting in flicker.
If you are drawing the entire client area, override WM_ERASEBKGND, and simply return TRUE. That will reduce the flicker.
As others have pointed out; use the HDC given by WM_PAINT, as it may contain clipping regions, and other stuff that may optimize the screen update.
EDIT
If you are not drawing the entire client area, you can perform background painting in the areas you know where your WM_PAINT handler won't paint.
BeginPaint gives you HDC you are supposed to paint to. You are ignoring it.
What OS are you running on ? If its Vista or Windows 7, are you running in some sort of "compatibility mode" disabling desktop compositing ?
Supposedly one of the advantages of the Desktop Window Manager (DWM) introduced with Vista is (source):
In Windows XP, applications update their windows directly when the OS
requests them to. These requests could be executed asynchronously with
respect to the refresh rate of the monitor or to any updates that may
be currently running. The effect of these requests is that the user
sees windows tearing and re-drawing incorrectly or slowly. The DWM
style of window presentation eliminates the tearing artifacts,
providing a high quality desktop experience. The benefit to the end
user is that the system appears to be more responsive and the
experience is cleaner.
ie with the DWM, compositing to the desktop will be synchronized with drawing to avoid ever seeing partially drawn "torn" things.
If that's not it, are you sure you're not confusing "tearing" with background erase flicker or something ?
Related
This code in my windowless framework is an area like just button,but some code I wanted to run it only once until the mouse move on the area next time.
All those code are in WM_MOUSEMOVE.
int ClickAreaPtInfo(HWND hWnd, int x, int y, int sizex, int sizey, LPARAM lParam,int &value)
{
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
RECT rect;
GetClientRect(hWnd, &rect);
RECT rc = { x,y,x + sizex,y + sizey };
if (PtInRect(&rc, pt))
{
value = 1;
return -1;
}
else
{
value = 0;
return -1;
}
return -1;
}
int _CreateMouseEvent(HWND hWnd, int x, int y, int sizex, int sizey, LPARAM lParam,RUNFUN function(), const wchar_t* Panelid, const wchar_t* CtlName)
{
int val = 0;
int msg = 0;
//int ist = 0; int istprev = 0;
RECT winrc;
GetClientRect(hWnd, &winrc);
RECT rc;
RectTypeConvert(rc,x, y, sizex, sizey);
if (Panelid == PanelID)
{
int nst = 1;
//OutputDebugString(L"HOVER!\n");
msg = 1;
ClickAreaPtInfo(hWnd, x, y, sizex, sizey, lParam, val);
if (val == 1)
{
if (ClickMsg == 1) //Click(Get from WM_LBUTTONUP)
{
ClickMsg = 0;
function();
}
else
{
//It must be run for only once until the mouse leave next time,or it will lead to a lot of resource occupation
if (CtlName == L"Button") //HOVER
{
if (nst == 1)
{
HDC hdc = GetDC(hWnd);
CreateSimpleButtonEx(hWnd, hdc, x, y, sizex, sizey, UICOLOR_GREENSEA, 1, ButtonText);
ReleaseDC(hWnd, hdc);
nst = 0;
return 0;
}
else
{
nst = 0;
return 0;
}
return 0;
}
if (CtlName == L"CloseButton") ///HOVER
{
if (nst == 1)
{
HDC hdc = GetDC(hWnd);
CreateRect(hWnd, hdc, x, y, sizex, sizey, UICOLOR_PEACHRED);
PanelDrawCloseBtn(hWnd, hdc, rc.right - 40, 0, 40, 40, 12, UICOLOR_WHITE);
ReleaseDC(hWnd, hdc);
nst = 0;
return 0;
}
else
{
nst = 0;
return 0;
}
return 0;
}
else
{
return 0;
}
}
}
if (val == 0) //Leave
{
nst = 1;
InvalidateRect(hWnd, &rc, 0); //It must be run for only once until the mouse leave next time,or it will lead to a lot of resource(CPU) occupation
}
}
if (Panelid == PrevPanelID)
{
msg = 1;
}
else
{
msg = 0;
}
return 0;
}
then handle CreateMouseEvent in WM_MOUSEMOVE:
case WM_MOUSEMOVE:
{
CreateMouseEvent(hWnd, 20, 60, 140, 40, lParam, test, L"Init",L"Button");
CreateMouseEvent(hWnd, 20, 120, 140, 40, lParam, test3, L"Init", L"Button");
CreateMouseEvent(hWnd, 20, 180, 140, 40, lParam, btn3, L"Init",L"Button");
CreateMouseEvent(hWnd, rc.right - 40, 0, 40, 40, lParam, CloseWindow, L"Init",L"CloseButton");
break;
}
And I will also give a picture to this question!
http://db.vertexstudio.xyz/lnk/PanelPic/debuginf.png
any solution?thanks!
Some of your problems have already been mentioned above.
There are some variables that are not defined in your example, neither type nor value, but I can extrapolate some at least.
Also, in several places, you try to directly compare a C style string pointer (not a std::string!) to another C style string pointer.
if (Panelid == PanelID) is one place
if (CtlName == L"Button") //HOVER === is another
if (CtlName == L"CloseButton") ///HOVER another
You can use something like int _wcsnicmp( const wchar_t *string1,const wchar_t *string2, size_t count); or whatever your compiler supports. Optionally, you could just use std::wstring.
As for the click, you need to save the rect you get with GetClientRect(hWnd, &winrc); It needs persistence, ie saved outside of the function and accessible. Then compare to this rectangle and act accordingly.
I am using this website to learn DirectX: http://www.rastertek.com/tutdx10.html I am trying to use their DirectInput tutorial to add more keybindings besides Escape. However, I cannot get my keys to fire. Here is the relevant code:
////////////////////////////////////////////////////////////////////////////////
// Filename: inputclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "inputclass.h"
InputClass::InputClass()
{
m_directInput = 0;
m_keyboard = 0;
m_mouse = 0;
}
InputClass::InputClass(const InputClass& other)
{
}
InputClass::~InputClass()
{
}
bool InputClass::Initialize(HINSTANCE hinstance, HWND hwnd, int screenWidth, int screenHeight)
{
HRESULT result;
//Store the screen sizew hcih will be used for positioning the mouse cursor.
m_screenWidth = screenWidth;
m_screenHeight = screenHeight;
//Initialize the location of the mouse on the screen.
m_mouseX = 0;
m_mouseY = 0;
//Initialize the main direct input interface.
result = DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_directInput, NULL);
if(FAILED(result))
{
return false;
}
//Initialize the direct input interface for the keyboard.
result = m_directInput->CreateDevice(GUID_SysKeyboard, &m_keyboard, NULL);
if(FAILED(result))
{
return false;
}
//Set the data format. In this case since it is a keyboard we can use the predefined data format.
result = m_keyboard->SetDataFormat(&c_dfDIKeyboard);
if(FAILED(result))
{
return false;
}
//Set the cooperative level of the keyboard to not share with other programs.
result = m_keyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
if(FAILED(result))
{
return false;
}
//Now aquire the keyboard.
result = m_keyboard->Acquire();
if(FAILED(result))
{
return false;
}
//Initialize the direct input interface for the mouse.
result = m_directInput->CreateDevice(GUID_SysMouse, &m_mouse, NULL);
if(FAILED(result))
{
return false;
}
//Set the data format for the mouse using the pre-defined mouse data format.
result = m_mouse->SetDataFormat(&c_dfDIMouse);
if(FAILED(result))
{
return false;
}
//Set the cooperative level of the mouse to share with other programs.
result = m_mouse->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if(FAILED(result))
{
return false;
}
//Aquire the mouse.
result = m_mouse->Acquire();
if(FAILED(result))
{
return false;
}
return true;
}
void InputClass::Shutdown()
{
//Release the mouse.
if(m_mouse)
{
m_mouse->Unacquire();
m_mouse->Release();
m_mouse = 0;
}
//Release the keyboard.
if(m_keyboard)
{
m_keyboard->Unacquire();
m_keyboard->Release();
m_keyboard = 0;
}
//Release the main interface to direct input.
if(m_directInput)
{
m_directInput->Release();
m_directInput = 0;
}
return;
}
bool InputClass::Frame()
{
bool result;
//Read the current state of the keyboard.
result = ReadKeyboard();
if(!result)
{
return false;
}
//Read the current state of the mouse.
result = ReadMouse();
if(!result)
{
return false;
}
//Process the changes in the mouse and keyboard.
ProcessInput();
return true;
}
bool InputClass::ReadKeyboard()
{
HRESULT result;
//Read the keyboard device.
result = m_keyboard->GetDeviceState(sizeof(m_keyboardState), (LPVOID)&m_keyboardState);
if(FAILED(result))
{
//If the keyboard lost focuse or was not aquired then try to get control back.
if((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
{
m_keyboard->Acquire();
}
else
{
return false;
}
}
return true;
}
bool InputClass::ReadMouse()
{
HRESULT result;
//Read the mouse device.
result = m_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&m_mouseState);
if(FAILED(result))
{
//If the mouse lost focus or was not aqcuired then try to get control back.
if((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
{
m_mouse->Acquire();
}
else
{
return false;
}
}
return true;
}
void InputClass::ProcessInput()
{
//Update the location of the mouse cursor based on the change of the mouse location during the frame.
m_mouseX += m_mouseState.lX;
m_mouseY += m_mouseState.lY;
//Ensure the mouse location doesn't exceed the screen width or height.
if(m_mouseX < 0) {m_mouseX = 0;}
if(m_mouseY < 0) {m_mouseY = 0;}
if(m_mouseX > m_screenWidth) {m_mouseX = m_screenWidth;}
if(m_mouseY > m_screenHeight) {m_mouseY = m_screenHeight;}
return;
}
bool InputClass::IsEscapePressed()
{
//Do a bitwise and on the keyboard state to check if the escape key is currently being pressed.
std::cout << "checking ESCAPE" << std::endl;
if(m_keyboardState[DIK_ESCAPE] & 0x80)
{
std::cout << "ESCAPE" << std::endl;
return true;
}
return false;
}
bool InputClass::IsWPressed()
{
if(m_keyboardState[DIK_W] & 0x80)
{
std::cout << "W" << std::endl;
return true;
}
return false;
}
bool InputClass::IsAPressed()
{
if(m_keyboardState[DIK_A] & 0x80)
{
return true;
}
return false;
}
bool InputClass::IsSPressed()
{
if(m_keyboardState[DIK_S] & 0x80)
{
return true;
}
return false;
}
bool InputClass::IsDPressed()
{
if(m_keyboardState[DIK_D] & 0x80)
{
return true;
}
return false;
}
void InputClass::GetMouseLocation(int& mouseX, int& mouseY)
{
mouseX = m_mouseX;
mouseY = m_mouseY;
return;
}
Other file:
////////////////////////////////////////////////////////////////////////////////
// Filename: systemclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "systemclass.h"
SystemClass::SystemClass()
{
m_Input = 0;
m_Graphics = 0;
}
SystemClass::SystemClass(const SystemClass& other)
{
}
SystemClass::~SystemClass()
{
}
bool SystemClass::Initialize()
{
int screenWidth, screenHeight;
bool result;
// Initialize the width and height of the screen to zero before sending the variables into the function.
screenWidth = 0;
screenHeight = 0;
// Initialize the windows api.
InitializeWindows(screenWidth, screenHeight);
// Create the input object. This object will be used to handle reading the keyboard input from the user.
m_Input = new InputClass;
if(!m_Input)
{
return false;
}
// Initialize the input object.
result = m_Input->Initialize(m_hinstance, m_hwnd, screenWidth, screenHeight);
if(!result)
{
MessageBox(m_hwnd, L"Could not initialize the input object.", L"Error", MB_OK);
return false;
}
// Create the graphics object. This object will handle rendering all the graphics for this application.
m_Graphics = new GraphicsClass;
if(!m_Graphics)
{
return false;
}
// Initialize the graphics object.
result = m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd);
if(!result)
{
return false;
}
return true;
}
void SystemClass::Shutdown()
{
// Release the graphics object.
if(m_Graphics)
{
m_Graphics->Shutdown();
delete m_Graphics;
m_Graphics = 0;
}
// Release the input object.
if(m_Input)
{
m_Input->Shutdown();
delete m_Input;
m_Input = 0;
}
// Shutdown the window.
ShutdownWindows();
return;
}
void SystemClass::Run()
{
MSG msg;
bool done, result;
// Initialize the message structure.
ZeroMemory(&msg, sizeof(MSG));
// Loop until there is a quit message from the window or the user.
done = false;
while(!done)
{
// Handle the windows messages.
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// If windows signals to end the application then exit out.
if(msg.message == WM_QUIT)
{
done = true;
}
else
{
// Otherwise do the frame processing.
result = Frame();
if(!result)
{
done = true;
}
}
//Check if the user pressed escape and wants to quit.
if(m_Input->IsEscapePressed() == true)
{
std::cout << "ESCAPE" << std::endl;
done = true;
}
if(m_Input->IsWPressed() == true)
{
m_Graphics->SetCameraPos(0, 1, 0);
std::cout << "W" << std::endl;
}
if(m_Input->IsAPressed() == true)
{
m_Graphics->SetCameraPos(1, 0, 0);
std::cout << "A" << std::endl;
}
if(m_Input->IsSPressed() == true)
{
m_Graphics->SetCameraPos(0, -1, 0);
std::cout << "S" << std::endl;
}
if(m_Input->IsDPressed() == true)
{
m_Graphics->SetCameraPos(-1, 0, 0);
std::cout << "D" << std::endl;
}
}
return;
}
bool SystemClass::Frame()
{
bool result;
int mouseX, mouseY;
//Do the frame processing.
result = m_Input->Frame();
if(!result)
{
return false;
}
//Get the location of the mouse from the input object.
m_Input->GetMouseLocation(mouseX, mouseY);
// Do the frame processing for the graphics object.
result = m_Graphics->Frame(mouseX, mouseY);
if(!result)
{
return false;
}
result = m_Graphics->Render();
if(!result)
{
return false;
}
return true;
}
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
void SystemClass::InitializeWindows(int& screenWidth, int& screenHeight)
{
WNDCLASSEX wc;
DEVMODE dmScreenSettings;
int posX, posY;
// Get an external pointer to this object.
ApplicationHandle = this;
// Get the instance of this application.
m_hinstance = GetModuleHandle(NULL);
// Give the application a name.
m_applicationName = L"Engine";
// Setup the windows class with default settings.
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hinstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = m_applicationName;
wc.cbSize = sizeof(WNDCLASSEX);
// Register the window class.
RegisterClassEx(&wc);
// Determine the resolution of the clients desktop screen.
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN);
// Setup the screen settings depending on whether it is running in full screen or in windowed mode.
if(FULL_SCREEN)
{
// If full screen set the screen to maximum size of the users desktop and 32bit.
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth;
dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// Change the display settings to full screen.
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
// Set the position of the window to the top left corner.
posX = posY = 0;
}
else
{
// If windowed then set it to 800x600 resolution.
screenWidth = 800;
screenHeight = 600;
// Place the window in the middle of the screen.
posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2;
posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
}
// Create the window with the screen settings and get the handle to it.
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
// Bring the window up on the screen and set it as main focus.
ShowWindow(m_hwnd, SW_SHOW);
SetForegroundWindow(m_hwnd);
SetFocus(m_hwnd);
// Hide the mouse cursor.
ShowCursor(false);
return;
}
void SystemClass::ShutdownWindows()
{
// Show the mouse cursor.
ShowCursor(true);
// Fix the display settings if leaving full screen mode.
if(FULL_SCREEN)
{
ChangeDisplaySettings(NULL, 0);
}
// Remove the window.
DestroyWindow(m_hwnd);
m_hwnd = NULL;
// Remove the application instance.
UnregisterClass(m_applicationName, m_hinstance);
m_hinstance = NULL;
// Release the pointer to this class.
ApplicationHandle = NULL;
return;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
switch(umessage)
{
// Check if the window is being destroyed.
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
// Check if the window is being closed.
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
// All other messages pass to the message handler in the system class.
default:
{
return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam);
}
}
}
Why don't try with GetAsyncKeyState function?
you can put that in your update function and check for the desired key code.
Something like this:
//check if num1 is pressed, if yes switch off the lights.
if(GetAsyncKeyState('1') & 0x8000)
{
mLightCount = 0;
}
As it turned out, the keybindings were working. I tried switching the close key to w and pressing W closed the window. What was wrong was how I was moving the camera. Thanks for helping!
I'm self learning programming using various online tutorials and a couple of books. Currently it's C++. I've done a bit of OpenGL and SDL in the last few days.
I have a small program that creates a wall to stop a small square from passing through it.
Here's my code:
//
// main.cpp
// SDL_Template
//
// The headers
#include <stdlib.h>
#include <string>
// SDL headers
#include <SDL/SDL.h>
#include "SDL_image/SDL_image.h"
//#include "SDL/SDL_ttf.h"
//#include "SDL/SDL_mixer.h"
// Other headers
#include <OpenGL/gl3.h>
// Screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
// The frame rate
const int FRAMES_PER_SECOND = 20;
// The attributes of the square
const int SQUARE_WIDTH = 20;
const int SQUARE_HEIGHT = 20;
// The surfaces
SDL_Surface *square = NULL;
SDL_Surface *screen = NULL;
// The event structure
SDL_Event event;
// The wall
SDL_Rect wall;
// The square
class Square
{
private:
// The collision box of the square
SDL_Rect box;
// The velocity of the square
int xVel, yVel;
public:
// Initializes the variables
Square();
// Takes key presses and adjusts the square's velocity
void handle_input();
// Moves the square
void move();
// Shows the square on the screen
void show();
};
//The timer
class Timer
{
private:
// The clock time when the timer started
int startTicks;
// The ticks stored when the timer was paused
int pausedTicks;
// The timer status
bool paused;
bool started;
public:
// Initializes variables
Timer();
// The various clock actions
void start();
void stop();
void pause();
void unpause();
// Gets the timer's time
int get_ticks();
// Checks the status of the timer
bool is_started();
bool is_paused();
};
SDL_Surface *load_image(std::string filename)
{
// The image that's loaded
SDL_Surface* loadedImage = NULL;
// The optimized surface that will be used
SDL_Surface* optimizedImage = NULL;
// Load the image
loadedImage = IMG_Load(filename.c_str());
// If the image loaded
if (loadedImage != NULL)
{
// Create an optimized surface
optimizedImage = SDL_DisplayFormat(loadedImage);
// Free the old surface
SDL_FreeSurface(loadedImage);
// If the surface was optimized
if (optimizedImage != NULL)
{
// Color key surface
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF));
}
}
// Return the optimized surface
return optimizedImage;
}
void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL)
{
// Holds offsets
SDL_Rect offset;
// Get offsets
offset.x = x;
offset.y = y;
// Blit
SDL_BlitSurface(source, clip, destination, &offset);
}
bool check_collision(SDL_Rect A, SDL_Rect B)
{
// The sides of the rectangles
int leftA, leftB;
int rightA, rightB;
int topA, topB;
int bottomA, bottomB;
// Calculate the sides of rect A
leftA = A.x;
rightA = A.x + A.w;
topA = A.y;
bottomA = A.y + A.h;
// Calculate the sides of rect B
leftB = B.x;
rightB = B.x + B.w;
topB = B.y;
bottomB = B.y + B.h;
// If any of the sides from A are outside of B
if( bottomA <= topB )
{
return false;
}
if( topA >= bottomB )
{
return false;
}
if( rightA <= leftB )
{
return false;
}
if( leftA >= rightB )
{
return false;
}
// If none of the sides from A are outside B
return true;
}
bool init()
{
// Initialize all SDL subsystems
if (SDL_Init( SDL_INIT_EVERYTHING ) == -1)
{
return false;
}
// Set up the screen
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);
// If there was an error in setting up the screen
if (screen == NULL)
{
return false;
}
// Set the window caption
SDL_WM_SetCaption("Move the Square", NULL);
// If everything initialized fine
return true;
}
bool load_files()
{
// Load the square image
square = load_image("square.bmp");
// If there was a problem in loading the square
if (square == NULL)
{
return false;
}
// If everything loaded fine
return true;
}
void clean_up()
{
// Free the surface
SDL_FreeSurface(square);
// Quit SDL
SDL_Quit();
}
Square::Square()
{
// Initialize the offsets
box.x = 0;
box.y = 0;
// Set the square's dimentions
box.w = SQUARE_WIDTH;
box.h = SQUARE_HEIGHT;
// Initialize the velocity
xVel = 0;
yVel = 0;
}
void Square::handle_input()
{
// If a key was pressed
if (event.type == SDL_KEYDOWN)
{
//Adjust the velocity
switch (event.key.keysym.sym)
{
case SDLK_UP: yVel -= SQUARE_HEIGHT / 2; break;
case SDLK_DOWN: yVel += SQUARE_HEIGHT / 2; break;
case SDLK_LEFT: xVel -= SQUARE_WIDTH / 2; break;
case SDLK_RIGHT: xVel += SQUARE_WIDTH / 2; break;
}
}
// If a key was released
else if (event.type == SDL_KEYUP)
{
//Adjust the velocity
switch (event.key.keysym.sym)
{
case SDLK_UP: yVel += SQUARE_HEIGHT / 2; break;
case SDLK_DOWN: yVel -= SQUARE_HEIGHT / 2; break;
case SDLK_LEFT: xVel += SQUARE_WIDTH / 2; break;
case SDLK_RIGHT: xVel -= SQUARE_WIDTH / 2; break;
}
}
}
void Square::move()
{
// Move the square left or right
box.x += xVel;
// If the square went too far to the left or right or has collided with the wall
if (( box.x < 0 ) || ( box.x + SQUARE_WIDTH > SCREEN_WIDTH ) || ( check_collision(box, wall)))
{
// Move back
box.x -= xVel;
}
// Move the square up or down
box.y += yVel;
// If the square went too far up or down or has collided with the wall
if (( box.y < 0 ) || ( box.y + SQUARE_HEIGHT > SCREEN_HEIGHT) || (check_collision(box, wall)))
{
// Move back
box.y -= yVel;
}
}
void Square::show()
{
// Show the square
apply_surface(box.x, box.y, square, screen);
}
Timer::Timer()
{
// Initialize the variables
startTicks = 0;
pausedTicks = 0;
paused = false;
started = false;
}
void Timer::start()
{
// Start the timer
started = true;
// Unpause the timer
paused = false;
// Get the current clock time
startTicks = SDL_GetTicks();
}
void Timer::stop()
{
// Stop the timer
started = false;
// Unpause the timer
paused = false;
}
void Timer::pause()
{
// If the timer is running and isn't already paused
if ((started == true) && (paused == false))
{
// Pause the timer
paused = true;
// Calculate the paused ticks
pausedTicks = SDL_GetTicks() - startTicks;
}
}
void Timer::unpause()
{
// If the timer is paused
if (paused == true)
{
// Unpause the timer
paused = false;
// Reset the starting ticks
startTicks = SDL_GetTicks() - pausedTicks;
// Reset the paused ticks
pausedTicks = 0;
}
}
int Timer::get_ticks()
{
// If the timer is running
if (started == true)
{
// If the timer is paused
if (paused == true)
{
// Return the number of ticks when the timer was paused
return pausedTicks;
}
else
{
// Return the current time minus the start time
return SDL_GetTicks() - startTicks;
}
}
// If the timer isn't running
return 0;
}
bool Timer::is_started()
{
return started;
}
bool Timer::is_paused()
{
return paused;
}
int main(int argc, char* args[])
{
// Quit flag
bool quit = false;
// The square
Square mySquare;
// The frame rate regulator
Timer fps;
// Initialize
if( init() == false )
{
return 1;
}
// Load the files
if (load_files() == false)
{
return 1;
}
// Set the wall
wall.x = 300;
wall.y = 40;
wall.w = 40;
wall.h = 400;
// While the user hasn't quit
while (quit == false)
{
// Start the frame timer
fps.start();
// While there are events to handle
while (SDL_PollEvent(&event))
{
// Handle events for the square
mySquare.handle_input();
// If the user has Xed out the window
if (event.type == SDL_QUIT)
{
// Quit the program
quit = true;
}
}
// Move the square
mySquare.move();
// Fill the screen white
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
// Show the wall
SDL_FillRect (screen, &wall, SDL_MapRGB(screen->format, 0x77, 0x77, 0x77));
// Show the square on the screen
mySquare.show();
// Update the screen
if (SDL_Flip(screen) == -1)
{
return 1;
}
// Cap the frame rate
if (fps.get_ticks() < 1000 / FRAMES_PER_SECOND)
{
SDL_Delay((1000 / FRAMES_PER_SECOND) - fps.get_ticks());
}
}
// Clean up
clean_up();
return 0;
}
I completely understand how this site works, so I'm not asking you to check my code. My code compiles in both Xcode 4.5 and Visual Studio 2010. In Xcode it compiles, but throws some warnings up (although it still builds), but nothing happens when it's run. However in Visual Studio 2012, it compiles, with no warnings and runs successfully.
I have searched here and the C++/SDL forums/help pages, but I haven't found any similar cases.
Why may this be? Seems it runs in Visual Studio 2010, I'm confident it isn't the code...
In case you were wondering the warnings flagged up in Xcode are:
229 enumeration values not handled in switch: 'SDLK_UNKNOWN','SDLK_BACKSPACE','SDLK_TAB'...
This is highlighted on the switch (event.key.keysym.sym) line of code.
So my questions are:
What kind of problems could case this warning error?
Are there any commonly know issues with programs working in Visual Studio and not Xcode?
I'm guessing (it seems I can't find anything about it) it's a setting somewhere that I haven't spotted...
I apologise for the length of this.
You are not handling all the possible choices in your switch statement. If this is what you intended then you can remove the warning by using the default case like the following:
switch (event.key.keysym.sym)
{
case SDLK_UP: yVel -= SQUARE_HEIGHT / 2; break;
case SDLK_DOWN: yVel += SQUARE_HEIGHT / 2; break;
case SDLK_LEFT: xVel -= SQUARE_WIDTH / 2; break;
case SDLK_RIGHT: xVel += SQUARE_WIDTH / 2; break;
default: break;
}
Xcode is simply warning you that you are not handling all possible values for the event.key.keysym.sym enumeration. Since I doubt you want to handle ever single different type of key press, this isn't a problem, as I would maybe see if I could turn down the warning level to suppress these warnings.
As for the program not running successfully when built by Xcode, I don't know. Perhaps SDL is set up in a different way?
I've been following LazyFoo's tutorial for a while. But I haven't been able to get this to initialize a week a go. I went back to it recently, after error checking, I found it that the window initializes properly, but the images won't load. What is the reason for it?
#include "SDL/SDL.h"
#include <string>
//setting screen info
const int SCH=640;
const int SCW=480;
const int BBP=32;
const char* name = "TEHGAEM";
// sprite height and width
const int SPH=45;
const int SPW=45;
//initilize event
SDL_Event event;
//loading surfaces for screen, sprite, and temp sprite
SDL_Surface *screen=NULL;
SDL_Surface *sprite=NULL;
SDL_Surface *temp = NULL;
//making class for movable objects
class Player
{
private:
int x,y;
int xVel,yVel;
public:
Player();
void show();
void move();
void handle_input();
};
//initializing variables
Player::Player()
{
x=0;
y=0;
xVel=0;
yVel=0;
}
//intended to show player picture
void Player::show()
{
SDL_Rect pos;
pos.x=x;
pos.y=y;
SDL_BlitSurface(sprite, NULL, screen, &pos);
SDL_UpdateRects(screen, 1, &pos);
}
//setting input
void Player::handle_input()
{
if (event.type ==SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_UP: yVel -= SPH /2; break;
case SDLK_DOWN: yVel += SPH /2; break;
case SDLK_LEFT: xVel -=SPW /2; break;
case SDLK_RIGHT: xVel +=SPW /2; break;
}
}
if (event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_UP: yVel += SPH /2; break;
case SDLK_DOWN: yVel -= SPH /2; break;
case SDLK_LEFT: xVel +=SPW /2; break;
case SDLK_RIGHT: xVel -=SPW /2; break;
}
}
}
void Player::move()
{
x=+xVel;
y=+yVel;
if (x >= SCW)
{
x-10;
}
if (y >= SCH)
{
y-10;
}
}
//initializing program
bool init()
{
if (SDL_Init(SDL_INIT_EVERYTHING)==-1)
{
return false;
}
screen = SDL_SetVideoMode(SCH,SCW,BBP, SDL_SWSURFACE);
if (screen == NULL)
{
return false;
}
SDL_WM_SetCaption(name, NULL);
return true;
}
//loading images
bool somethings()
{
temp = SDL_LoadBMP("sprite.bmp");
if (temp == NULL)
{
return false;
}
sprite = SDL_DisplayFormat (temp);
if (sprite ==NULL)
{
return false;
}
SDL_FreeSurface(temp);
return true;
}
//clean up function
void clean()
{
SDL_FreeSurface(sprite);
SDL_Quit();
}
int main(int argc, char* args[])
{
Player P1;
bool quit;
if (init() == false)
{
return 1;
}
if (somethings() ==false)
{
return 1;
}
while (quit ==false)
{
while (SDL_PollEvent(&event))
{
P1.handle_input();
if (event.type == SDL_QUIT)
{
quit == true;
}
}
if (SDL_Flip(screen) ==-1)
{
return 1;
}
P1.move();
P1.show();
}
clean();
return 0;
}
This isn't completely related to your problem but the varible bool quit; isn't defined as true or false before the main while( quit == false ) { ... }loop. This could produce undefined while loop behavior.
int main(int argc, char* args[])
{
Player P1;
bool quit = false; // CHANGE THIS AND SEE WHAT HAPPENS
if (init() == false)
{
return 1;
}
if (somethings() ==false)
{
return 1;
}
while (quit ==false)
{
while (SDL_PollEvent(&event))
{
P1.handle_input();
if (event.type == SDL_QUIT)
{
quit == true;
}
}
if (SDL_Flip(screen) ==-1)
{
return 1;
}
P1.move();
P1.show();
}
clean();
return 0;
}
About the images not loading, step through your program with a debugger and watch your somethings()function and follow the variables temp and sprite.
Make sure your "sprite.bmp" file is located in the running directory of this program. I tested it and it works for me.
Also this has no effect:
if (x >= SCW)
{
x-10;
}
if (y >= SCH)
{
y-10;
}
You probably wanted to say x -= 10; and y -= 10;.
This makes your 'player' jump back to the original position immediately:
if (event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_UP: yVel += SPH /2; break;
case SDLK_DOWN: yVel -= SPH /2; break;
case SDLK_LEFT: xVel +=SPW /2; break;
case SDLK_RIGHT: xVel -=SPW /2; break;
}
}
You probably only need to handle SDL_KEYDOWN event.
Hope that helps.
There are big chances that you aren't loading the bitmap. But anything that you are trying to print on the screen and wasn't loaded can terminate the app.
i have to event that should insert values in two vectors but when event get called for the first time it inserts the values successfully but when it get called again it will insert the values in the first vector but not in the second vector than when another event get called the second vector's values will be deleted.
here is the full code
#define MAX_LOADSTRING 100
RECT *rect;
const UINT_PTR EVERYTHING_ID=0x1;
const UINT_PTR LBUTTONDOWN_ID=0x3;
const UINT_PTR TDENEMIE1_ID=0x4;
const UINT_PTR TAENEMIE1_ID=0x5;
int conno=2;
int side=0;
int cEnemie1=0;
int dEnemie1=1;
int aEnemie1=0;
int sEnemie1=1;
bool e1=true;
time_t now;
time_t tEnemie1;
vector <POINT> vRegularShots;
vector <POINT> vS1Enemie1;
vector <POINT> vS2Enemie1;
VOID Paint(HDC hdc, HWND hWnd)
{
hdc=GetDC(hWnd);
HDC memDC=CreateCompatibleDC(hdc);
HBITMAP hMemMap=CreateCompatibleBitmap(hdc, 225, 350);
HBITMAP hOldMap=(HBITMAP)SelectObject(memDC, hMemMap);
Graphics draw(memDC);
// Drawing
Image bg(L"bg.jpg");
draw.DrawImage(&bg, 0, 0);
// Regular shots
Image shot(L"RegularShots.png");
long s=vRegularShots.size();
// Draw shots
for(long index=0; index < (long)vRegularShots.size(); ++index)
{
draw.DrawImage(&shot, vRegularShots[index].x, vRegularShots[index].y);
}
// Update the shots
for(long index=0; index < (long)vRegularShots.size(); ++index)
{
vRegularShots[index].y--;
}
// Create Enemies
if(dEnemie1==0)
{
if(cEnemie1<2)
{
if(aEnemie1==0)
{
SetTimer(hWnd, TAENEMIE1_ID, 550, NULL);
}
aEnemie1=1;
cEnemie1++;
}
else
{
KillTimer(hWnd, TDENEMIE1_ID);
}
dEnemie1=1;
}
// Draw enemies
for(long index=0; index < (long)vS1Enemie1.size(); ++index)
{
Image iEnemie1(L"Enemie1.png");
draw.DrawImage(&iEnemie1, vS1Enemie1[index].x, vS1Enemie1[index].y);
}
for(long index=0; index < (long)vS2Enemie1.size(); ++index)
{
Image iEnemie1(L"Enemie1.png");
draw.DrawImage(&iEnemie1, vS2Enemie1[index].x, vS2Enemie1[index].y);
}
// Update enemies
for(long index=0; index < (long)vS1Enemie1.size(); index++)
{
vS1Enemie1[index].x++;
vS1Enemie1[index].y++;
}
for(long index=0; index < (long)vS2Enemie1.size(); index++)
{
vS2Enemie1[index].x--;
vS2Enemie1[index].y++;
}
// Delete enemies
for(long index=0; index < (long)vS1Enemie1.size(); index++)
{
if(vS1Enemie1[index].x>225)
{
vS1Enemie1.erase(vS1Enemie1.begin()+index);
}
}
for(long index=0; index < (long)vS2Enemie1.size(); index++)
{
if(vS2Enemie1[index].x>225)
{
vS2Enemie1.erase(vS2Enemie1.begin()+index);
}
}
BitBlt(hdc, 0, 0, 225, 350, memDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd, hdc);
SelectObject(memDC, hOldMap);
DeleteObject(hMemMap);
DeleteDC(memDC);
}
VOID CheckDead()
{
for(long index=0; index < (long)vRegularShots.size(); ++index)
{
vRegularShots[index].x, vRegularShots[index].y;
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
POINT pt;
POINT pts;
switch (message)
{
case WM_CREATE:
SetTimer(hWnd, EVERYTHING_ID, 1, NULL);
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);
Paint(hdc, hWnd);
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
if(conno==1)
{
conno++;
}
else
{
pt.x+=18;
conno--;
}
vRegularShots.push_back(pt);
SetTimer(hWnd, LBUTTONDOWN_ID, 350, NULL);
InvalidateRect(hWnd, rect, false);
break;
case WM_LBUTTONUP:
KillTimer(hWnd, LBUTTONDOWN_ID);
break;
case WM_TIMER:
switch(wParam)
{
case EVERYTHING_ID:
if(e1==true)
{
now=time(NULL);
tEnemie1=now+1;
e1=false;
}
now=time(NULL);
if(now==tEnemie1)
{
SetTimer(hWnd, TDENEMIE1_ID, 550, NULL);
}
InvalidateRect(hWnd, rect, false);
break;
case LBUTTONDOWN_ID:
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
if(conno==1)
{
conno++;
}
else
{
pt.x+=18;
conno--;
}
vRegularShots.push_back(pt);
break;
case TDENEMIE1_ID:
pt.y=5;
pt.x=-26;
vS1Enemie1.push_back(pt);
pt.y=52;
pt.x=251;
vS2Enemie1.push_back(pt);
dEnemie1=0;
InvalidateRect(hWnd, rect, false);
break;
case TAENEMIE1_ID:
InvalidateRect(hWnd, rect, false);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
i set a break point at dEnemie1=0 in TAENEMIE1_ID.
anyidea?
For one thing, these two loops have issues:
// Delete enemies
for(long index=0; index < (long)vS1Enemie1.size(); index++)
{
if(vS1Enemie1[index].x>225)
{
vS1Enemie1.erase(vS1Enemie1.begin()+index);
}
}
for(long index=0; index < (long)vS2Enemie1.size(); index++)
{
if(vS2Enemie1[index].x>225)
{
vS2Enemie1.erase(vS2Enemie1.begin()+index);
}
}
One issue with each is that when you erase the POINT at index index, then all POINTs at indices index + 1, index + 2, etc. are shifted to the left by one. So, when you increment index, you skip a POINT. The other issue is that you should be using the unsigned size_type as the type of your indexing variable rather than casting to long, which is signed.
Here is corrected code:
// Delete enemies
vector <POINT>::size_type index;
for(index=0; index < vS1Enemie1.size(); )
{
if(vS1Enemie1[index].x>225)
{
vS1Enemie1.erase(vS1Enemie1.begin()+index);
}
else
++index;
}
for(index=0; index < vS2Enemie1.size(); )
{
if(vS2Enemie1[index].x>225)
{
vS2Enemie1.erase(vS2Enemie1.begin()+index);
}
else
++index;
}
It would be even better if you used iterators:
// Delete enemies
vector <POINT>::iterator it;
for(it=vS1Enemie1.begin(); it != vS1Enemie1.end(); )
{
if(it->x > 225)
{
it = vS1Enemie1.erase(it);
}
else
++it;
}
for(it=vS2Enemie1.begin(); it != vS2Enemie1.end(); )
{
if(it->x > 225)
{
it = vS2Enemie1.erase(it);
}
else
++it;
}