最近利用Cocos2dx制作了异形窗口,记录下制作流程【Cocos版本3.17.2】:
1.去掉标题栏
在cocos/platform/desktop/CCGLViewImpl-desktop.cpp文件中的initWithRect函数里添加
glfwWindowHint(GLFW_DECORATED, GL_FALSE);
效果图:
2.窗口背景透明
网上搜索【异形窗口】的实现都是剔除像素的做法,也就是使用下面这个函数
SetLayeredWindowAttributes
这个函数需要美术同学出图配合,否则边缘处会遗留锯齿状的残留颜色【最终未采用这种方式】
后续的资料查找过程中,发现下面的方法也能实现窗口背景透明
#pragma comment(lib, "dwmapi")
DWM_BLURBEHIND bb = { 0 };
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = true;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hwnd, &bb);
后经测试发现当前参数在Win10设备会出现一层黑色遮罩,需调整参数,调整后的代码如下【该参数在Win7平台也能正常表现】
::RECT rect2;
GetWindowRect(hwnd, &rect2);
HRGN hRgn = CreateRectRgn(rect2.left, rect2.bottom, rect2.right, rect2.bottom - rect2.top);
DWM_BLURBEHIND bb = { 0 };
bb.dwFlags = DWM_BB_ENABLE| DWM_BB_BLURREGION;
bb.fEnable = true;
bb.hRgnBlur = hRgn;
DwmEnableBlurBehindWindow(hwnd, &bb);
调整之后编译运行,背景依然全黑,那是因为Cocos使用的OpenGL默认渲染一个黑色的画布。
3.清空OpenGL的画布
AppDelegate::applicationDidFinishLaunching函数中调用
Director::getInstance()->setClearColor(Color4F(0, 0, 0, 0));
效果图:
4.实现窗口的移动
封装了一个监测鼠标事件的接口,代码如下:
#ifndef __MoveWindowNode__
#define __MoveWindowNode__
#include "cocos2d.h"
#include "ui/CocosGUI.h"
class MoveWindowNode : public cocos2d::Node
{
public:
MoveWindowNode();
~MoveWindowNode();
CREATE_FUNC(MoveWindowNode)
virtual bool init();
protected:
void onMouseDown(cocos2d::Event* event);
void onMouseUp(cocos2d::Event* event);
void onMouseMove(cocos2d::Event* event);
private:
cocos2d::EventListenerMouse* m_mouseListener;
bool m_isMouseDowned;
};
#endif // __MoveWindowNode__
#include "MoveWindowNode.h"
MoveWindowNode::MoveWindowNode()
:m_mouseListener(nullptr)
,m_isMouseDowned(false)
{
}
MoveWindowNode::~MoveWindowNode()
{
if (m_mouseListener)
{
cocos2d::Director::getInstance()->getEventDispatcher()->removeEventListener(m_mouseListener);
}
}
bool MoveWindowNode::init()
{
if ( !Node::init() )
{
return false;
}
m_mouseListener = cocos2d::EventListenerMouse::create();
m_mouseListener->onMouseDown = CC_CALLBACK_1(MoveWindowNode::onMouseDown, this);
m_mouseListener->onMouseUp = CC_CALLBACK_1(MoveWindowNode::onMouseUp, this);
m_mouseListener->onMouseMove = CC_CALLBACK_1(MoveWindowNode::onMouseMove, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(m_mouseListener, this);
return true;
}
static POINT pt, pe;
static RECT rt, re;
void MoveWindowNode::onMouseDown(cocos2d::Event* event)
{
auto hwnd = cocos2d::Director::getInstance()->getOpenGLView()->getWin32Window();
SetCapture(hwnd); // 设置鼠标捕获(防止光标跑出窗口失去鼠标热点)
GetCursorPos(&pt); // 获取鼠标光标指针当前位置
GetWindowRect(hwnd, &rt); // 获取窗口位置与大小
re.right = rt.right - rt.left; // 保存窗口宽度
re.bottom = rt.bottom - rt.top; // 保存窗口高度
m_isMouseDowned = true;
}
void MoveWindowNode::onMouseUp(cocos2d::Event* event)
{
m_isMouseDowned = false;
ReleaseCapture(); // 释放鼠标捕获,恢复正常状态
}
void MoveWindowNode::onMouseMove(cocos2d::Event* event)
{
if (m_isMouseDowned)
{
GetCursorPos(&pe);
auto hwnd = cocos2d::Director::getInstance()->getOpenGLView()->getWin32Window();
re.left = rt.left + (pe.x - pt.x); // 窗口新的水平位置
re.top = rt.top + (pe.y - pt.y); // 窗口新的垂直位置
MoveWindow(hwnd, re.left, re.top, re.right, re.bottom, true); // 移动窗口
pt = pe;
GetWindowRect(hwnd, &rt); // 获取窗口位置与大小
re.right = rt.right - rt.left; // 保存窗口宽度
re.bottom = rt.bottom - rt.top; // 保存窗口高度
}
}
使用方法:
auto node = MoveWindowNode::create();
this->addChild(node);
这样一个异形窗口便制作完成了.....
效果图:
参考资料: