diff --git a/Easy2D/v1/Action/Action.cpp b/Easy2D/v1/Action/Action.cpp new file mode 100644 index 00000000..1d99e527 --- /dev/null +++ b/Easy2D/v1/Action/Action.cpp @@ -0,0 +1,85 @@ +#include "..\easy2d.h" +#include + +Action::Action() : + m_bRunning(true), + m_bWaiting(false), + m_bEnding(false), + m_bInit(false), + m_pTargetSprite(nullptr), + m_pParentScene(nullptr) +{ + // 默认动作 15ms 运行一次 + setInterval(15); +} + +Action::~Action() +{ +} + +bool Action::isRunning() +{ + return m_bRunning && !m_bWaiting; +} + +bool Action::isEnding() +{ + return m_bEnding; +} + +void Action::start() +{ + m_bRunning = true; +} + +void Action::resume() +{ + m_bRunning = true; +} + +void Action::pause() +{ + m_bRunning = false; +} + +void Action::stop() +{ + m_bEnding = true; +} +void Action::wait() +{ + m_bWaiting = true; +} + +void Action::notify() +{ + m_bWaiting = false; +} + +void Action::setInterval(LONGLONG milliSeconds) +{ + // 设置动作的时间间隔 + m_nAnimationInterval = milliSeconds; +} + +Action * Action::reverse() const +{ + assert(0); + return nullptr; +} + +Sprite * Action::getTarget() +{ + return m_pTargetSprite; +} + +void Action::_init() +{ + m_bInit = true; +} + +void Action::_reset() +{ + m_bInit = false; + m_bEnding = false; +} diff --git a/Easy2D/v1/Action/ActionCallback.cpp b/Easy2D/v1/Action/ActionCallback.cpp new file mode 100644 index 00000000..c1cf46e1 --- /dev/null +++ b/Easy2D/v1/Action/ActionCallback.cpp @@ -0,0 +1,31 @@ +#include "..\easy2d.h" + +ActionCallback::ActionCallback(const std::function& callback) : + m_Callback(callback) +{ +} + +ActionCallback::~ActionCallback() +{ +} + +ActionCallback * ActionCallback::copy() const +{ + return new ActionCallback(m_Callback); +} + +void ActionCallback::_init() +{ + Action::_init(); +} + +void ActionCallback::_exec(std::chrono::steady_clock::time_point nNow) +{ + m_Callback(); + this->stop(); +} + +void ActionCallback::_reset() +{ + Action::_reset(); +} diff --git a/Easy2D/v1/Action/ActionDelay.cpp b/Easy2D/v1/Action/ActionDelay.cpp new file mode 100644 index 00000000..4e5c8b6a --- /dev/null +++ b/Easy2D/v1/Action/ActionDelay.cpp @@ -0,0 +1,39 @@ +#include "..\easy2d.h" +#include "..\Win\winbase.h" + +ActionDelay::ActionDelay(float duration) +{ + setInterval(LONGLONG(duration * 1000)); +} + +ActionDelay::~ActionDelay() +{ +} + +ActionDelay * ActionDelay::copy() const +{ + return new ActionDelay(m_nAnimationInterval / 1000.0f); +} + +void ActionDelay::_init() +{ + Action::_init(); + // 记录当前时间 + m_nLast = steady_clock::now(); +} + +void ActionDelay::_exec(steady_clock::time_point nNow) +{ + // 判断时间间隔是否足够 + if (duration_cast(nNow - m_nLast).count() > m_nAnimationInterval) + { + this->stop(); + } +} + +void ActionDelay::_reset() +{ + Action::_reset(); + // 记录当前时间 + m_nLast = steady_clock::now(); +} diff --git a/Easy2D/v1/Action/ActionFrames.cpp b/Easy2D/v1/Action/ActionFrames.cpp new file mode 100644 index 00000000..582bf48b --- /dev/null +++ b/Easy2D/v1/Action/ActionFrames.cpp @@ -0,0 +1,83 @@ +#include "..\easy2d.h" +#include "..\Win\winbase.h" + +ActionFrames::ActionFrames() : + m_nFrameIndex(0) +{ + // 帧动画默认 .5s 刷新一次 + setInterval(500); +} + +ActionFrames::ActionFrames(LONGLONG frameDelay) : + m_nFrameIndex(0) +{ + setInterval(frameDelay); +} + +ActionFrames::~ActionFrames() +{ + for (auto frame : m_vFrames) + { + frame->autoRelease(); + frame->release(); + } +} + +void ActionFrames::_init() +{ + Action::_init(); + // 记录当前时间 + m_nLast = steady_clock::now(); +} + +void ActionFrames::_exec(steady_clock::time_point nNow) +{ + // 判断时间间隔是否足够 + while (duration_cast(nNow - m_nLast).count() > m_nAnimationInterval) + { + // 重新记录时间 + m_nLast += milliseconds(m_nAnimationInterval); + m_pTargetSprite->setImage(m_vFrames[m_nFrameIndex]); + m_nFrameIndex++; + // 判断动作是否结束 + if (m_nFrameIndex == m_vFrames.size()) + { + this->stop(); + break; + } + } +} + +void ActionFrames::_reset() +{ + Action::_reset(); + m_nFrameIndex = 0; + // 记录当前时间 + m_nLast = steady_clock::now(); +} + +void ActionFrames::addFrame(Image * frame) +{ + if (frame) + { + m_vFrames.push_back(frame); + frame->retain(); + } +} + +ActionFrames * ActionFrames::copy() const +{ + auto a = new ActionFrames(this->m_nAnimationInterval); + for (auto f : m_vFrames) + { + a->addFrame(f); + } + return a; +} + +ActionFrames * ActionFrames::reverse() const +{ + auto a = this->copy(); + a->m_vFrames.reserve(m_vFrames.size()); + return a; +} diff --git a/Easy2D/v1/Action/ActionMoveBy.cpp b/Easy2D/v1/Action/ActionMoveBy.cpp new file mode 100644 index 00000000..ebc83a66 --- /dev/null +++ b/Easy2D/v1/Action/ActionMoveBy.cpp @@ -0,0 +1,51 @@ +#include "..\easy2d.h" +#include "..\Win\winbase.h" + +ActionMoveBy::ActionMoveBy(float duration, CVector vec) : + Animation(duration) +{ + m_MoveVector = vec; +} + +ActionMoveBy::~ActionMoveBy() +{ +} + +void ActionMoveBy::_init() +{ + Animation::_init(); + m_BeginPos = m_pTargetSprite->getPos(); +} + +void ActionMoveBy::_exec(steady_clock::time_point nNow) +{ + while (Animation::_isDelayEnough(nNow)) + { + // 计算移动位置 + float scale = float(m_nDuration) / m_nTotalDuration; + // 移动 Sprite + m_pTargetSprite->setPos(int(m_BeginPos.x + m_MoveVector.x * scale), + int(m_BeginPos.y + m_MoveVector.y * scale)); + // 判断动作是否结束 + if (_isEnd()) + { + this->stop(); + break; + } + } +} + +void ActionMoveBy::_reset() +{ + Animation::_reset(); +} + +ActionMoveBy * ActionMoveBy::copy() const +{ + return new ActionMoveBy(m_nAnimationInterval / 1000.0f, m_MoveVector); +} + +ActionMoveBy * ActionMoveBy::reverse() const +{ + return new ActionMoveBy(m_nTotalDuration / 1000.0f, CVector(-m_MoveVector.x, -m_MoveVector.y)); +} \ No newline at end of file diff --git a/Easy2D/v1/Action/ActionMoveTo.cpp b/Easy2D/v1/Action/ActionMoveTo.cpp new file mode 100644 index 00000000..c4249317 --- /dev/null +++ b/Easy2D/v1/Action/ActionMoveTo.cpp @@ -0,0 +1,27 @@ +#include "..\easy2d.h" + +ActionMoveTo::ActionMoveTo(float duration, CPoint pos) : + ActionMoveBy(duration, CVector()) +{ + m_EndPos = pos; +} + +ActionMoveTo::~ActionMoveTo() +{ +} + +ActionMoveTo * ActionMoveTo::copy() const +{ + return new ActionMoveTo(m_nAnimationInterval / 1000.0f, m_EndPos); +} + +void ActionMoveTo::_init() +{ + ActionMoveBy::_init(); + m_MoveVector = m_EndPos - m_BeginPos; +} + +void ActionMoveTo::_reset() +{ + ActionMoveBy::_reset(); +} diff --git a/Easy2D/v1/Action/ActionNeverStop.cpp b/Easy2D/v1/Action/ActionNeverStop.cpp new file mode 100644 index 00000000..ac11b65c --- /dev/null +++ b/Easy2D/v1/Action/ActionNeverStop.cpp @@ -0,0 +1,39 @@ +#include "..\easy2d.h" + +ActionNeverStop::ActionNeverStop(Action * action) : + m_Action(action) +{ + m_Action->retain(); +} + +ActionNeverStop::~ActionNeverStop() +{ + SafeRelease(m_Action); +} + +ActionNeverStop * ActionNeverStop::copy() const +{ + return new ActionNeverStop(m_Action->copy()); +} + +void ActionNeverStop::_init() +{ + Action::_init(); + m_Action->m_pTargetSprite = m_pTargetSprite; + m_Action->_init(); +} + +void ActionNeverStop::_exec(std::chrono::steady_clock::time_point nNow) +{ + m_Action->_exec(nNow); + + if (m_Action->isEnding()) + { + m_Action->_reset(); + } +} + +void ActionNeverStop::_reset() +{ + Action::_reset(); +} diff --git a/Easy2D/v1/Action/ActionOpacityBy.cpp b/Easy2D/v1/Action/ActionOpacityBy.cpp new file mode 100644 index 00000000..2d9ea7c0 --- /dev/null +++ b/Easy2D/v1/Action/ActionOpacityBy.cpp @@ -0,0 +1,50 @@ +#include "..\easy2d.h" +#include "..\Win\winbase.h" + +ActionOpacityBy::ActionOpacityBy(float duration, float opacity) : + Animation(duration) +{ + m_nVariation = opacity; +} + +ActionOpacityBy::~ActionOpacityBy() +{ +} + +void ActionOpacityBy::_init() +{ + Animation::_init(); + m_nBeginVal = m_pTargetSprite->getOpacity(); +} + +void ActionOpacityBy::_exec(steady_clock::time_point nNow) +{ + while (Animation::_isDelayEnough(nNow)) + { + // 计算移动位置 + float scale = float(m_nDuration) / m_nTotalDuration; + // 移动 Sprite + m_pTargetSprite->setOpacity(m_nBeginVal + m_nVariation * scale); + // 判断动作是否结束 + if (_isEnd()) + { + this->stop(); + break; + } + } +} + +void ActionOpacityBy::_reset() +{ + Animation::_reset(); +} + +ActionOpacityBy * ActionOpacityBy::copy() const +{ + return new ActionOpacityBy(m_nAnimationInterval / 1000.0f, m_nVariation); +} + +ActionOpacityBy * ActionOpacityBy::reverse() const +{ + return new ActionOpacityBy(m_nTotalDuration / 1000.0f, -m_nVariation); +} \ No newline at end of file diff --git a/Easy2D/v1/Action/ActionOpacityTo.cpp b/Easy2D/v1/Action/ActionOpacityTo.cpp new file mode 100644 index 00000000..5bd7c001 --- /dev/null +++ b/Easy2D/v1/Action/ActionOpacityTo.cpp @@ -0,0 +1,27 @@ +#include "..\easy2d.h" + +ActionOpacityTo::ActionOpacityTo(float duration, float opacity) : + ActionOpacityBy(duration, 0) +{ + m_nEndVal = opacity; +} + +ActionOpacityTo::~ActionOpacityTo() +{ +} + +ActionOpacityTo * ActionOpacityTo::copy() const +{ + return new ActionOpacityTo(m_nAnimationInterval / 1000.0f, m_nEndVal); +} + +void ActionOpacityTo::_init() +{ + ActionOpacityBy::_init(); + m_nVariation = m_nEndVal - m_nBeginVal; +} + +void ActionOpacityTo::_reset() +{ + ActionOpacityBy::_reset(); +} diff --git a/Easy2D/v1/Action/ActionScaleBy.cpp b/Easy2D/v1/Action/ActionScaleBy.cpp new file mode 100644 index 00000000..b86f0f5c --- /dev/null +++ b/Easy2D/v1/Action/ActionScaleBy.cpp @@ -0,0 +1,52 @@ +#include "..\easy2d.h" +#include "..\Win\winbase.h" + +ActionScaleBy::ActionScaleBy(float duration, float scaleX, float scaleY) : + Animation(duration) +{ + m_nVariationX = scaleX; + m_nVariationY = scaleY; +} + +ActionScaleBy::~ActionScaleBy() +{ +} + +void ActionScaleBy::_init() +{ + Animation::_init(); + m_nBeginScaleX = m_pTargetSprite->getScaleX(); + m_nBeginScaleY = m_pTargetSprite->getScaleY(); +} + +void ActionScaleBy::_exec(steady_clock::time_point nNow) +{ + while (Animation::_isDelayEnough(nNow)) + { + // 计算移动位置 + float scale = float(m_nDuration) / m_nTotalDuration; + // 移动 Sprite + m_pTargetSprite->setScale(m_nBeginScaleX + m_nVariationX * scale, m_nBeginScaleX + m_nVariationX * scale); + // 判断动作是否结束 + if (_isEnd()) + { + this->stop(); + break; + } + } +} + +void ActionScaleBy::_reset() +{ + Animation::_reset(); +} + +ActionScaleBy * ActionScaleBy::copy() const +{ + return new ActionScaleBy(m_nAnimationInterval / 1000.0f, m_nVariationX, m_nVariationY); +} + +ActionScaleBy * ActionScaleBy::reverse() const +{ + return new ActionScaleBy(m_nTotalDuration / 1000.0f, -m_nVariationX, -m_nVariationY); +} \ No newline at end of file diff --git a/Easy2D/v1/Action/ActionScaleTo.cpp b/Easy2D/v1/Action/ActionScaleTo.cpp new file mode 100644 index 00000000..76b8fdcc --- /dev/null +++ b/Easy2D/v1/Action/ActionScaleTo.cpp @@ -0,0 +1,29 @@ +#include "..\easy2d.h" + +ActionScaleTo::ActionScaleTo(float duration, float scaleX, float scaleY) : + ActionScaleBy(duration, 0, 0) +{ + m_nEndScaleX = scaleX; + m_nEndScaleY = scaleY; +} + +ActionScaleTo::~ActionScaleTo() +{ +} + +ActionScaleTo * ActionScaleTo::copy() const +{ + return new ActionScaleTo(m_nAnimationInterval / 1000.0f, m_nEndScaleX, m_nEndScaleY); +} + +void ActionScaleTo::_init() +{ + ActionScaleBy::_init(); + m_nVariationX = m_nEndScaleX - m_nBeginScaleX; + m_nVariationY = m_nEndScaleY - m_nBeginScaleY; +} + +void ActionScaleTo::_reset() +{ + ActionScaleBy::_reset(); +} diff --git a/Easy2D/v1/Action/ActionSequence.cpp b/Easy2D/v1/Action/ActionSequence.cpp new file mode 100644 index 00000000..911dfde9 --- /dev/null +++ b/Easy2D/v1/Action/ActionSequence.cpp @@ -0,0 +1,105 @@ +#include "..\easy2d.h" +#include + +ActionSequence::ActionSequence() : + m_nActionIndex(0) +{ +} + +ActionSequence::ActionSequence(int number, Action * action1, ...) : + m_nActionIndex(0) +{ + va_list params; + va_start(params, number); + + while (number > 0) + { + this->addAction(va_arg(params, Action*)); + number--; + } + + va_end(params); +} + +ActionSequence::~ActionSequence() +{ + for (auto action : m_vActions) + { + SafeRelease(action); + } +} + +void ActionSequence::_init() +{ + Action::_init(); + // 将所有动作与目标绑定 + for (auto action : m_vActions) + { + action->m_pTargetSprite = m_pTargetSprite; + } + // 初始化第一个动作 + m_vActions[0]->_init(); +} + +void ActionSequence::_exec(std::chrono::steady_clock::time_point nNow) +{ + m_vActions[m_nActionIndex]->_exec(nNow); + + if (m_vActions[m_nActionIndex]->isEnding()) + { + m_nActionIndex++; + if (m_nActionIndex == m_vActions.size()) + { + this->stop(); + } + else + { + m_vActions[m_nActionIndex]->_init(); + } + } +} + +void ActionSequence::_reset() +{ + Action::_reset(); + for (auto action : m_vActions) + { + action->_reset(); + } + m_nActionIndex = 0; +} + +void ActionSequence::addAction(Action * action) +{ + m_vActions.push_back(action); + action->retain(); +} + +ActionSequence * ActionSequence::copy() const +{ + auto a = new ActionSequence(); + for (auto action : m_vActions) + { + a->addAction(action->copy()); + } + return a; +} + +ActionSequence * ActionSequence::reverse(bool actionReverse) const +{ + auto a = new ActionSequence(); + for (auto action : a->m_vActions) + { + if (actionReverse) + { + a->addAction(action->reverse()); + } + else + { + a->addAction(action->copy()); + } + } + // 将动作顺序逆序排列 + a->m_vActions.reserve(m_vActions.size()); + return a; +} \ No newline at end of file diff --git a/Easy2D/v1/Action/ActionTwo.cpp b/Easy2D/v1/Action/ActionTwo.cpp new file mode 100644 index 00000000..669ebcd4 --- /dev/null +++ b/Easy2D/v1/Action/ActionTwo.cpp @@ -0,0 +1,70 @@ +#include "..\easy2d.h" + +ActionTwo::ActionTwo(Action * actionFirst, Action * actionSecond) : + m_FirstAction(actionFirst), + m_SecondAction(actionSecond) +{ + m_FirstAction->retain(); + m_SecondAction->retain(); +} + +ActionTwo::~ActionTwo() +{ + SafeRelease(m_FirstAction); + SafeRelease(m_SecondAction); +} + +ActionTwo * ActionTwo::copy() const +{ + return new ActionTwo(m_FirstAction->copy(), m_SecondAction->copy()); +} + +ActionTwo * ActionTwo::reverse(bool actionReverse) const +{ + if (actionReverse) + { + return new ActionTwo(m_SecondAction->reverse(), m_FirstAction->reverse()); + } + else + { + return new ActionTwo(m_SecondAction->copy(), m_FirstAction->copy()); + } +} + +void ActionTwo::_init() +{ + Action::_init(); + m_FirstAction->m_pTargetSprite = m_pTargetSprite; + m_SecondAction->m_pTargetSprite = m_pTargetSprite; + + m_FirstAction->_init(); +} + +void ActionTwo::_exec(std::chrono::steady_clock::time_point nNow) +{ + if (!m_FirstAction->isEnding()) + { + m_FirstAction->_exec(nNow); + if (m_FirstAction->isEnding()) + { + // 返回 true 表示第一个动作已经结束 + m_SecondAction->_init(); + } + } + else if (!m_SecondAction->isEnding()) + { + m_SecondAction->_exec(nNow); + } + else + { + this->stop(); + } +} + +void ActionTwo::_reset() +{ + Action::_reset(); + + m_FirstAction->_reset(); + m_SecondAction->_reset(); +} diff --git a/Easy2D/v1/Action/Animation.cpp b/Easy2D/v1/Action/Animation.cpp new file mode 100644 index 00000000..0ad44d20 --- /dev/null +++ b/Easy2D/v1/Action/Animation.cpp @@ -0,0 +1,45 @@ +#include "..\easy2d.h" +#include "..\Win\winbase.h" + +Animation::Animation(float duration) +{ + m_nDuration = 0; + m_nTotalDuration = UINT(duration * 1000); +} + +Animation::~Animation() +{ +} + +bool Animation::_isEnd() const +{ + return m_nDuration >= m_nTotalDuration; +} + +void Animation::_init() +{ + Action::_init(); + // 记录当前时间 + m_nLast = steady_clock::now(); +} + +bool Animation::_isDelayEnough(steady_clock::time_point nNow) +{ + // 判断时间间隔是否足够 + if (duration_cast(nNow - m_nLast).count() > m_nAnimationInterval) + { + // 重新记录时间 + m_nLast += milliseconds(m_nAnimationInterval); + m_nDuration += m_nAnimationInterval; + return true; + } + return false; +} + +void Animation::_reset() +{ + Action::_reset(); + m_nDuration = 0; + // 记录当前时间 + m_nLast = steady_clock::now(); +} diff --git a/Easy2D/v1/Msg/KeyMsg.cpp b/Easy2D/v1/Msg/KeyMsg.cpp new file mode 100644 index 00000000..b3a76b14 --- /dev/null +++ b/Easy2D/v1/Msg/KeyMsg.cpp @@ -0,0 +1,314 @@ +#include "..\easy2d.h" +#include "..\EasyX\easyx.h" +#include + +// 按键监听回调函数的容器 +static std::vector s_vListeners; + +// 虚拟键值的定义 +const VK_KEY KeyMsg::A = 'A'; +const VK_KEY KeyMsg::B = 'B'; +const VK_KEY KeyMsg::C = 'C'; +const VK_KEY KeyMsg::D = 'D'; +const VK_KEY KeyMsg::E = 'E'; +const VK_KEY KeyMsg::F = 'F'; +const VK_KEY KeyMsg::G = 'G'; +const VK_KEY KeyMsg::H = 'H'; +const VK_KEY KeyMsg::I = 'I'; +const VK_KEY KeyMsg::J = 'J'; +const VK_KEY KeyMsg::K = 'K'; +const VK_KEY KeyMsg::L = 'L'; +const VK_KEY KeyMsg::M = 'M'; +const VK_KEY KeyMsg::N = 'N'; +const VK_KEY KeyMsg::O = 'O'; +const VK_KEY KeyMsg::P = 'P'; +const VK_KEY KeyMsg::Q = 'Q'; +const VK_KEY KeyMsg::R = 'R'; +const VK_KEY KeyMsg::S = 'S'; +const VK_KEY KeyMsg::T = 'T'; +const VK_KEY KeyMsg::U = 'U'; +const VK_KEY KeyMsg::V = 'V'; +const VK_KEY KeyMsg::W = 'W'; +const VK_KEY KeyMsg::X = 'X'; +const VK_KEY KeyMsg::Y = 'Y'; +const VK_KEY KeyMsg::Z = 'Z'; +const VK_KEY KeyMsg::NUM_0 = '0'; +const VK_KEY KeyMsg::NUM_1 = '1'; +const VK_KEY KeyMsg::NUM_2 = '2'; +const VK_KEY KeyMsg::NUM_3 = '3'; +const VK_KEY KeyMsg::NUM_4 = '4'; +const VK_KEY KeyMsg::NUM_5 = '5'; +const VK_KEY KeyMsg::NUM_6 = '6'; +const VK_KEY KeyMsg::NUM_7 = '7'; +const VK_KEY KeyMsg::NUM_8 = '8'; +const VK_KEY KeyMsg::NUM_9 = '9'; +const VK_KEY KeyMsg::NUMPAD_0 = VK_NUMPAD0; +const VK_KEY KeyMsg::NUMPAD_1 = VK_NUMPAD1; +const VK_KEY KeyMsg::NUMPAD_2 = VK_NUMPAD2; +const VK_KEY KeyMsg::NUMPAD_3 = VK_NUMPAD3; +const VK_KEY KeyMsg::NUMPAD_4 = VK_NUMPAD4; +const VK_KEY KeyMsg::NUMPAD_5 = VK_NUMPAD5; +const VK_KEY KeyMsg::NUMPAD_6 = VK_NUMPAD6; +const VK_KEY KeyMsg::NUMPAD_7 = VK_NUMPAD7; +const VK_KEY KeyMsg::NUMPAD_8 = VK_NUMPAD8; +const VK_KEY KeyMsg::NUMPAD_9 = VK_NUMPAD9; +const VK_KEY KeyMsg::Enter = VK_RETURN; +const VK_KEY KeyMsg::Space = VK_SPACE; +const VK_KEY KeyMsg::Ctrl = VK_CONTROL; +const VK_KEY KeyMsg::LCtrl = VK_LCONTROL; +const VK_KEY KeyMsg::RCtrl = VK_RCONTROL; +const VK_KEY KeyMsg::Shift = VK_SHIFT; +const VK_KEY KeyMsg::LShift = VK_LSHIFT; +const VK_KEY KeyMsg::RShift = VK_RSHIFT; +const VK_KEY KeyMsg::Up = VK_UP; +const VK_KEY KeyMsg::Down = VK_DOWN; +const VK_KEY KeyMsg::Left = VK_LEFT; +const VK_KEY KeyMsg::Right = VK_RIGHT; +const VK_KEY KeyMsg::Esc = VK_ESCAPE; +const VK_KEY KeyMsg::F1 = VK_F1; +const VK_KEY KeyMsg::F2 = VK_F2; +const VK_KEY KeyMsg::F3 = VK_F3; +const VK_KEY KeyMsg::F4 = VK_F4; +const VK_KEY KeyMsg::F5 = VK_F5; +const VK_KEY KeyMsg::F6 = VK_F6; +const VK_KEY KeyMsg::F7 = VK_F7; +const VK_KEY KeyMsg::F8 = VK_F8; +const VK_KEY KeyMsg::F9 = VK_F9; +const VK_KEY KeyMsg::F10 = VK_F10; +const VK_KEY KeyMsg::F11 = VK_F11; +const VK_KEY KeyMsg::F12 = VK_F12; + +static VK_KEY convert(int ascii); + +KeyMsg::KeyMsg(TString name, const KEY_CALLBACK & callback) : + m_sName(name), + m_callback(callback), + m_pParentScene(nullptr), + m_bRunning(true), + m_bWaiting(false) +{ +} + +KeyMsg::~KeyMsg() +{ +} + +void KeyMsg::onKbHit(VK_KEY key) +{ + m_callback(key); +} + +void KeyMsg::start() +{ + m_bRunning = true; +} + +void KeyMsg::stop() +{ + m_bRunning = false; +} + +void KeyMsg::wait() +{ + m_bWaiting = true; +} + +void KeyMsg::notify() +{ + m_bWaiting = false; +} + +void KeyMsg::__exec() +{ + if (_kbhit()) // 检测有无按键消息 + { + VK_KEY key = convert(_getch()); // 获取键盘消息 + + for (auto l : s_vListeners) // 分发该消息 + { + if (!l->m_bWaiting && l->m_bRunning) + { + l->onKbHit(key); // 执行按键回调函数 + } + } + } +} + +void KeyMsg::addListener(TString name, const KEY_CALLBACK & callback) +{ + // 创建新的监听对象 + auto listener = new KeyMsg(name, callback); + // 绑定在场景上 + listener->m_pParentScene = EApp::getLoadingScene(); + // 添加新的按键回调函数 + s_vListeners.push_back(listener); +} + +void KeyMsg::startListener(TString name) +{ + // 查找名称相同的监听器 + for (auto l : s_vListeners) + { + if (l->m_sName == name && l->m_pParentScene == EApp::getCurrentScene()) + { + l->start(); + } + } +} + +void KeyMsg::stopListener(TString name) +{ + // 查找名称相同的监听器 + for (auto l : s_vListeners) + { + if (l->m_sName == name && l->m_pParentScene == EApp::getCurrentScene()) + { + l->stop(); + } + } +} + +void KeyMsg::delListener(TString name) +{ + // 创建迭代器 + std::vector::iterator iter; + // 循环遍历所有监听器 + for (iter = s_vListeners.begin(); iter != s_vListeners.end();) + { + // 查找相同名称的监听器 + if ((*iter)->m_sName == name && (*iter)->m_pParentScene == EApp::getCurrentScene()) + { + // 删除该定时器 + delete (*iter); + iter = s_vListeners.erase(iter); + } + else + { + iter++; + } + } +} + +void KeyMsg::notifyAllSceneListeners(EScene * scene) +{ + for (auto l : s_vListeners) + { + if (l->m_pParentScene == scene) + { + l->notify(); + } + } +} + +void KeyMsg::waitAllSceneListeners(EScene * scene) +{ + for (auto l : s_vListeners) + { + if (l->m_pParentScene == scene) + { + l->wait(); + } + } +} + +void KeyMsg::clearAllSceneListeners(EScene * scene) +{ + // 创建迭代器 + std::vector::iterator iter; + // 循环遍历所有监听器 + for (iter = s_vListeners.begin(); iter != s_vListeners.end();) + { + // 查找相同名称的监听器 + if ((*iter)->m_pParentScene == scene) + { + // 删除该定时器 + delete (*iter); + iter = s_vListeners.erase(iter); + } + else + { + iter++; + } + } +} + +void KeyMsg::clearAllListeners() +{ + // 删除所有监听器 + for (auto l : s_vListeners) + { + delete l; + } + // 清空容器 + s_vListeners.clear(); +} + +bool KeyMsg::isKeyDown(VK_KEY key) +{ + // 获取 key 的按下情况 + return (GetAsyncKeyState(key) & 0x8000); +} + + +VK_KEY convert(int ascii) +{ + // 字母键 + if (ascii >= 'a' && ascii <= 'z') + { + return VK_KEY(ascii - ('a' - 'A')); + } + else if (ascii >= 'A' && ascii <= 'Z') + { + return VK_KEY(ascii); + } + // 数字键 + else if (ascii >= '0' && ascii <= '9') + { + return VK_KEY(ascii); + } + // 回车、空格、Esc键 + else if (ascii == 0x0D || ascii == 0x20 || ascii == 0x1B) + { + return VK_KEY(ascii); + } + // 功能键 + else if (ascii == 0 || ascii == 0xE0) + { + switch (_getch()) + { + case 72: + return KeyMsg::Up; + case 75: + return KeyMsg::Left; + case 77: + return KeyMsg::Right; + case 80: + return KeyMsg::Down; + case 59: + return KeyMsg::F1; + case 60: + return KeyMsg::F2; + case 61: + return KeyMsg::F3; + case 62: + return KeyMsg::F4; + case 63: + return KeyMsg::F5; + case 64: + return KeyMsg::F6; + case 65: + return KeyMsg::F7; + case 66: + return KeyMsg::F8; + case 67: + return KeyMsg::F9; + case 133: + return KeyMsg::F10; + case 134: + return KeyMsg::F11; + default: + return 0; + } + } + return 0; +} \ No newline at end of file diff --git a/Easy2D/v1/Msg/MouseMsg.cpp b/Easy2D/v1/Msg/MouseMsg.cpp new file mode 100644 index 00000000..8234e7ef --- /dev/null +++ b/Easy2D/v1/Msg/MouseMsg.cpp @@ -0,0 +1,223 @@ +#include "..\easy2d.h" +#include "..\EasyX\easyx.h" + +// 鼠标监听回调函数的容器 +static std::vector s_vListeners; + +// 鼠标消息 +static MOUSEMSG s_mouseMsg; + +void MouseMsg::__exec() +{ + // 获取鼠标消息 + while (MouseHit()) + { + // 获取鼠标消息 + s_mouseMsg = GetMouseMsg(); + // 执行场景程序 + EApp::get()->getCurrentScene()->_exec(); + // 执行鼠标监听回调函数 + for (auto l : s_vListeners) // 循环遍历所有的鼠标监听 + { + if (!l->m_bWaiting && l->m_bRunning) + { + l->onMouseMsg(); // 执行回调函数 + } + } + } +} + +MouseMsg::MouseMsg() : + m_callback([]() {}), + m_pParentScene(nullptr), + m_bRunning(true), + m_bWaiting(false) +{ +} + +MouseMsg::MouseMsg(TString name, const MOUSE_CALLBACK & callback) : + m_sName(name), + m_callback(callback), + m_pParentScene(nullptr), + m_bRunning(true), + m_bWaiting(false) +{ +} + +MouseMsg::~MouseMsg() +{ +} + +void MouseMsg::onMouseMsg() +{ + m_callback(); +} + +void MouseMsg::addListener(TString name, const MOUSE_CALLBACK & callback) +{ + // 创建新的监听对象 + auto listener = new MouseMsg(name, callback); + // 绑定在场景上 + listener->m_pParentScene = EApp::getLoadingScene(); + // 添加新的按键回调函数 + s_vListeners.push_back(listener); +} + +void MouseMsg::startListener(TString name) +{ + // 查找名称相同的监听器 + for (auto l : s_vListeners) + { + if (l->m_sName == name && l->m_pParentScene == EApp::getCurrentScene()) + { + l->start(); + } + } +} + +void MouseMsg::stopListener(TString name) +{ + // 查找名称相同的监听器 + for (auto l : s_vListeners) + { + if (l->m_sName == name && l->m_pParentScene == EApp::getCurrentScene()) + { + l->stop(); + } + } +} + +void MouseMsg::delListener(TString name) +{ + // 创建迭代器 + std::vector::iterator iter; + // 循环遍历所有监听器 + for (iter = s_vListeners.begin(); iter != s_vListeners.end();) + { + // 查找相同名称的监听器 + if ((*iter)->m_sName == name && (*iter)->m_pParentScene == EApp::getCurrentScene()) + { + // 删除该定时器 + delete (*iter); + iter = s_vListeners.erase(iter); + } + else + { + iter++; + } + } +} + +void MouseMsg::start() +{ + m_bRunning = true; +} + +void MouseMsg::stop() +{ + m_bRunning = false; +} + +void MouseMsg::wait() +{ + m_bWaiting = true; +} + +void MouseMsg::notify() +{ + m_bWaiting = false; +} + +void MouseMsg::clearAllListeners() +{ + // 删除所有监听器 + for (auto l : s_vListeners) + { + delete l; + } + // 清空容器 + s_vListeners.clear(); +} + +void MouseMsg::notifyAllSceneListeners(EScene * scene) +{ + for (auto l : s_vListeners) + { + if (l->m_pParentScene == scene) + { + l->notify(); + } + } +} + +void MouseMsg::waitAllSceneListeners(EScene * scene) +{ + for (auto l : s_vListeners) + { + if (l->m_pParentScene == scene) + { + l->wait(); + } + } +} + +void MouseMsg::clearAllSceneListeners(EScene * scene) +{ + // 创建迭代器 + std::vector::iterator iter; + // 循环遍历所有监听器 + for (iter = s_vListeners.begin(); iter != s_vListeners.end();) + { + // 查找相同名称的监听器 + if ((*iter)->m_pParentScene == scene) + { + // 删除该定时器 + delete (*iter); + iter = s_vListeners.erase(iter); + } + else + { + iter++; + } + } +} + +bool MouseMsg::isLButtonDown() +{ + return s_mouseMsg.mkLButton; +} + +bool MouseMsg::isRButtonDown() +{ + return s_mouseMsg.mkRButton; +} + +bool MouseMsg::isMButtonDown() +{ + return s_mouseMsg.mkMButton; +} + +int MouseMsg::getX() +{ + return s_mouseMsg.x; +} + +int MouseMsg::getY() +{ + return s_mouseMsg.y; +} + +CPoint MouseMsg::getPos() +{ + return CPoint(s_mouseMsg.x, s_mouseMsg.y); +} + +int MouseMsg::getWheel() +{ + return s_mouseMsg.wheel; +} + +MouseMsg::MESSAGE MouseMsg::getMsg() +{ + return MESSAGE(s_mouseMsg.uMsg); +} diff --git a/Easy2D/v1/Node/BatchNode.cpp b/Easy2D/v1/Node/BatchNode.cpp new file mode 100644 index 00000000..63716580 --- /dev/null +++ b/Easy2D/v1/Node/BatchNode.cpp @@ -0,0 +1,190 @@ +#include "..\easy2d.h" +#include "..\EasyX\easyx.h" + +BatchNode::BatchNode() +{ +} + + +BatchNode::~BatchNode() +{ + clearAllChildren(); +} + +bool BatchNode::_exec(bool active) +{ + // 批量节点是否显示 + if (!m_bDisplay) + { + return false; + } + // 逆序遍历所有子节点 + for (int i = int(m_vChildren.size() - 1); i >= 0; i--) + { + if (m_vChildren[i]->_exec(active)) + { + active = false; + } + } + // 若子节点取得了画面焦点,则该节点也取得了焦点 + return !active; +} + +void BatchNode::_onDraw() +{ + // 节点是否显示 + if (!m_bDisplay) + { + return; + } + + for (auto child : m_vChildren) + { + // 绘制子节点 + child->_onDraw(); + } +} + +void BatchNode::add(Node * child, int z_Order) +{ + if (child == nullptr) return; + + // 设置节点的父场景 + child->setParentScene(this->getParentScene()); + // 设置节点在批量节点中的 z 轴顺序 + child->setZOrder(z_Order); + // 对象的引用计数加一 + child->retain(); + // 修改子节点位置 + child->move(getPos()); + + // 按 z 轴顺序插入节点 + size_t size = m_vChildren.size(); + for (unsigned i = 0; i <= size; i++) + { + if (i != size) + { + if (z_Order < m_vChildren.at(i)->getZOrder()) + { + m_vChildren.insert(m_vChildren.begin() + i, child); + break; + } + } + else + { + m_vChildren.push_back(child); + break; + } + } +} + +bool BatchNode::del(Node * child) +{ + if (child == nullptr) return false; + + // 寻找是否有相同节点 + std::vector::iterator iter; + for (iter = m_vChildren.begin(); iter != m_vChildren.end(); iter++) + { + // 找到相同节点 + if ((*iter) == child) + { + // 对象的引用计数减一 + (*iter)->release(); + // 去掉该节点 + m_vChildren.erase(iter); + return true; + } + } + return false; +} + +int BatchNode::getCount() +{ + return (int)m_vChildren.size(); +} + +std::vector& BatchNode::getChildren() +{ + return m_vChildren; +} + +void BatchNode::clearAllChildren() +{ + // 所有节点的引用计数减一 + for (auto child : m_vChildren) + { + child->autoRelease(); + child->release(); + } + // 清空储存节点的容器 + m_vChildren.clear(); +} + +void BatchNode::setX(int x) +{ + // 计算相对移动位置 + int var = x - getX(); + // 移动所有子节点的位置 + for (auto child : m_vChildren) + { + child->move(var, 0); + } + Node::setX(x); +} + +void BatchNode::setY(int y) +{ + // 计算相对移动位置 + int var = y - getY(); + // 移动所有子节点的位置 + for (auto child : m_vChildren) + { + child->move(0, var); + } + Node::setY(y); +} + +void BatchNode::setPos(int x, int y) +{ + // 计算相对移动位置 + CPoint var(x - getX(), y - getY()); + // 移动所有子节点的位置 + for (auto child : m_vChildren) + { + child->move(var); + } + Node::setPos(x, y); +} + +void BatchNode::setPos(CPoint p) +{ + // 计算相对移动位置 + CPoint var(p - getPos()); + // 移动所有子节点的位置 + for (auto child : m_vChildren) + { + child->move(var); + } + Node::setPos(p); +} + +void BatchNode::move(int x, int y) +{ + // 移动所有子节点的位置 + for (auto child : m_vChildren) + { + child->move(x, y); + } + Node::move(x, y); +} + +void BatchNode::move(CVector v) +{ + // 移动所有子节点的位置 + for (auto child : m_vChildren) + { + child->move(v); + } + Node::move(v); +} diff --git a/Easy2D/v1/Node/BatchSprite.cpp b/Easy2D/v1/Node/BatchSprite.cpp new file mode 100644 index 00000000..edbb9e84 --- /dev/null +++ b/Easy2D/v1/Node/BatchSprite.cpp @@ -0,0 +1,260 @@ +#include "..\easy2d.h" + +BatchSprite::BatchSprite() +{ +} + +BatchSprite::~BatchSprite() +{ +} + +void BatchSprite::addSprite(Sprite * sprite, int z_Order) +{ + if (sprite == nullptr) return; + + // 设置节点的父场景 + sprite->setParentScene(this->getParentScene()); + // 设置节点在批量节点中的 z 轴顺序 + sprite->setZOrder(z_Order); + // 对象的引用计数加一 + sprite->retain(); + + // 按 z 轴顺序插入节点 + size_t size = m_vSprites.size(); + for (unsigned i = 0; i <= size; i++) + { + if (i != size) + { + if (z_Order < m_vSprites.at(i)->getZOrder()) + { + m_vSprites.insert(m_vSprites.begin() + i, sprite); + break; + } + } + else + { + m_vSprites.push_back(sprite); + break; + } + } +} + +bool BatchSprite::delSprite(Sprite * sprite) +{ + if (sprite == nullptr) return false; + + // 寻找是否有相同节点 + std::vector::iterator iter; + for (iter = m_vSprites.begin(); iter != m_vSprites.end(); iter++) + { + // 找到相同节点 + if ((*iter) == sprite) + { + // 对象的引用计数减一 + (*iter)->release(); + // 去掉该节点 + m_vSprites.erase(iter); + return true; + } + } + return false; +} + +int BatchSprite::getCount() +{ + return (int)m_vSprites.size(); +} + +std::vector& BatchSprite::getChildren() +{ + return m_vSprites; +} + +void BatchSprite::clearAllSprites() +{ + // 所有节点的引用计数减一 + for (auto s : m_vSprites) + { + s->release(); + } + // 清空储存节点的容器 + m_vSprites.clear(); +} + +bool BatchSprite::_exec(bool active) +{ + // 批量节点是否显示 + if (!m_bDisplay) + { + return false; + } + // 逆序遍历所有子节点 + for (int i = int(m_vSprites.size() - 1); i >= 0; i--) + { + if (m_vSprites[i]->_exec(active)) + { + active = false; + } + } + // 若子节点取得了画面焦点,则该节点也取得了焦点 + return !active; +} + +void BatchSprite::_onDraw() +{ + // 节点是否显示 + if (!m_bDisplay) + { + return; + } + + // 在相对位置绘制子节点 + for (auto sprite : m_vSprites) + { + // 将子节点移动到相对位置 + sprite->move(getX(), getY()); + // 绘制子节点 + sprite->_onDraw(); + // 将子节点移回原位 + sprite->move(-getX(), -getY()); + } +} + +Sprite * BatchSprite::isCollisionWith(Sprite * sprite) +{ + for (int i = int(m_vSprites.size() - 1); i >= 0; i--) + { + if (m_vSprites[i]->isCollisionWith(sprite)) + { + return m_vSprites[i]; + } + } + return nullptr; +} + +Sprite * BatchSprite::isPointIn(CPoint point) +{ + for (int i = int(m_vSprites.size() - 1); i >= 0; i--) + { + if (m_vSprites[i]->isPointIn(point)) + { + return m_vSprites[i]; + } + } + return nullptr; +} + +void BatchSprite::addAction(Action * action) +{ + Sprite::addAction(action); +} + +float BatchSprite::getScaleX() const +{ + return m_fScaleX; +} + +float BatchSprite::getScaleY() const +{ + return m_fScaleY; +} + +float BatchSprite::getOpacity() const +{ + return m_nAlpha / 255.0f; +} + +void BatchSprite::setScale(float scaleX, float scaleY) +{ + m_fScaleX = scaleX; + m_fScaleY = scaleY; + for (auto s : m_vSprites) + { + s->setScale(scaleX, scaleY); + } +} + +void BatchSprite::setOpacity(float opacity) +{ + m_nAlpha = BYTE(min(max(opacity, 0), 1) * 255); + for (auto s : m_vSprites) + { + s->setOpacity(opacity); + } +} + +void BatchSprite::setImage(Image * image) +{ + for (auto s : m_vSprites) + { + s->setImage(image); + } +} + +void BatchSprite::setX(int x) +{ + // 计算相对移动位置 + int var = x - getX(); + // 移动所有子节点的位置 + for (auto s : m_vSprites) + { + s->move(var, 0); + } + RectNode::setX(x); +} + +void BatchSprite::setY(int y) +{ + // 计算相对移动位置 + int var = y - getY(); + // 移动所有子节点的位置 + for (auto s : m_vSprites) + { + s->move(0, var); + } + RectNode::setY(y); +} + +void BatchSprite::setPos(int x, int y) +{ + // 计算相对移动位置 + CPoint var(x - getX(), y - getY()); + // 移动所有子节点的位置 + for (auto s : m_vSprites) + { + s->move(var); + } + RectNode::setPos(x, y); +} + +void BatchSprite::setPos(CPoint p) +{ + // 计算相对移动位置 + CPoint var(p - getPos()); + // 移动所有子节点的位置 + for (auto s : m_vSprites) + { + s->move(var); + } + RectNode::setPos(p); +} + +void BatchSprite::move(int x, int y) +{ + // 移动所有子节点的位置 + for (auto s : m_vSprites) + { + s->move(x, y); + } + RectNode::move(x, y); +} + +void BatchSprite::move(CVector v) +{ + // 移动所有子节点的位置 + for (auto s : m_vSprites) + { + s->move(v); + } + RectNode::move(v); +} \ No newline at end of file diff --git a/Easy2D/v1/Node/Button/Button.cpp b/Easy2D/v1/Node/Button/Button.cpp new file mode 100644 index 00000000..8044d691 --- /dev/null +++ b/Easy2D/v1/Node/Button/Button.cpp @@ -0,0 +1,80 @@ +#include "..\..\easy2d.h" +#include "..\..\EasyX\easyx.h" + + +Button::Button() : + m_bEnable(true) +{ +} + +Button::~Button() +{ +} + +bool Button::_exec(bool active) +{ + // 按钮是否启用 + if (!m_bEnable) + { + return false; + } + return MouseNode::_exec(active); +} + +void Button::_onDraw() +{ + // 按钮是否启用 + if (!m_bEnable) + { + // 未启用时,绘制 Disable 状态 + _onDisable(); + return; + } + MouseNode::_onDraw(); +} + +bool Button::isEnable() +{ + return m_bEnable; +} + +void Button::setEnable(bool enable) +{ + m_bEnable = enable; +} + +void Button::setX(int x) +{ + MouseNode::setX(x); + _resetPosition(); +} + +void Button::setY(int y) +{ + MouseNode::setY(y); + _resetPosition(); +} + +void Button::setPos(int x, int y) +{ + MouseNode::setPos(x, y); + _resetPosition(); +} + +void Button::setPos(CPoint p) +{ + MouseNode::setPos(p); + _resetPosition(); +} + +void Button::move(int x, int y) +{ + MouseNode::move(x, y); + _resetPosition(); +} + +void Button::move(CVector v) +{ + MouseNode::move(v); + _resetPosition(); +} diff --git a/Easy2D/v1/Node/Button/ImageButton.cpp b/Easy2D/v1/Node/Button/ImageButton.cpp new file mode 100644 index 00000000..824b8113 --- /dev/null +++ b/Easy2D/v1/Node/Button/ImageButton.cpp @@ -0,0 +1,172 @@ +#include "..\..\easy2d.h" + + +ImageButton::ImageButton() : + m_pNormalImage(nullptr), + m_pMouseInImage(nullptr), + m_pSelectedImage(nullptr), + m_pUnableImage(nullptr) +{ +} + +ImageButton::ImageButton(LPCTSTR image) : + ImageButton() +{ + setNormal(new Image(image)); // 设置按钮在正常状态时的图片 +} + +ImageButton::ImageButton(Image * image) : + ImageButton() +{ + setNormal(image); // 设置按钮在正常状态时的图片 +} + +ImageButton::~ImageButton() +{ + // 所有图片的引用计数减一 + SafeRelease(m_pNormalImage); + SafeRelease(m_pMouseInImage); + SafeRelease(m_pSelectedImage); + SafeRelease(m_pUnableImage); +} + +void ImageButton::_setStatus(Status status) +{ + if (m_eStatus != status) + { + if (status == MOUSEIN) + { + if (m_pMouseInImage) setRect(m_pMouseInImage->getRect()); + } + else if (status == SELECTED) + { + if (m_pSelectedImage) setRect(m_pSelectedImage->getRect()); + } + else + { + setRect(m_pNormalImage->getRect()); + } + } + MouseNode::_setStatus(status); +} + +void ImageButton::_onNormal() +{ + if (m_pNormalImage) + { + m_pNormalImage->_onDraw(); + } +} + +void ImageButton::_onMouseIn() +{ + if (m_pMouseInImage) + { + m_pMouseInImage->_onDraw(); + } + else + { + _onNormal(); + } +} + +void ImageButton::_onSelected() +{ + if (m_pSelectedImage) + { + m_pSelectedImage->_onDraw(); + } + else + { + _onNormal(); + } +} + +void ImageButton::_onDisable() +{ + if (m_pUnableImage) + { + m_pUnableImage->_onDraw(); + } + else + { + _onNormal(); + } +} + +void ImageButton::setNormal(Image * image) +{ + if (image) + { + // 原图片引用计数减一 + SafeRelease(m_pNormalImage); + // 修改图片 + m_pNormalImage = image; + // 现图片引用计数加一 + m_pNormalImage->retain(); + // 根据图片宽高设定按钮大小 + setSize(m_pNormalImage->getSize()); + // 重新计算图片位置 + _resetPosition(); + } +} + +void ImageButton::setMouseIn(Image * image) +{ + if (image) + { + SafeRelease(m_pMouseInImage); + m_pMouseInImage = image; + m_pMouseInImage->retain(); + _resetPosition(); + } +} + +void ImageButton::setSelected(Image * image) +{ + if (image) + { + SafeRelease(m_pSelectedImage); + m_pSelectedImage = image; + m_pSelectedImage->retain(); + _resetPosition(); + } +} + +void ImageButton::setUnable(Image * image) +{ + if (image) + { + SafeRelease(m_pUnableImage); + m_pUnableImage = image; + m_pUnableImage->retain(); + _resetPosition(); + } +} + +void ImageButton::_resetPosition() +{ + if (m_pNormalImage) + { + // 根据按钮位置和图片宽高设置图片位置居中显示 + m_pNormalImage->setPos(getX(), getY()); + } + if (m_pMouseInImage) + { + m_pMouseInImage->setPos( + getX() + (getWidth() - m_pMouseInImage->getWidth()) / 2, + getY() + (getHeight() - m_pMouseInImage->getHeight()) / 2); + } + if (m_pSelectedImage) + { + m_pSelectedImage->setPos( + getX() + (getWidth() - m_pSelectedImage->getWidth()) / 2, + getY() + (getHeight() - m_pSelectedImage->getHeight()) / 2); + } + if (m_pUnableImage) + { + m_pUnableImage->setPos( + getX() + (getWidth() - m_pUnableImage->getWidth()) / 2, + getY() + (getHeight() - m_pUnableImage->getHeight()) / 2); + } +} diff --git a/Easy2D/v1/Node/Button/TextButton.cpp b/Easy2D/v1/Node/Button/TextButton.cpp new file mode 100644 index 00000000..fcebafad --- /dev/null +++ b/Easy2D/v1/Node/Button/TextButton.cpp @@ -0,0 +1,172 @@ +#include "..\..\easy2d.h" + + +TextButton::TextButton() : + m_pNormalText(nullptr), + m_pMouseInText(nullptr), + m_pSelectedText(nullptr), + m_pUnableText(nullptr) +{ +} + +TextButton::TextButton(TString text) : + TextButton() +{ + setNormal(new Text(text)); // 设置按钮在正常状态时的文字 +} + +TextButton::TextButton(Text * text) : + TextButton() +{ + setNormal(text); // 设置按钮在正常状态时的文字 +} + +TextButton::~TextButton() +{ + // 所有文本的引用计数减一 + SafeRelease(m_pNormalText); + SafeRelease(m_pMouseInText); + SafeRelease(m_pSelectedText); + SafeRelease(m_pUnableText); +} + +void TextButton::_setStatus(Status status) +{ + if (m_eStatus != status) + { + if (status == MOUSEIN) + { + if (m_pMouseInText) setRect(m_pMouseInText->getRect()); + } + else if (status == SELECTED) + { + if (m_pSelectedText) setRect(m_pSelectedText->getRect()); + } + else + { + setRect(m_pNormalText->getRect()); + } + } + MouseNode::_setStatus(status); +} + +void TextButton::_onNormal() +{ + if (m_pNormalText) + { + m_pNormalText->_onDraw(); + } +} + +void TextButton::_onMouseIn() +{ + if (m_pMouseInText) + { + m_pMouseInText->_onDraw(); + } + else + { + _onNormal(); + } +} + +void TextButton::_onSelected() +{ + if (m_pSelectedText) + { + m_pSelectedText->_onDraw(); + } + else + { + _onNormal(); + } +} + +void TextButton::_onDisable() +{ + if (m_pUnableText) + { + m_pUnableText->_onDraw(); + } + else + { + _onNormal(); + } +} + +void TextButton::setNormal(Text * text) +{ + if (text) + { + // 原文本引用计数减一 + SafeRelease(m_pNormalText); + // 修改文本 + m_pNormalText = text; + // 现文本引用计数加一 + m_pNormalText->retain(); + // 根据文字宽高设定按钮大小 + setSize(m_pNormalText->getSize()); + // 重新计算文本位置 + _resetPosition(); + } +} + +void TextButton::setMouseIn(Text * text) +{ + if (text) + { + SafeRelease(m_pMouseInText); + m_pMouseInText = text; + m_pMouseInText->retain(); + _resetPosition(); + } +} + +void TextButton::setSelected(Text * text) +{ + if (text) + { + SafeRelease(m_pSelectedText); + m_pSelectedText = text; + m_pSelectedText->retain(); + _resetPosition(); + } +} + +void TextButton::setUnable(Text * text) +{ + if (text) + { + SafeRelease(m_pUnableText); + m_pUnableText = text; + m_pUnableText->retain(); + _resetPosition(); + } +} + +void TextButton::_resetPosition() +{ + if (m_pNormalText) + { + // 根据按钮位置和文字宽高设置文字位置居中显示 + m_pNormalText->setPos(getX() , getY()); + } + if (m_pMouseInText) + { + m_pMouseInText->setPos( + getX() + (getWidth() - m_pMouseInText->getWidth()) / 2, + getY() + (getHeight() - m_pMouseInText->getHeight()) / 2); + } + if (m_pSelectedText) + { + m_pSelectedText->setPos( + getX() + (getWidth() - m_pSelectedText->getWidth()) / 2, + getY() + (getHeight() - m_pSelectedText->getHeight()) / 2); + } + if (m_pUnableText) + { + m_pUnableText->setPos( + getX() + (getWidth() - m_pUnableText->getWidth()) / 2, + getY() + (getHeight() - m_pUnableText->getHeight()) / 2); + } +} diff --git a/Easy2D/v1/Node/ENode.cpp b/Easy2D/v1/Node/ENode.cpp new file mode 100644 index 00000000..bc99d68a --- /dev/null +++ b/Easy2D/v1/Node/ENode.cpp @@ -0,0 +1,199 @@ +#include "..\enodes.h" +#include "..\Win\winbase.h" + +e2d::ENode::ENode() + : m_nZOrder(0) + , m_bVisiable(true) +{ +} + +e2d::ENode::ENode(EPoint p) + : ENode() +{ + setPos(p); +} + +e2d::ENode::ENode(int x, int y) + : ENode() +{ + setPos(x, y); +} + +e2d::ENode::~ENode() +{ +} + +bool e2d::ENode::_exec(bool active) +{ + return false; +} + +void e2d::ENode::_onDraw() +{ + D2D1_RECT_F rectangle = D2D1::RectF( + m_Rect.left, + m_Rect.top, + m_Rect.right, + m_Rect.bottom + ); + ID2D1SolidColorBrush* m_pLightSlateGrayBrush; + GetRenderTarget()->CreateSolidColorBrush( + D2D1::ColorF(D2D1::ColorF::LightSlateGray), + &m_pLightSlateGrayBrush + ); + GetRenderTarget()->FillRectangle(&rectangle, m_pLightSlateGrayBrush); +} + +int e2d::ENode::getX() const +{ + if (m_pParent) + { + return m_pParent->getX() + m_Rect.TopLeft().x; + } + return m_Rect.TopLeft().x; +} + +int e2d::ENode::getY() const +{ + if (m_pParent) + { + return m_pParent->getY() + m_Rect.TopLeft().y; + } + return m_Rect.TopLeft().y; +} + +CPoint e2d::ENode::getPos() const +{ + if (m_pParent) + { + return m_pParent->getPos() + m_Rect.TopLeft(); + } + return m_Rect.TopLeft(); +} + +UINT32 e2d::ENode::getWidth() const +{ + return UINT32(m_Rect.Size().cx); +} + +UINT32 e2d::ENode::getHeight() const +{ + return UINT32(m_Rect.Size().cy); +} + +e2d::ESize e2d::ENode::getSize() const +{ + return e2d::ESize(m_Rect.Size()); +} + +e2d::ERect e2d::ENode::getRect() const +{ + return e2d::ERect(m_Rect); +} + +void e2d::ENode::setX(int x) +{ + m_Rect.TopLeft().x = x; +} + +void e2d::ENode::setY(int y) +{ + m_Rect.TopLeft().y = y; +} + +void e2d::ENode::setPos(int x, int y) +{ + m_Rect.TopLeft().SetPoint(x, y); +} + +void e2d::ENode::setPos(EPoint p) +{ + m_Rect.TopLeft() = p; +} + +void e2d::ENode::move(int x, int y) +{ + m_Rect.OffsetRect(x, y); +} + +void e2d::ENode::move(EVector v) +{ + m_Rect.OffsetRect(v); +} + +void e2d::ENode::setWidth(UINT32 width) +{ + m_Rect.BottomRight().x = m_Rect.TopLeft().x + width; +} + +void e2d::ENode::setHeight(UINT32 height) +{ + m_Rect.BottomRight().y = m_Rect.TopLeft().y + height; +} + +void e2d::ENode::setSize(UINT32 width, UINT32 height) +{ + setWidth(width); + setHeight(height); +} + +void e2d::ENode::setSize(e2d::ESize size) +{ + setSize(size.cx, size.cy); +} + +void e2d::ENode::setRect(int x1, int y1, int x2, int y2) +{ + m_Rect.SetRect(x1, y1, x2, y2); +} + +void e2d::ENode::setRect(EPoint leftTop, EPoint rightBottom) +{ + m_Rect.TopLeft() = leftTop; + m_Rect.BottomRight() = rightBottom; +} + +void e2d::ENode::setRect(e2d::ERect rect) +{ + m_Rect = rect; +} + +int e2d::ENode::getZOrder() const +{ + return m_nZOrder; +} + +void e2d::ENode::setZOrder(int z) +{ + m_nZOrder = z; +} + +void e2d::ENode::setParent(e2d::ENode * parent) +{ + m_pParent = parent; +} + +e2d::ENode *& e2d::ENode::getParent() +{ + return m_pParent; +} + +e2d::EScene * &e2d::ENode::getParentScene() +{ + return m_pParentScene; +} + +void e2d::ENode::setParentScene(e2d::EScene * scene) +{ + m_pParentScene = scene; +} + +void e2d::ENode::setVisiable(bool value) +{ + m_bVisiable = value; +} + +bool e2d::ENode::isVisiable() const +{ + return m_bVisiable; +} \ No newline at end of file diff --git a/Easy2D/v1/Node/Image.cpp b/Easy2D/v1/Node/Image.cpp new file mode 100644 index 00000000..83b8a0b7 --- /dev/null +++ b/Easy2D/v1/Node/Image.cpp @@ -0,0 +1,251 @@ +#include "..\easy2d.h" +#include "..\EasyX\easyx.h" +#include +using namespace std; + +// 图片缓存 +static map s_mCImages; +// 从图片缓存中读取图片 +static CImage* GetCImage(TString name, bool fromRes = false); +// 对 PNG 图像进行像素转换 +static void CrossImage(CImage &img); + + +Image::Image() : + m_pCImage(nullptr), + m_nAlpha(255), + m_fScaleX(1), + m_fScaleY(1) +{ +} + +Image::Image(LPCTSTR ImageFile) : + Image() +{ + setImage(ImageFile); // 设置图片资源 +} + +Image::Image(LPCTSTR ImageFile, int x, int y, int width, int height) : + Image() +{ + setImage(ImageFile, x, y, width, height); // 设置图片资源和裁剪大小 +} + +Image::~Image() +{ +} + +void Image::_onDraw() +{ + // display 属性为 false,或未设置图片资源时,不绘制该图片 + if (!m_bDisplay || !m_pCImage) + { + return; + } + // 绘制图片 + if (m_pCImage->GetBPP() == 32) + { + m_pCImage->AlphaBlend(GetImageHDC(), m_Rect, m_SrcRect, m_nAlpha, AC_SRC_OVER); + } + else + { + m_pCImage->Draw(GetImageHDC(), m_Rect, m_SrcRect); + } +} + +float Image::getScaleX() const +{ + return m_fScaleX; +} + +float Image::getScaleY() const +{ + return m_fScaleY; +} + +float Image::getOpacity() const +{ + return m_nAlpha / 255.0f; +} + +bool Image::setImage(LPCTSTR ImageFile) +{ + m_pCImage = GetCImage(ImageFile); + if (m_pCImage) + { + reset(); + return true; + } + return false; +} + +bool Image::setImage(LPCTSTR ImageFile, int x, int y, int width, int height) +{ + if (!setImage(ImageFile)) + { + return false; + } + // 裁剪图片大小 + crop(x, y, width, height); + + return true; +} + +bool Image::setImageFromRes(LPCTSTR pResName) +{ + m_pCImage = GetCImage(pResName, true); + if (m_pCImage) + { + reset(); + return true; + } + return false; +} + +bool Image::setImageFromRes(LPCTSTR pResName, int x, int y, int width, int height) +{ + if (!setImageFromRes(pResName)) + { + return false; + } + // 裁剪图片大小 + crop(x, y, width, height); + + return true; +} + +void Image::crop(int x, int y, int width, int height) +{ + width = min(max(width, 0), m_pCImage->GetWidth() - x); + height = min(max(height, 0), m_pCImage->GetHeight() - y); + // 设置源矩形的位置和大小(用于裁剪) + m_SrcRect.SetRect(x, y, x + width, y + height); + // 设置目标矩形(即绘制到窗口的位置和大小) + setSize(int(width * m_fScaleX), int(height * m_fScaleY)); +} + +void Image::stretch(int width, int height) +{ + // 设置目标矩形的位置和大小(即绘制到窗口的位置和大小,用于拉伸图片) + setSize(max(width, 0), max(height, 0)); + // 重置比例缩放属性 + m_fScaleX = 1; + m_fScaleY = 1; +} + +void Image::setScale(float scaleX, float scaleY) +{ + m_fScaleX = max(scaleX, 0); + m_fScaleY = max(scaleY, 0); + setSize(int(m_SrcRect.Width() * scaleX), int(m_SrcRect.Height() * scaleY)); +} + +void Image::setOpacity(float value) +{ + if (m_pCImage->GetBPP() == 32) + { + m_nAlpha = BYTE(min(max(value, 0), 1) * 255); + } +} + +void Image::setTransparentColor(COLORREF value) +{ + // 设置透明色 + m_pCImage->SetTransparentColor(value); +} + +void Image::reset() +{ + // 设置目标矩形(即绘制到窗口的位置和大小) + setSize(m_pCImage->GetWidth(), m_pCImage->GetHeight()); + // 设置源矩形(即截取图片的大小) + m_SrcRect.SetRect(0, 0, m_pCImage->GetWidth(), m_pCImage->GetHeight()); + // 重置缩放属性 + m_fScaleX = 1; + m_fScaleY = 1; + // 重置透明度 + m_nAlpha = 255; +} + +bool Image::preload(LPCTSTR fileName, bool fromRes) +{ + // 判断图片是否已经加载 + if (s_mCImages.find(fileName) != s_mCImages.end()) + { + return true; + } + // 加载图片 + CImage* cImage = nullptr; + if (fromRes) + { + cImage = new CImage(); + // 从资源加载图片(不支持 PNG) + cImage->LoadFromResource(GetModuleHandle(NULL), fileName); + } + else + { + //判断图片路径是否存在 + if (!PathFileExists(fileName)) + { + return false; + } + cImage = new CImage(); + cImage->Load(fileName); + } + // 加载失败 + if (!cImage || cImage->IsNull()) + { + return false; + } + // 确认该图像包含 Alpha 通道 + if (cImage->GetBPP() == 32) + { + // 透明图片处理 + CrossImage(*cImage); + } + s_mCImages.insert(map::value_type(fileName, cImage)); + + return true; +} + +void Image::saveScreenshot() +{ + TString savePath; + // 获取保存位置 + if (FileUtils::getSaveFilePath(savePath, _T("截图保存到"), _T("jpg"))) + { + // 保存窗口截图 + IMAGE image; + getimage(&image, 0, 0, EApp::getWidth(), EApp::getHeight()); + saveimage(savePath.c_str(), &image); + } +} + + +// 对 PNG 图像进行像素转换 +void CrossImage(CImage &img) +{ + // 进行像素转换 + for (int i = 0; i < img.GetWidth(); i++) + { + for (int j = 0; j < img.GetHeight(); j++) + { + UCHAR *cr = (UCHAR*)img.GetPixelAddress(i, j); + cr[0] = cr[0] * cr[3] / 255; + cr[1] = cr[1] * cr[3] / 255; + cr[2] = cr[2] * cr[3] / 255; + } + } +} + +CImage* GetCImage(TString name, bool fromRes) +{ + if (Image::preload(name.c_str())) + { + return s_mCImages.at(name); + } + else + { + return nullptr; + } +} \ No newline at end of file diff --git a/Easy2D/v1/Node/Layer.cpp b/Easy2D/v1/Node/Layer.cpp new file mode 100644 index 00000000..85c5e2e1 --- /dev/null +++ b/Easy2D/v1/Node/Layer.cpp @@ -0,0 +1,27 @@ +#include "..\easy2d.h" + + +Layer::Layer() : + m_bBlock(true) +{ +} + +Layer::~Layer() +{ +} + +int Layer::getBlock() const +{ + return m_bBlock; +} + +void Layer::setBlock(bool block) +{ + m_bBlock = block; +} + +bool Layer::_exec(bool active) +{ + // 若图层阻塞消息,则永远取得画面焦点 + return BatchNode::_exec(active) || m_bBlock; +} diff --git a/Easy2D/v1/Node/MouseNode.cpp b/Easy2D/v1/Node/MouseNode.cpp new file mode 100644 index 00000000..3ef74b2d --- /dev/null +++ b/Easy2D/v1/Node/MouseNode.cpp @@ -0,0 +1,174 @@ +#include "..\easy2d.h" + + +MouseNode::MouseNode() : + m_bBlock(true), + m_bTarget(false), + m_ClickCallback([]() {}), + m_OnMouseInCallback([]() {}), + m_OnMouseOutCallback([]() {}), + m_OnSelectCallback([]() {}), + m_OnUnselectCallback([]() {}) +{ +} + +MouseNode::~MouseNode() +{ +} + +bool MouseNode::_exec(bool active) +{ + // 若 display 属性为 false,退出函数 + if (!m_bDisplay) + { + return false; + } + // 若画面已取得焦点,重置按钮属性并退出 + if (!active) + { + reset(); + return false; + } + // 判断节点当前的状态 + // 若节点未取得焦点,则重新判断节点状态 + if (!m_bTarget) + { + // 若鼠标位置在节点所在的矩形区域中 + if (_isMouseIn()) + { + // 状态设为 MOUSEIN + _setStatus(MOUSEIN); + // 若此时按下鼠标左键 + if (MouseMsg::getMsg() == MouseMsg::LBUTTON_DOWN) + { + m_bTarget = true; // 取得焦点标记 + _setStatus(SELECTED); // 状态设为 SELECTED + } + // 若节点阻塞鼠标消息,则取得画面焦点 + if (m_bBlock) return true; + } + else + { + reset(); // 恢复默认状态 + } + } + else + { + // 节点取得焦点时鼠标左键抬起 + if (MouseMsg::getMsg() == MouseMsg::LBUTTON_UP) + { + // 若左键抬起时鼠标仍在节点内 + if (_isMouseIn()) + { + m_ClickCallback(); // 执行回调函数 + } + reset(); // 恢复默认状态 + } + // 若节点阻塞鼠标消息,则取得画面焦点 + if (m_bBlock) return true; + } + return false; +} + +void MouseNode::_onDraw() +{ + // 节点是否显示 + if (!m_bDisplay) + { + return; + } + // 节点是否被选中 + if (m_eStatus == SELECTED) + { + _onSelected(); + } + else + { + // 鼠标是否在节点上 + if (m_eStatus == MOUSEIN) + { + _onMouseIn(); + } + else + { + _onNormal(); + } + } +} + +bool MouseNode::_isMouseIn() +{ + return isPointIn(MouseMsg::getPos()); +} + +void MouseNode::_setStatus(Status status) +{ + if (m_eStatus != status) + { + // 退出某个状态的回调函数 + if (m_eStatus == MOUSEIN) + { + m_OnMouseOutCallback(); + } + else if (m_eStatus == SELECTED) + { + m_OnUnselectCallback(); + } + // 进入某个状态的回调函数 + if (status == MOUSEIN) + { + m_OnMouseInCallback(); + } + else if (status == SELECTED) + { + m_OnSelectCallback(); + } + m_eStatus = status; + } +} + +bool MouseNode::isMouseIn() +{ + return m_eStatus == MOUSEIN || m_eStatus == SELECTED; +} + +bool MouseNode::isSelected() +{ + return m_eStatus == SELECTED; +} + +void MouseNode::setClickedCallback(const CLICK_CALLBACK & callback) +{ + m_ClickCallback = callback; +} + +void MouseNode::setMouseInCallback(const CLICK_CALLBACK & callback) +{ + m_OnMouseInCallback = callback; +} + +void MouseNode::setMouseOutCallback(const CLICK_CALLBACK & callback) +{ + m_OnMouseOutCallback = callback; +} + +void MouseNode::setSelectCallback(const CLICK_CALLBACK & callback) +{ + m_OnSelectCallback = callback; +} + +void MouseNode::setUnselectCallback(const CLICK_CALLBACK & callback) +{ + m_OnUnselectCallback = callback; +} + +void MouseNode::reset() +{ + m_bTarget = false; // 失去焦点标记 + _setStatus(NORMAL); // 恢复默认状态 +} + +void MouseNode::setBlock(bool block) +{ + m_bBlock = block; +} diff --git a/Easy2D/v1/Node/RectNode.cpp b/Easy2D/v1/Node/RectNode.cpp new file mode 100644 index 00000000..ba5854da --- /dev/null +++ b/Easy2D/v1/Node/RectNode.cpp @@ -0,0 +1,139 @@ +#include "..\easy2d.h" + +RectNode::RectNode() : + m_Rect(0, 0, 0, 0) +{ + +} + +RectNode::~RectNode() +{ +} + +bool RectNode::isCollisionWith(RectNode * rectNode) const +{ + static CRect rt; + return IntersectRect(&rt, &m_Rect, &rectNode->m_Rect); +} + +bool RectNode::isPointIn(CPoint p) const +{ + return m_Rect.PtInRect(p); +} + +void RectNode::setWindowCenterX() +{ + setX((EApp::getWidth() - getWidth()) / 2); +} + +void RectNode::setWindowCenterY() +{ + setY((EApp::getHeight() - getHeight()) / 2); +} + +void RectNode::setWindowCenter() +{ + setWindowCenterX(); + setWindowCenterY(); +} + +int RectNode::getX() const +{ + return m_Rect.left; +} + +int RectNode::getY() const +{ + return m_Rect.top; +} + +CPoint RectNode::getPos() const +{ + return m_Rect.TopLeft(); +} + +int RectNode::getWidth() const +{ + return m_Rect.Width(); // 矩形宽度 +} + +int RectNode::getHeight() const +{ + return m_Rect.Height(); // 矩形高度 +} + +CSize RectNode::getSize() const +{ + return m_Rect.Size(); +} + +CRect RectNode::getRect() const +{ + return m_Rect; +} + +void RectNode::setX(int x) +{ + m_Rect.MoveToX(x); +} + +void RectNode::setY(int y) +{ + m_Rect.MoveToY(y); +} + +void RectNode::setPos(int x, int y) +{ + m_Rect.MoveToXY(x, y); // 修改矩形位置 +} + +void RectNode::setPos(CPoint p) +{ + m_Rect.MoveToXY(p); // 修改矩形位置 +} + +void RectNode::move(int x, int y) +{ + m_Rect.OffsetRect(x, y); // 移动矩形 +} + +void RectNode::move(CVector v) +{ + m_Rect.OffsetRect(v); // 移动矩形 +} + +void RectNode::setWidth(int width) +{ + m_Rect.right = max(m_Rect.left + width, 0); +} + +void RectNode::setHeight(int height) +{ + m_Rect.bottom = max(m_Rect.top + height, 0); +} + +void RectNode::setSize(int width, int height) +{ + setWidth(width); + setHeight(height); +} + +void RectNode::setSize(CSize size) +{ + setSize(size.cx, size.cy); +} + +void RectNode::setRect(int x1, int y1, int x2, int y2) +{ + m_Rect.SetRect(x1, y1, x2, y2); +} + +void RectNode::setRect(CPoint leftTop, CPoint rightBottom) +{ + m_Rect.SetRect(leftTop, rightBottom); +} + +void RectNode::setRect(CRect rect) +{ + m_Rect.CopyRect(&rect); +} diff --git a/Easy2D/v1/Node/Shape/Circle.cpp b/Easy2D/v1/Node/Shape/Circle.cpp new file mode 100644 index 00000000..a8e1c3e6 --- /dev/null +++ b/Easy2D/v1/Node/Shape/Circle.cpp @@ -0,0 +1,43 @@ +#include "..\..\easy2d.h" +#include "..\..\EasyX\easyx.h" + + +Circle::Circle() : + m_nRadius(0) +{ +} + +Circle::Circle(int x, int y, int radius) : + m_nRadius(radius) +{ + setPos(x, y); +} + +Circle::~Circle() +{ +} + +void Circle::solidShape() +{ + solidcircle(getX(), getY(), m_nRadius); +} + +void Circle::fillShape() +{ + fillcircle(getX(), getY(), m_nRadius); +} + +void Circle::roundShape() +{ + circle(getX(), getY(), m_nRadius); +} + +int Circle::getRadius() const +{ + return m_nRadius; +} + +void Circle::setRadius(int r) +{ + m_nRadius = r; +} \ No newline at end of file diff --git a/Easy2D/v1/Node/Shape/Rectangle.cpp b/Easy2D/v1/Node/Shape/Rectangle.cpp new file mode 100644 index 00000000..854163d2 --- /dev/null +++ b/Easy2D/v1/Node/Shape/Rectangle.cpp @@ -0,0 +1,58 @@ +#include "..\..\easy2d.h" +#include "..\..\EasyX\easyx.h" + + +Rect::Rect() +{ +} + +Rect::Rect(int x, int y, int width, int height) : + m_Size(width, height) +{ + setPos(x, y); +} + +Rect::~Rect() +{ +} + +void Rect::solidShape() +{ + solidrectangle(getX(), getY(), getX() + m_Size.cx, getY() + m_Size.cy); +} + +void Rect::fillShape() +{ + fillrectangle(getX(), getY(), getX() + m_Size.cx, getY() + m_Size.cy); +} + +void Rect::roundShape() +{ + rectangle(getX(), getY(), getX() + m_Size.cx, getY() + m_Size.cy); +} + +int Rect::getWidth() const +{ + return m_Size.cx; +} + +int Rect::getHeight() const +{ + return m_Size.cy; +} + +void Rect::setWidth(int width) +{ + m_Size.cx = width; +} + +void Rect::setHeight(int height) +{ + m_Size.cy = height; +} + +void Rect::setSize(int width, int height) +{ + m_Size.cx = width; + m_Size.cy = height; +} \ No newline at end of file diff --git a/Easy2D/v1/Node/Shape/Shape.cpp b/Easy2D/v1/Node/Shape/Shape.cpp new file mode 100644 index 00000000..f0747499 --- /dev/null +++ b/Easy2D/v1/Node/Shape/Shape.cpp @@ -0,0 +1,64 @@ +#include "..\..\easy2d.h" +#include "..\..\EasyX\easyx.h" + +Shape::Shape() : + lineColor(Color::black), + fillColor(Color::white), + m_eStyle(SOLID) +{ +} + +Shape::~Shape() +{ +} + +void Shape::_onDraw() +{ + // 形状是否显示 + if (!m_bDisplay) + { + return; + } + // 设置线条和填充颜色 + setlinecolor(lineColor); + setfillcolor(fillColor); + + // 根据形状的样式进行不同的绘制 + if (m_eStyle == Shape::STYLE::ROUND) + { + roundShape(); + } + else if (m_eStyle == Shape::STYLE::SOLID) + { + solidShape(); + } + else if (m_eStyle == Shape::STYLE::FILL) + { + fillShape(); + } +} + +inline COLORREF Shape::getFillColor() const +{ + return fillColor; +} + +inline COLORREF Shape::getLineColor() const +{ + return lineColor; +} + +void Shape::setFillColor(COLORREF color) +{ + fillColor = color; +} + +void Shape::setLineColor(COLORREF color) +{ + lineColor = color; +} + +void Shape::setStyle(STYLE style) +{ + m_eStyle = style; +} diff --git a/Easy2D/v1/Node/Sprite.cpp b/Easy2D/v1/Node/Sprite.cpp new file mode 100644 index 00000000..870dd868 --- /dev/null +++ b/Easy2D/v1/Node/Sprite.cpp @@ -0,0 +1,147 @@ +#include "..\easy2d.h" +#include "..\EasyX\easyx.h" + +Sprite::Sprite() : + m_nAlpha(255), + m_fScaleX(1), + m_fScaleY(1), + m_pImage(nullptr) +{ + +} + +Sprite::Sprite(Image * image) : + Sprite() +{ + setImage(image); +} + +Sprite::Sprite(LPCTSTR imageFileName) : + Sprite() +{ + setImage(new Image(imageFileName)); +} + +Sprite::~Sprite() +{ + SafeRelease(m_pImage); +} + +bool Sprite::_exec(bool active) +{ + return false; +} + +void Sprite::_onDraw() +{ + // display 属性为 false,或未设置图片资源时,不绘制该图片 + if (!m_bDisplay || !m_pImage || !m_pImage->m_pCImage) + { + return; + } + // 绘制图片 + if (m_pImage->m_pCImage->GetBPP() == 32) + { + m_pImage->m_pCImage->AlphaBlend(GetImageHDC(), getRect(), m_pImage->m_SrcRect, m_nAlpha, AC_SRC_OVER); + } + else + { + m_pImage->m_pCImage->Draw(GetImageHDC(), getRect(), m_pImage->m_SrcRect); + } +} + +void Sprite::setImage(Image * image) +{ + SafeRelease(m_pImage); + m_pImage = image; + setSize(int(m_pImage->getWidth() * m_fScaleX), int(m_pImage->getHeight() * m_fScaleY)); + m_pImage->retain(); +} + +bool Sprite::isCollisionWith(Sprite * sprite) +{ + static CRect rt; + return IntersectRect(&rt, &getRect(), &sprite->getRect()); +} + +void Sprite::addAction(Action * action) +{ + if (action) + { + // 将动作与 Sprite 绑定 + action->m_pTargetSprite = this; + // 将动作加入动作管理器,管理器会处理这个动作 + ActionManager::addAction(action); + } +} + +void Sprite::runAction(Action * action) +{ + addAction(action); +} + +void Sprite::resumeAction(Action * action) +{ + if (action->getTarget() == this) + { + ActionManager::resumeAction(action); + } +} + +void Sprite::pauseAction(Action * action) +{ + if (action->getTarget() == this) + { + ActionManager::pauseAction(action); + } +} + +void Sprite::stopAction(Action * action) +{ + if (action->getTarget() == this) + { + ActionManager::stopAction(action); + } +} + +void Sprite::pauseAllActions() +{ + ActionManager::pauseSpriteAllActions(this); +} + +void Sprite::resumeAllActions() +{ + ActionManager::resumeSpriteAllActions(this); +} + +void Sprite::stopAllActions() +{ + ActionManager::stopSpriteAllActions(this); +} + +float Sprite::getScaleX() const +{ + return m_fScaleX; +} + +float Sprite::getScaleY() const +{ + return m_fScaleY; +} + +float Sprite::getOpacity() const +{ + return m_nAlpha / 255.0f; +} + +void Sprite::setScale(float scaleX, float scaleY) +{ + m_fScaleX = max(scaleX, 0); + m_fScaleY = max(scaleY, 0); + setSize(int(m_pImage->getWidth() * scaleX), int(m_pImage->getHeight() * scaleY)); +} + +void Sprite::setOpacity(float opacity) +{ + m_nAlpha = BYTE(min(max(opacity, 0), 1) * 255); +} diff --git a/Easy2D/v1/Node/Text.cpp b/Easy2D/v1/Node/Text.cpp new file mode 100644 index 00000000..607eb328 --- /dev/null +++ b/Easy2D/v1/Node/Text.cpp @@ -0,0 +1,91 @@ +#include "..\easy2d.h" +#include "..\EasyX\easyx.h" + + +Text::Text() : + m_sText(_T("")), + m_color(Color::white), + m_pFontStyle(FontStyle::getDefault()) +{ + m_pFontStyle->retain(); // 字体引用计数加一 +} + +Text::Text(TString text, COLORREF color, FontStyle * font) : + m_color(color), + m_pFontStyle(font) +{ + setText(text); + m_pFontStyle->retain(); // 字体引用计数加一 +} + +Text::Text(int x, int y, TString text, COLORREF color, FontStyle * font) : + m_color(color), + m_pFontStyle(font) +{ + setText(text); + setPos(x, y); + m_pFontStyle->retain(); // 字体引用计数加一 +} + +Text::~Text() +{ + SafeRelease(m_pFontStyle); // 字体引用计数减一 +} + +void Text::_onDraw() +{ + // 若 display 属性为 false,不绘制这个文本 + if (!m_bDisplay) + { + return; + } + // 设置字体 + settextstyle(&m_pFontStyle->m_font); + // 设置文本颜色 + settextcolor(m_color); + // 输出文字 + outtextxy(getX(), getY(), m_sText.c_str()); +} + +COLORREF Text::getColor() const +{ + return m_color; +} + +TString Text::getText() const +{ + return m_sText; +} + +FontStyle * Text::getFontStyle() +{ + return m_pFontStyle; +} + +bool Text::isEmpty() const +{ + return m_sText.empty(); // 文本是否为空 +} + +void Text::setText(TString text) +{ + m_sText = text; + // 先设置字体,然后获取该文本在该字体下的宽度和高度 + settextstyle(&m_pFontStyle->m_font); + setSize(textwidth(getText().c_str()), textheight(getText().c_str())); +} + +void Text::setColor(COLORREF color) +{ + m_color = color; +} + +void Text::setFontStyle(FontStyle * style) +{ + SafeRelease(m_pFontStyle); // 原字体引用计数减一 + m_pFontStyle = style; // 修改字体 + m_pFontStyle->retain(); // 现字体引用计数加一 + // 先设置字体,然后获取该文本在该字体下的宽度和高度 + settextstyle(&m_pFontStyle->m_font); + setSize(textwidth(getText().c_str()), textheight(getText().c_str())); +} diff --git a/Easy2D/v1/Style/Color.cpp b/Easy2D/v1/Style/Color.cpp new file mode 100644 index 00000000..c14aa401 --- /dev/null +++ b/Easy2D/v1/Style/Color.cpp @@ -0,0 +1,56 @@ +#include "..\easy2d.h" +#include "..\EasyX\easyx.h" + +// 常用颜色值的定义 +const COLORREF Color::black = BLACK; +const COLORREF Color::blue = BLUE; +const COLORREF Color::green = GREEN; +const COLORREF Color::cyan = CYAN; +const COLORREF Color::red = RED; +const COLORREF Color::magenta = MAGENTA; +const COLORREF Color::brown = BROWN; +const COLORREF Color::lightgray = LIGHTGRAY; +const COLORREF Color::darkgray = DARKGRAY; +const COLORREF Color::lightblue = LIGHTBLUE; +const COLORREF Color::lightgreen = LIGHTGREEN; +const COLORREF Color::lightcyan = LIGHTCYAN; +const COLORREF Color::lightred = LIGHTRED; +const COLORREF Color::lightmagenta = LIGHTMAGENTA; +const COLORREF Color::yellow = YELLOW; +const COLORREF Color::white = WHITE; + + +COLORREF Color::getFromRGB(BYTE r, BYTE g, BYTE b) +{ + return RGB(r, g, b); // 从 (r, g, b) 三色值转化为颜色 +} + +COLORREF Color::getFromHSL(float H, float S, float L) +{ + return HSLtoRGB(H, S, L); +} + +COLORREF Color::getFromHSV(float H, float S, float V) +{ + return HSVtoRGB(H, S, V); +} + +BYTE Color::getRValue(COLORREF color) +{ + return GetRValue(color); // 返回颜色中的红色值 +} + +BYTE Color::getGValue(COLORREF color) +{ + return GetGValue(color); // 返回颜色中的绿色值 +} + +BYTE Color::getBValue(COLORREF color) +{ + return GetBValue(color); // 返回颜色中的蓝色值 +} + +COLORREF Color::getGray(COLORREF color) +{ + return RGBtoGRAY(color); // 获取颜色中的灰度值 +} diff --git a/Easy2D/v1/Style/FillStyle.cpp b/Easy2D/v1/Style/FillStyle.cpp new file mode 100644 index 00000000..498580d5 --- /dev/null +++ b/Easy2D/v1/Style/FillStyle.cpp @@ -0,0 +1 @@ +/* FillStyle 是 EasyX 中的类,目前尚未考虑实现 */ \ No newline at end of file diff --git a/Easy2D/v1/Style/FontStyle.cpp b/Easy2D/v1/Style/FontStyle.cpp new file mode 100644 index 00000000..2c5c69ba --- /dev/null +++ b/Easy2D/v1/Style/FontStyle.cpp @@ -0,0 +1,103 @@ +#include "..\easy2d.h" + +// 常用字体粗细值的定义 +const LONG FontWeight::dontcare = 0; +const LONG FontWeight::thin = 100; +const LONG FontWeight::extraLight = 200; +const LONG FontWeight::light = 300; +const LONG FontWeight::normal = 400; +const LONG FontWeight::regular = 400; +const LONG FontWeight::medium = 500; +const LONG FontWeight::demiBlod = 600; +const LONG FontWeight::blod = 700; +const LONG FontWeight::extraBold = 800; +const LONG FontWeight::black = 900; +const LONG FontWeight::heavy = 900; + + +FontStyle::FontStyle() +{ + setFontFamily(_T("")); + m_font.lfWeight = 18; + m_font.lfHeight = 0; + m_font.lfWidth = 0; + m_font.lfItalic = 0; + m_font.lfUnderline = 0; + m_font.lfStrikeOut = 0; + m_font.lfEscapement = 0; + m_font.lfOrientation = 0; + setQuality(true); +} + +FontStyle::FontStyle(LPCTSTR fontfamily, LONG height, LONG weight, LONG width, bool italic, bool underline, bool strikeout, LONG escapement, LONG orientation, bool quality) +{ + setFontFamily(fontfamily); + m_font.lfWeight = weight; + m_font.lfHeight = height; + m_font.lfWidth = width; + m_font.lfItalic = italic; + m_font.lfUnderline = underline; + m_font.lfStrikeOut = strikeout; + m_font.lfEscapement = escapement; + m_font.lfOrientation = orientation; + setQuality(quality); +} + +FontStyle::~FontStyle() +{ +} + +FontStyle * FontStyle::getDefault() +{ + return new FontStyle(_T(""), 18, FontWeight::normal); +} + +void FontStyle::setHeight(LONG value) +{ + m_font.lfHeight = value; +} + +void FontStyle::setWidth(LONG value) +{ + m_font.lfWidth = value; +} + +void FontStyle::setFontFamily(LPCTSTR value) +{ + _tcscpy_s(m_font.lfFaceName, 32, value); +} + +void FontStyle::setEscapement(LONG value) +{ + m_font.lfEscapement = value; +} + +void FontStyle::setOrientation(LONG value) +{ + m_font.lfOrientation = value; +} + +void FontStyle::setQuality(bool value) +{ + m_font.lfQuality = value ? ANTIALIASED_QUALITY : DEFAULT_QUALITY; +} + +void FontStyle::setWeight(LONG value) +{ + m_font.lfWeight = value; +} + +void FontStyle::setItalic(bool value) +{ + m_font.lfItalic = value; +} + +void FontStyle::setUnderline(bool value) +{ + m_font.lfUnderline = value; +} + +void FontStyle::setStrikeOut(bool value) +{ + m_font.lfStrikeOut = value; +} \ No newline at end of file diff --git a/Easy2D/v1/Style/LineStyle.cpp b/Easy2D/v1/Style/LineStyle.cpp new file mode 100644 index 00000000..1b613360 --- /dev/null +++ b/Easy2D/v1/Style/LineStyle.cpp @@ -0,0 +1 @@ +/* LineStyle 是 EasyX 中的类,目前尚未考虑实现 */ \ No newline at end of file diff --git a/Easy2D/v1/Tool/ActionManager.cpp b/Easy2D/v1/Tool/ActionManager.cpp new file mode 100644 index 00000000..f9f62b6e --- /dev/null +++ b/Easy2D/v1/Tool/ActionManager.cpp @@ -0,0 +1,200 @@ +#include "..\easy2d.h" +#include "..\Win\winbase.h" +#include + +static std::vector s_vActions; + +void ActionManager::__exec() +{ + // 临时指针 + static Action * action; + // 循环遍历所有正在运行的动作 + for (size_t i = 0; i < s_vActions.size(); i++) + { + action = s_vActions[i]; + // 获取动作运行状态 + if (action->isRunning()) + { + if (action->isEnding()) + { + // 动作已经结束 + action->autoRelease(); + action->release(); + s_vActions.erase(s_vActions.begin() + i); + } + else + { + // 初始化动作 + if (!action->m_bInit) + { + action->_init(); + } + // 执行动作 + action->_exec(GetNow()); + } + } + } +} + +void ActionManager::addAction(Action * action) +{ + if (action) + { +#ifdef _DEBUG + for (auto a : s_vActions) + { + assert(a != action); + } +#endif + action->m_pParentScene = EApp::getLoadingScene(); + s_vActions.push_back(action); + } +} + +void ActionManager::notifyAllSceneActions(EScene * scene) +{ + for (auto action : s_vActions) + { + if (action->m_pParentScene == scene) + { + action->notify(); + } + } +} + +void ActionManager::waitAllSceneActions(EScene * scene) +{ + for (auto action : s_vActions) + { + if (action->m_pParentScene == scene) + { + action->wait(); + } + } +} + +void ActionManager::stopAllSceneActions(EScene * scene) +{ + for (auto action : s_vActions) + { + if (action->m_pParentScene == scene) + { + action->stop(); + } + } +} + +void ActionManager::startAction(Action * action) +{ + resumeAction(action); +} + +void ActionManager::resumeAction(Action * action) +{ + for (auto act : s_vActions) + { + if (act == action) + { + act->resume(); + } + } +} + +void ActionManager::pauseAction(Action * action) +{ + for (auto act : s_vActions) + { + if (act == action) + { + act->pause(); + } + } +} + +void ActionManager::stopAction(Action * action) +{ + for (auto act : s_vActions) + { + if (act == action) + { + act->stop(); + } + } +} + +void ActionManager::startSpriteAllActions(Sprite * sprite) +{ + resumeSpriteAllActions(sprite); +} + +void ActionManager::resumeSpriteAllActions(Sprite * sprite) +{ + for (auto action : s_vActions) + { + if (action->m_pTargetSprite == sprite) + { + action->resume(); + } + } +} + +void ActionManager::pauseSpriteAllActions(Sprite * sprite) +{ + for (auto action : s_vActions) + { + if (action->m_pTargetSprite == sprite) + { + action->pause(); + } + } +} + +void ActionManager::stopSpriteAllActions(Sprite * sprite) +{ + for (auto action : s_vActions) + { + if (action->m_pTargetSprite == sprite) + { + action->stop(); + } + } +} + +void ActionManager::startAllActions() +{ + resumeAllActions(); +} + +void ActionManager::resumeAllActions() +{ + for (auto action : s_vActions) + { + action->resume(); + } +} + +void ActionManager::pauseAllActions() +{ + for (auto action : s_vActions) + { + action->pause(); + } +} + +void ActionManager::stopAllActions() +{ + for (auto action : s_vActions) + { + action->stop(); + } +} + +void ActionManager::clearAllActions() +{ + for (auto action : s_vActions) + { + action->autoRelease(); + action->release(); + } + s_vActions.clear(); +} diff --git a/Easy2D/v1/Tool/EObjectManager.cpp b/Easy2D/v1/Tool/EObjectManager.cpp new file mode 100644 index 00000000..acf65928 --- /dev/null +++ b/Easy2D/v1/Tool/EObjectManager.cpp @@ -0,0 +1,51 @@ +#include "..\etools.h" +#include + +// EObjectManager 释放池的实现机制: +/// EObject 类中的引用计数(m_nRefCount)保证了指针的使用安全 +/// 它记录了对象被使用的次数,当计数为 0 时,EObjectManager 会自动释放这个对象 +/// 所有的 EObject 对象都应在被使用时(例如 Text 添加到了场景中) +/// 调用 retain 函数保证该对象不被删除,并在不再使用时调用 release 函数 +/// 让其自动释放 + +// 释放池容器 +static std::vector s_vPool; + +void e2d::EObjectManager::__flush() +{ + // 创建迭代器 + static std::vector::iterator iter; + // 循环遍历容器中的所有对象 + for (iter = s_vPool.begin(); iter != s_vPool.end();) + { + if ((*iter)->m_bAutoRelease && (*iter)->m_nRefCount == 0) + { + // 若对象的引用的计数为 0, 释放该对象 + delete (*iter); + // 从释放池中删除该对象 + iter = s_vPool.erase(iter); + } + else + { + iter++; // 移动迭代器 + } + } +} + +void e2d::EObjectManager::add(e2d::EObject * nptr) +{ + if (!nptr->m_bManaged) + { + nptr->m_bManaged = true; + s_vPool.push_back(nptr); // 将一个对象放入释放池中 + } +} + +void e2d::EObjectManager::clearAllObjects() +{ + for (auto o : s_vPool) + { + delete o; + } + s_vPool.clear(); +} diff --git a/Easy2D/v1/Tool/FileUtils.cpp b/Easy2D/v1/Tool/FileUtils.cpp new file mode 100644 index 00000000..0c14dec6 --- /dev/null +++ b/Easy2D/v1/Tool/FileUtils.cpp @@ -0,0 +1,168 @@ +#include "..\easy2d.h" +#include "..\EasyX\easyx.h" +#include +#pragma comment(lib, "shell32.lib") +#include +#include + +#ifndef UNICODE + #include + #include +#endif + +TString FileUtils::getLocalAppDataPath() +{ + TCHAR m_lpszDefaultDir[MAX_PATH] = { 0 }; + TCHAR szDocument[MAX_PATH] = { 0 }; + + // 获取 AppData\Local 文件夹的 ID + LPITEMIDLIST pidl = NULL; + SHGetSpecialFolderLocation(NULL, CSIDL_LOCAL_APPDATA, &pidl); + if (pidl && SHGetPathFromIDList(pidl, szDocument)) + { + // 获取文件夹路径 + GetShortPathName(szDocument, m_lpszDefaultDir, _MAX_PATH); + } + + return m_lpszDefaultDir; +} + +TString FileUtils::getDefaultSavePath() +{ + TCHAR m_lpszDefaultDir[MAX_PATH] = { 0 }; + TCHAR szDocument[MAX_PATH] = { 0 }; + + // 获取 AppData\Local 文件夹的 ID + LPITEMIDLIST pidl = NULL; + SHGetSpecialFolderLocation(NULL, CSIDL_LOCAL_APPDATA, &pidl); + if (pidl && SHGetPathFromIDList(pidl, szDocument)) + { + // 获取文件夹路径 + GetShortPathName(szDocument, m_lpszDefaultDir, _MAX_PATH); + } + + TString path = m_lpszDefaultDir; + path.append(_T("\\")); + path.append(EApp::getAppName()); + +#ifdef UNICODE + if (_waccess(path.c_str(), 0) == -1) + { + _wmkdir(path.c_str()); + } +#else + if (_access(path.c_str(), 0) == -1) + { + _mkdir(path.c_str()); + } +#endif + + path.append(_T("\\DefaultData.ini")); + + return path; +} + +void FileUtils::saveInt(LPCTSTR key, int value) +{ +#ifdef UNICODE + std::wstringstream ss; +#else + std::stringstream ss; +#endif + ss << value; + ::WritePrivateProfileString(_T("Default"), key, ss.str().c_str(), getDefaultSavePath().c_str()); +} + +void FileUtils::saveDouble(LPCTSTR key, double value) +{ +#ifdef UNICODE + std::wstringstream ss; +#else + std::stringstream ss; +#endif + ss << value; + ::WritePrivateProfileString(_T("Default"), key, ss.str().c_str(), getDefaultSavePath().c_str()); +} + +void FileUtils::saveString(LPCTSTR key, TString value) +{ + ::WritePrivateProfileString(_T("Default"), key, value.c_str(), getDefaultSavePath().c_str()); +} + +int FileUtils::getInt(LPCTSTR key, int default) +{ + return ::GetPrivateProfileInt(_T("Default"), key, default, getDefaultSavePath().c_str()); +} +#include +using namespace std; +double FileUtils::getDouble(LPCTSTR key, double default) +{ + // 将 default 参数转化为字符串 +#ifdef UNICODE + std::wstringstream ss; +#else + std::stringstream ss; +#endif + ss << default; + // 读取数据 + TCHAR temp[128] = { 0 }; + ::GetPrivateProfileString(_T("Default"), key, ss.str().c_str(), temp, 128, getDefaultSavePath().c_str()); + // 转换为字符串流 + ss.str(_T("")); + ss << temp; + // 将字符串转化为 double +#ifdef UNICODE + double d = _wtof(ss.str().c_str()); +#else + double d = atof(ss.str().c_str()); +#endif + return d; +} + +TString FileUtils::geTString(LPCTSTR key, TString default) +{ + TCHAR temp[128] = { 0 }; + ::GetPrivateProfileString(_T("Default"), key, default.c_str(), temp, 128, getDefaultSavePath().c_str()); + return TString(temp); +} + +TString FileUtils::getFileExtension(const TString & filePath) +{ + TString fileExtension; + // 找到文件名中的最后一个 '.' 的位置 + size_t pos = filePath.find_last_of('.'); + // 判断 pos 是否是个有效位置 + if (pos != TString::npos) + { + // 截取扩展名 + fileExtension = filePath.substr(pos, filePath.length()); + // 转换为小写字母 + std::transform(fileExtension.begin(), fileExtension.end(), fileExtension.begin(), ::tolower); + } + + return fileExtension; +} + +bool FileUtils::getSaveFilePath(TString& path, LPCTSTR title, LPCTSTR defExt) +{ + // 弹出保存对话框 + OPENFILENAME ofn = { 0 }; + TCHAR strFilename[MAX_PATH] = { 0 }; // 用于接收文件名 + ofn.lStructSize = sizeof(OPENFILENAME); // 结构体大小 + ofn.hwndOwner = GetHWnd(); // 拥有着窗口句柄,NULL 表示对话框是非模态的 + ofn.lpstrFilter = _T("所有文件\0*.*\0\0"); // 设置过滤 + ofn.nFilterIndex = 1; // 过滤器索引 + ofn.lpstrFile = strFilename; // 接收返回的文件路径和文件名 + ofn.nMaxFile = sizeof(strFilename); // 缓冲区长度 + ofn.lpstrInitialDir = NULL; // 初始目录为默认 + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;// 目录必须存在,覆盖文件前发出警告 + ofn.lpstrTitle = title; // 使用系统默认标题留空即可 + ofn.lpstrDefExt = defExt; // 默认追加的扩展名 + + if (GetSaveFileName(&ofn)) + { + path = strFilename; + return true; + } + return false; +} diff --git a/Easy2D/v1/Tool/Math.cpp b/Easy2D/v1/Tool/Math.cpp new file mode 100644 index 00000000..2d0a3821 --- /dev/null +++ b/Easy2D/v1/Tool/Math.cpp @@ -0,0 +1,9 @@ +#include "..\easy2d.h" + + +std::default_random_engine &Math::getEngine() +{ + static std::random_device device; + static std::default_random_engine engine(device()); + return engine; +} diff --git a/Easy2D/v1/Tool/MusicUtils.cpp b/Easy2D/v1/Tool/MusicUtils.cpp new file mode 100644 index 00000000..f374b3b1 --- /dev/null +++ b/Easy2D/v1/Tool/MusicUtils.cpp @@ -0,0 +1,417 @@ +#include "..\easy2d.h" +#include +#pragma comment(lib , "winmm.lib") + +#include +#include + +//////////////////////////////////////////////////////////////////// +// MciPlayer +//////////////////////////////////////////////////////////////////// + +class MciPlayer +{ +public: + MciPlayer(); + ~MciPlayer(); + + void close(); + void open(TString pFileName, UINT uId); + void play(bool bLoop = false); + void pause(); + void resume(); + void stop(); + void rewind(); + void setVolume(float volume); + bool isPlaying(); + UINT getSoundID(); + +private: + void _sendCommand(int nCommand, DWORD_PTR param1 = 0, DWORD_PTR parma2 = 0); + + MCIDEVICEID m_dev; + UINT m_nSoundID; + bool m_bPlaying; + bool m_bLoop; + TString m_sExt; +}; + + +MciPlayer::MciPlayer() : + m_dev(0L), + m_nSoundID(0), + m_bPlaying(false), + m_bLoop(false), + m_sExt(_T("")) +{ +} + +MciPlayer::~MciPlayer() +{ + close(); // 关闭播放器 +} + +void MciPlayer::open(TString pFileName, UINT uId) +{ + // 忽略不存在的文件 + if (pFileName.empty() || !PathFileExists(pFileName.c_str())) return; + // 获取文件后缀名 + m_sExt = FileUtils::getFileExtension(pFileName); + // 停止当前音乐 + close(); + + // 设置 MCI_OPEN_PARMS 参数 + MCI_OPEN_PARMS mciOpen = { 0 }; + mciOpen.lpstrDeviceType = (LPCTSTR)-1; // device ID for "all devices" + mciOpen.lpstrElementName = pFileName.c_str(); + + // 打开这个文件 + MCIERROR mciError; + mciError = mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, reinterpret_cast(&mciOpen)); + // 出现错误时,忽略这次操作 + if (mciError) return; + + // 保存设备等信息 + m_dev = mciOpen.wDeviceID; + m_nSoundID = uId; + m_bPlaying = false; +} + +void MciPlayer::play(bool bLoop) +{ + // 设备为空时,忽略这次操作 + if (!m_dev) + { + return; + } + // 设置播放参数 + MCI_PLAY_PARMS mciPlay = { 0 }; + MCIERROR s_mciError; + // 播放声音 + s_mciError = mciSendCommand(m_dev, MCI_PLAY, MCI_FROM | (bLoop ? MCI_DGV_PLAY_REPEAT : 0), reinterpret_cast(&mciPlay)); + // 未出错时,置 m_bPlaying 为 true + if (!s_mciError) + { + m_bPlaying = true; + m_bLoop = bLoop; + } +} + +void MciPlayer::close() +{ + // 停止音乐 + if (m_bPlaying) + { + stop(); + } + // 关闭设备 + if (m_dev) + { + _sendCommand(MCI_CLOSE); + } + // 恢复默认属性 + m_dev = 0; + m_bPlaying = false; +} + +void MciPlayer::pause() +{ + // 暂停音乐 + _sendCommand(MCI_PAUSE); + m_bPlaying = false; +} + +void MciPlayer::resume() +{ + // 继续音乐 + if (m_sExt == _T(".mid")) + { + // midi 不支持 MCI_RESUME 参数,应使用 MCI_FROM 设置播放起始位置 + // 获取 MCI 状态 + MCI_STATUS_PARMS mciStatusParms; + mciStatusParms.dwItem = MCI_STATUS_POSITION; + _sendCommand(MCI_STATUS, MCI_STATUS_ITEM, reinterpret_cast(&mciStatusParms)); + // 设置播放起始位置,并开始播放 + MCI_PLAY_PARMS mciPlayParms; + mciPlayParms.dwFrom = (DWORD)mciStatusParms.dwReturn; + _sendCommand(MCI_PLAY, MCI_FROM, reinterpret_cast(&mciPlayParms)); + } + else + { + // 继续播放音乐 + _sendCommand(MCI_RESUME); + m_bPlaying = true; + } +} + +void MciPlayer::stop() +{ + // 停止音乐 + _sendCommand(MCI_STOP); + m_bPlaying = false; +} + +void MciPlayer::rewind() +{ + // 设备为空时,忽略这次操作 + if (!m_dev) + { + return; + } + // 重置播放位置 + mciSendCommand(m_dev, MCI_SEEK, MCI_SEEK_TO_START, 0); + // 播放音乐 + MCI_PLAY_PARMS mciPlay = { 0 }; + m_bPlaying = mciSendCommand(m_dev, MCI_PLAY, (m_bLoop ? MCI_DGV_PLAY_REPEAT : 0), reinterpret_cast(&mciPlay)) ? false : true; +} + +void MciPlayer::setVolume(float volume) +{ + volume = min(max(volume, 0), 1); + MCI_DGV_SETAUDIO_PARMS mciSetAudioPara = { 0 }; + mciSetAudioPara.dwItem = MCI_DGV_SETAUDIO_VOLUME; + mciSetAudioPara.dwValue = DWORD(1000 * volume); + mciSendCommand(m_dev, MCI_SETAUDIO, MCI_DGV_SETAUDIO_VALUE | MCI_DGV_SETAUDIO_ITEM, (DWORD_PTR)&mciSetAudioPara); +} + +bool MciPlayer::isPlaying() +{ + return m_bPlaying; +} + +UINT MciPlayer::getSoundID() +{ + return m_nSoundID; +} + +void MciPlayer::_sendCommand(int nCommand, DWORD_PTR param1, DWORD_PTR parma2) +{ + // 空设备时忽略这次操作 + if (!m_dev) + { + return; + } + // 向当前设备发送操作 + mciSendCommand(m_dev, nCommand, param1, parma2); +} + + + + +//////////////////////////////////////////////////////////////////// +// MusicUtils +//////////////////////////////////////////////////////////////////// + + +typedef std::map MusicList; +typedef std::pair Music; + +static unsigned int _Hash(TString key); + + +static MusicList& getMciPlayerList() +{ + static MusicList s_List; + return s_List; +} + +static MciPlayer& getBgMciPlayer() +{ + static MciPlayer s_Music; + return s_Music; +} + +void MusicUtils::end() +{ + // 停止背景音乐 + getBgMciPlayer().close(); + // 停止其他所有音乐 + for (auto& iter : getMciPlayerList()) + { + SafeDelete(iter.second); + } + // 清空音乐列表 + getMciPlayerList().clear(); + return; +} + +void MusicUtils::setVolume(float volume) +{ + // 设置背景音乐音量 + getBgMciPlayer().setVolume(volume); + // 设置其他音乐音量 + for (auto& iter : getMciPlayerList()) + { + iter.second->setVolume(volume); + } +} + +void MusicUtils::setVolume(TString pszFilePath, float volume) +{ + unsigned int nRet = ::_Hash(pszFilePath); + + MusicList::iterator p = getMciPlayerList().find(nRet); + if (p != getMciPlayerList().end()) + { + p->second->setVolume(volume); + } +} + +void MusicUtils::playBackgroundMusic(TString pszFilePath, bool bLoop) +{ + if (pszFilePath.empty()) + { + return; + } + + getBgMciPlayer().open(pszFilePath, ::_Hash(pszFilePath)); + getBgMciPlayer().play(bLoop); +} + +void MusicUtils::stopBackgroundMusic(bool bReleaseData) +{ + if (bReleaseData) + { + getBgMciPlayer().close(); + } + else + { + getBgMciPlayer().stop(); + } +} + +void MusicUtils::pauseBackgroundMusic() +{ + getBgMciPlayer().pause(); +} + +void MusicUtils::resumeBackgroundMusic() +{ + getBgMciPlayer().resume(); +} + +void MusicUtils::rewindBackgroundMusic() +{ + getBgMciPlayer().rewind(); +} + +bool MusicUtils::isBackgroundMusicPlaying() +{ + return getBgMciPlayer().isPlaying(); +} + +void MusicUtils::setBackgroundMusicVolume(float volume) +{ + getBgMciPlayer().setVolume(volume); +} + +unsigned int MusicUtils::playMusic(TString pszFilePath, bool bLoop) +{ + unsigned int nRet = ::_Hash(pszFilePath); + + preloadMusic(pszFilePath); + + MusicList::iterator p = getMciPlayerList().find(nRet); + if (p != getMciPlayerList().end()) + { + p->second->play(bLoop); + } + return nRet; +} + +void MusicUtils::stopMusic(unsigned int nSoundId) +{ + MusicList::iterator p = getMciPlayerList().find(nSoundId); + if (p != getMciPlayerList().end()) + { + p->second->stop(); + } +} + +void MusicUtils::preloadMusic(TString pszFilePath) +{ + if (pszFilePath.empty()) return; + + int nRet = ::_Hash(pszFilePath); + + if (getMciPlayerList().end() != getMciPlayerList().find(nRet)) return; + + getMciPlayerList().insert(Music(nRet, new MciPlayer())); + MciPlayer * pPlayer = getMciPlayerList()[nRet]; + pPlayer->open(pszFilePath, nRet); + + if (nRet == pPlayer->getSoundID()) return; + + delete pPlayer; + getMciPlayerList().erase(nRet); + nRet = 0; +} + +void MusicUtils::pauseMusic(unsigned int nSoundId) +{ + MusicList::iterator p = getMciPlayerList().find(nSoundId); + if (p != getMciPlayerList().end()) + { + p->second->pause(); + } +} + +void MusicUtils::pauseAllMusics() +{ + for (auto& iter : getMciPlayerList()) + { + iter.second->pause(); + } +} + +void MusicUtils::resumeMusic(unsigned int nSoundId) +{ + MusicList::iterator p = getMciPlayerList().find(nSoundId); + if (p != getMciPlayerList().end()) + { + p->second->resume(); + } +} + +void MusicUtils::resumeAllMusics() +{ + for (auto& iter : getMciPlayerList()) + { + iter.second->resume(); + } +} + +void MusicUtils::stopAllMusics() +{ + for (auto& iter : getMciPlayerList()) + { + iter.second->stop(); + } +} + +void MusicUtils::unloadMusic(LPCTSTR pszFilePath) +{ + unsigned int nID = ::_Hash(pszFilePath); + + MusicList::iterator p = getMciPlayerList().find(nID); + if (p != getMciPlayerList().end()) + { + SafeDelete(p->second); + getMciPlayerList().erase(nID); + } +} + + + +unsigned int _Hash(TString key) +{ + unsigned int len = unsigned(key.size()); + unsigned int hash = 0; + + for (unsigned i = 0; i < len; i++) + { + hash *= 16777619; + hash ^= (unsigned int)(unsigned char)toupper(key[i]); + } + return (hash); +} \ No newline at end of file diff --git a/Easy2D/v1/Tool/Timer.cpp b/Easy2D/v1/Tool/Timer.cpp new file mode 100644 index 00000000..e3c44ce7 --- /dev/null +++ b/Easy2D/v1/Tool/Timer.cpp @@ -0,0 +1,223 @@ +#include "..\easy2d.h" +#include "..\Win\winbase.h" + +// 储存所有定时器的容器 +static std::vector s_vTimers; + +Timer::Timer(TString name, LONGLONG milliSeconds, const TIMER_CALLBACK & callback) : + m_sName(name), + m_bRunning(false), + m_bWaiting(false), + m_callback(callback), + m_pParentScene(nullptr) +{ + setInterval(milliSeconds); // 设置定时器的时间间隔 +} + +Timer::~Timer() +{ +} + +void Timer::start() +{ + // 标志该定时器正在运行 + m_bRunning = true; + // 记录当前时间 + m_nLast = steady_clock::now(); +} + +void Timer::stop() +{ + m_bRunning = false; // 标志该定时器已停止 +} + +void Timer::wait() +{ + m_bWaiting = true; +} + +void Timer::notify() +{ + m_bWaiting = false; +} + +bool Timer::isRunning() +{ + return m_bRunning && !m_bWaiting; // 获取该定时器的运行状态 +} + +void Timer::setInterval(LONGLONG milliSeconds) +{ + // 设置定时器的时间间隔 + m_nAnimationInterval = milliSeconds; +} + +void Timer::setCallback(const TIMER_CALLBACK & callback) +{ + m_callback = callback; // 保存回调函数 +} + +void Timer::setName(TString name) +{ + m_sName = name; // 修改定时器名称 +} + +LONGLONG Timer::getInterval() const +{ + return m_nAnimationInterval;// 获取定时器的时间间隔 +} + +TString Timer::getName() const +{ + return m_sName; // 获取定时器的名称 +} + +void Timer::__exec() +{ + // 定时器容器为空 + if (!s_vTimers.size()) + { + return; + } + // 循环遍历所有的定时器 + for (auto timer : s_vTimers) + { + // 若定时器未运行,跳过这个定时器 + if (!timer->isRunning()) + { + continue; + } + // 判断时间间隔是否足够 + while (duration_cast(GetNow() - timer->m_nLast).count() > timer->m_nAnimationInterval) + { + // 重新记录时间 + timer->m_nLast += milliseconds(timer->m_nAnimationInterval); + // 运行回调函数 + timer->m_callback(); + } + } +} + +void Timer::addTimer(Timer * timer) +{ + // 启动定时器 + timer->start(); + // 绑定在场景上 + timer->m_pParentScene = EApp::getLoadingScene(); + // 将该定时器放入容器 + s_vTimers.push_back(timer); +} + +void Timer::addTimer(TString name, const TIMER_CALLBACK & callback) +{ + addTimer(name, 20, callback); +} + +void Timer::addTimer(TString name, LONGLONG milliSeconds, const TIMER_CALLBACK & callback) +{ + // 创建定时器 + auto timer = new Timer(name, milliSeconds, callback); + // 添加定时器 + addTimer(timer); +} + +void Timer::startTimer(TString name) +{ + // 查找名称相同的定时器 + for (auto timer : s_vTimers) + { + if (timer->m_sName == name && timer->m_pParentScene == EApp::getCurrentScene()) + { + // 启动定时器 + timer->start(); + } + } +} + +void Timer::stopTimer(TString name) +{ + // 查找名称相同的定时器 + for (auto timer : s_vTimers) + { + if (timer->m_sName == name && timer->m_pParentScene == EApp::getCurrentScene()) + { + // 停止定时器 + timer->stop(); + } + } +} + +void Timer::delTimer(TString name) +{ + // 创建迭代器 + std::vector::iterator iter; + // 循环遍历所有定时器 + for (iter = s_vTimers.begin(); iter != s_vTimers.end();) + { + // 查找相同名称的定时器 + if ((*iter)->m_sName == name && (*iter)->m_pParentScene == EApp::getCurrentScene()) + { + // 删除该定时器 + delete (*iter); + iter = s_vTimers.erase(iter); + } + else + { + iter++; + } + } +} + +void Timer::clearAllTimers() +{ + // 删除所有定时器 + for (auto t : s_vTimers) + { + delete t; + } + // 清空容器 + s_vTimers.clear(); +} + +void Timer::notifyAllSceneTimers(EScene * scene) +{ + for (auto t : s_vTimers) + { + if (t->m_pParentScene == scene) + { + t->notify(); + } + } +} + +void Timer::waitAllSceneTimers(EScene * scene) +{ + for (auto t : s_vTimers) + { + if (t->m_pParentScene == scene) + { + t->wait(); + } + } +} + +void Timer::clearAllSceneTimers(EScene * scene) +{ + // 创建迭代器 + std::vector::iterator iter; + // 循环遍历所有定时器 + for (iter = s_vTimers.begin(); iter != s_vTimers.end();) + { + // 查找相同名称的定时器 + if ((*iter)->m_pParentScene == scene) + { + // 删除该定时器 + delete (*iter); + iter = s_vTimers.erase(iter); + } + else + { + iter++; + } + } +} diff --git a/Easy2D/v1/easy2d.h b/Easy2D/v1/easy2d.h new file mode 100644 index 00000000..558be506 --- /dev/null +++ b/Easy2D/v1/easy2d.h @@ -0,0 +1,1662 @@ +/****************************************************** +* Easy2D Game Engine +* +* Website: http://www.easy2d.cn +* Github: https://github.com/Nomango/Easy2D +* Gitee: https://gitee.com/werelone/Easy2D +******************************************************/ + +#pragma once + +#ifndef __cplusplus + #error Easy2D is only for C++ +#endif + +#if _MSC_VER < 1900 + #error Do Visual Studio 2015/2017 specific stuff +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include + + +#if defined(UNICODE) && (_DEBUG) + #pragma comment(lib,"Easy2Ddw.lib") +#elif !defined(UNICODE) && (_DEBUG) + #pragma comment(lib,"Easy2Dd.lib") +#elif defined(UNICODE) + #pragma comment(lib,"Easy2Dw.lib") +#elif !defined(UNICODE) + #pragma comment(lib,"Easy2D.lib") +#endif + + +// Type Declare + +typedef CPoint CVector; +typedef unsigned int VK_KEY; +typedef std::function CLICK_CALLBACK; +typedef std::function TIMER_CALLBACK; +typedef std::function KEY_CALLBACK; +typedef std::function MOUSE_CALLBACK; + +#ifdef UNICODE + typedef std::wstring TString; +#else + typedef std::string TString; +#endif + +// Classes Declare + +namespace easy2d +{ + class App; + class Scene; + + class Object; + class Node; + class FontStyle; + class Color; + class RectNode; + class Text; + class Image; + class BatchNode; + class MouseNode; + class Button; + class TextButton; + class ImageButton; + class Layer; + class Sprite; + class BatchSprite; + class Shape; + class Circle; + class Rectangle; + + class Action; + class Animation; + class ActionMoveTo; + class ActionMoveBy; + class ActionScaleTo; + class ActionScaleBy; + class ActionOpacityTo; + class ActionOpacityBy; + class ActionFadeIn; + class ActionFadeOut; + class ActionFrames; + class ActionDelay; + class ActionCallback; + class ActionTwo; + class ActionSequence; + class ActionNeverStop; + + class MouseMsg; + class KeyMsg; + + class FreePool; + class FileUtils; + class MusicUtils; + class ActionManager; +} + + +// Classes + +namespace easy2d +{ + +class App +{ + friend Scene; +public: + App(); + ~App(); + + // 绐楀彛鍙夋ā寮 + enum MODE { SHOW_CONSOLE = 1, NO_CLOSE = 2, NO_MINI_MIZE = 4 }; + + // 瀹氫箟缁樺浘绐楀彛 + void createWindow(int width, int height, int mode = 0); + // 瀹氫箟缁樺浘绐楀彛 + void createWindow(CSize size, int mode = 0); + // 瀹氫箟缁樺浘绐楀彛 + void createWindow(TString title, int width, int height, int mode = 0); + // 瀹氫箟缁樺浘绐楀彛 + void createWindow(TString title, CSize size, int mode = 0); + // 鍚姩绋嬪簭 + int run(); + // 閲婃斁鎵鏈夊唴瀛樿祫婧 + void free(); + + // 鑾峰彇绋嬪簭瀹炰緥 + static App * get(); + // 缁堟绋嬪簭 + static void quit(); + // 缁堟绋嬪簭 + static void end(); + // 淇敼绐楀彛澶у皬 + static void setWindowSize(int width, int height); + // 淇敼绐楀彛澶у皬 + static void setWindowSize(CSize size); + // 鍏抽棴绐楀彛 + static void close(); + // 璁剧疆绐楀彛鏍囬 + static void setWindowTitle(TString title); + // 鑾峰彇绐楀彛鏍囬 + static TString getWindowTitle(); + // 鑾峰彇绐楀彛瀹藉害 + static int getWidth(); + // 鑾峰彇绐楀彛楂樺害 + static int getHeight(); + // 鍒囨崲鍦烘櫙 + static void enterScene(Scene *scene, bool save = true); + // 杩斿洖涓婁竴鍦烘櫙 + static void backScene(); + // 娓呯┖涔嬪墠淇濆瓨鐨勬墍鏈夊満鏅 + static void clearScene(); + // 璁剧疆 AppName + static void setAppName(TString appname); + // 鑾峰彇 AppName + static TString getAppName(); + // 淇敼绐楀彛鑳屾櫙鑹 + static void setBkColor(COLORREF color); + // 閲嶇疆缁樺浘鏍峰紡涓洪粯璁ゅ + static void reset(); + // 鑾峰彇褰撳墠鍦烘櫙 + static Scene * getCurrentScene(); + // 鑾峰彇姝e浜庡姞杞戒腑鐨勫満鏅 + static Scene * getLoadingScene(); + +protected: + TString m_sTitle; + TString m_sAppName; + Scene* m_pCurrentScene; + Scene* m_pNextScene; + Scene* m_pLoadingScene; + CSize m_Size; + int m_nWindowMode; + bool m_bRunning; + bool m_bSaveScene; + +protected: + void _initGraph(); + void _draw(); + void _mainLoop(); + void _enterNextScene(); +}; + +class FreePool +{ + friend App; + friend Object; +private: + // 鍒锋柊鍐呭瓨姹 + static void __flush(); + // 灏嗕竴涓妭鐐规斁鍏ラ噴鏀炬睜 + static void __add(Object * nptr); + // 鍒犻櫎鎵鏈夎妭鐐 + static void __clearAllObjects(); +}; + +class Scene +{ + friend App; + friend MouseMsg; +public: + Scene(); + ~Scene(); + + // 閲嶅啓杩欎釜鍑芥暟锛屽垵濮嬪寲杩欎釜鍦烘櫙 + virtual void init(); + // 閲嶅啓杩欎釜鍑芥暟锛屽畠灏嗗湪杩涘叆杩欎釜鍦烘櫙鏃惰嚜鍔ㄦ墽琛 + virtual void onEnter(); + // 閲嶅啓杩欎釜鍑芥暟锛屽畠灏嗗湪绂诲紑杩欎釜鍦烘櫙鏃惰嚜鍔ㄦ墽琛 + virtual void onExit(); + // 娣诲姞瀛愭垚鍛樺埌鍦烘櫙 + void add(Node * child, int zOrder = 0); + // 鍒犻櫎瀛愭垚鍛 + bool del(Node * child); + // 娓呯┖鎵鏈夊瓙鎴愬憳 + void clearAllChildren(); + +protected: + std::vector m_vChildren; + +protected: + void _exec(); + void _onDraw(); +}; + +class Object +{ + friend FreePool; +public: + Object(); + virtual ~Object(); + + // 淇濈暀杩欎釜瀵硅薄 + void retain(); + // 閲婃斁杩欎釜瀵硅薄 + void release(); + // 璁╁紩鎿庤嚜鍔ㄩ噴鏀捐繖涓璞 + void autoRelease(); + +protected: + int m_nRefCount; + bool m_bAutoRelease; +}; + +class MouseMsg +{ + friend App; +public: + MouseMsg(); + MouseMsg(TString name, const MOUSE_CALLBACK& callback); + ~MouseMsg(); + + enum MESSAGE + { + MOVE = 0x0200, // 榧犳爣绉诲姩 + LBUTTON_DOWN, // 榧犳爣宸﹂敭鎸変笅 + LBUTTON_UP, // 榧犳爣宸﹂敭鎶捣 + LBUTTON_DBLCLK, // 榧犳爣宸﹂敭鍙屽嚮 + RBUTTON_DOWN, // 榧犳爣鍙抽敭鎸変笅 + RBUTTON_UP, // 榧犳爣鍙抽敭鎶捣 + RBUTTON_DBLCLK, // 榧犳爣鍙抽敭鍙屽嚮 + MBUTTON_DOWN, // 榧犳爣涓敭鎸変笅 + MBUTTON_UP, // 榧犳爣涓敭鎶捣 + MBUTTON_DBLCLK, // 榧犳爣涓敭鍙屽嚮 + WHEEL // 婊戝姩婊氳疆 + }; + + // 鍚姩鐩戝惉 + void start(); + // 鍋滄鐩戝惉 + void stop(); + // 杩涘叆绛夊緟鐘舵 + void wait(); + // 鍞ら啋 + void notify(); + + // 宸﹂敭鏄惁鎸変笅 + static bool isLButtonDown(); + // 鍙抽敭鏄惁鎸変笅 + static bool isRButtonDown(); + // 涓敭鏄惁鎸変笅 + static bool isMButtonDown(); + // 鑾峰彇榧犳爣X鍧愭爣 + static int getX(); + // 鑾峰彇榧犳爣Y鍧愭爣 + static int getY(); + // 鑾峰彇榧犳爣鍧愭爣 + static CPoint getPos(); + // 鑾峰彇榧犳爣婊氳疆鍊 + static int getWheel(); + // 鑾峰彇褰撳墠榧犳爣娑堟伅 + static MESSAGE getMsg(); + + // 娣诲姞榧犳爣娑堟伅鐩戝惉 + static void addListener(TString name, const MOUSE_CALLBACK& callback); + // 鍚姩榧犳爣娑堟伅鐩戝惉 + static void startListener(TString name); + // 鍋滄榧犳爣娑堟伅鐩戝惉 + static void stopListener(TString name); + // 鍒犻櫎榧犳爣娑堟伅鐩戝惉 + static void delListener(TString name); + // 鍒犻櫎鎵鏈夐紶鏍囨秷鎭洃鍚 + static void clearAllListeners(); + // 鍚姩缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夌洃鍚櫒 + static void notifyAllSceneListeners(Scene* scene); + // 鍋滄缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夌洃鍚櫒 + static void waitAllSceneListeners(Scene* scene); + // 娓呴櫎缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夌洃鍚櫒 + static void clearAllSceneListeners(Scene* scene); + +private: + static void __exec(); + +protected: + bool m_bRunning; + bool m_bWaiting; + TString m_sName; + MOUSE_CALLBACK m_callback; + Scene * m_pParentScene; + +protected: + // 鎵ц鍥炶皟鍑芥暟 + void onMouseMsg(); +}; + +class KeyMsg +{ + friend App; +public: + KeyMsg(TString name, const KEY_CALLBACK& callback); + ~KeyMsg(); + + // 鎵ц鍥炶皟鍑芥暟 + void onKbHit(VK_KEY key); + // 鍚姩鐩戝惉 + void start(); + // 鍋滄鐩戝惉 + void stop(); + // 杩涘叆绛夊緟鐘舵 + void wait(); + // 鍞ら啋 + void notify(); + + // 鍒ゆ柇閿槸鍚﹁鎸変笅锛屾寜涓嬭繑鍥瀟rue + static bool isKeyDown(VK_KEY key); + // 娣诲姞鎸夐敭鐩戝惉 + static void addListener(TString name, const KEY_CALLBACK& callback); + // 鍚姩鎸夐敭鐩戝惉 + static void startListener(TString name); + // 鍋滄鎸夐敭鐩戝惉 + static void stopListener(TString name); + // 鍒犻櫎鎸夐敭鐩戝惉 + static void KeyMsg::delListener(TString name); + // 鍚姩缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夌洃鍚櫒 + static void notifyAllSceneListeners(Scene* scene); + // 鍋滄缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夌洃鍚櫒 + static void waitAllSceneListeners(Scene* scene); + // 鍋滄缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夊畾鏃跺櫒 + static void clearAllSceneListeners(Scene* scene); + // 鍒犻櫎鎵鏈夋寜閿洃鍚 + static void clearAllListeners(); + +public: + // 瀛楁瘝閿 + static const VK_KEY A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z; + // 鏁板瓧閿 + static const VK_KEY NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9, NUM_0; + // 灏忔暟瀛楅敭鐩樺 + static const VK_KEY NUMPAD_1, NUMPAD_2, NUMPAD_3, NUMPAD_4, NUMPAD_5, NUMPAD_6, NUMPAD_7, NUMPAD_8, NUMPAD_9, NUMPAD_0; + // 鎺у埗閿 + static const VK_KEY Enter, Space, Up, Down, Left, Right, Esc, Shift, LShift, RShift, Ctrl, LCtrl, RCtrl; + // F 閿 + static const VK_KEY F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12; + +private: + static void __exec(); + +protected: + bool m_bRunning; + bool m_bWaiting; + TString m_sName; + KEY_CALLBACK m_callback; + Scene * m_pParentScene; +}; + +class FontStyle : + public Object +{ + friend Text; +public: + FontStyle(); + /** + * 浣跨敤 [瀛椾綋鍚嶇О銆佸瓧鍙枫佺矖缁嗐佸瓧瀹姐佹枩浣撱佷笅鍒掔嚎銆佸垹闄ょ嚎銆佸瓧绗︿覆涔﹀啓瑙掑害銆 + * 姣忎釜瀛楃涔﹀啓瑙掑害銆佹姉閿娇] 灞炴у垱寤哄瓧浣撴牱寮 + */ + FontStyle(LPCTSTR fontfamily, LONG height = 18, LONG weight = 0, LONG width = 0, + bool italic = 0, bool underline = 0, bool strikeout = 0, LONG escapement = 0, + LONG orientation = 0, bool quality = true); + virtual ~FontStyle(); + + // 鑾峰彇榛樿瀛椾綋 + static FontStyle * getDefault(); + // 璁剧疆瀛楃骞冲潎楂樺害 + void setHeight(LONG value); + // 璁剧疆瀛楃骞冲潎瀹藉害锛0琛ㄧず鑷傚簲锛 + void setWidth(LONG value); + // 璁剧疆瀛椾綋 + void setFontFamily(LPCTSTR value); + // 璁剧疆瀛楃绗旂敾绮楃粏锛岃寖鍥0~1000锛岄粯璁や负0 + void setWeight(LONG value); + // 璁剧疆鏂滀綋 + void setItalic(bool value); + // 璁剧疆涓嬪垝绾 + void setUnderline(bool value); + // 璁剧疆鍒犻櫎绾 + void setStrikeOut(bool value); + // 璁剧疆瀛楃涓茬殑涔﹀啓瑙掑害锛屽崟浣0.1搴︼紝榛樿涓0 + void setEscapement(LONG value); + // 璁剧疆姣忎釜瀛楃鐨勪功鍐欒搴︼紝鍗曚綅0.1搴︼紝榛樿涓0 + void setOrientation(LONG value); + // 璁剧疆瀛椾綋鎶楅敮榻匡紝榛樿涓簍rue + void setQuality(bool value); + +protected: + LOGFONT m_font; +}; + +class FontWeight +{ +public: + static const LONG dontcare; // 绮楃粏鍊 0 + static const LONG thin; // 绮楃粏鍊 100 + static const LONG extraLight; // 绮楃粏鍊 200 + static const LONG light; // 绮楃粏鍊 300 + static const LONG normal; // 绮楃粏鍊 400 + static const LONG regular; // 绮楃粏鍊 400 + static const LONG medium; // 绮楃粏鍊 500 + static const LONG demiBlod; // 绮楃粏鍊 600 + static const LONG blod; // 绮楃粏鍊 700 + static const LONG extraBold; // 绮楃粏鍊 800 + static const LONG black; // 绮楃粏鍊 900 + static const LONG heavy; // 绮楃粏鍊 900 +}; + +class Color +{ +public: + static const COLORREF black; // 榛戣壊 + static const COLORREF blue; // 钃濊壊 + static const COLORREF green; // 缁胯壊 + static const COLORREF cyan; // 闈掕壊 + static const COLORREF red; // 绾㈣壊 + static const COLORREF magenta; // 绱壊 + static const COLORREF brown; // 妫曡壊 + static const COLORREF lightgray; // 浜伆鑹 + static const COLORREF darkgray; // 娣辩伆鑹 + static const COLORREF lightblue; // 浜摑鑹 + static const COLORREF lightgreen; // 浜豢鑹 + static const COLORREF lightcyan; // 浜潚鑹 + static const COLORREF lightred; // 浜孩鑹 + static const COLORREF lightmagenta; // 浜传鑹 + static const COLORREF yellow; // 浜粍鑹 + static const COLORREF white; // 鐧借壊 + + // 閫氳繃绾€佺豢銆佽摑棰滆壊鍒嗛噺鍚堟垚棰滆壊 + static COLORREF getFromRGB(BYTE r, BYTE g, BYTE b); + // 閫氳繃鑹茬浉銆侀ケ鍜屽害銆佷寒搴﹀悎鎴愰鑹 + static COLORREF getFromHSL(float H, float S, float L); + // 閫氳繃鑹茬浉銆侀ケ鍜屽害銆佹槑搴﹀悎鎴愰鑹 + static COLORREF getFromHSV(float H, float S, float V); + + // 杩斿洖鎸囧畾棰滆壊涓殑绾㈣壊鍊 + static BYTE getRValue(COLORREF color); + // 杩斿洖鎸囧畾棰滆壊涓殑缁胯壊鍊 + static BYTE getGValue(COLORREF color); + // 杩斿洖鎸囧畾棰滆壊涓殑钃濊壊鍊 + static BYTE getBValue(COLORREF color); + // 杩斿洖涓庢寚瀹氶鑹插搴旂殑鐏板害鍊奸鑹 + static COLORREF getGray(COLORREF color); +}; + +class Node : + public Object +{ + friend Scene; + friend BatchNode; +public: + Node(); + Node(CPoint p); + Node(int x, int y); + virtual ~Node(); + + // 鑾峰彇鑺傜偣妯潗鏍 + virtual int getX() const; + // 鑾峰彇鑺傜偣绾靛潗鏍 + virtual int getY() const; + // 鑾峰彇鑺傜偣鍧愭爣 + virtual CPoint getPos() const; + // 璁剧疆鑺傜偣妯潗鏍 + virtual void setX(int x); + // 璁剧疆鑺傜偣绾靛潗鏍 + virtual void setY(int y); + // 璁剧疆鑺傜偣妯旱鍧愭爣 + virtual void setPos(int x, int y); + // 璁剧疆鑺傜偣妯旱鍧愭爣 + virtual void setPos(CPoint p); + // 绉诲姩鑺傜偣 + virtual void move(int x, int y); + // 璁剧疆鑺傜偣妯旱鍧愭爣 + virtual void move(CVector v); + // 鑺傜偣鏄惁鏄剧ず + virtual bool display() const; + // 璁剧疆鑺傜偣鏄惁鏄剧ず + virtual void setDisplay(bool value); + // 鑾峰彇鑺傜偣缁樺浘椤哄簭 + virtual int getZOrder() const; + // 璁剧疆鑺傜偣缁樺浘椤哄簭锛0涓烘渶鍏堢粯鍒讹紝鏄剧ず鍦ㄦ渶搴曞眰锛 + virtual void setZOrder(int z); + // 鑾峰彇鐖惰妭鐐 + virtual Node* getParent(); + // 璁剧疆鐖惰妭鐐 + virtual void setParent(Node* parent); + // 鑾峰彇鑺傜偣鎵鍦ㄥ満鏅 + Scene * getParentScene(); + +protected: + int m_nZOrder; + bool m_bDisplay; + Scene* m_pScene; + CPoint m_Pos; + Node* m_pParent; + +protected: + virtual bool _exec(bool active); + virtual void _onDraw() = 0; + void setParentScene(Scene * scene); +}; + +class BatchNode : + public Node +{ +public: + BatchNode(); + virtual ~BatchNode(); + + // 娣诲姞瀛愯妭鐐 + void add(Node *child, int z_Order = 0); + // 鍒犻櫎瀛愯妭鐐 + bool del(Node * child); + // 鑾峰彇瀛愯妭鐐规暟閲 + int getCount(); + // 鑾峰彇鎵鏈夊瓙鑺傜偣 + std::vector &getChildren(); + // 娓呯┖鎵鏈夊瓙鑺傜偣 + void clearAllChildren(); + + // 璁剧疆鑺傜偣妯潗鏍 + virtual void setX(int x) override; + // 璁剧疆鑺傜偣绾靛潗鏍 + virtual void setY(int y) override; + // 璁剧疆鑺傜偣鍧愭爣 + virtual void setPos(int x, int y) override; + // 璁剧疆鑺傜偣鍧愭爣 + virtual void setPos(CPoint p) override; + // 绉诲姩鑺傜偣 + virtual void move(int x, int y) override; + // 绉诲姩鑺傜偣 + virtual void move(CVector v) override; + +protected: + std::vector m_vChildren; + +protected: + virtual bool _exec(bool active) override; + virtual void _onDraw() override; +}; + +class Layer : + public BatchNode +{ +public: + Layer(); + virtual ~Layer(); + + // 鍥惧眰鏄惁闃诲娑堟伅 + int getBlock() const; + // 璁剧疆鍥惧眰鏄惁闃诲娑堟伅 + void setBlock(bool block); + +protected: + bool m_bBlock; + +protected: + virtual bool _exec(bool active) override; +}; + +class RectNode : + public Node +{ +public: + RectNode(); + ~RectNode(); + + // 鍒ゆ柇涓よ妭鐐规槸鍚︾鎾 + virtual bool isCollisionWith(RectNode * rectNode) const; + // 鍒ゆ柇鐐规槸鍚﹀湪鑺傜偣鍐 + virtual bool isPointIn(CPoint p) const; + + // 璁剧疆鑺傜偣鍦ㄧ獥鍙e眳涓 + virtual void setWindowCenter(); + // 璁剧疆鑺傜偣鍦ㄧ獥鍙fí鍚戝眳涓 + virtual void setWindowCenterX(); + // 璁剧疆鑺傜偣鍦ㄧ獥鍙g旱鍚戝眳涓 + virtual void setWindowCenterY(); + + // 鑾峰彇鑺傜偣妯潗鏍 + virtual int getX() const override; + // 鑾峰彇鑺傜偣绾靛潗鏍 + virtual int getY() const override; + // 鑾峰彇鑺傜偣鍧愭爣 + virtual CPoint getPos() const override; + // 鑾峰彇鑺傜偣瀹藉害 + virtual int getWidth() const; + // 鑾峰彇鑺傜偣楂樺害 + virtual int getHeight() const; + // 鑾峰彇鑺傜偣澶у皬 + virtual CSize getSize() const; + // 鑾峰彇鑺傜偣鎵鍦ㄧ殑鐭╁舰 + virtual CRect getRect() const; + + // 璁剧疆鑺傜偣妯潗鏍 + virtual void setX(int x) override; + // 璁剧疆鑺傜偣绾靛潗鏍 + virtual void setY(int y) override; + // 璁剧疆鑺傜偣鍧愭爣 + virtual void setPos(int x, int y) override; + // 璁剧疆鑺傜偣鍧愭爣 + virtual void setPos(CPoint p) override; + // 绉诲姩鑺傜偣 + virtual void move(int x, int y) override; + // 绉诲姩鑺傜偣 + virtual void move(CVector v) override; + // 璁剧疆鑺傜偣瀹藉害 + virtual void setWidth(int width); + // 璁剧疆鑺傜偣楂樺害 + virtual void setHeight(int height); + // 璁剧疆鑺傜偣澶у皬 + virtual void setSize(int width, int height); + // 璁剧疆鑺傜偣澶у皬 + virtual void setSize(CSize size); + // 璁剧疆鑺傜偣鎵鍦ㄧ殑鐭╁舰 + virtual void setRect(int x1, int y1, int x2, int y2); + // 璁剧疆鑺傜偣鎵鍦ㄧ殑鐭╁舰 + virtual void setRect(CPoint leftTop, CPoint rightBottom); + // 璁剧疆鑺傜偣鎵鍦ㄧ殑鐭╁舰 + virtual void setRect(CRect rect); + +protected: + CRect m_Rect; +}; + +class Text : + public RectNode +{ + friend TextButton; +public: + Text(); + // 鏍规嵁瀛楃涓层侀鑹插拰瀛椾綋鍒涘缓鏂囧瓧 + Text(TString text, COLORREF color = Color::white, FontStyle * font = FontStyle::getDefault()); + // 鏍规嵁妯旱鍧愭爣銆佸瓧绗︿覆銆侀鑹插拰瀛椾綋鍒涘缓鏂囧瓧 + Text(int x, int y, TString text, COLORREF color = Color::white, FontStyle * font = FontStyle::getDefault()); + virtual ~Text(); + + // 鑾峰彇褰撳墠棰滆壊 + COLORREF getColor() const; + // 鑾峰彇褰撳墠鏂囧瓧 + TString getText() const; + // 鑾峰彇褰撳墠瀛椾綋 + FontStyle * getFontStyle(); + // 鏂囨湰鏄惁涓虹┖ + bool isEmpty() const; + + // 璁剧疆鏂囧瓧 + void setText(TString text); + // 璁剧疆鏂囧瓧棰滆壊 + void setColor(COLORREF color); + // 璁剧疆瀛椾綋 + void setFontStyle(FontStyle * style); + +protected: + TString m_sText; + COLORREF m_color; + FontStyle * m_pFontStyle; + +protected: + virtual void _onDraw() override; +}; + +class Image : + public RectNode +{ + friend Sprite; + friend ImageButton; +public: + Image(); + // 浠庡浘鐗囨枃浠惰幏鍙栧浘鍍 + Image(LPCTSTR ImageFile); + /** + * 浠庡浘鐗囨枃浠惰幏鍙栧浘鍍 + * 鍙傛暟锛氬浘鐗囨枃浠跺悕锛屽浘鐗囪鍓潗鏍囷紝鍥剧墖瑁佸壀瀹藉害鍜岄珮搴 + */ + Image(LPCTSTR ImageFile, int x, int y, int width, int height); + virtual ~Image(); + + // 鑾峰彇妯悜鎷変几姣斾緥 + float getScaleX() const; + // 鑾峰彇绾靛悜鎷変几姣斾緥 + float getScaleY() const; + // 鑾峰彇閫忔槑搴 + float getOpacity() const; + + /** + * 浠庡浘鐗囨枃浠惰幏鍙栧浘鍍 + * 杩斿洖鍊硷細鍥剧墖鍔犺浇鏄惁鎴愬姛 + */ + bool setImage(LPCTSTR ImageFile); + /** + * 浠庡浘鐗囨枃浠惰幏鍙栧浘鍍 + * 鍙傛暟锛氬浘鐗囨枃浠跺悕锛屽浘鐗囪鍓捣濮嬪潗鏍囷紝鍥剧墖瑁佸壀瀹藉害鍜岄珮搴 + * 杩斿洖鍊硷細鍥剧墖鍔犺浇鏄惁鎴愬姛 + */ + bool setImage(LPCTSTR ImageFile, int x, int y, int width, int height); + /** + * 浠庤祫婧愭枃浠惰幏鍙栧浘鍍忥紝涓嶆敮鎸 png + * 杩斿洖鍊硷細鍥剧墖鍔犺浇鏄惁鎴愬姛 + */ + bool setImageFromRes(LPCTSTR pResName); + /** + * 浠庤祫婧愭枃浠惰幏鍙栧浘鍍忥紝涓嶆敮鎸 png + * 鍙傛暟锛氳祫婧愬悕绉帮紝鍥剧墖瑁佸壀鍧愭爣锛屽浘鐗囪鍓搴﹀拰楂樺害 + * 杩斿洖鍊硷細鍥剧墖鍔犺浇鏄惁鎴愬姛 + */ + bool setImageFromRes(LPCTSTR pResName, int x, int y, int width, int height); + // 瑁佸壀鍥剧墖锛堣鍓悗浼氭仮澶 stretch 鎷変几锛 + void crop(int x, int y, int width, int height); + // 灏嗗浘鐗囨媺浼稿埌鍥哄畾瀹介珮 + void stretch(int width, int height); + // 鎸夋瘮渚嬫媺浼稿浘鐗 + void setScale(float scaleX, float scaleY); + // 璁剧疆閫忔槑搴︼紝鑼冨洿 0~1.0f锛堝彧瀵 png 鍥剧墖鐢熸晥锛 + void setOpacity(float value); + // 璁剧疆閫忔槑鑹 + void setTransparentColor(COLORREF value); + // 閲嶇疆鍥剧墖灞炴 + void reset(); + + // 棰勫姞杞藉浘鐗 + static bool preload(LPCTSTR fileName, bool fromRes = false); + // 淇濆瓨娓告垙鎴浘 + static void saveScreenshot(); + +protected: + CImage* m_pCImage; + CRect m_SrcRect; + BYTE m_nAlpha; + float m_fScaleX; + float m_fScaleY; + +protected: + virtual void _onDraw() override; +}; + +class Sprite : + public RectNode +{ + friend BatchSprite; +public: + Sprite(); + Sprite(Image * image); + Sprite(LPCTSTR imageFileName); + virtual ~Sprite(); + + // 鍒ゆ柇鏄惁鍜屽彟涓涓簿鐏电鎾 + bool isCollisionWith(Sprite * sprite); + // 淇敼绮剧伒鍥剧墖 + virtual void setImage(Image * image); + // 鎵ц鍔ㄤ綔 + virtual void addAction(Action * action); + // 鎵ц鍔ㄤ綔 + virtual void runAction(Action * action); + // 缁х画鍔ㄤ綔 + virtual void resumeAction(Action * action); + // 鏆傚仠鍔ㄤ綔 + virtual void pauseAction(Action * action); + // 鍋滄鍔ㄤ綔 + virtual void stopAction(Action * action); + // 鏆傚仠鎵鏈夊姩浣 + virtual void pauseAllActions(); + // 缁х画鎵鏈夊姩浣 + virtual void resumeAllActions(); + // 鍋滄鎵鏈夊姩浣 + virtual void stopAllActions(); + + virtual float getScaleX() const; + virtual float getScaleY() const; + virtual float getOpacity() const; + + virtual void setScale(float scaleX, float scaleY); + virtual void setOpacity(float opacity); + +protected: + float m_fScaleX; + float m_fScaleY; + BYTE m_nAlpha; + Image * m_pImage; + +protected: + bool _exec(bool active) override; + void _onDraw() override; +}; + +class BatchSprite : + public Sprite +{ +public: + BatchSprite(); + virtual ~BatchSprite(); + + // 娣诲姞绮剧伒 + void add(Sprite * sprite, int z_Order = 0); + // 鍒犻櫎绮剧伒 + bool delSprite(Sprite * child); + // 鑾峰彇绮剧伒鏁伴噺 + int getCount(); + // 鑾峰彇鎵鏈夌簿鐏 + std::vector &getChildren(); + // 鍒犻櫎鎵鏈夌簿鐏 + void clearAllSprites(); + // 鍒ゆ柇鏄惁鏈夌簿鐏典骇鐢熺鎾 + // 杩斿洖鍊硷細鑻ユ湁纰版挒锛岃繑鍥炵涓涓骇鐢熺鎾炵殑绮剧伒锛屽惁鍒欒繑鍥炵┖鎸囬拡 + Sprite * isCollisionWith(Sprite * sprite); + // 鍒ゆ柇鐐规槸鍚﹀湪绮剧伒鍐呴儴 + // 杩斿洖鍊硷細鑻ヨ繖涓偣鍦ㄤ换鎰忎竴涓簿鐏靛唴閮紝杩斿洖杩欎釜绮剧伒锛屽惁鍒欒繑鍥炵┖鎸囬拡 + Sprite * isPointIn(CPoint point); + // 鎵鏈夌簿鐏靛悓鏃舵墽琛屼竴娈靛姩鐢 + virtual void addAction(Action * action) override; + // 鍚屾椂淇敼鎵鏈夌簿鐏电殑鍥剧墖 + virtual void setImage(Image * image) override; + + // 璁剧疆鑺傜偣妯潗鏍 + virtual void setX(int x) override; + // 璁剧疆鑺傜偣绾靛潗鏍 + virtual void setY(int y) override; + // 璁剧疆鑺傜偣鍧愭爣 + virtual void setPos(int x, int y) override; + // 璁剧疆鑺傜偣鍧愭爣 + virtual void setPos(CPoint p) override; + // 绉诲姩鑺傜偣 + virtual void move(int x, int y) override; + // 绉诲姩鑺傜偣 + virtual void move(CVector v) override; + + virtual float getScaleX() const override; + virtual float getScaleY() const override; + virtual float getOpacity() const override; + + virtual void setScale(float scaleX, float scaleY) override; + virtual void setOpacity(float opacity) override; + +protected: + std::vector m_vSprites; + +protected: + bool _exec(bool active) override; + void _onDraw() override; +}; + +class MouseNode : + public RectNode +{ +public: + MouseNode(); + virtual ~MouseNode(); + + // 榧犳爣鏄惁绉诲叆 + virtual bool isMouseIn(); + // 榧犳爣鏄惁閫変腑 + virtual bool isSelected(); + // 璁剧疆鍥炶皟鍑芥暟 + virtual void setClickedCallback(const CLICK_CALLBACK & callback); + // 璁剧疆鍥炶皟鍑芥暟 + virtual void setMouseInCallback(const CLICK_CALLBACK & callback); + // 璁剧疆鍥炶皟鍑芥暟 + virtual void setMouseOutCallback(const CLICK_CALLBACK & callback); + // 璁剧疆鍥炶皟鍑芥暟 + virtual void setSelectCallback(const CLICK_CALLBACK & callback); + // 璁剧疆鍥炶皟鍑芥暟 + virtual void setUnselectCallback(const CLICK_CALLBACK & callback); + // 閲嶇疆鐘舵 + virtual void reset(); + // 璁剧疆鑺傜偣鏄惁闃诲榧犳爣娑堟伅 + void setBlock(bool block); + +protected: + bool m_bTarget; + bool m_bBlock; + enum Status { NORMAL, MOUSEIN, SELECTED } m_eStatus; + CLICK_CALLBACK m_OnMouseInCallback; + CLICK_CALLBACK m_OnMouseOutCallback; + CLICK_CALLBACK m_OnSelectCallback; + CLICK_CALLBACK m_OnUnselectCallback; + CLICK_CALLBACK m_ClickCallback; + +protected: + virtual bool _exec(bool active) override; + virtual void _onDraw() override; + + // 閲嶅啓杩欎釜鏂规硶鍙互鑷畾涔夋寜閽殑鍒ゆ柇鏂规硶 + virtual bool _isMouseIn(); + // 鍒囨崲鐘舵 + virtual void _setStatus(Status status); + // 姝e父鐘舵 + virtual void _onNormal() = 0; + // 榧犳爣绉诲叆鏃 + virtual void _onMouseIn() = 0; + // 榧犳爣閫変腑鏃 + virtual void _onSelected() = 0; +}; + +class Button : + public MouseNode +{ +public: + Button(); + virtual ~Button(); + + // 鎸夐挳鏄惁鍚敤 + virtual bool isEnable(); + // 璁剧疆鏄惁鍚敤 + virtual void setEnable(bool enable); + + // 璁剧疆鎸夐挳妯潗鏍 + virtual void setX(int x) override; + // 璁剧疆鎸夐挳绾靛潗鏍 + virtual void setY(int y) override; + // 璁剧疆鎸夐挳鍧愭爣 + virtual void setPos(int x, int y) override; + // 璁剧疆鎸夐挳鍧愭爣 + virtual void setPos(CPoint p) override; + // 绉诲姩鎸夐挳 + virtual void move(int x, int y) override; + // 绉诲姩鎸夐挳 + virtual void move(CVector v) override; + +protected: + bool m_bEnable; + +protected: + virtual bool _exec(bool active) override; + virtual void _onDraw() override; + virtual void _resetPosition() = 0; + + virtual void _onNormal() = 0; + virtual void _onMouseIn() = 0; + virtual void _onSelected() = 0; + virtual void _onDisable() = 0; +}; + +class TextButton : + public Button +{ +public: + TextButton(); + TextButton(TString text); + TextButton(Text * text); + virtual ~TextButton(); + + // 璁剧疆鎸夐挳鏂囧瓧 + void setNormal(Text * text); + // 璁剧疆榧犳爣绉诲叆鏃剁殑鎸夐挳鏂囧瓧 + void setMouseIn(Text * text); + // 璁剧疆榧犳爣閫変腑鏃剁殑鎸夐挳鏂囧瓧 + void setSelected(Text * text); + // 璁剧疆鎸夐挳绂佺敤鏃剁殑鎸夐挳鏂囧瓧 + void setUnable(Text * text); + +protected: + Text * m_pNormalText; + Text * m_pMouseInText; + Text * m_pSelectedText; + Text * m_pUnableText; + +protected: + virtual void _resetPosition() override; + + virtual void _setStatus(Status status) override; + virtual void _onNormal() override; + virtual void _onMouseIn() override; + virtual void _onSelected() override; + virtual void _onDisable() override; +}; + +class ImageButton : + public Button +{ +public: + ImageButton(); + ImageButton(LPCTSTR image); + ImageButton(Image * image); + virtual ~ImageButton(); + + // 璁剧疆鎸夐挳鍥剧墖 + void setNormal(Image * image); + // 璁剧疆榧犳爣绉诲叆鏃剁殑鎸夐挳鍥剧墖 + void setMouseIn(Image * image); + // 璁剧疆榧犳爣閫変腑鏃剁殑鎸夐挳鍥剧墖 + void setSelected(Image * image); + // 璁剧疆鎸夐挳绂佺敤鏃剁殑鎸夐挳鍥剧墖 + void setUnable(Image * image); + +protected: + Image * m_pNormalImage; + Image * m_pMouseInImage; + Image * m_pSelectedImage; + Image * m_pUnableImage; + +protected: + virtual void _resetPosition() override; + virtual void _setStatus(Status status) override; + virtual void _onNormal() override; + virtual void _onMouseIn() override; + virtual void _onSelected() override; + virtual void _onDisable() override; +}; + +class Shape : + public Node +{ +public: + Shape(); + virtual ~Shape(); + + // 褰㈢姸濉厖鏍峰紡 + enum STYLE { ROUND, SOLID, FILL } m_eStyle; + + // 鑾峰彇褰㈢姸鐨勫~鍏呴鑹 + COLORREF getFillColor() const; + // 鑾峰彇褰㈢姸鐨勭嚎鏉¢鑹 + COLORREF getLineColor() const; + // 璁剧疆濉厖棰滆壊 + void setFillColor(COLORREF color); + // 璁剧疆绾挎潯棰滆壊 + void setLineColor(COLORREF color); + // 璁剧疆濉厖鏍峰紡 + void setStyle(STYLE style); + +protected: + COLORREF fillColor; + COLORREF lineColor; + +protected: + virtual void _onDraw() override; + virtual void solidShape() = 0; + virtual void fillShape() = 0; + virtual void roundShape() = 0; +}; + +class Rect : + public Shape +{ +public: + Rect(); + Rect(int x, int y, int width, int height); + virtual ~Rect(); + + // 鑾峰彇鐭╁舰瀹藉害 + int getWidth() const; + // 鑾峰彇鐭╁舰楂樺害 + int getHeight() const; + // 璁剧疆鐭╁舰瀹藉害 + void setWidth(int width); + // 璁剧疆鐭╁舰楂樺害 + void setHeight(int height); + // 璁剧疆鐭╁舰澶у皬 + void setSize(int width, int height); + +protected: + CSize m_Size; + +protected: + virtual void solidShape() override; + virtual void fillShape() override; + virtual void roundShape() override; +}; + +class Circle : + public Shape +{ +public: + Circle(); + Circle(int x, int y, int radius); + virtual ~Circle(); + + // 鑾峰彇鍦嗗舰鍗婂緞 + int getRadius() const; + // 璁剧疆鍦嗗舰鍗婂緞 + void setRadius(int m_nRadius); + +protected: + int m_nRadius; + +protected: + virtual void solidShape() override; + virtual void fillShape() override; + virtual void roundShape() override; +}; + +class Action : + public Object +{ + friend Sprite; + friend ActionManager; + friend ActionTwo; + friend ActionNeverStop; + friend ActionSequence; +public: + Action(); + virtual ~Action(); + + // 鑾峰彇鍔ㄤ綔杩愯鐘舵 + virtual bool isRunning(); + // 鑾峰彇鍔ㄤ綔缁撴潫鐘舵 + virtual bool isEnding(); + // 缁х画鍔ㄤ綔 + virtual void start(); + // 缁х画鍔ㄤ綔 + virtual void resume(); + // 鏆傚仠鍔ㄤ綔 + virtual void pause(); + // 鍋滄鍔ㄤ綔 + virtual void stop(); + // 杩涘叆绛夊緟鐘舵 + virtual void wait(); + // 鍞ら啋 + virtual void notify(); + // 璁剧疆鍔ㄤ綔姣忎竴甯ф椂闂撮棿闅 + virtual void setInterval(LONGLONG milliSeconds); + // 鑾峰彇涓涓柊鐨勬嫹璐濆姩浣 + virtual Action * copy() const = 0; + // 鑾峰彇涓涓柊鐨勯嗗悜鍔ㄤ綔 + virtual Action * reverse() const; + // 鑾峰彇鎵ц璇ュ姩浣滅殑鐩爣 + virtual Sprite * getTarget(); + +protected: + bool m_bRunning; + bool m_bWaiting; + bool m_bEnding; + bool m_bInit; + Sprite * m_pTargetSprite; + Scene * m_pParentScene; + LONGLONG m_nAnimationInterval; + std::chrono::steady_clock::time_point m_nLast; + +protected: + virtual void _init(); + virtual void _exec(std::chrono::steady_clock::time_point nNow) = 0; + virtual void _reset(); +}; + +class Animation : + public Action +{ +public: + Animation(float duration); + virtual ~Animation(); + +protected: + LONGLONG m_nDuration; + LONGLONG m_nTotalDuration; + +protected: + bool _isEnd() const; + bool _isDelayEnough(std::chrono::steady_clock::time_point nNow); + virtual void _init() override; + virtual void _reset() override; +}; + +class ActionMoveBy : + public Animation +{ +public: + ActionMoveBy(float duration, CVector vec); + virtual ~ActionMoveBy(); + + virtual ActionMoveBy * copy() const override; + virtual ActionMoveBy * reverse() const override; + +protected: + CPoint m_BeginPos; + CVector m_MoveVector; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class ActionMoveTo : + public ActionMoveBy +{ +public: + ActionMoveTo(float duration, CPoint pos); + virtual ~ActionMoveTo(); + + virtual ActionMoveTo * copy() const override; + +protected: + CPoint m_EndPos; + +protected: + virtual void _init() override; + virtual void _reset() override; +}; + +class ActionScaleBy : + public Animation +{ +public: + ActionScaleBy(float duration, float scaleX, float scaleY); + virtual ~ActionScaleBy(); + + virtual ActionScaleBy * copy() const override; + virtual ActionScaleBy * reverse() const override; + +protected: + float m_nBeginScaleX; + float m_nBeginScaleY; + float m_nVariationX; + float m_nVariationY; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class ActionScaleTo : + public ActionScaleBy +{ +public: + ActionScaleTo(float duration, float scaleX, float scaleY); + virtual ~ActionScaleTo(); + + virtual ActionScaleTo * copy() const override; + +protected: + float m_nEndScaleX; + float m_nEndScaleY; + +protected: + virtual void _init() override; + virtual void _reset() override; +}; + +class ActionOpacityBy : + public Animation +{ +public: + ActionOpacityBy(float duration, float opacity); + virtual ~ActionOpacityBy(); + + virtual ActionOpacityBy * copy() const override; + virtual ActionOpacityBy * reverse() const override; + +protected: + float m_nBeginVal; + float m_nVariation; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class ActionOpacityTo : + public ActionOpacityBy +{ +public: + ActionOpacityTo(float duration, float opacity); + virtual ~ActionOpacityTo(); + + virtual ActionOpacityTo * copy() const override; + +protected: + float m_nEndVal; + +protected: + virtual void _init() override; + virtual void _reset() override; +}; + +class ActionFadeIn : + public ActionOpacityTo +{ +public: + ActionFadeIn(float duration) : ActionOpacityTo(duration, 1) {} +}; + +class ActionFadeOut : + public ActionOpacityTo +{ +public: + ActionFadeOut(float duration) : ActionOpacityTo(duration, 0) {} +}; + +class ActionTwo : + public Action +{ +public: + ActionTwo(Action * actionFirst, Action * actionSecond); + virtual ~ActionTwo(); + + virtual ActionTwo * copy() const override; + virtual ActionTwo * reverse(bool actionReverse = true) const; + +protected: + Action * m_FirstAction; + Action * m_SecondAction; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class ActionSequence : + public Action +{ +public: + ActionSequence(); + ActionSequence(int number, Action * action1, ...); + virtual ~ActionSequence(); + + void addAction(Action * action); + virtual ActionSequence * copy() const override; + virtual ActionSequence * reverse(bool actionReverse = true) const; + +protected: + UINT m_nActionIndex; + std::vector m_vActions; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class ActionDelay : + public Action +{ +public: + ActionDelay(float duration); + virtual ~ActionDelay(); + + virtual ActionDelay * copy() const override; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class ActionNeverStop : + public Action +{ +public: + ActionNeverStop(Action * action); + virtual ~ActionNeverStop(); + + virtual ActionNeverStop * copy() const override; + +protected: + Action * m_Action; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class ActionFrames : + public Action +{ +public: + ActionFrames(); + ActionFrames(LONGLONG frameDelay); + ~ActionFrames(); + + void addFrame(Image * frame); + virtual ActionFrames * copy() const override; + virtual ActionFrames * reverse() const override; + +protected: + UINT m_nFrameIndex; + std::vector m_vFrames; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class ActionCallback : + public Action +{ +public: + ActionCallback(const std::function& callback); + ~ActionCallback(); + + virtual ActionCallback * copy() const override; + +protected: + std::function m_Callback; + +protected: + virtual void _init() override; + virtual void _exec(std::chrono::steady_clock::time_point nNow) override; + virtual void _reset() override; +}; + +class FileUtils +{ +public: + // 鑾峰彇绯荤粺鐨 AppData\Local 璺緞 + static TString getLocalAppDataPath(); + // 鑾峰彇榛樿鐨勪繚瀛樿矾寰 + static TString getDefaultSavePath(); + // 淇濆瓨 int 鍨嬬殑鍊 + static void saveInt(LPCTSTR key, int value); + // 淇濆瓨 double 鍨嬬殑鍊 + static void saveDouble(LPCTSTR key, double value); + // 淇濆瓨 瀛楃涓 鍨嬬殑鍊硷紙涓嶈鍦 Unicode 瀛楃闆嗕笅淇濆瓨涓枃瀛楃锛 + static void saveString(LPCTSTR key, TString value); + // 鑾峰彇 int 鍨嬬殑鍊硷紙鑻ヤ笉瀛樺湪鍒欒繑鍥 default 鍙傛暟鐨勫硷級 + static int getInt(LPCTSTR key, int default); + // 鑾峰彇 double 鍨嬬殑鍊硷紙鑻ヤ笉瀛樺湪鍒欒繑鍥 default 鍙傛暟鐨勫硷級 + static double getDouble(LPCTSTR key, double default); + // 鑾峰彇 瀛楃涓 鍨嬬殑鍊硷紙鑻ヤ笉瀛樺湪鍒欒繑鍥 default 鍙傛暟鐨勫硷級 + static TString geTString(LPCTSTR key, TString default); + // 寰楀埌鏂囦欢鎵╁睍鍚嶏紙灏忓啓锛 + static TString getFileExtension(const TString& filePath); + /** + * 鎵撳紑淇濆瓨鏂囦欢瀵硅瘽妗嗭紝寰楀埌鏈夋晥淇濆瓨璺緞杩斿洖 true + * 鍙傛暟锛氳繑鍥炴枃浠惰矾寰勭殑瀛楃涓诧紝绐楀彛鏍囬锛岃缃墿灞曞悕杩囨护锛岃缃粯璁ゆ墿灞曞悕 + */ + static bool getSaveFilePath(TString& path, LPCTSTR title = _T("淇濆瓨鍒"), LPCTSTR defExt = NULL); +}; + +class MusicUtils +{ +public: + // 鎾斁鑳屾櫙闊充箰 + static void playBackgroundMusic(TString pszFilePath, bool bLoop = true); + // 鍋滄鑳屾櫙闊充箰 + static void stopBackgroundMusic(bool bReleaseData = false); + // 鏆傚仠鑳屾櫙闊充箰 + static void pauseBackgroundMusic(); + // 缁х画鎾斁鑳屾櫙闊充箰 + static void resumeBackgroundMusic(); + // 浠庡ご鎾斁鑳屾櫙闊充箰 + static void rewindBackgroundMusic(); + // 鑳屾櫙闊充箰鏄惁姝e湪鎾斁 + static bool isBackgroundMusicPlaying(); + // 璁剧疆鑳屾櫙闊充箰闊抽噺锛0 ~ 1.0f + static void setBackgroundMusicVolume(float volume); + + // 鎾斁闊虫晥 + static unsigned int playMusic(TString pszFilePath, bool loop = false); + // 鍋滄闊虫晥 + static void stopMusic(unsigned int nSoundId); + // 棰勫姞杞介煶鏁 + static void preloadMusic(TString pszFilePath); + // 鏆傚仠闊虫晥 + static void pauseMusic(unsigned int nSoundId); + // 缁х画鎾斁闊虫晥 + static void resumeMusic(unsigned int nSoundId); + // 鍗歌浇闊虫晥 + static void unloadMusic(LPCTSTR pszFilePath); + // 璁剧疆鐗瑰畾闊充箰鐨勯煶閲忥紝0 ~ 1.0f + static void setVolume(TString pszFilePath, float volume); + + // 鏆傚仠鎵鏈夐煶涔 + static void pauseAllMusics(); + // 缁х画鎾斁鎵鏈夐煶涔 + static void resumeAllMusics(); + // 鍋滄鎵鏈夐煶涔 + static void stopAllMusics(); + // 鍋滄鎵鏈夐煶涔愶紝骞堕噴鏀惧唴瀛 + static void end(); + // 璁剧疆鎬婚煶閲忥紝0 ~ 1.0f + static void setVolume(float volume); +}; + +class Timer +{ + friend App; +public: + Timer(TString name, LONGLONG milliSeconds, const TIMER_CALLBACK & callback); + ~Timer(); + + // 鍚姩瀹氭椂鍣 + void start(); + // 鍋滄瀹氭椂鍣 + void stop(); + // 杩涘叆绛夊緟鐘舵 + void wait(); + // 鍞ら啋 + void notify(); + // 瀹氭椂鍣ㄦ槸鍚︽鍦ㄨ繍琛 + bool isRunning(); + // 璁剧疆闂撮殧鏃堕棿 + void setInterval(LONGLONG milliSeconds); + // 璁剧疆鍥炶皟鍑芥暟 + void setCallback(const TIMER_CALLBACK& callback); + // 璁剧疆瀹氭椂鍣ㄥ悕绉 + void setName(TString name); + // 鑾峰彇瀹氭椂鍣ㄩ棿闅旀椂闂 + LONGLONG getInterval() const; + // 鑾峰彇瀹氭椂鍣ㄥ悕绉 + TString getName() const; + + // 娣诲姞瀹氭椂鍣 + static void addTimer(Timer * timer); + // 娣诲姞瀹氭椂鍣 + static void addTimer(TString name, const TIMER_CALLBACK & callback); + // 娣诲姞瀹氭椂鍣 + static void addTimer(TString name, LONGLONG milliSeconds, const TIMER_CALLBACK & callback); + // 鍚姩鐗瑰畾瀹氭椂鍣 + static void startTimer(TString name); + // 鍋滄鐗瑰畾瀹氭椂鍣 + static void stopTimer(TString name); + // 鍒犻櫎鐗瑰畾瀹氭椂鍣 + static void delTimer(TString name); + // 鍒犻櫎鎵鏈夊畾鏃跺櫒 + static void clearAllTimers(); + + // 缁х画缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夊畾鏃跺櫒 + static void notifyAllSceneTimers(Scene* scene); + // 鍋滄缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夊畾鏃跺櫒 + static void waitAllSceneTimers(Scene* scene); + // 娓呴櫎缁戝畾鍦ㄥ満鏅笂鐨勬墍鏈夊畾鏃跺櫒 + static void clearAllSceneTimers(Scene* scene); + +protected: + bool m_bRunning; + bool m_bWaiting; + TString m_sName; + TIMER_CALLBACK m_callback; + LONGLONG m_nAnimationInterval; + Scene * m_pParentScene; + std::chrono::steady_clock::time_point m_nLast; + +private: + static void __exec(); +}; + +class ActionManager +{ + friend App; + friend Sprite; +public: + // 缁х画涓涓壒瀹氱殑鍔ㄤ綔 + static void startAction(Action * action); + // 缁х画涓涓壒瀹氱殑鍔ㄤ綔 + static void resumeAction(Action * action); + // 鏆傚仠涓涓壒瀹氱殑鍔ㄤ綔 + static void pauseAction(Action * action); + // 鍋滄涓涓壒瀹氱殑鍔ㄤ綔 + static void stopAction(Action * action); + + // 缁х画涓涓 Sprite 鐨勬墍鏈夊姩浣 + static void startSpriteAllActions(Sprite * sprite); + // 缁х画涓涓 Sprite 鐨勬墍鏈夊姩浣 + static void resumeSpriteAllActions(Sprite * sprite); + // 鏆傚仠涓涓 Sprite 鐨勬墍鏈夊姩浣 + static void pauseSpriteAllActions(Sprite * sprite); + // 鍋滄涓涓 Sprite 鐨勬墍鏈夊姩浣 + static void stopSpriteAllActions(Sprite * sprite); + + // 缁х画褰撳墠瀛樺湪鐨勬墍鏈夊姩浣 + static void startAllActions(); + // 缁х画褰撳墠瀛樺湪鐨勬墍鏈夊姩浣 + static void resumeAllActions(); + // 鏆傚仠褰撳墠瀛樺湪鐨勬墍鏈夊姩浣 + static void pauseAllActions(); + // 鍋滄褰撳墠瀛樺湪鐨勬墍鏈夊姩浣 + static void stopAllActions(); + // 鍒犻櫎褰撳墠瀛樺湪鐨勬墍鏈夊姩浣 + static void clearAllActions(); + + // 缁х画缁戝畾鍦ㄥ満鏅笂鐨勫姩浣 + static void notifyAllSceneActions(Scene* scene); + // 鏆傚仠缁戝畾鍦ㄥ満鏅笂鐨勫姩浣 + static void waitAllSceneActions(Scene* scene); + // 鍋滄缁戝畾鍦ㄥ満鏅笂鐨勫姩浣 + static void stopAllSceneActions(Scene* scene); + +private: + static void __exec(); + // 灏嗕竴涓姩浣滄坊鍔犺繘鍔ㄤ綔绠$悊鍣 + static void addAction(Action * action); +}; + +class Math +{ +public: + // 鍙栧緱鏁村瀷鑼冨洿鍐呯殑涓涓殢鏈烘暟 + template + static T randomInt(T min, T max) + { + std::uniform_int_distribution dist(min, max); + return dist(getEngine()); + } + // 鍙栧緱娴偣鏁扮被鍨嬭寖鍥村唴鐨勪竴涓殢鏈烘暟 + template + static T randomReal(T min, T max) + { + std::uniform_real_distribution dist(min, max); + return dist(getEngine()); + } + // 鑾峰彇闅忔満鏁颁骇鐢熷櫒 + static std::default_random_engine &getEngine(); +}; + +} // End of easy2d namespace + + +// Functions Declare + +template +inline void SafeRelease(T* p) { if (p) p->release(); } +template +inline void SafeDelete(T* p) { if (p) delete p; } + +template +inline T random(T min, T max) { return easy2d::Math::randomInt(min, max); } +inline float random(float min, float max) { return easy2d::Math::randomReal(min, max); } +inline double random(double min, double max) { return easy2d::Math::randomReal(min, max); } +inline long double random(long double min, long double max) { return easy2d::Math::randomReal(min, max); } + +using namespace easy2d; \ No newline at end of file