用OGRE1.74搭建游戏框架(一)

新版的OGRE出来了,不知什么原因抛弃了CEGUI。国内的教程好像也更新比较少了,在官网上还是发现不少资料的,现在参考官网上的一些资料来搭建一个游戏的框架。

参考的资料:

http://www.ogre3d.org/tikiwiki/Advanced+Ogre+Framework&structure=Tutorials

首先要先一个能启动OGRE的类(OgreFramework),把OGRE的初始化的相关工作放入其中,大体有如下几个东西:

  • Root
  • RenderWindow
  • Viewport
  • Log
  • Timer
  • InputManager / Keyboard / Mouse
  • SDKTrays Manager

OgreFramework.h

/********************************************************************

created: 2012/02/25

created: 25:2:2012 11:31

filename: E:\Ogre\Project\Ogre_Project\Game_Demo\OgreFramework.h

file path: E:\Ogre\Project\Ogre_Project\Game_Demo

file base: OgreFramework

file ext: h

author: Star purpose: ogre framework

*********************************************************************/ #ifndef _ZH_OGREFRAMEWORK_H_

#define _ZH_OGREFRAMEWORK_H_ #pragma once #include <Ogre.h>

#include <ois/OIS.h>

#include <SdkTrays.h> class OgreFramework: public Ogre::Singleton<OgreFramework>, OIS::KeyListener, OIS::MouseListener

{

public:

OgreFramework();

~OgreFramework(); bool InitOgre(Ogre::String wndTitle, OIS::KeyListener* pKeyListener = , OIS::MouseListener* pMouseListener = );

void UpdateOgre(double timeSinceLastFrame); // for key event

bool keyPressed(const OIS::KeyEvent& evt);

bool keyReleased(const OIS::KeyEvent& evt); // for mouse event

bool mouseMoved(const OIS::MouseEvent& evt);

bool mousePressed(const OIS::MouseEvent& evt, OIS::MouseButtonID id);

bool mouseReleased(const OIS::MouseEvent& evt, OIS::MouseButtonID id); public:

Ogre::Root* m_pRoot;

Ogre::RenderWindow* m_pRenderWnd;

Ogre::Viewport* m_pViewport;

Ogre::Log* m_pLog;

Ogre::Timer* m_pTimer; OIS::InputManager* m_pInputMgr;

OIS::Keyboard* m_pKeyboard;

OIS::Mouse* m_pMouse; OgreBites::SdkTrayManager* m_pTrayMgr; private:

OgreFramework(const OgreFramework&);

OgreFramework& operator= (const OgreFramework&); }; #endif //_ZH_OGREFRAMEWORK_H_

主要还是要看InitOgre的实现:

bool OgreFramework::InitOgre(Ogre::String wndTitle, OIS::KeyListener* pKeyListener /* = 0 */, OIS::MouseListener* pMouseListener /* = 0 */)

{

Ogre::LogManager* logMgr = new Ogre::LogManager(); m_pLog = Ogre::LogManager::getSingleton().createLog("OgreLogfile.log", true, true, flase);

m_pLog->setDebugOutputEnabled(true); m_pRoot = new Ogre::Root(); if (!m_pRoot->showConfigDialog())

return false; m_pRenderWnd = m_pRoot->initialise(true, wndTitle); m_pViewport = m_pRenderWnd->addViewport();

m_pViewport->setBackgroundColour(ColourValue(0.5f, 0.5f, 0.5f, 1.0f)); m_pViewport->setCamera(); size_t hWnd = ;

OIS::ParamList paramList;

m_pRenderWnd->getCustomAttribute("WINDOW", &hWnd); paramList.insert(OIS::ParamList::value_type("WINDOW", Ogre::StringConverter::toSgring(hWnd))); m_pInputMgr = OIS::InputManager::createInputSystem(paramList); m_pKeyboard = static_cast<OIS::Keyboard*>(m_pInputMgr->createInputObject(OIS::OISKeyboard, true));

m_pMouse = static_cast<OIS::Mouse*>(m_pInputMgr->createInputObject(OIS::OISMouse, true)); m_pMouse->getMouseState().height = m_pRenderWnd->getHeight();

m_pMouse->getMouseState().width = m_pRenderWnd->getWidth(); if (pKeyListener == NULL)

m_pKeyboard->setEventCallback(this);

else

m_pKeyboard->setEventCallback(pKeyListener); if (pMouseListener == NULL)

m_pMouse->setEventCallback(this);

else

m_pMouse->setEventCallback(pMouseListener); // load resources

Ogre::String secName, typeName, archName;

Ogre::ConfigFile cf;

cf.load("resources.cfg"); Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

while (seci.hasMoreElements)

{

secName = seci.peekNextKey();

Ogre::ConfigFile::SettingsMultiMap* settings = seci.getNext();

Ogre::ConfigFile::SettingsMultiMap::iterator i;

for (i = settings->begin(); i != settings->end(); ++i)

{

typeName = i->first;

archName = i->second;

Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);

}

}

