diff --git a/.gitignore b/.gitignore index 2e612965..e456e94c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ # ignore all files in the /Easy2D/** directory Easy2D/Win32/ -Easy2D/x64/ \ No newline at end of file +Easy2D/x64/ +Win32 +x64 +backup +*.lnk +.vs \ No newline at end of file diff --git a/Easy2D/App.cpp b/Easy2D/App.cpp index 5a109ab5..b834aa5d 100644 --- a/Easy2D/App.cpp +++ b/Easy2D/App.cpp @@ -18,7 +18,6 @@ App::App() : m_currentScene(nullptr), m_nextScene(nullptr), m_bRunning(false), - m_bPause(false), m_nWidth(0), m_nHeight(0), m_nWindowMode(0) @@ -154,11 +153,6 @@ void App::_initGraph() void App::_mainLoop() { - // 游戏暂停 - if (m_bPause) - { - return; - } // 进入下一场景 if (m_nextScene) { @@ -294,16 +288,6 @@ void App::end() m_bRunning = false; } -void App::pause() -{ - m_bPause = true; -} - -bool App::isRunning() -{ - return m_bRunning && !m_bPause; -} - void App::reset() { // 重置绘图环境 @@ -320,7 +304,7 @@ Scene * App::getCurrentScene() LPCTSTR easy2d::App::getVersion() { - return _T("1.0.0"); + return _T("1.0.2"); } void App::setFPS(DWORD fps) diff --git a/Easy2D/Easy2D.vcxproj b/Easy2D/Easy2D.vcxproj index 2390ea2a..c95d3354 100644 --- a/Easy2D/Easy2D.vcxproj +++ b/Easy2D/Easy2D.vcxproj @@ -334,9 +334,6 @@ EasyX\x64 - - - diff --git a/Easy2D/Easy2D.vcxproj.filters b/Easy2D/Easy2D.vcxproj.filters index f3559bc9..fc9489b6 100644 --- a/Easy2D/Easy2D.vcxproj.filters +++ b/Easy2D/Easy2D.vcxproj.filters @@ -35,9 +35,6 @@ {bdcd902b-b53d-4537-9632-76ea14c141a0} - - - 婧愭枃浠 diff --git a/Easy2D/FreePool.cpp b/Easy2D/FreePool.cpp index 01b5a72b..924a189d 100644 --- a/Easy2D/FreePool.cpp +++ b/Easy2D/FreePool.cpp @@ -32,7 +32,11 @@ void FreePool::__flush() } } -void FreePool::add(Object * nptr) +void FreePool::__add(Object * nptr) { - pool.push_back(nptr); // 将一个对象放入释放池中 + for (auto o : pool) + { + if (o == nptr) return; // 不得有重复的指针存在 + } + pool.push_back(nptr); // 将一个对象放入释放池中 } diff --git a/Easy2D/Msg/KeyMsg.cpp b/Easy2D/Msg/KeyMsg.cpp index 6ed05471..6fb0ddd8 100644 --- a/Easy2D/Msg/KeyMsg.cpp +++ b/Easy2D/Msg/KeyMsg.cpp @@ -134,7 +134,7 @@ void KeyMsg::addListener(tstring name, const KEY_CALLBACK & callback) s_vKeyMsg.push_back(key); } -bool easy2d::KeyMsg::delListener(tstring name) +bool KeyMsg::delListener(tstring name) { // 创建迭代器 std::vector::iterator iter; @@ -154,12 +154,12 @@ bool easy2d::KeyMsg::delListener(tstring name) return false; } -void easy2d::KeyMsg::clearAllListener() +void KeyMsg::clearAllListener() { // 删除所有监听器 - for (auto t : s_vKeyMsg) + for (auto k : s_vKeyMsg) { - delete t; + delete k; } // 清空容器 s_vKeyMsg.clear(); diff --git a/Easy2D/Msg/MouseMsg.cpp b/Easy2D/Msg/MouseMsg.cpp index 98b8de6a..6a3084d9 100644 --- a/Easy2D/Msg/MouseMsg.cpp +++ b/Easy2D/Msg/MouseMsg.cpp @@ -1,13 +1,16 @@ #include "..\easy2d.h" #include "..\EasyX\easyx.h" +// 鼠标监听回调函数的容器 +static std::vector s_vMouseMsg; + // 鼠标消息 static MouseMsg s_mouseMsg = MouseMsg(); // 将 EasyX 的 MOUSEMSG 转换为 MouseMsg static void ConvertMsg(MOUSEMSG msg); -void easy2d::MouseMsg::__exec() +void MouseMsg::__exec() { // 获取鼠标消息 while (MouseHit()) @@ -16,9 +19,72 @@ void easy2d::MouseMsg::__exec() ConvertMsg(GetMouseMsg()); // 执行场景程序 App::get()->getCurrentScene()->_exec(); + // 执行鼠标监听回调函数 + for (auto m : s_vMouseMsg) // 循环遍历所有的鼠标监听 + { + m->onMouseMsg(s_mouseMsg); // 执行回调函数 + } } } +MouseMsg::MouseMsg() +{ +} + +MouseMsg::MouseMsg(tstring name, const MOUSE_CALLBACK & callback) +{ + m_sName = name; + m_callback = callback; +} + +MouseMsg::~MouseMsg() +{ +} + +void MouseMsg::onMouseMsg(MouseMsg mouse) +{ + m_callback(mouse); +} + +void MouseMsg::addListener(tstring name, const MOUSE_CALLBACK & callback) +{ + // 创建新的监听对象 + auto mouse = new MouseMsg(name, callback); + // 添加新的按键回调函数 + s_vMouseMsg.push_back(mouse); +} + +bool MouseMsg::delListener(tstring name) +{ + // 创建迭代器 + std::vector::iterator iter; + // 循环遍历所有监听器 + for (iter = s_vMouseMsg.begin(); iter != s_vMouseMsg.end(); iter++) + { + // 查找相同名称的监听器 + if ((*iter)->m_sName == name) + { + // 删除该定时器 + delete (*iter); + s_vMouseMsg.erase(iter); + return true; + } + } + // 若未找到同样名称的监听器,返回 false + return false; +} + +void MouseMsg::clearAllListener() +{ + // 删除所有监听器 + for (auto m : s_vMouseMsg) + { + delete m; + } + // 清空容器 + s_vMouseMsg.clear(); +} + MouseMsg MouseMsg::getMsg() { return s_mouseMsg; // 获取当前鼠标消息 diff --git a/Easy2D/Node/Button/Button.cpp b/Easy2D/Node/Button/Button.cpp index 8c52a4ca..112d3c74 100644 --- a/Easy2D/Node/Button/Button.cpp +++ b/Easy2D/Node/Button/Button.cpp @@ -14,7 +14,7 @@ Button::~Button() bool Button::_exec(bool active) { // 按钮是否启用 - if (!m_bEnable || !m_bDisplay) + if (!m_bEnable) { return false; } @@ -33,27 +33,6 @@ void Button::_onDraw() MouseNode::_onDraw(); } -void Button::_judge() -{ - // 判断按钮当前的状态 - // 若鼠标位置在按钮所在的矩形区域中 - if (MouseMsg::getMsg().x >= m_nX && MouseMsg::getMsg().x <= m_nX + m_nWidth && - MouseMsg::getMsg().y >= m_nY && MouseMsg::getMsg().y <= m_nY + m_nHeight) - { - _setMouseIn(); - - // 若鼠标在按钮上,且鼠标左键按下 - if (MouseMsg::isLButtonDown()) - { - _setSelected(); - } - } - else - { - _setNormal(); - } -} - bool Button::isEnable() { return m_bEnable; diff --git a/Easy2D/Node/Image.cpp b/Easy2D/Node/Image.cpp index 3b4a48fc..2ceab9a0 100644 --- a/Easy2D/Node/Image.cpp +++ b/Easy2D/Node/Image.cpp @@ -52,10 +52,25 @@ float Image::getScaleY() const return m_fScaleY; } -void Image::setImageFile(LPCTSTR ImageFile, int x, int y, int width, int height) +bool Image::setImageFile(LPCTSTR ImageFile, int x, int y, int width, int height) { + //判断图片路径是否存在 + if (!PathFileExists(ImageFile)) + { + return false; + } + // 清空原资源 + if (!m_Image.IsNull()) + { + m_Image.Destroy(); + } // 加载图片 m_Image.Load(ImageFile); + // 加载失败 + if (m_Image.IsNull()) + { + return false; + } // 获取扩展名,对 PNG 图片进行特殊处理 if (_T(".png") == FileUtils::getFileExtension(ImageFile)) { @@ -68,18 +83,27 @@ void Image::setImageFile(LPCTSTR ImageFile, int x, int y, int width, int height) m_rDest.SetRect(0, 0, m_Image.GetWidth(), m_Image.GetHeight()); // 裁剪图片大小 crop(x, y, width, height); + + return true; } -void Image::setImageRes(LPCTSTR pResName, int x, int y, int width, int height) +bool Image::setImageRes(LPCTSTR pResName, int x, int y, int width, int height) { // 从资源加载图片(不支持 PNG) m_Image.LoadFromResource(GetModuleHandle(NULL), pResName); + // 加载失败 + if (m_Image.IsNull()) + { + return false; + } // 重置缩放属性 m_fScaleX = 0, m_fScaleY = 0; // 设置目标矩形(即绘制到窗口的位置和大小) m_rDest.SetRect(0, 0, m_Image.GetWidth(), m_Image.GetHeight()); // 裁剪图片大小 crop(x, y, width, height); + + return true; } void Image::crop(int x, int y, int width, int height) diff --git a/Easy2D/Node/MouseNode.cpp b/Easy2D/Node/MouseNode.cpp index c70c870b..a648b327 100644 --- a/Easy2D/Node/MouseNode.cpp +++ b/Easy2D/Node/MouseNode.cpp @@ -4,7 +4,11 @@ MouseNode::MouseNode() : m_bBlock(true), m_bTarget(false), - m_callback([]() {}) + m_ClickCallback([]() {}), + m_OnMouseInCallback([]() {}), + m_OnMouseOutCallback([]() {}), + m_OnSelectCallback([]() {}), + m_OnUnselectCallback([]() {}) { } @@ -19,15 +23,40 @@ bool MouseNode::_exec(bool active) { return false; } - // 判断节点状态 - _judge(); - // 鼠标在节点上(被选中时鼠标也在节点上) - if (m_eStatus == MOUSEIN || m_eStatus == SELECTED) + // 判断节点当前的状态 + // 若节点未取得焦点,则重新判断节点状态 + if (!m_bTarget) { - // 节点被鼠标选中,且鼠标左键抬起 - if (m_bTarget && MouseMsg::isOnLButtonUp()) + // 若鼠标位置在节点所在的矩形区域中 + if (_judge()) { - onClicked(); // 执行回调函数 + // 状态设为 MOUSEIN + _setStatus(MOUSEIN); + // 若此时按下鼠标左键 + if (MouseMsg::isOnLButtonDown()) + { + m_bTarget = true; // 取得焦点标记 + _setStatus(SELECTED); // 状态设为 SELECTED + } + // 若节点不阻塞鼠标消息,则取得画面焦点 + if (!m_bBlock) return true; + } + else + { + reset(); // 恢复默认状态 + } + } + else + { + // 节点取得焦点时鼠标左键抬起 + if (MouseMsg::isOnLButtonUp()) + { + // 若左键抬起时鼠标仍在节点内 + if (_judge()) + { + m_ClickCallback(); // 执行回调函数 + } + reset(); // 恢复默认状态 } // 若节点不阻塞鼠标消息,则取得画面焦点 if (!m_bBlock) return true; @@ -61,26 +90,36 @@ void MouseNode::_onDraw() } } -void MouseNode::_setNormal() +bool MouseNode::_judge() { - m_bTarget = false; // 失去焦点标记 - m_eStatus = NORMAL; + return (MouseMsg::getMsg().x >= m_nX && MouseMsg::getMsg().x <= m_nX + m_nWidth) && + (MouseMsg::getMsg().y >= m_nY && MouseMsg::getMsg().y <= m_nY + m_nHeight); } -void MouseNode::_setMouseIn() +void MouseNode::_setStatus(Status status) { - m_eStatus = MOUSEIN; -} - -void MouseNode::_setSelected() -{ - m_bTarget = true; // 取得焦点标记 - m_eStatus = SELECTED; -} - -void MouseNode::onClicked() -{ - m_callback(); + 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() @@ -93,14 +132,35 @@ bool MouseNode::isSelected() return m_eStatus == SELECTED; } -void MouseNode::setOnMouseClicked(const CLICK_CALLBACK & callback) +void MouseNode::setClickedCallback(const CLICK_CALLBACK & callback) { - m_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_eStatus = NORMAL; + m_bTarget = false; // 失去焦点标记 + _setStatus(NORMAL); // 恢复默认状态 } void MouseNode::setBlock(bool block) diff --git a/Easy2D/Object.cpp b/Easy2D/Object.cpp index 08ca53aa..8d77e82e 100644 --- a/Easy2D/Object.cpp +++ b/Easy2D/Object.cpp @@ -3,7 +3,7 @@ Object::Object() : m_nRef(0) { - FreePool::add(this); // 将该对象放入释放池中 + FreePool::__add(this); // 将该对象放入释放池中 } Object::~Object() diff --git a/Easy2D/Tool/MusicUtils.cpp b/Easy2D/Tool/MusicUtils.cpp index e5575f35..33fed5da 100644 --- a/Easy2D/Tool/MusicUtils.cpp +++ b/Easy2D/Tool/MusicUtils.cpp @@ -266,6 +266,14 @@ void MusicUtils::end() // BackgroundMusic ////////////////////////////////////////////////////////////////////////// +/* +void MusicUtils::setVolume(float volume) +{ + if (volume < 0 || volume > 1) return; + waveOutSetVolume(NULL, DWORD(volume * 65535)); +} +*/ + void MusicUtils::playBackgroundMusic(tstring pszFilePath, bool bLoop) { if (pszFilePath.empty()) diff --git a/Easy2D/easy2d.h b/Easy2D/easy2d.h index 1b0125fe..9b4f4af6 100644 --- a/Easy2D/easy2d.h +++ b/Easy2D/easy2d.h @@ -1,5 +1,5 @@ /****************************************************** -* Easy2D Game Engine (v1.0.0) +* Easy2D Game Engine (v1.0.2) * http://www.easy2d.cn * * Depends on EasyX (Ver:20170827(beta)) @@ -31,6 +31,7 @@ #define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p) = nullptr; } } #define SAFE_RELEASE(p) { if (p) p->release(); } +#pragma warning (disable: 4099) #include #include @@ -83,10 +84,12 @@ class TextButton; class ImageButton; +typedef BatchNode Layer; 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; class App @@ -101,7 +104,6 @@ protected: int m_nHeight; int m_nWindowMode; bool m_bRunning; - bool m_bPause; bool m_bSaveScene; protected: @@ -125,8 +127,6 @@ public: static int getOriginY(); // 启动程序 int run(); - // 暂停程序 - void pause(); // 终止程序 void quit(); // 终止程序 @@ -151,8 +151,6 @@ public: void backScene(); // 修改窗口背景色 void setBkColor(COLORREF color); - // 游戏是否正在运行 - bool isRunning(); // 设置帧率 void setFPS(DWORD fps); // 重置绘图样式为默认值 @@ -170,13 +168,13 @@ public: class FreePool { friend class App; + friend class Object; private: + // 刷新内存池 static void __flush(); - -public: // 将一个节点放入释放池 - static void add(Object * nptr); + static void __add(Object * nptr); }; class Scene @@ -211,6 +209,10 @@ class MouseMsg private: static void __exec(); +protected: + tstring m_sName; + MOUSE_CALLBACK m_callback; + public: UINT uMsg; // 当前鼠标消息 bool mkLButton; // 鼠标左键是否按下 @@ -220,6 +222,21 @@ public: short y; // 当前鼠标 y 坐标 short wheel; // 鼠标滚轮滚动值 (120 的倍数) +public: + MouseMsg(); + MouseMsg(tstring name, const MOUSE_CALLBACK& callback); + ~MouseMsg(); + + // 执行回调函数 + void onMouseMsg(MouseMsg mouse); + + // 添加键盘监听 + static void addListener(tstring name, const MOUSE_CALLBACK& callback); + // 删除键盘监听 + static bool delListener(tstring name); + // 删除所有键盘监听 + static void clearAllListener(); + public: // 获取当前鼠标消息 static MouseMsg getMsg(); @@ -530,7 +547,6 @@ class Node : public virtual Object { friend class Scene; - friend class Layer; friend class BatchNode; protected: @@ -634,13 +650,15 @@ public: /** * 从图片文件获取图像(png/bmp/jpg/gif/emf/wmf/ico) * 参数:图片文件名,图片裁剪坐标,图片裁剪宽度和高度 + * 返回值:图片加载是否成功 */ - void setImageFile(LPCTSTR ImageFile, int x = 0, int y = 0, int width = 0, int height = 0); + bool setImageFile(LPCTSTR ImageFile, int x = 0, int y = 0, int width = 0, int height = 0); /** * 从资源文件获取图像,不支持 png (bmp/jpg/gif/emf/wmf/ico) * 参数:资源名称,图片裁剪坐标,图片裁剪宽度和高度 + * 返回值:图片加载是否成功 */ - void setImageRes(LPCTSTR pResName, int x = 0, int y = 0, int width = 0, int height = 0); + bool setImageRes(LPCTSTR pResName, int x = 0, int y = 0, int width = 0, int height = 0); // 裁剪图片(裁剪后会恢复 stretch 拉伸) void crop(int x = 0, int y = 0, int width = 0, int height = 0); // 将图片拉伸到固定宽高 @@ -711,19 +729,25 @@ class MouseNode : private: bool m_bTarget; bool m_bBlock; - enum { NORMAL, MOUSEIN, SELECTED } m_eStatus; - CLICK_CALLBACK m_callback; + 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: + int m_nWidth; + int m_nHeight; protected: virtual bool _exec(bool active) override; virtual void _onDraw() override; - void _setNormal(); - void _setMouseIn(); - void _setSelected(); - - // 重写该函数,实现鼠标位置的判定 - virtual void _judge() = 0; + // 重写这个方法可以自定义按钮的判断方法 + virtual bool _judge(); + // 切换状态 + void _setStatus(Status status); // 正常状态 virtual void _onNormal() = 0; // 鼠标移入时 @@ -735,14 +759,20 @@ public: MouseNode(); virtual ~MouseNode(); - // 鼠标点击时 - virtual void onClicked(); // 鼠标是否移入 virtual bool isMouseIn(); // 鼠标是否选中 virtual bool isSelected(); // 设置回调函数 - virtual void setOnMouseClicked(const CLICK_CALLBACK & callback); + 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(); // 设置节点是否阻塞鼠标消息 @@ -754,14 +784,11 @@ class Button : public virtual MouseNode { protected: - int m_nWidth; - int m_nHeight; bool m_bEnable; protected: virtual bool _exec(bool active) override; virtual void _onDraw() override; - virtual void _judge() override; virtual void _onNormal() = 0; virtual void _onMouseIn() = 0;