devjeetroy
devjeetroy

Reputation: 1945

Simple animation in c++

Okay so i was trying out some very basic animation stuff(if you could even call it animation) in windows. I messed with the parameters of TextOut(the coordinates for the text)be no animation. Like basically, it would print "hello" in a couple of different places once and after that it seemed as if nothing was happening. The problem is that the text is being drawn on screen without the text from the previous call to InvalidateRect being cleared off the screen. Also, when put some simple incrementing series values(like 1,2,3,4,5 etc) as parameters to TextOut, there is no such problem.

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
struct point
{
    double x;
    double y;
    double t;
};


point obj={30,30,1};

int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR cmdLine,int cmdShow)
{
    WNDCLASSEX windowsClass={0};



    windowsClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    windowsClass.cbSize=sizeof(WNDCLASSEX);
    windowsClass.hInstance=hInstance;
    windowsClass.lpfnWndProc=WndProc;
    windowsClass.cbClsExtra=NULL;
    windowsClass.style=CS_HREDRAW | CS_VREDRAW;
    windowsClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    windowsClass.hbrBackground=(HBRUSH)GetStockObject(NULL_BRUSH);
    windowsClass.lpszClassName="Devjeet's Window";

    if(!RegisterClassExA(&windowsClass))
        return -1;
    HWND hWnd = CreateWindowExA(NULL,"Devjeet's Window","Animation V1 By Devjeet",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,400,400,NULL,NULL,hInstance,NULL);

    if(!hWnd)
        return -1;
    ShowWindow(hWnd,cmdShow);


    MSG msg={0};

    while(msg.message!=WM_QUIT)
    {
        if(PeekMessage(&msg,0,0,0,PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return static_cast<int>(msg.wParam);
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HDC hDC;
    PAINTSTRUCT paintStruct;

    switch(message)
    {

    case WM_PAINT:
        hDC=BeginPaint(hWnd,&paintStruct);

        TextOut(hDC,(int)(obj.x),(int)(obj.y),"Hello",sizeof("Hello"));
        obj.y=(double)(30*obj.t+(obj.t*obj.t*9.8/2));
        obj.x=(double)(30*obj.t+(obj.t*obj.t*9.8/2));
        obj.t+=.8;


        EndPaint(hWnd,&paintStruct);
        if(obj.y>100.0)
        {
            obj.x=30.0;
            obj.y=30.0;
            obj.t=1.0;
        }

        Sleep(800);
        InvalidateRect(hWnd,NULL,TRUE);
        break;
    case WM_DESTROY:
        PostQuitMessage(NULL);
        break;
    default:
        return DefWindowProc(hWnd,message,wParam,lParam);
        break;
    }
    return 0;
}

Upvotes: 0

Views: 3871

Answers (1)

Roger Lipscombe
Roger Lipscombe

Reputation: 91825

First: Never, ever, call Sleep from your WM_PAINT hander. You'll lock your UI up.

The recommended way to do simple animation on Windows is to use SetTimer, and handle the WM_TIMER message. Your WM_TIMER handler works out where your sprite needs to be, and calls InvalidateRect. You can either invalidate the entire window, or just the old and new positions of the moved sprite.

In response to the InvalidateRect, Windows will send you a WM_PAINT message, allowing you to repaint your window.

As for why it's not erasing the old one: You've specified NULL_BRUSH as the Window background, which means that the default WM_ERASEBKGND handler (where Windows will erase your window content) does nothing. You either need to handle WM_ERASEBKGND yourself (to erase the window, using -- for example -- FillRect), or you need to handle that part in your WM_PAINT handler as well.

Oh and the reason that the simple increment of position works is probably because (if I recall correctly), TextOut will erase the background of the bounding box for the given text. Since this is probably a couple of pixels larger than the text, it'll erase the previous text, if it's only a pixel away.

Upvotes: 1

Related Questions