Ogre::TextureManager::getSingleton().setDefaultNumMipmaps();

Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); m_pTrayMgr = new OgreBites::SdkTrayManager("OFTrayMgr", m_pRenderWnd, m_pMouse, ); m_pTimer = new Ogre::Timer();

m_pTimer->reset(); m_pRenderWnd->setActive(true); return true;

}

里边主要做了以下几个工作:

1.创建日志管理

2.创建OGRE的Root

3.创建渲染窗口(RenderWindow)和视口(Viewport)

4.启动OIS

5.设置鼠标和键盘的监听

6.载入资源

7.设置Timer

8.初始化SDKTrayManager

9.创建并显示debug overlay

注意,这里边没有像机和场景管理器,这个要到后面的状态类中才用到。

void OgreFramework::UpdateOgre(double timeSinceLastFrame)

{ }

这个函数用于在每一帧中更新和OGRE相关的一些东西,自己写的东西是要在每个状态中自己更新。

其实游戏的框架,普遍还是用的State这个设计模式。这样就可以在开始菜单,游戏画面,结束画面中自由的切换。看Android的libgdx引擎也是这样做的,分成不同的Screen来相互切换。

用OGRE1.74搭建游戏框架(二)--添加菜单

在上一节中,已经把OGRE的一个框架搭出来了,而且用的是一个单例模式,这样就意味着我们在后面的状态模式中可以很容易的就使用OGRE来帮我们进行图形绘制。

首先,写一个所有游戏状态的基类,因为我们大体可以抽象出所有游戏状态都应该有:

1.进入这个状态时应该做一些准备工作

2.退出这个状态时应该删除某些东西

3.暂停和继续时的一些动作。

4.更新

而一个游戏里有很多状态的切换,而我们又不想让一个状态知道另一个状态的存在,于是我们就要有一个统一管理这些状态的一个类,这样就能让这些状态之间解耦。(如果不这样做,比如说我想从菜单状态切换到游戏开始状态,那么我得在开始菜单中保存一个指向游戏开始状态的指针,而游戏开始状态想切到其它的状态也得这么做。)

因此我们写一个状态管理类,它实现一个状态监听接口。

状态管理用一个栈来存储所有的状态,当从当前状态切换到另一个状态时,就把栈顶的状态取出,并调用它的Exit()函数,并Pop出去,然后再初始化新的状态,并调用新状态的Enter()函数。

void CGameStateManager::ChangeGameState(CGameState* state)
{
if (!m_ActiveStateStack.empty())
{
m_ActiveStateStack.back()->Exit();
m_ActiveStateStack.pop_back();
} m_ActiveStateStack.push_back(state);
Init(state);
m_ActiveStateStack.back()->Enter();
}

GameState.h文件如下:

