Will try this. Thanks.
The mechanism I'm using updates itself. The thread function monitors the time that has elapsed since the thread last executed it's task. So the thread is responsible for updating it's time deltas relative to it's animation. So if I sleep() inside of the thread, the updating will still work correctly. If I attempt to do this externally or wait for a lock or unlock condition the time deltas will not be correct since the time is retrieved at the beginning of the thread task and immediately after.
Why'd they have to make it so hard?
Portion of CAnimSystem.h
Code:
class CAnimSequence
{
//Container class friend
friend class CAnimSequenceContainer;
//vector of CAnimFrames (not included in this post)
std::vector<CAnimFrame *> AnimFrames;
//pointer to MFC window that this animation belongs to
CWnd *m_pWindow;
//Size of animation (horiz and vert)
DWORD m_dwSize;
//Position of animation
CPoint m_Position;
//Current frame ID
DWORD m_dwCurFrame;
//Accumulated time for current frame
float m_fAccumTime;
//Pointer to tile manager
CTileManager *m_pTileManager;
//Looping animation flag
bool m_bLooping;
//DC of CWnd for this animation
CDC *m_pCDC;
//Bitmap (not currently used)
//CBitmap *m_pBitmap;
//Thread object for this animation
CWinThread *m_pThread;
//Client rect for window this animation resides in
CRect m_rectClient;
//Current scroll values of window this animation resides in
int m_iScrollX;
int m_iScrollY;
//Update position flag - true =animation moves, false=animation
//is stationary and xoffset and yoffset are ignored
bool m_bUpdatePos;
//Current time
float m_fCurTime;
//Last time
float m_fLastTime;
//Active boolean for animation
bool m_bActive;
public:
CAnimSequence(void):m_dwCurFrame(0),m_Position(0,0),m_bLooping(false),
m_fAccumTime(0.0f),m_pTileManager(NULL),
m_pCDC(NULL),m_pBitmap(NULL),m_iScrollX(0),
m_iScrollY(0),m_bUpdatePos(false),m_pThread(NULL),
m_fCurTime(0.0f),m_fLastTime(0.0f),m_bActive(false) {}
virtual ~CAnimSequence(void)
{
if (m_pCDC)
{
m_pCDC->Detach();
delete m_pCDC;
}
AnimFrames.clear();
}
//Return TileManager TileID of frame with ID of dwID
DWORD GetID(DWORD dwID)
{
if (dwID<AnimFrames.size())
{
return AnimFrames[dwID]->m_dwTileID;
} else return 0xFFFFFFFF;
}
//Set animation offsets
void SetXYOffsets(DWORD dwID,float xo,float yo)
{
if (dwID<AnimFrames.size())
{
AnimFrames[dwID]->m_fXOffset=xo;
AnimFrames[dwID]->m_fYOffset=yo;
}
}
//Get animation offsets
void GetXYOffsets(DWORD dwID,float &xo,float &yo)
{
if (dwID<AnimFrames.size())
{
xo=AnimFrames[dwID]->m_fXOffset;
yo=AnimFrames[dwID]->m_fYOffset;
}
}
//Set frame duration for frame with id of dwID
void SetFrameDuration(DWORD dwID,float fDuration)
{
if (dwID<AnimFrames.size())
{
AnimFrames[dwID]->m_fFrameDuration=fDuration;
}
}
//Get frame duration for frame dwID
float GetFrameDuration(DWORD dwID)
{
if (dwID<AnimFrames.size())
{
return AnimFrames[dwID]->m_fFrameDuration;
} else return (0.0f);
}
//Create animation and start thread
void Create(CWnd *ptrWin,
CDC *ptrCDC,
DWORD dwSize,
CPoint pos,
CTileManager *ptrTileManager,
bool bLooping=true,
bool bUpdatePos=false)
{
m_pWindow=ptrWin;
m_dwSize=dwSize;
m_pCDC=new CDC();
m_pCDC->Attach(*ptrCDC);
ptrWin->GetClientRect(&m_rectClient);
m_iScrollX=0;
m_iScrollY=0;
m_bUpdatePos=bUpdatePos;
m_Position.x=pos.x;
m_Position.y=pos.y;
m_dwCurFrame=0;
m_pTileManager=ptrTileManager;
m_bLooping=bLooping;
m_fAccumTime=0.0f;
m_fLastTime=(float)::timeGetTime();
m_pThread=AfxBeginThread(DoThreading,this,THREAD_PRIORITY_IDLE);
m_bActive=true;
}
//Add frame with Tile ID dwID, etc.
void AddFrame(DWORD dwID,float fFrameDuration,float xo,float yo)
{
CAnimFrame *frame=new CAnimFrame();
frame->Create(dwID,fFrameDuration,xo,yo);
AnimFrames.push_back(frame);
}
//Another way to set important frame data, if needed
void SetFrameData(DWORD dwID,float fFrameDuration,float xo,float yo)
{
if (dwID<AnimFrames.size())
{
AnimFrames[dwID]->m_fFrameDuration=fFrameDuration;
AnimFrames[dwID]->m_fXOffset=xo;
AnimFrames[dwID]->m_fYOffset=yo;
}
}
//Set current frame to dwID if valid
bool SetCurFrame(DWORD dwID)
{
if (dwID<AnimFrames.size())
{
m_dwCurFrame=dwID;
return false;
} else return true;
}
//Reset animation (loop it)
void Reset(void) {m_dwCurFrame=0,m_fAccumTime=0.0f;}
//Update function - timeDelta is time elapsed since last Update
void Update(float fTimeDelta);
//Draws current frame of animation
void Draw(void);
//DoThreading static member
//Thread entry point
static UINT DoThreading(LPVOID p)
{
CAnimSequence *ptrSeq=(CAnimSequence *)p;
//While this animation is active
while (ptrSeq->m_bActive)
{
//Get current time
ptrSeq->m_fCurTime=(float)::timeGetTime();
//Subtract froim last time to get elapsed time
float fElapsed=ptrSeq->m_fCurTime-ptrSeq->m_fLastTime;
//Update frame based on timedelta
ptrSeq->Update(fElapsed);
//Set last time to current time
ptrSeq->m_fLastTime=ptrSeq->m_fCurTime;
}
return (0);
}
};
CAnimSystem.cpp
Code:
#include <stdafx.h>
#include "CAnimSystem.h"
#include "MainFrm.h"
//Update function for animation
void CAnimSequence::Update(float fTimeDelta)
{
//Not used - DC was null here for some reason
//m_pCDC=m_pWindow->GetDC();
//If vector is not empty
if (AnimFrames.size()>0)
{
//Add delta to accumulated time
m_fAccumTime+=fTimeDelta;
//Check to see if we need a frame change
if (m_fAccumTime>=AnimFrames[m_dwCurFrame]->m_fFrameDuration)
{
//Yes we do so draw
Draw();
//Rest accum time
m_fAccumTime=0.0f;
//Advance animation forward by 1 frame
m_dwCurFrame++;
//Check for end of annimation sequence
if (m_dwCurFrame>AnimFrames.size()-1)
{
//Loop animation (does not check loop bool yet)
m_dwCurFrame=0;
m_fAccumTime=0.0f;
}
}
}
}
void CAnimSequence::Draw(void)
{
//Draw to pDC with TileDC
//If vector is not empty
if (AnimFrames.size()>0)
{
//Get Tile ID from vector
DWORD dwTileID=AnimFrames[m_dwCurFrame]->m_dwTileID;
//Get TileDC from tile manager
CDC *TileDC=m_pTileManager->GetDC(dwTileID);
//Setup x and y locations
int ScreenX=m_Position.x+AnimFrames[m_dwCurFrame]->m_fXOffset;
int ScreenY=m_Position.y+AnimFrames[m_dwCurFrame]->m_fYOffset;
//Update position if specified
if (m_bUpdatePos)
{
m_Position.x=ScreenX;
m_Position.y=ScreenY;
}
//Move position relative to scroll values
ScreenX+=m_iScrollX;
ScreenY+=m_iScrollY;
//If animation is visible, draw it
if (ScreenX>m_rectClient.left &&
ScreenX<m_rectClient.right &&
ScreenY>m_rectClient.top &&
ScreenY<m_rectClient.bottom)
{
if (m_pCDC!=NULL)
{
m_pCDC->BitBlt(ScreenX,ScreenY,
m_dwSize,
m_dwSize,
TileDC,
0,0,
SRCCOPY);
}
}
}
}