计时功能优化

This commit is contained in:
Nomango 2018-08-02 00:27:45 +08:00
parent d1ad592df7
commit c7115a1162
22 changed files with 297 additions and 341 deletions

View File

@ -6,7 +6,6 @@ e2d::Action::Action()
, _done(false) , _done(false)
, _initialized(false) , _initialized(false)
, _target(nullptr) , _target(nullptr)
, _last(0)
{ {
ActionManager::getInstance()->__add(this); ActionManager::getInstance()->__add(this);
} }
@ -24,7 +23,6 @@ bool e2d::Action::isRunning()
void e2d::Action::resume() void e2d::Action::resume()
{ {
_running = true; _running = true;
_last = Game::getInstance()->getTotalDuration().seconds();
} }
void e2d::Action::pause() void e2d::Action::pause()
@ -56,7 +54,7 @@ void e2d::Action::reset()
{ {
_initialized = false; _initialized = false;
_done = false; _done = false;
_last = Game::getInstance()->getTotalDuration().seconds(); _started = Time::now();
} }
bool e2d::Action::_isDone() bool e2d::Action::_isDone()
@ -74,7 +72,7 @@ void e2d::Action::_startWithTarget(Node* target)
void e2d::Action::_init() void e2d::Action::_init()
{ {
_initialized = true; _initialized = true;
_last = Game::getInstance()->getTotalDuration().seconds(); _started = Time::now();
} }
void e2d::Action::_update() void e2d::Action::_update()

View File

@ -56,8 +56,7 @@ void e2d::Animate::_update()
return; return;
} }
auto game = Game::getInstance(); while ((Time::now() - _started).seconds() >= _animation->getInterval())
while ((game->getTotalDuration().seconds() - _last) >= _animation->getInterval())
{ {
auto& frames = _animation->getFrames(); auto& frames = _animation->getFrames();
auto target = dynamic_cast<Sprite*>(_target); auto target = dynamic_cast<Sprite*>(_target);
@ -67,7 +66,7 @@ void e2d::Animate::_update()
target->open(frames[_frameIndex]); target->open(frames[_frameIndex]);
} }
_last += _animation->getInterval(); _started += Duration(_animation->getInterval());
++_frameIndex; ++_frameIndex;
if (_frameIndex == frames.size()) if (_frameIndex == frames.size())
@ -81,7 +80,6 @@ void e2d::Animate::_update()
void e2d::Animate::_resetTime() void e2d::Animate::_resetTime()
{ {
Action::_resetTime(); Action::_resetTime();
_last = Game::getInstance()->getTotalDuration().seconds();
} }
void e2d::Animate::reset() void e2d::Animate::reset()

View File