/********************************************************************
created: 2012/02/25
created: 25:2:2012 15:05
filename: E:\Ogre\Project\Ogre_Project\Game_Demo\GameState.h
file path: E:\Ogre\Project\Ogre_Project\Game_Demo
file base: GameState
file ext: h
author: Star purpose: the parent of all the game state
*********************************************************************/ #ifndef _ZH_GAMESTATE_H_
#define _ZH_GAMESTATE_H_ #pragma once #include "OgreFramework.h" class CGameState; class CGameStateListener
{
public:
CGameStateListener(){};
virtual ~CGameStateListener(){}; virtual void ManageGameState(Ogre::String stateName, CGameState* state) = ; virtual CGameState* FindByName(Ogre::String stateName) = ;
virtual void ChangeGameState(CGameState* state) = ;
virtual bool PushGameState(CGameState* state) = ;
virtual void PopGameState() = ;
virtual void PauseCurGameState() = ;
virtual void Shutdown() = ;
virtual void PopAllAndPushGameState(CGameState* state) = ;
}; class CGameState : public OIS::KeyListener,public OIS::MouseListener, public OgreBites::SdkTrayListener
{
public:
static void Create(CGameStateListener* parent, const Ogre::String name) {}; void destroy() { delete this; } virtual void Enter() = ;
virtual void Exit() = ;
virtual bool Pause() { return true;}
virtual void Resume() {};
virtual void Update(double timeSinceLastFrame) = ; protected:
CGameState(){}; CGameState* FindByName(Ogre::String stateName) {return m_pListener->FindByName(stateName); }
void ChangeGameState(CGameState* state) { m_pListener->ChangeGameState(state); }
bool PushGameState(CGameState* state) { return m_pListener->PushGameState(state);}
void PopGameState() {m_pListener->PopGameState(); }
void Shutdown() { m_pListener->Shutdown(); }
void PopAllAndPushGameState(CGameState* state) { m_pListener->PopAllAndPushGameState(state); } CGameStateListener* m_pListener; Ogre::Camera* m_pCamera;
Ogre::SceneManager* m_pSceneMgr;
Ogre::FrameEvent m_FrameEvent;
}; // macro define
#define DECLARE_GAMESTATE_CLASS(T) \
static void Create(CGameStateListener* pListener, const Ogre::String name) \
{ \
T* newState = new T(); \
newState->m_pListener = pListener; \
pListener->ManageGameState(name, newState); \
} \ #endif //_ZH_GAMESTATE_H_

上面代码中最后有一个宏定义,它的做用就是定义每个状态,并把它自己注册进状态管理类里。这是为了让你少写一些代码,不然你每定义一个状态类就得写一遍这个函数,有这个宏就方便多了。

可以看一下类图:

GameStateManager.h

/********************************************************************
created: 2012/02/25
created: 25:2:2012 16:05
filename: E:\Ogre\Project\Ogre_Project\Game_Demo\GameStateManager.h
file path: E:\Ogre\Project\Ogre_Project\Game_Demo
file base: GameStateManager
file ext: h
author: Star purpose: Manage all the game states
*********************************************************************/ #ifndef _ZH_GAMESTATEMANAGER_H_
#define _ZH_GAMESTATEMANAGER_H_ #pragma once
#include "GameState.h" class CGameStateManager : public CGameStateListener
{
public:
typedef struct
{
Ogre::String name;
CGameState* state;
} SState_info; CGameStateManager();
~CGameStateManager(); void ManageGameState(Ogre::String stateName, CGameState* state); CGameState* FindByName(Ogre::String stateName); void Start(CGameState* state);
void ChangeGameState(CGameState* state);
bool PushGameState(CGameState* state);
void PopGameState();
void PauseCurGameState();
void Shutdown();
void PopAllAndPushGameState(CGameState* state); protected:
void Init(CGameState* state); std::vector<CGameState*> m_ActiveStateStack;
std::vector<SState_info> m_States;
bool m_bShutdown;
}; #endif //_ZH_GAMESTATEMANAGER_H_

这个就是状态管理类,这里边的Start函数,就是程序消息循环的位置了。状态的切换也都在这里边发生。

这些函数的实现我就不复制,粘贴了,到时最后会发一个代码链接。

有了这些状态定义,我们现在就来试一下,先做一个MenuState。

MenuState.h

/********************************************************************
created: 2012/02/27
created: 27:2:2012 11:40
filename: E:\Ogre\Project\Ogre_Project\Game_Demo\MenuState.h
file path: E:\Ogre\Project\Ogre_Project\Game_Demo
file base: MenuState
file ext: h
author: Star purpose: the menu of the game
*********************************************************************/ #ifndef _ZH_MENUSTATE_H_
#define _ZH_MENUSTATE_H_ #pragma once #include "GameState.h" class CMenuState : public CGameState
{
public:
CMenuState(); DECLARE_GAMESTATE_CLASS(CMenuState) void Enter();
void CreateScene();
void Exit(); bool keyPressed(const OIS::KeyEvent &evt);
bool keyReleased(const OIS::KeyEvent &evt); bool mouseMoved( const OIS::MouseEvent &evt);
bool mousePressed( const OIS::MouseEvent &evt, OIS::MouseButtonID id );
bool mouseReleased( const OIS::MouseEvent &evt, OIS::MouseButtonID id ); void buttonHit(OgreBites::Button* button); void Update(double timeSinceLastFrame); private:
bool m_bQuit; }; #endif //_ZH_MENUSTATE_H_

