I am creating a billiards game and am having major problems with tunneling at high speeds. I figured using linear interpolation for animations would help quite a bit, but the problem persists. To see this, I drew a circle at the previous few positions an object has been. At the highest velocity the ball can travel, the path looks like this:
Surely, these increments of advancement are much too large even after using linear interpolation.
At each frame, every object's location is updated based on the amount of time since the window was last drawn. I noticed that the average time for the window to be redrawn is somewhere between 70 and 80ms. I would really like this game to work at 60 fps, so this is about 4 or 5 times longer than what I am looking for.
Is there a way to change how often the window is redrawn? Here is how I am currently redrawing the screen
#include "pch.h"
#include "framework.h"
#include "ChildView.h"
#include "DoubleBufferDC.h"
const int FrameDuration = 16;
void CChildView::OnPaint()
{
CPaintDC paintDC(this); // device context for painting
CDoubleBufferDC dc(&paintDC); // device context for painting
Graphics graphics(dc.m_hDC); // Create GDI+ graphics context
mGame.OnDraw(&graphics);
if (mFirstDraw)
{
mFirstDraw = false;
SetTimer(1, FrameDuration, nullptr);
LARGE_INTEGER time, freq;
QueryPerformanceCounter(&time);
QueryPerformanceFrequency(&freq);
mLastTime = time.QuadPart;
mTimeFreq = double(freq.QuadPart);
}
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
long long diff = time.QuadPart - mLastTime;
double elapsed = double(diff) / mTimeFreq;
mLastTime = time.QuadPart;
mGame.Update(elapsed);
}
void CChildView::OnTimer(UINT_PTR nIDEvent)
{
RedrawWindow(NULL, NULL, RDW_UPDATENOW);
Invalidate();
CWnd::OnTimer(nIDEvent);
}
EDIT: Upon request, here is how the actual drawing is done:
void CGame::OnDraw(Gdiplus::Graphics* graphics)
{
// Draw the background
graphics->DrawImage(mBackground.get(), 0, 0,
mBackground->GetWidth(), mBackground->GetHeight());
mTable->Draw(graphics);
Pen pen(Color(500, 128, 0), 1);
Pen penW(Color(1000, 1000, 1000), 1);
this->mCue->Draw(graphics);
for (shared_ptr<CBall> ball : this->mBalls)
{
ball->Draw(graphics);
}
for (shared_ptr<CBall> ball : this->mSunkenSolidBalls)
{
ball->Draw(graphics);
}
for (shared_ptr<CBall> ball : this->mSunkenStripedBalls)
{
ball->Draw(graphics);
}
this->mPowerBar->Draw(graphics);
}
Game::OnDraw will call Draw on all of the game items, which draw on the graphics object they receive as an argument.