cocos实现拖动窗口继续渲染

6 篇文章 0 订阅

cocos虽然定位于移动端的手机游戏引擎,但也有不少公司用它开发PC游戏,由于cocos自身的原因,许多功能并不尽如人意。开发cocos游戏时,都有这样的经历,拖动cocos窗口时,或者点击窗口边框,cocos就会暂停渲染主线程,这个时候主进程阻塞(如同切入后台不渲染一样,切入后台不渲染问题,可以直接更改invalid属性解决)。然而有些游戏,需要拖动的时候,需要继续渲染,完成此需求的代码如下。

首先director中提供主渲染:

void Director::drawMoveScene(int frameNumbers)
{
	//if (bFlag == true)
	//	return;
	bFlag = true;
	if (frameNumbers < 1)
		return;
	LONGLONG interval = 0LL;
	LONG waitMS = 0L;
	static LARGE_INTEGER nLast;
	static LARGE_INTEGER nNow;
	static bool bFirst = true;
	if (bFirst)
	{
		bFirst = false;
		QueryPerformanceCounter(&nLast);
	}
	LARGE_INTEGER freq;
	QueryPerformanceFrequency(&freq);
	double lastPositionX=-999, lastPositionY=-999;
	_openGLView->getCursorPos(&lastPositionX, &lastPositionY);
	while (frameNumbers > 0)
	{
		QueryPerformanceCounter(&nNow);
		interval = nNow.QuadPart - nLast.QuadPart;
		//_openGLView->pollEvents();
		if (interval >= 30000)
		{
			nLast.QuadPart = nNow.QuadPart;
			double curPositionX = -999, curPositionY = -999;
			_openGLView->getCursorPos(&curPositionX, &curPositionY);
			if (curPositionX != lastPositionX || curPositionY != lastPositionY)
			{
				bFlag = false;
				return;
			}
			calculateDeltaTime();
			//tick before glClear: issue #533
			if (!_paused)
			{
				_eventDispatcher->dispatchEvent(_eventBeforeUpdate);
				_scheduler->update(_deltaTime);
				_eventDispatcher->dispatchEvent(_eventAfterUpdate);
			}

			_renderer->clear();
			experimental::FrameBuffer::clearAllFBOs();
			/* to avoid flickr, nextScene MUST be here: after tick and before draw.
			* FIXME: Which bug is this one. It seems that it can't be reproduced with v0.9
			*/
			if (_nextScene)
			{
				setNextScene();
			}

			pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

			if (_runningScene)
			{
#if (CC_USE_PHYSICS || (CC_USE_3D_PHYSICS && CC_ENABLE_BULLET_INTEGRATION) || CC_USE_NAVMESH)
				_runningScene->stepPhysicsAndNavigation(_deltaTime);
#endif
				//clear draw stats
				_renderer->clearDrawStats();

				//render the scene
				_openGLView->renderScene(_runningScene, _renderer);

				_eventDispatcher->dispatchEvent(_eventAfterVisit);

			}

			// draw the notifications node
			if (_notificationNode)
			{
				_notificationNode->visit(_renderer, Mat4::IDENTITY, 0);
			}

			if (_displayStats)
			{
				showStats();
			}
			else
			{
				static float prevDeltaTime = 0.016f; // 60FPS
				static const float FPS_FILTER = 0.10f;
				float dt = _deltaTime * FPS_FILTER + (1 - FPS_FILTER) * prevDeltaTime;
				prevDeltaTime = dt;
				_frameRate = 1 / dt;
			}
			_renderer->render();

			_eventDispatcher->dispatchEvent(_eventAfterDraw);

			popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

			_totalFrames++;

			// swap buffers
			if (_openGLView)
			{
				_openGLView->swapBuffers();
			}

			if (_displayStats)
			{
				calculateMPF();
			}
			frameNumbers -= 1;
			
		}
		else{
			waitMS = (30000 - interval) * 1000LL / freq.QuadPart - 1L;
			if (waitMS > 1L)
				Sleep(waitMS);

		}
		bFlag = false;
	//	_openGLView->pollEvents();
		
	}

	
}

然后,debug模式下更改SimulatorWindow函数:

LRESULT CALLBACK SNewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    switch (message)
    {
	case WM_MOVING:
		Director::getInstance()->drawMoveScene(100000);
		break;
	case WM_NCLBUTTONDOWN:
		Director::getInstance()->drawMoveScene(100000);
		break;
   
   }
  return g_oldProc(hWnd, message, wParam, lParam);
}

release模式,在AppDelegate下修改:

/*@brief new windows process*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	switch (message)
	{
	case WM_MOVING:
		Director::getInstance()->drawMoveScene(100000);
		break;
	case WM_NCLBUTTONDOWN:
		Director::getInstance()->drawMoveScene(100000);
		break;

	}
	return g_Proc(hWnd, message, wParam, lParam);

}

bool AppDelegate::applicationDidFinishLaunching()
{
	    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
	
#if (LUA_SUPPORT && COCOS2D_DEBUG > 0 && CC_CODE_IDE_DEBUG_SUPPORT > 0)
	// NOTE:Please don't remove this call if you want to debug with Cocos Code IDE
	initRuntime();
	
	// turn on display FPS
    director->setDisplayStats(true);
#endif

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0 / 60);

	if (!glview) {
		Size viewSize = ConfigParser::getInstance()->getInitViewSize();
		//string title = ConfigParser::getInstance()->getInitViewName();
		string title = StringUtils::UTF8Str("无线棋牌Demo");
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_MAC) && (COCOS2D_DEBUG > 0 && CC_CODE_IDE_DEBUG_SUPPORT > 0)
			extern void createSimulator(const char* viewName, float width, float height, bool isLandscape = true, float frameZoomFactor = 1.0f);
		bool isLanscape = ConfigParser::getInstance()->isLanscape();
		createSimulator(title.c_str(), viewSize.width, viewSize.height, isLanscape);

		director->getOpenGLView()->setFrameSize(ConfigParser::getInstance()->getInitViewSize().width, ConfigParser::getInstance()->getInitViewSize().height);
	
#else
	auto glView = cocos2d::GLViewImpl::createWithRect(title.c_str(), Rect(0, 0, viewSize.width, viewSize.height));
		auto director = Director::getInstance();
		director->setOpenGLView(glView);
		HWND hWnd = glView->getWin32Window();
		g_Proc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (LONG)WndProc);
		if (g_Proc == 0)
		{
			printf("SetWindowLong NewWndProc Error:%d\n", GetLastError());
		}	
	
#endif
	}

后续:有提出,当点击最小化,不放移动后,依旧渲染,接着修改如下:

void Director::drawMoveScene(int frameNumbers)
{
	bFlag = true;
	if (frameNumbers < 1)
		return;
	LONGLONG interval = 0LL;
	LONG waitMS = 0L;
	static LARGE_INTEGER nLast;
	static LARGE_INTEGER nNow;
	static bool bFirst = true;
	if (bFirst)
	{
		bFirst = false;
		QueryPerformanceCounter(&nLast);
	}
	LARGE_INTEGER freq;
	QueryPerformanceFrequency(&freq);
	double lastPositionX=-999, lastPositionY=-999;
	_openGLView->getCursorPos(&lastPositionX, &lastPositionY);
	auto frameSize = _openGLView->getFrameSize();
	bool bClose = false;
	int det = (_openGLView->getChangeScreen()?10:0)+105;
	int fullscreenWidth, fullscreenHeight;
	Device::getWidthAndHeight(fullscreenWidth, fullscreenHeight);
	int bottomY=-8;
	if (frameSize.width == fullscreenWidth)
	{
		bottomY += 6;
		det = 114;
	}	
	if ((frameSize.width - det < lastPositionX &&lastPositionX <= frameSize.width) && (-31 < lastPositionY&&lastPositionY < bottomY))
		bClose = true;

	while (frameNumbers > 0)
	{
		QueryPerformanceCounter(&nNow);
		interval = nNow.QuadPart - nLast.QuadPart;
		if (interval >= 30000)
		{
			nLast.QuadPart = nNow.QuadPart;
			double curPositionX = -999, curPositionY = -999;
			_openGLView->getCursorPos(&curPositionX, &curPositionY);
			auto frameSize = _openGLView->getFrameSize();
			auto state = GetAsyncKeyState(VK_LBUTTON);
			if (!state)
			{
				bFlag = false;
				return;
			}
			if ((curPositionX != lastPositionX || curPositionY != lastPositionY)&&(!bClose))
			{
					
				bFlag = false;
				return;
			}
			calculateDeltaTime();
			//tick before glClear: issue #533
			if (!_paused)
			{
				_eventDispatcher->dispatchEvent(_eventBeforeUpdate);
				_scheduler->update(_deltaTime);
				_eventDispatcher->dispatchEvent(_eventAfterUpdate);
			}

			_renderer->clear();
			experimental::FrameBuffer::clearAllFBOs();
			/* to avoid flickr, nextScene MUST be here: after tick and before draw.
			* FIXME: Which bug is this one. It seems that it can't be reproduced with v0.9
			*/
			if (_nextScene)
			{
				setNextScene();
			}

			pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

			if (_runningScene)
			{
#if (CC_USE_PHYSICS || (CC_USE_3D_PHYSICS && CC_ENABLE_BULLET_INTEGRATION) || CC_USE_NAVMESH)
				_runningScene->stepPhysicsAndNavigation(_deltaTime);
#endif
				//clear draw stats
				_renderer->clearDrawStats();

				//render the scene
				_openGLView->renderScene(_runningScene, _renderer);

				_eventDispatcher->dispatchEvent(_eventAfterVisit);

			}

			// draw the notifications node
			if (_notificationNode)
			{
				_notificationNode->visit(_renderer, Mat4::IDENTITY, 0);
			}

			if (_displayStats)
			{
				showStats();
			}
			else
			{
				static float prevDeltaTime = 0.016f; // 60FPS
				static const float FPS_FILTER = 0.10f;
				float dt = _deltaTime * FPS_FILTER + (1 - FPS_FILTER) * prevDeltaTime;
				prevDeltaTime = dt;
				_frameRate = 1 / dt;
			}
			_renderer->render();

			_eventDispatcher->dispatchEvent(_eventAfterDraw);

			popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

			_totalFrames++;

			// swap buffers
			if (_openGLView)
			{
				_openGLView->swapBuffers();
			}

			if (_displayStats)
			{
				calculateMPF();
			}
			frameNumbers -= 1;
			
		}
		else{
			waitMS = (30000 - interval) * 1000LL / freq.QuadPart - 1L;
			if (waitMS > 1L)
				Sleep(waitMS);

		}
		bFlag = false;
	//	_openGLView->pollEvents();
		
	}

	
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值