主要讲一下Enter函数,这里边就要创建一下菜单界面了,还有Camera和SceneManager的创建,用的是OGRE现在带的SDKTray。然后也可以创建场景,这样就会有比较动感的开始菜单界面了等。

void CMenuState::Enter()
{
Ogre::FontManager::getSingleton().getByName("SdkTrays/Caption")->load();
COgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering MenuState.h."); m_pSceneMgr = COgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "MenuSceneMgr");
m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f)); m_pCamera = m_pSceneMgr->createCamera("MenuCam");
m_pCamera->setPosition(Vector3(, , -));
m_pCamera->lookAt(Vector3(, , ));
m_pCamera->setNearClipDistance(); m_pCamera->setAspectRatio(Real(COgreFramework::getSingletonPtr()->m_pViewport->getActualWidth())/
Real(COgreFramework::getSingletonPtr()->m_pViewport->getActualHeight())); COgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera); COgreFramework::getSingletonPtr()->m_pTrayMgr->destroyAllWidgets();
COgreFramework::getSingletonPtr()->m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
COgreFramework::getSingletonPtr()->m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
COgreFramework::getSingletonPtr()->m_pTrayMgr->showCursor();
COgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "EnterBtn", "Enter GameState", );
COgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "ExitBtn", "Exit OgreFramework", );
COgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOP, "MenuLbl","Menu mode", ); CreateScene();
}

这边有一个注意项:

如果没有这句的话

 Ogre::FontManager::getSingleton().getByName("SdkTrays/Caption")->load();

我这边顶上的那个Label里是不显示文字的,在他的论坛里找到这么一个解决方案。

最后的效果截图:

通过这样的框架就可以搭建自己的游戏了,只要继承GameState,实现自己的场景绘制和UI,就好了。期待你的游戏的产生。

资源下载:

http://download.csdn.net/detail/sunstar1989/4094433

用OGRE1.74搭建游戏框架(三)--加入人物控制和场景

有了前面的状态机,我们就可以很方便的扩展出自己的游戏场景状态的类。

现在我们要写一个RunState的类,这个就是游戏的主场景所在的地方,从MenuState可以跳转过来。

一、加入第三人称控制器

对于人物的控制,新版的OGRE已经给出了一个示例,就是那个Sample_Charater。

里边是对一个OGRE新模型的控制,操作起来感觉不错,就是向前跑动的时候没法看身后的东西,得停下来,Camera才会回到自由模式。

这个地方主要用到两个类:

SdkCameraMan:封装了OGRE的像机,可以比较自由的控制像机。

SinbadCharacterController:对于Sinbad的角色的控制以及动画的播放。

只要声明并定义好这两个类就能快速的实现第三人称的控制。

CRunState.h

class CRunState : public CGameState
{
public:
CRunState(); DECLARE_GAMESTATE_CLASS(CRunState) void Enter();
void CreateScene();
void Exit();
bool Pause();
void Resume(); bool keyPressed(const OIS::KeyEvent &evt);
bool keyReleased(const OIS::KeyEvent &evt); bool mouseMoved( const OIS::MouseEvent &evt);
bool mousePressed( const OIS::MouseEvent &evt, OIS::MouseButtonID id );
bool mouseReleased( const OIS::MouseEvent &evt, OIS::MouseButtonID id ); void Update(double timeSinceLastFrame); protected:
OgreBites::SdkCameraMan* m_pCameraMan; bool m_bIsQuit; SinbadCharacterController* m_pChara;
};

在Enter函数中初始化:

void CRunState::Enter()
{
COgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering RunState.h."); m_pSceneMgr = COgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "RunSceneMgr");
m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); m_pCamera = m_pSceneMgr->createCamera("MainCam");
m_pCamera->setNearClipDistance(5); m_pCamera->setAspectRatio(Real(COgreFramework::getSingletonPtr()->m_pViewport->getActualWidth())/
Real(COgreFramework::getSingletonPtr()->m_pViewport->getActualHeight())); COgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera); m_pCameraMan = new OgreBites::SdkCameraMan(m_pCamera);
m_pCameraMan->setStyle(OgreBites::CS_MANUAL); m_pChara = new SinbadCharacterController(m_pCamera); COgreFramework::getSingletonPtr()->m_pTrayMgr->destroyAllWidgets();
COgreFramework::getSingletonPtr()->m_pTrayMgr->hideCursor(); CreateScene(); }