@ -31,7 +31,7 @@ void e2d::Delay::_update()
{ {
Action::_update(); Action::_update();
_delta = Game::getInstance()->getTotalDuration().seconds() - _last; _delta = (Time::now() - _started).seconds();
if (_delta >= _delay) if (_delta >= _delay)
{ {
@ -42,5 +42,5 @@ void e2d::Delay::_update()
void e2d::Delay::_resetTime() void e2d::Delay::_resetTime()
{ {
Action::_resetTime(); Action::_resetTime();
_last = Game::getInstance()->getTotalDuration().seconds() - _delta; _started = Time::now() - Duration(_delta);
} }

View File

@ -28,7 +28,7 @@ void e2d::FiniteTimeAction::_update()
} }
else else
{ {
_delta = std::min((Game::getInstance()->getTotalDuration().seconds() - _last) / _duration, 1.f); _delta = std::min((Time::now() - _started).seconds() / _duration, 1.f);
if (_delta >= 1) if (_delta >= 1)
{ {
@ -40,5 +40,5 @@ void e2d::FiniteTimeAction::_update()
void e2d::FiniteTimeAction::_resetTime() void e2d::FiniteTimeAction::_resetTime()
{ {
Action::_resetTime(); Action::_resetTime();
_last = Game::getInstance()->getTotalDuration().seconds() - _delta * _duration; _started = Time::now() - Duration(_delta * _duration);
} }

View File

@ -12,8 +12,6 @@ e2d::Game::Game()
, _config() , _config()
{ {
CoInitialize(nullptr); CoInitialize(nullptr);
_start = _last = _now = Time::now();
} }
e2d::Game::~Game() e2d::Game::~Game()
@ -39,26 +37,25 @@ void e2d::Game::destroyInstance()
void e2d::Game::start() void e2d::Game::start()
{ {
SceneManager::getInstance()->update(); _quit = false;
const int minInterval = 5;
Time last = Time::now();
HWND hWnd = Window::getInstance()->getHWnd(); HWND hWnd = Window::getInstance()->getHWnd();
::ShowWindow(hWnd, SW_SHOWNORMAL); ::ShowWindow(hWnd, SW_SHOWNORMAL);
::UpdateWindow(hWnd); ::UpdateWindow(hWnd);
Window::getInstance()->poll(); Window::getInstance()->poll();
SceneManager::getInstance()->update();
_quit = false;
_last = _now = Time::now();
const Duration minInterval(15);
while (!_quit) while (!_quit)
{ {
_now = Time::now(); auto now = Time::now();
Duration interval = _now - _last; auto dur = now - last;
if (minInterval < interval) if (dur.milliseconds() > minInterval)
{ {
_last = _now; last = now;
Input::getInstance()->update(); Input::getInstance()->update();
Timer::getInstance()->update(); Timer::getInstance()->update();
ActionManager::getInstance()->update(); ActionManager::getInstance()->update();
@ -72,7 +69,7 @@ void e2d::Game::start()
// ID2D1HwndRenderTarget 在渲染时会等待显示器刷新,即开启了垂直同步, // ID2D1HwndRenderTarget 在渲染时会等待显示器刷新,即开启了垂直同步,
// 它起到了非常稳定的延时作用,所以大部分时候不需要手动挂起线程进行延时。 // 它起到了非常稳定的延时作用,所以大部分时候不需要手动挂起线程进行延时。
// 下面的代码仅在一些情况下(例如窗口最小化时)挂起线程,防止占用过高 CPU 。 // 下面的代码仅在一些情况下(例如窗口最小化时)挂起线程,防止占用过高 CPU 。
int wait = (minInterval - interval).milliseconds(); int wait = minInterval - dur.milliseconds();
if (wait > 1) if (wait > 1)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(wait)); std::this_thread::sleep_for(std::chrono::milliseconds(wait));
@ -90,7 +87,6 @@ void e2d::Game::resume()
{ {
if (_paused && !_quit) if (_paused && !_quit)
{ {
_last = _now = Time::now();
Timer::getInstance()->updateTime(); Timer::getInstance()->updateTime();
ActionManager::getInstance()->updateTime(); ActionManager::getInstance()->updateTime();
} }
@ -120,11 +116,6 @@ const e2d::Config& e2d::Game::getConfig()
return _config; return _config;
} }
e2d::Duration e2d::Game::getTotalDuration() const
{
return std::move(_now - _start);
}
void e2d::Game::quit() void e2d::Game::quit()
{ {
_quit = true; _quit = true;

View File

@ -107,15 +107,14 @@ void e2d::Renderer::render()
void e2d::Renderer::_renderFps() void e2d::Renderer::_renderFps()
{ {
++_renderTimes; int duration = (Time::now() - _lastRenderTime).milliseconds();
auto& now = Time::now(); ++_renderTimes;
int duration = (now - _lastRenderTime).milliseconds();
if (duration >= 100) if (duration >= 100)
{ {
String fpsText = String::format(L"FPS: %.1f", (1000.f / duration * _renderTimes)); String fpsText = String::format(L"FPS: %.1f", (1000.f / duration * _renderTimes));
_lastRenderTime = Time::now();
_renderTimes = 0; _renderTimes = 0;
_lastRenderTime = now;
auto writeFactory = Renderer::getWriteFactory(); auto writeFactory = Renderer::getWriteFactory();
if (!_fpsFormat) if (!_fpsFormat)

View File

@ -3,6 +3,9 @@
#include <imm.h> #include <imm.h>
#pragma comment (lib ,"imm32.lib") #pragma comment (lib ,"imm32.lib")
#define WINDOW_STYLE WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME
#define REGISTER_CLASS L"Easy2DApp"
e2d::Window * e2d::Window::_instance = nullptr; e2d::Window * e2d::Window::_instance = nullptr;
@ -51,9 +54,7 @@ bool e2d::Window::createMutex(const String & mutex)
if (mutex.isEmpty()) if (mutex.isEmpty())
return false; return false;
// 创建进程互斥体 HANDLE hMutex = ::CreateMutex(nullptr, TRUE, LPCWSTR(L"Easy2DApp-" + mutex));
String fullMutexName = L"Easy2DApp-" + mutex;
HANDLE hMutex = ::CreateMutex(nullptr, TRUE, (LPCWSTR)fullMutexName);
if (hMutex == nullptr) if (hMutex == nullptr)
{ {
@ -68,7 +69,7 @@ bool e2d::Window::createMutex(const String & mutex)
if (!this->_title.isEmpty()) if (!this->_title.isEmpty())
{ {
// 获取窗口句柄 // 获取窗口句柄
HWND hProgramWnd = ::FindWindow(L"Easy2DApp", (LPCTSTR)this->_title); HWND hProgramWnd = ::FindWindow(REGISTER_CLASS, (LPCTSTR)_title);
if (hProgramWnd) if (hProgramWnd)
{ {
// 获取窗口显示状态 // 获取窗口显示状态
@ -85,14 +86,14 @@ bool e2d::Window::createMutex(const String & mutex)
return true; return true;
} }
HWND e2d::Window::__create() HWND e2d::Window::__registerWindow()
{ {
// 注册窗口类
WNDCLASSEX wcex = { 0 }; WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX); wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = L"Easy2DApp"; wcex.lpszClassName = REGISTER_CLASS;
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = Window::WndProc; wcex.lpfnWndProc = Window::WndProc;
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0; wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR); wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT; wcex.hInstance = HINST_THISCOMPONENT;
@ -100,64 +101,44 @@ HWND e2d::Window::__create()
wcex.lpszMenuName = nullptr; wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW); wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
if (this->_iconID != 0) if (_iconID != 0)
{ {
wcex.hIcon = (HICON)::LoadImage( wcex.hIcon = (HICON)::LoadImage(
HINST_THISCOMPONENT, HINST_THISCOMPONENT,
MAKEINTRESOURCE(this->_iconID), MAKEINTRESOURCE(_iconID),
IMAGE_ICON, IMAGE_ICON,
0, 0,
0, 0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
); );
} }
else
{
wcex.hIcon = nullptr;
}
// 注册窗口类
RegisterClassEx(&wcex); RegisterClassEx(&wcex);
// 因为 CreateWindow 函数使用的是像素大小,获取系统的 DPI 以使它
// 适应窗口缩放
float dpiScaleX = 0.f, dpiScaleY = 0.f;
Renderer::getFactory()->GetDesktopDpi(&dpiScaleX, &dpiScaleY);
int nWidth = static_cast<int>(ceil(_size.width * dpiScaleX / 96.f));
int nHeight = static_cast<int>(ceil(_size.height * dpiScaleY / 96.f));
// 计算窗口大小 // 计算窗口大小
DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME; Rect wRect = __adjustWindow(int(_size.width), int(_size.height));
RECT wr = { 0, 0, static_cast<LONG>(nWidth), static_cast<LONG>(nHeight) };
::AdjustWindowRectEx(&wr, dwStyle, FALSE, NULL);
// 获取新的宽高
nWidth = static_cast<int>(wr.right - wr.left);
nHeight = static_cast<int>(wr.bottom - wr.top);
// 获取屏幕分辨率
int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
// 创建窗口 // 创建窗口
HWND hWnd = ::CreateWindowEx( HWND hWnd = ::CreateWindowEx(
NULL, NULL,
L"Easy2DApp", REGISTER_CLASS,
(LPCTSTR)_title, (LPCTSTR)_title,
dwStyle, WINDOW_STYLE,
(screenWidth - nWidth) / 2, (screenHeight - nHeight) / 2, int(wRect.origin.x),
nWidth, nHeight, int(wRect.origin.y),
int(wRect.size.width),
int(wRect.size.height),
nullptr, nullptr,
nullptr, nullptr,
HINST_THISCOMPONENT, HINST_THISCOMPONENT,
nullptr nullptr
); );
HRESULT hr = hWnd ? S_OK : E_FAIL; if (hWnd)
if (SUCCEEDED(hr))
{ {
// 禁用输入法 // 禁用输入法
this->setTypewritingEnabled(false); setTypewritingEnabled(false);
// 禁用控制台关闭按钮 // 禁用控制台关闭按钮
HWND consoleHWnd = ::GetConsoleWindow(); HWND consoleHWnd = ::GetConsoleWindow();
if (consoleHWnd) if (consoleHWnd)
@ -170,11 +151,35 @@ HWND e2d::Window::__create()
} }
else else
{ {
::UnregisterClass(L"Easy2DApp", HINST_THISCOMPONENT); ::UnregisterClass(REGISTER_CLASS, HINST_THISCOMPONENT);
} }
return hWnd; return hWnd;
} }
e2d::Rect e2d::Window::__adjustWindow(int width, int height)
{
float dpiScaleX = 0.f, dpiScaleY = 0.f;
Renderer::getFactory()->GetDesktopDpi(&dpiScaleX, &dpiScaleY);
Rect result;
RECT wRECT = { 0, 0, LONG(ceil(width * dpiScaleX / 96.f)), LONG(ceil(height * dpiScaleY / 96.f)) };
int maxWidth = ::GetSystemMetrics(SM_CXSCREEN);
int maxHeight = ::GetSystemMetrics(SM_CYSCREEN);
// 计算合适的窗口大小
::AdjustWindowRectEx(&wRECT, WINDOW_STYLE, FALSE, NULL);
width = static_cast<int>(wRECT.right - wRECT.left);
height = static_cast<int>(wRECT.bottom - wRECT.top);
// 当输入的窗口大小比分辨率大时,给出警告
WARN_IF(maxWidth < width || maxHeight < height, "The window is larger than screen!");
width = std::min(width, maxWidth);
height = std::min(height, maxHeight);
float x = float((maxWidth - width) / 2), y = float((maxHeight - height) / 2);
return std::move(Rect(x, y, float(width), float(height)));
}
void e2d::Window::poll() void e2d::Window::poll()
{ {
while (::PeekMessage(&_msg, nullptr, 0, 0, PM_REMOVE)) while (::PeekMessage(&_msg, nullptr, 0, 0, PM_REMOVE))
@ -213,7 +218,7 @@ HWND e2d::Window::getHWnd()
{ {
if (!_hWnd) if (!_hWnd)
{ {
_hWnd = this->__create(); _hWnd = __registerWindow();
if (_hWnd == nullptr) if (_hWnd == nullptr)
{ {
throw SystemException(L"注册窗口失败"); throw SystemException(L"注册窗口失败");
@ -224,37 +229,24 @@ HWND e2d::Window::getHWnd()
void e2d::Window::setSize(int width, int height) void e2d::Window::setSize(int width, int height)
{ {
this->_size = Size(static_cast<float>(width), static_cast<float>(height)); _size = Size(static_cast<float>(width), static_cast<float>(height));
if (_hWnd) if (_hWnd)
{ {
float dpiScaleX = 0.f, dpiScaleY = 0.f; Rect wRect = __adjustWindow(width, height);
Renderer::getFactory()->GetDesktopDpi(&dpiScaleX, &dpiScaleY); ::MoveWindow(
_hWnd,
width = static_cast<int>(ceil(width * dpiScaleX / 96.f)); int(wRect.origin.x),
height = static_cast<int>(ceil(height * dpiScaleY / 96.f)); int(wRect.origin.y),
// 计算窗口大小 int(wRect.size.width),
DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME; int(wRect.size.height),
RECT wr = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) }; TRUE
::AdjustWindowRectEx(&wr, dwStyle, FALSE, NULL); );
// 获取新的宽高
width = static_cast<int>(wr.right - wr.left);
height = static_cast<int>(wr.bottom - wr.top);
// 获取屏幕分辨率
int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
// 当输入的窗口大小比分辨率大时,给出警告
WARN_IF(screenWidth < width || screenHeight < height, "The window is larger than screen!");
// 取最小值
width = std::min(width, screenWidth);
height = std::min(height, screenHeight);
// 修改窗口大小,并设置窗口在屏幕居中
::MoveWindow(_hWnd, (screenWidth - width) / 2, (screenHeight - height) / 2, width, height, TRUE);
} }
} }
void e2d::Window::setTitle(const String& title) void e2d::Window::setTitle(const String& title)
{ {
this->_title = title; _title = title;
if (_hWnd) if (_hWnd)
{ {
::SetWindowText(_hWnd, (LPCWSTR)title); ::SetWindowText(_hWnd, (LPCWSTR)title);

View File

@ -7,13 +7,8 @@ e2d::Duration::Duration()
{ {
} }
e2d::Duration::Duration(int ms) e2d::Duration::Duration(float seconds)
: _ms(ms) : _ms(static_cast<long long>(seconds * 1000.f))
{
}
e2d::Duration::Duration(const std::chrono::milliseconds& ms)
: _ms(ms)
{ {
} }
@ -59,12 +54,16 @@ bool e2d::Duration::operator<=(const Duration & other) const
e2d::Duration e2d::Duration::operator+(Duration const & other) const e2d::Duration e2d::Duration::operator+(Duration const & other) const
{ {
return std::move(Duration(_ms + other._ms)); Duration d;
d._ms = _ms + other._ms;
return std::move(d);
} }
e2d::Duration e2d::Duration::operator-(Duration const & other) const e2d::Duration e2d::Duration::operator-(Duration const & other) const
{ {
return std::move(Duration(_ms - other._ms)); Duration d;
d._ms = _ms - other._ms;
return std::move(d);
} }
e2d::Duration & e2d::Duration::operator+=(Duration const &other) e2d::Duration & e2d::Duration::operator+=(Duration const &other)

View File

@ -7,11 +7,6 @@ e2d::Time::Time()
{ {
} }
e2d::Time::Time(const steady_clock::time_point& time)
: _timePoint(time)
{
}
time_t e2d::Time::getTimeStamp() const time_t e2d::Time::getTimeStamp() const
{ {
auto& duration = time_point_cast<milliseconds>(_timePoint).time_since_epoch(); auto& duration = time_point_cast<milliseconds>(_timePoint).time_since_epoch();
@ -25,7 +20,16 @@ bool e2d::Time::isZero() const
e2d::Time e2d::Time::operator+(Duration const & other) const e2d::Time e2d::Time::operator+(Duration const & other) const
{ {
return std::move(Time(_timePoint + milliseconds(other.milliseconds()))); Time t;
t._timePoint = _timePoint + milliseconds(other.milliseconds());
return std::move(t);
}
e2d::Time e2d::Time::operator-(Duration const & other) const
{
Time t;
t._timePoint = _timePoint - milliseconds(other.milliseconds());
return std::move(t);
} }
e2d::Time & e2d::Time::operator+=(Duration const & other) e2d::Time & e2d::Time::operator+=(Duration const & other)
@ -34,11 +38,6 @@ e2d::Time & e2d::Time::operator+=(Duration const & other)
return (*this); return (*this);
} }
e2d::Time e2d::Time::operator-(Duration const & other) const
{
return std::move(Time(_timePoint - milliseconds(other.milliseconds())));
}
e2d::Time & e2d::Time::operator-=(Duration const &other) e2d::Time & e2d::Time::operator-=(Duration const &other)
{ {
_timePoint -= milliseconds(other.milliseconds()); _timePoint -= milliseconds(other.milliseconds());
@ -47,11 +46,13 @@ e2d::Time & e2d::Time::operator-=(Duration const &other)
e2d::Duration e2d::Time::operator-(Time const & other) const e2d::Duration e2d::Time::operator-(Time const & other) const
{ {
auto& ms = duration_cast<milliseconds>(_timePoint - other._timePoint); auto ms = duration_cast<milliseconds>(_timePoint - other._timePoint).count();
return std::move(Duration(ms)); return std::move(Duration(static_cast<float>(ms) / 1000.f));
} }
e2d::Time e2d::Time::now() e2d::Time e2d::Time::now()
{ {
return std::move(Time(steady_clock::now())); Time t;
t._timePoint = steady_clock::now();
return std::move(t);
} }

View File

@ -22,8 +22,7 @@ void e2d::SceneManager::destroyInstance()
} }
e2d::SceneManager::SceneManager() e2d::SceneManager::SceneManager()
: _saveCurrScene(true) : _currScene(nullptr)
, _currScene(nullptr)
, _nextScene(nullptr) , _nextScene(nullptr)
, _transition(nullptr) , _transition(nullptr)
, _scenes() , _scenes()
@ -34,7 +33,7 @@ e2d::SceneManager::~SceneManager()
{ {
} }
void e2d::SceneManager::push(Scene * scene, Transition * transition /* = nullptr */, bool saveCurrentScene /* = true */) void e2d::SceneManager::push(Scene * scene, bool saveCurrentScene)
{ {
if (!scene) if (!scene)
return; return;
@ -44,58 +43,59 @@ void e2d::SceneManager::push(Scene * scene, Transition * transition /* = nullptr
_nextScene = scene; _nextScene = scene;
_nextScene->retain(); _nextScene->retain();
// 设置切换场景动作 // 初始化场景切换动画
if (transition) if (_transition && !_transition->init(_currScene, _nextScene))
{ {
if (_transition) WARN("Transition initialize failed!");
{
_transition->_stop();
_transition->release(); _transition->release();
} _transition = nullptr;
_transition = transition;
transition->retain();
transition->_init(_currScene, _nextScene);
transition->_update();
} }
if (_currScene) if (saveCurrentScene && _currScene)
{ {
_saveCurrScene = saveCurrentScene; _scenes.push(_currScene);
} }
} }
void e2d::SceneManager::pop(Transition * transition /* = nullptr */) e2d::Scene* e2d::SceneManager::pop()
{ {
// 栈为空时,调用返回场景函数失败 // 栈为空时,调用返回场景函数失败
if (_scenes.size() == 0) if (_scenes.size() == 0)
{ {
WARN("Scene stack is empty!"); WARN("Scene stack is empty!");
return; return nullptr;
} }
// 从栈顶取出场景指针,作为下一场景
_nextScene = _scenes.top(); _nextScene = _scenes.top();
_scenes.pop(); _scenes.pop();
// 返回上一场景时,不保存当前场景 // 初始化场景切换动画
if (_currScene) if (_transition && !_transition->init(_currScene, _nextScene))
{ {
_saveCurrScene = false; WARN("Transition initialize failed!");
_transition->release();
_transition = nullptr;
} }
// 设置切换场景动作 return _nextScene;
}
void e2d::SceneManager::setTransition(Transition * transition)
{
if (transition) if (transition)
{ {
transition->retain(); if (_transition)
transition->_init(_currScene, _nextScene); {
transition->_update(); _transition->stop();
_transition->release();
}
_transition = transition; _transition = transition;
_transition->retain();
} }
} }
void e2d::SceneManager::clear() void e2d::SceneManager::clear()
{ {
// 清空场景栈
while (!_scenes.empty()) while (!_scenes.empty())
{ {
_scenes.top()->release(); _scenes.top()->release();
@ -108,7 +108,7 @@ e2d::Scene * e2d::SceneManager::getCurrentScene()
return _currScene; return _currScene;
} }
std::stack<e2d::Scene*> e2d::SceneManager::getSceneStack() const std::stack<e2d::Scene*>& e2d::SceneManager::getSceneStack()
{ {
return _scenes; return _scenes;
} }
@ -120,18 +120,12 @@ bool e2d::SceneManager::isTransitioning()
void e2d::SceneManager::update() void e2d::SceneManager::update()
{ {
if (_transition == nullptr) if (_currScene) _currScene->update();
if (_nextScene) _nextScene->update();
if (_transition)
{ {
// 更新场景内容 _transition->update();
if (_currScene)
{
_currScene->update();
}
}
else
{
// 更新场景动作
_transition->_update();
if (_transition->isDone()) if (_transition->isDone())
{ {
@ -144,26 +138,17 @@ void e2d::SceneManager::update()
} }
} }
// 下一场景指针不为空时,切换场景
if (_nextScene) if (_nextScene)
{ {
if (_currScene) if (_currScene)
{ {
// 执行当前场景的 onExit 函数
_currScene->onExit(); _currScene->onExit();
if (_scenes.empty() || _scenes.top() != _currScene)
// 若要保存当前场景,把它放入栈中
if (_saveCurrScene)
{
_scenes.push(_currScene);
}
else
{ {
_currScene->release(); _currScene->release();
} }
} }
// 执行下一场景的 onEnter 函数
_nextScene->onEnter(); _nextScene->onEnter();
_currScene = _nextScene; _currScene = _nextScene;
@ -175,17 +160,13 @@ void e2d::SceneManager::render()
{ {
if (_transition) if (_transition)
{ {
_transition->_render(); _transition->render();
} }
else else if (_currScene)
{
// 绘制当前场景
if (_currScene)
{ {
_currScene->render(); _currScene->render();
} }
} }
}
void e2d::SceneManager::dispatch(const MouseEvent & e) void e2d::SceneManager::dispatch(const MouseEvent & e)
{ {

View File

@ -6,8 +6,7 @@ e2d::Task::Task(const Function & func, const String & name)
, _stopped(false) , _stopped(false)
, _runTimes(0) , _runTimes(0)
, _totalTimes(-1) , _totalTimes(-1)
, _delay(0.f) , _delay()
, _lastTime(0.f)
, _callback(func) , _callback(func)
, _name(name) , _name(name)
{ {
@ -17,9 +16,8 @@ e2d::Task::Task(const Function & func, float delay, int times, const String & na
: _running(true) : _running(true)
, _stopped(false) , _stopped(false)
, _runTimes(0) , _runTimes(0)
, _totalTimes(times)
, _delay(std::max(delay, 0.f)) , _delay(std::max(delay, 0.f))
, _lastTime(0.f) , _totalTimes(times)
, _callback(func) , _callback(func)
, _name(name) , _name(name)
{ {
@ -38,17 +36,24 @@ void e2d::Task::resume()
void e2d::Task::update() void e2d::Task::update()
{ {
if (_callback) if (_totalTimes == 0)
{ {
_callback(); _stopped = true;
return;
} }
++_runTimes; ++_runTimes;
_lastTime += _delay; _lastTime += _delay;
if (_callback)
{
_callback();
}
if (_runTimes == _totalTimes) if (_runTimes == _totalTimes)
{ {
_stopped = true; _stopped = true;
return;
} }
} }
@ -56,11 +61,11 @@ bool e2d::Task::isReady() const
{ {
if (_running) if (_running)
{ {
if (_delay == 0) if (_delay.milliseconds() == 0)
{ {
return true; return true;
} }
if ((Game::getInstance()->getTotalDuration().seconds() - _lastTime) >= _delay) if (Time::now() - _lastTime >= _delay)
{ {
return true; return true;
} }
@ -80,5 +85,5 @@ e2d::String e2d::Task::getName() const
void e2d::Task::updateTime() void e2d::Task::updateTime()
{ {
_lastTime = Game::getInstance()->getTotalDuration().seconds(); _lastTime = Time::now();
} }

View File

@ -6,14 +6,20 @@ e2d::BoxTransition::BoxTransition(float duration)
{ {
} }
void e2d::BoxTransition::_init(Scene * prev, Scene * next) bool e2d::BoxTransition::init(Scene * prev, Scene * next)
{
if (Transition::init(prev, next))
{ {
Transition::_init(prev, next);
_inLayerParam.opacity = 0; _inLayerParam.opacity = 0;
return true;
}
return false;
} }
void e2d::BoxTransition::_updateCustom() void e2d::BoxTransition::update()
{ {
Transition::update();
if (_delta <= 0.5) if (_delta <= 0.5)
{ {
_outLayerParam.contentBounds = D2D1::RectF( _outLayerParam.contentBounds = D2D1::RectF(
@ -35,11 +41,11 @@ void e2d::BoxTransition::_updateCustom()
); );
if (_delta >= 1) if (_delta >= 1)
{ {
this->_stop(); this->stop();
} }
} }
} }
void e2d::BoxTransition::_reset() void e2d::BoxTransition::reset()
{ {
} }

View File

@ -6,24 +6,30 @@ e2d::EmergeTransition::EmergeTransition(float duration)
{ {
} }
void e2d::EmergeTransition::_init(Scene * prev, Scene * next) bool e2d::EmergeTransition::init(Scene * prev, Scene * next)
{
if (Transition::init(prev, next))
{ {
Transition::_init(prev, next);
_outLayerParam.opacity = 1; _outLayerParam.opacity = 1;
_inLayerParam.opacity = 0; _inLayerParam.opacity = 0;
return true;
}
return false;
} }
void e2d::EmergeTransition::_updateCustom() void e2d::EmergeTransition::update()
{ {
Transition::update();
_outLayerParam.opacity = 1 - _delta; _outLayerParam.opacity = 1 - _delta;
_inLayerParam.opacity = _delta; _inLayerParam.opacity = _delta;
if (_delta >= 1) if (_delta >= 1)
{ {
this->_stop(); this->stop();
} }
} }
void e2d::EmergeTransition::_reset() void e2d::EmergeTransition::reset()
{ {
} }

View File

@ -6,15 +6,21 @@ e2d::FadeTransition::FadeTransition(float duration)
{ {
} }
void e2d::FadeTransition::_init(Scene * prev, Scene * next) bool e2d::FadeTransition::init(Scene * prev, Scene * next)
{
if (Transition::init(prev, next))
{ {
Transition::_init(prev, next);
_outLayerParam.opacity = 1; _outLayerParam.opacity = 1;
_inLayerParam.opacity = 0; _inLayerParam.opacity = 0;
return true;
}
return false;
} }
void e2d::FadeTransition::_updateCustom() void e2d::FadeTransition::update()
{ {
Transition::update();
if (_delta < 0.5) if (_delta < 0.5)
{ {
_outLayerParam.opacity = 1 - _delta * 2; _outLayerParam.opacity = 1 - _delta * 2;
@ -26,11 +32,11 @@ void e2d::FadeTransition::_updateCustom()
_inLayerParam.opacity = (_delta - 0.5f) * 2; _inLayerParam.opacity = (_delta - 0.5f) * 2;
if (_delta >= 1) if (_delta >= 1)
{ {
this->_stop(); this->stop();
} }
} }
} }
void e2d::FadeTransition::_reset() void e2d::FadeTransition::reset()
{ {
} }

View File

@ -7,10 +7,10 @@ e2d::MoveTransition::MoveTransition(float duration, Direction direction)
{ {
} }
void e2d::MoveTransition::_init(Scene * prev, Scene * next) bool e2d::MoveTransition::init(Scene * prev, Scene * next)
{
if (Transition::init(prev, next))
{ {
Transition::_init(prev, next);
float width = _windowSize.width; float width = _windowSize.width;
float height = _windowSize.height; float height = _windowSize.height;
if (_direction == Direction::Up) if (_direction == Direction::Up)
@ -36,10 +36,15 @@ void e2d::MoveTransition::_init(Scene * prev, Scene * next)
if (_outScene) _outScene->getRoot()->setPos(0, 0); if (_outScene) _outScene->getRoot()->setPos(0, 0);
_inScene->getRoot()->setPos(_startPos); _inScene->getRoot()->setPos(_startPos);
return true;
}
return false;
} }
void e2d::MoveTransition::_updateCustom() void e2d::MoveTransition::update()
{ {
Transition::update();
if (_outScene) if (_outScene)
{ {
_outScene->getRoot()->setPos(_posDelta * _delta); _outScene->getRoot()->setPos(_posDelta * _delta);
@ -51,11 +56,11 @@ void e2d::MoveTransition::_updateCustom()
if (_delta >= 1) if (_delta >= 1)
{ {
this->_stop(); this->stop();
} }
} }
void e2d::MoveTransition::_reset() void e2d::MoveTransition::reset()
{ {
if (_outScene) _outScene->getRoot()->setPos(0, 0); if (_outScene) _outScene->getRoot()->setPos(0, 0);
_inScene->getRoot()->setPos(0, 0); _inScene->getRoot()->setPos(0, 0);

View File

@ -4,7 +4,7 @@
e2d::Transition::Transition(float duration) e2d::Transition::Transition(float duration)
: _end(false) : _end(false)
, _last() , _started()
, _delta(0) , _delta(0)
, _outScene(nullptr) , _outScene(nullptr)
, _inScene(nullptr) , _inScene(nullptr)
@ -29,7 +29,7 @@ bool e2d::Transition::isDone()
return _end; return _end;
} }
void e2d::Transition::_init(Scene * prev, Scene * next) bool e2d::Transition::init(Scene * prev, Scene * next)
{ {
auto renderer = Renderer::getInstance(); auto renderer = Renderer::getInstance();
// ´´½¨Í¼²ã // ´´½¨Í¼²ã
@ -42,10 +42,10 @@ void e2d::Transition::_init(Scene * prev, Scene * next)
if (FAILED(hr)) if (FAILED(hr))
{ {
throw SystemException(L"场景过渡动画图层创建失败"); return false;
} }
_last = Game::getInstance()->getTotalDuration(); _started = Time::now();
_outScene = prev; _outScene = prev;
_inScene = next; _inScene = next;
if (_outScene) _outScene->retain(); if (_outScene) _outScene->retain();
@ -61,35 +61,24 @@ void e2d::Transition::_init(Scene * prev, Scene * next)
renderer->getSolidColorBrush(), renderer->getSolidColorBrush(),
D2D1_LAYER_OPTIONS_NONE D2D1_LAYER_OPTIONS_NONE
); );
return true;
} }
void e2d::Transition::_update() void e2d::Transition::update()
{ {
// 计算动作进度
if (_duration == 0) if (_duration == 0)
{ {
_delta = 1; _delta = 1;
} }
else else
{ {
_delta = (Game::getInstance()->getTotalDuration() - _last).seconds() / _duration; _delta = (Time::now() - _started).seconds() / _duration;
_delta = std::min(_delta, 1.f); _delta = std::min(_delta, 1.f);
} }
this->_updateCustom();
// 更新场景内容
if (_outScene)
{
_outScene->update();
}
if (_inScene)
{
_inScene->update();
}
} }
void e2d::Transition::_render() void e2d::Transition::render()
{ {
auto pRT = Renderer::getInstance()->getRenderTarget(); auto pRT = Renderer::getInstance()->getRenderTarget();
@ -132,8 +121,8 @@ void e2d::Transition::_render()
} }
} }
void e2d::Transition::_stop() void e2d::Transition::stop()
{ {
_end = true; _end = true;
_reset(); reset();
} }

View File

@ -85,7 +85,7 @@ protected:
bool _done; bool _done;
bool _initialized; bool _initialized;
Node * _target; Node * _target;
float _last; Time _started;
}; };

View File

@ -118,9 +118,6 @@ public:
// 获取游戏配置 // 获取游戏配置
const Config& getConfig(); const Config& getConfig();
// 获取游戏总时长
Duration getTotalDuration() const;
private: private:
Game(); Game();
@ -132,9 +129,6 @@ private:
bool _quit; bool _quit;
bool _paused; bool _paused;
Config _config; Config _config;
Time _start;
Time _now;
Time _last;
static Game * _instance; static Game * _instance;
}; };
@ -243,7 +237,13 @@ private:
E2D_DISABLE_COPY(Window); E2D_DISABLE_COPY(Window);
// 注册窗口 // 注册窗口
HWND __create(); HWND __registerWindow();
// 根据客户区大小计算合适的窗口区域
Rect __adjustWindow(
int width,
int height
);
// Win32 窗口消息回调程序 // Win32 窗口消息回调程序
static LRESULT CALLBACK WndProc( static LRESULT CALLBACK WndProc(
@ -342,12 +342,6 @@ public:
Color color Color color
); );
// 渲染游戏画面
void render();
// 删除设备相关资源
void discardDeviceResources();
// 获取文字渲染器 // 获取文字渲染器
TextRenderer * getTextRenderer(); TextRenderer * getTextRenderer();
@ -357,6 +351,12 @@ public:
// 获取 ID2D1SolidColorBrush 对象 // 获取 ID2D1SolidColorBrush 对象
ID2D1SolidColorBrush * getSolidColorBrush(); ID2D1SolidColorBrush * getSolidColorBrush();
// 渲染游戏画面
void render();
// 删除设备相关资源
void discardDeviceResources();
// 获取 ID2D1Factory 对象 // 获取 ID2D1Factory 对象
static ID2D1Factory * getFactory(); static ID2D1Factory * getFactory();

View File

@ -414,11 +414,7 @@ public:
Duration(); Duration();
explicit Duration( explicit Duration(
int ms float seconds
);
explicit Duration(
const std::chrono::milliseconds& ms
); );
// 获取毫秒数 // 获取毫秒数
@ -451,10 +447,6 @@ class Time
public: public:
Time(); Time();
explicit Time(
const std::chrono::steady_clock::time_point& time
);
// 获取时间戳 // 获取时间戳
time_t getTimeStamp() const; time_t getTimeStamp() const;

View File

@ -25,13 +25,15 @@ public:
// 场景入栈 // 场景入栈
void push( void push(
Scene * scene, /* 下一个场景的指针 */ Scene * scene, /* 下一个场景的指针 */
Transition * transition = nullptr, /* 场景切换动作 */
bool saveCurrentScene = true /* 是否保存当前场景 */ bool saveCurrentScene = true /* 是否保存当前场景 */
); );
// 场景出栈 // 场景出栈
void pop( Scene* pop();
Transition * transition = nullptr /* 场景切换动作 */
// 设置场景切换动作
void setTransition(
Transition * transition /* 场景切换动作 */
); );
// 清空保存的所有场景 // 清空保存的所有场景
@ -41,7 +43,7 @@ public:
Scene * getCurrentScene(); Scene * getCurrentScene();
// 获取场景栈 // 获取场景栈
std::stack<Scene*> getSceneStack(); const std::stack<Scene*>& getSceneStack();
// 是否正在进行转场动作 // 是否正在进行转场动作
bool isTransitioning(); bool isTransitioning();
@ -70,7 +72,6 @@ private:
E2D_DISABLE_COPY(SceneManager); E2D_DISABLE_COPY(SceneManager);
private: private:
bool _saveCurrScene;
Scene * _currScene; Scene * _currScene;
Scene * _nextScene; Scene * _nextScene;
Transition * _transition; Transition * _transition;

View File

@ -308,8 +308,8 @@ private:
bool _stopped; bool _stopped;
int _runTimes; int _runTimes;
int _totalTimes; int _totalTimes;
float _delay; Duration _delay;
float _lastTime; Time _lastTime;
String _name; String _name;
Function _callback; Function _callback;
}; };

View File

@ -5,15 +5,10 @@ namespace e2d
{ {
class SceneManager;
// 场景过渡 // 场景过渡
class Transition : class Transition :
public Ref public Ref
{ {
friend class SceneManager;
public: public:
explicit Transition(float duration); explicit Transition(float duration);
@ -22,33 +17,29 @@ public:
// 场景过渡动画是否结束 // 场景过渡动画是否结束
bool isDone(); bool isDone();
protected:
// 初始化场景过渡动画 // 初始化场景过渡动画
virtual void _init( virtual bool init(
Scene * prev, Scene * prev,
Scene * next Scene * next
); );
// 更新场景过渡动画 // 更新场景过渡动画
virtual void _update(); virtual void update();
// 更新场景过渡动画
virtual void _updateCustom() = 0;
// 渲染场景过渡动画 // 渲染场景过渡动画
virtual void _render(); virtual void render();
// 重置场景过渡动画
virtual void _reset() = 0;
// 停止场景过渡动画 // 停止场景过渡动画
virtual void _stop(); virtual void stop();
// 重置场景过渡动画
virtual void reset() = 0;
protected: protected:
bool _end; bool _end;
float _duration; float _duration;
float _delta; float _delta;
Duration _last; Time _started;
Size _windowSize; Size _windowSize;
Scene* _outScene; Scene* _outScene;
Scene* _inScene; Scene* _inScene;
@ -68,16 +59,15 @@ public:
float duration /* 动画持续时长 */ float duration /* 动画持续时长 */
); );
protected:
// 更新动画 // 更新动画
virtual void _updateCustom() override; virtual void update() override;
virtual void _init( virtual bool init(
Scene * prev, Scene * prev,
Scene * next Scene * next
) override; ) override;
virtual void _reset() override; virtual void reset() override;
}; };
@ -90,16 +80,15 @@ public:
float duration /* 浮现动画持续时长 */ float duration /* 浮现动画持续时长 */
); );
protected:
// 更新动画 // 更新动画
virtual void _updateCustom() override; virtual void update() override;
virtual void _init( virtual bool init(
Scene * prev, Scene * prev,
Scene * next Scene * next
) override; ) override;
virtual void _reset() override; virtual void reset() override;
}; };
@ -112,16 +101,15 @@ public:
float duration /* 动画持续时长 */ float duration /* 动画持续时长 */
); );
protected:
// 更新动画 // 更新动画
virtual void _updateCustom() override; virtual void update() override;
virtual void _init( virtual bool init(
Scene * prev, Scene * prev,
Scene * next Scene * next
) override; ) override;
virtual void _reset() override; virtual void reset() override;
}; };
@ -135,16 +123,15 @@ public:
Direction direction = Direction::Left /* 场景移动方向 */ Direction direction = Direction::Left /* 场景移动方向 */
); );
protected:
// 更新动画 // 更新动画
virtual void _updateCustom() override; virtual void update() override;
virtual void _init( virtual bool init(
Scene * prev, Scene * prev,
Scene * next Scene * next
) override; ) override;
virtual void _reset() override; virtual void reset() override;
protected: protected:
Direction _direction; Direction _direction;