在那些键盘和鼠标消息中响应人物和摄像机的事件。最后要在Update中更新动画。

void CRunState::Update(double timeSinceLastFrame)
{
if (m_bIsQuit)
{
Shutdown();
return;
} if (m_pChara)
m_pChara->addTime(timeSinceLastFrame/1000); // from miliseconds to seconds }

这边注意,因为我们前面用的是毫秒,这边动画更新需要的是秒为单位,所以要除,否则画面不会动。

二、载入.Scene场景文件

如果要用代码加入物体,不仅麻烦(得算坐标),而且不易修改(修改后得重新编译)。于是就有了场景文件的出现,而且也有了开源的场景编辑器(Ogitor)。

Ogitor是一个基于QT的OGRE场景的编辑器,可以到官网上下载:

http://www.ogitor.org/HomePage

在我们的工程中要用到的就是三个文件(在Ogitor的安装目录的/SampleApp_Source/下):

DotSceneLoader.h

DotSceneLoader.cpp

rapidxml.h

把他们拷进我们的工程里,我们将要使用他们来载入场景。

这时,会发现程序有错,DotSceneLoader.cpp里要引用到PagedGeometry的一些东西,这是一个用来植树造林的工具,我们也可以去下载。

http://www.ogre3d.org/tikiwiki/PagedGeometry+Engine

官方没有提供已经编译好的,所以需要自己编译,要配置OGRE的头文件和库的路径。

新的OGRE中的material的一个方法改了,所以编译会有错误:

需要将:

bestTechnique = material->getBestTechnique(material->getLodIndexSquaredDepth(parent->minDistanceSquared));

转换为:

bestTechnique = getLodIndex(parent->minDistanceSquared)

这样就可以编译出LIB库了。

回到我们的工程:

在CreateScene函数中载入场景:

void CRunState::CreateScene()
{
DotSceneLoader* pDotSceneLoader = new DotSceneLoader();
pDotSceneLoader->parseDotScene("CubeScene.xml", "General", m_pSceneMgr, m_pSceneMgr->getRootSceneNode());
delete pDotSceneLoader; // add a bright light above the scene
Light* light = m_pSceneMgr->createLight();
light->setType(Light::LT_POINT);
light->setPosition(-10, 40, 20);
light->setSpecularColour(ColourValue::White); // create a floor mesh resource
MeshManager::getSingleton().createPlane("floor", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Plane(Vector3::UNIT_Y, 0), 100, 100, 10, 10, true, 1, 10, 10, Vector3::UNIT_Z); // create a floor entity, give it a material, and place it at the origin
Entity* floor = m_pSceneMgr->createEntity("Floor", "floor");
floor->setMaterialName("Examples/Rockwall");
floor->setCastShadows(false);
m_pSceneMgr->getRootSceneNode()->attachObject(floor);
}

这边要注意在资源文件(resource.cfg)中加入CubeScene.xml和Cube模型的资源路径,否则OGRE不会载入他们,就找不到这些资源。

最后就可以看到结果了:

尝试着载入了Ogitor自带的Sample文件,SampleScene3.scene。注意要把资源路径配好。

人缩小一倍还比房子大。。。有点像绿巨人,人物的位置要根据地形高低来设置好。

 
 
 
 

用用OGRE1.74搭建游戏框架(转载)的更多相关文章

  1. 使用Html5+C#+微信 开发移动端游戏详细教程 :(三)使用html5引擎搭建游戏框架

    教程里的案例我们是通过H5游戏引擎开发,目前H5的游戏引擎比较好用的是白鹭,不过对于新手来说白鹭的开发环境和工具使用过于复杂,这里推荐一个国内大神编写的游戏引擎:lufylegend. 直接在页面引入 ...

  2. Unity 游戏框架搭建 (六) 关于框架的一些好文和一些思考

      在进行项目架构阶段,游戏框架可以解决一部分问题.剩下的架构问题还需要根据不同的项目解决.总之游戏框架是游戏架构的一部分. 关于锤子和钉子:   最近又拿起了<代码大全>和<暗时间 ...

  3. Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介

    约定 还记得上版本的第二十四篇的约定嘛?现在出来履行啦~ 为什么要重制? 之前写的专栏都是按照心情写的,在最初的时候笔者什么都不懂,而且文章的发布是按照很随性的一个顺序.结果就是说,大家都看完了,都还 ...

  4. Unity 游戏框架搭建 (十七) 静态扩展GameObject实现链式编程

    本篇本来是作为原来 优雅的QChain的第一篇的内容,但是QChain流产了,所以收录到了游戏框架搭建系列.本篇介绍如何实现GameObject的链式编程. 链式编程的实现技术之一是C#的静态扩展.静 ...

  5. Unity 游戏框架搭建 (十六) v0.0.1 架构调整

    背景: 前段时间用Xamarin.OSX开发一些工具,遇到了两个问题. QFramework的大部分的类耦合了Unity的API,这样导致不能在其他CLR平台使用QFramework. QFramew ...

  6. Unity 游戏框架搭建 (十三) 无需继承的单例的模板

    之前的文章中介绍的Unity 游戏框架搭建 (二) 单例的模板和Unity 游戏框架搭建 (三) MonoBehaviour单例的模板有一些问题. 存在的问题: 只要继承了单例的模板就无法再继承其他的 ...

  7. Unity 游戏框架搭建 (十) QFramework v0.0.2小结

    从框架搭建系列的第一篇文章开始到现在有四个多月时间了,这段时间对自己来说有很多的收获,好多小伙伴和前辈不管是在评论区还是私下里给出的建议非常有参考性,在此先谢过各位. 说到是一篇小节,先列出框架的概要 ...

  8. 凉鞋:我所理解的框架 【Unity 游戏框架搭建】

    前言 架构和框架这些概念听起来很遥远,让很多初学者不明觉厉.会产生"等自己技术牛逼了再去做架构或者搭建框架"这样的想法.在这里笔者可以很肯定地告诉大家,初学者是完全可以去做这些事情 ...

  9. [Android游戏开发]游戏框架的搭建

    通常情况下,游戏开发的基本框架中,一般包括以下模块: 窗口管理(Window management):该模块负责在Android平台上创建.运行.暂停.恢复游戏界面等功能. 输入模块(Input):该 ...

随机推荐

  1. SendMessage用法

    SendMessage(hWnd,wMsg,wParam,lParam) 参数1:hWnd-窗口句柄.窗口可以是任何类型的屏幕对象. 参数2:wMsg-用于区别其他消息的常量值. 参数3:wParam ...

  2. Keepalived + MySQLfailover + GTIDs 高可用

    架构图     10.1.1.207    mysql master + keepalived     10.1.1.206    mysql slave ( backup master ) + ke ...

  3. [译]GLUT教程 - 修改菜单

    Lighthouse3d.com >> GLUT Tutorial >> Pop-up Menus >> Modifying Menus 肯定会有菜单需要被修改的状 ...

  4. android 软键盘监听显示和隐藏

    githup中找到:https://github.com/yescpu/KeyboardChangeListener import android.app.Activity; import andro ...

  5. keil中使用Astyle格式化你的代码的方法2篇合

    关于Astyle Astyle 的全称是Artistic Style的简称,是一个开源的源代码格式化工具,可以对C,C++,C#以及Java等编程语言的源代码进行缩进.格式化.美化.Home Page ...

  6. 转载:Python 包管理工具解惑

    Python 包管理工具解惑 本站文章除注明转载外,均为本站原创或者翻译. 本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处,尊重我的劳动,也尊重你的智商: 本站部分原创和翻译文章提供m ...

  7. Android-BroadcastReceiver具体解释

    什么是Broadcast Broadcast即广播,在Android广播是很重要的功能.比如我们想在系统开机之后做某些事情.监控手机的电量.监控手机的网络状态等等.这些功能都须要用到广播.当然我们也能 ...

  8. 初识Modbus TCP/IP-------------C#编写Modbus TCP客户端程序(二)

    由于感觉上一次写的篇幅过长,所以新开一贴,继续介绍Modbus TCP/IP的初步认识, 书接上回 3).03(0x03)功能码--------读保持寄存器 请求与响应格式 这是一个请求读寄存器108 ...

  9. iOS-Core-Animation-Advanced-Techniques(二)

    本文转载至 http://www.cocoachina.com/ios/20150104/10816.html 视觉效果和变换 (四)视觉效果 嗯,园和椭圆还不错,但如果是带圆角的矩形呢? 我们现在能 ...

  10. GS与MS之间通信

    GS与MS之间通信 注意GS与MS是两个线程,现在是每个map一个线程,他们之间是内部协议进行通信的,那既然是两个线程那如何通信呢,看了net进程通信这个就比较简单了 举个例子 m_pMap-> ...