现在的位置: 首页 > 综合 > 正文

OGRE+CEGUI游戏教程(1)—-GUI框架

2013年02月20日 ⁄ 综合 ⁄ 共 7179字 ⁄ 字号 评论关闭

 转载文章请注明出处:http://blog.csdn.net/pizzazhang 

  源码和可执行程序链接http://code.google.com/p/pizzaprojects/downloads/list

  今天起我会陆续更新一些原创的Ogre结合CEGUI的游戏教程。想到什么就做什么,没有固定的内容,不过基本是游戏里可以用到的。 

  请先确保学习完了Ogre Wiki上的基础和中级教程后再来讨论这里的教程。因为一些基础的Ogre知识这里不会多做解释。

  今天先建立一个用来演示的框架。其中我们已经有了BaseFramework框架,这个框架里已经帮你弄好了一些资源、场景管理器等设置,当然还有一个Overlay,但我们的GUI不打算使用Overlay,所以我们需要一个GUI框架。所以赶紧来做一个GUI框架使用吧!

 

MyGUISystem.h

class MyGUISystem
{
public:
	virtual ~MyGUISystem();
	//把OIS的鼠标ID转换成CEGUI的鼠标ID
	static CEGUI::MouseButton convertButton(OIS::MouseButtonID buttonId);
	//销毁资源
	bool destroy();
	//初始化CEGUI, 必须在RenderWindow创始后初始, 只在第一次调用有效
	bool init();
	//GUI更新
	void update(float timeSinceLastFrame);
	/**
	根据图片构造Imageset
	params:
	@name		创建的Imageset名称, 全局唯一
	@filename	创建Imageset的图片名称
	*/
	static void createImageset(const std::string& name, const std::string& filename);
	//加载layout
	bool loadLayout(const std::string& layoutName);
	//得到指定名称的窗口
	inline CEGUI::Window* getWindow(const std::string& windowName) 
	{
		return getGUIWindowManager()->getWindow(windowName); 
	}
	//销毁指定名称的窗口
	bool destroyWindow(const std::string& windowName);
	/*
	*	给指定名称的窗口设定属性
	params:
	@windowName	窗口名称
	@key			XML标签  key值
	@value			XML标签  value值
	*/
	static void setProperty(const std::string& windowName, const std::string& key, 
		const std::string& value);
	/**
	注册CEGUI控件事件
	params:
	@windowName		要注册事件的控件名称
	@eventName		注册的控件事件
	@subscriber		事件触发时的回调函数
	*/
	static void subscribeEvent(const CEGUI::String& windowName, 
		const CEGUI::String &eventName, 
		const CEGUI::Event::Subscriber &subscriber);
	//得到窗口管理器,用来获取管理GUI的窗口对象的管理器
	inline CEGUI::WindowManager* getGUIWindowManager()
	{
		return CEGUI::WindowManager::getSingletonPtr();
	}
	// 注入CEGUI鼠标点击事件
	bool injectMouseButtonDown(CEGUI::MouseButton id) 
	{
		return mGUISystem->injectMouseButtonDown(id);
	}
	bool injectMouseButtonUp(CEGUI::MouseButton id) 
	{
		return mGUISystem->injectMouseButtonUp(id); 
	}
	// 注入CEGUI鼠标移动事件
	bool injectMouseMove(float xRel, float yRel)
	{
		return mGUISystem->injectMouseMove(xRel, yRel);
	}
	//显示/隐藏GUI鼠标
	inline void showGUICursor(bool showCursor)
	{
		if(showCursor)
		{
			CEGUI::MouseCursor::getSingleton().show();
		}
		else
		{
			CEGUI::MouseCursor::getSingleton().hide();
		}
		//隐藏系统鼠标
		ShowCursor(false);
	}
	/*
	*	设置默认鼠标样式
	params:
	@schemeName	样式名称
	@mouseName		样式中的鼠标名称
	*/
	inline void setDefaultMouseCursor(const std::string& schemeName, const std::string& mouseName) 
	{
		CEGUI::System::getSingleton().setDefaultMouseCursor(schemeName, mouseName);
		CEGUI::MouseCursor::getSingleton().setImage(mGUISystem->getDefaultMouseCursor());
	}
public:
	/*
	*	单件实例方法
	*/
	static MyGUISystem* getSingletonPtr()
	{
		if(ms_singleton == NULL)
		{
			ms_singleton = new MyGUISystem;
		}
		return ms_singleton;
	}
private:
	//单件实例指针
	static MyGUISystem* ms_singleton;
private:
	CEGUI::OgreRenderer* mGUIRender;
	CEGUI::System*		 mGUISystem;
private:
	/*
	*	私有化实例函数,实现单件
	*/
	MyGUISystem()
		:mGUIRender(0), mGUISystem(0)
	{}
	MyGUISystem(const MyGUISystem&);
	MyGUISystem& operator=(const MyGUISystem&);
};

这里采用一个简单的单价模式来实现GUI系统。 其中最重要的方法是 loadLayout,createImageset , setProperty和subscribeEvent。

 loadLayout方法主要是载入layout,但是传入的参数是指定layout的根窗口,把它作为GUISheet进行显示。

createImageset是载入图片资源让CEGUI转化为纹理供有StaticImage的地方使用。

setProperty主要用来设置窗口的属性,尤其是StaticImage的设置。

subscribeEvent用来注册GUI事件。

 

下面是实现文件:

MyGUISystem.cpp

#include "MyGUISystem.h"
#include <cassert>
//-----------------------------------------------------------------------------
MyGUISystem* MyGUISystem::ms_singleton = NULL;
//-----------------------------------------------------------------------------
MyGUISystem::~MyGUISystem()
{
	destroy();
}
//-----------------------------------------------------------------------------
bool MyGUISystem::destroy()
{
	CEGUI::OgreRenderer::destroySystem();
	delete ms_singleton;
	ms_singleton = 0;
	return true;
}
//-----------------------------------------------------------------------------
CEGUI::MouseButton MyGUISystem::convertButton(OIS::MouseButtonID buttonId)
{
	switch(buttonId)
	{
	case OIS::MB_Left:
		return CEGUI::LeftButton;
	case OIS::MB_Right:
		return CEGUI::RightButton;
	case OIS::MB_Middle:
		return CEGUI::MiddleButton;
	default:
		return CEGUI::LeftButton;
	}
}
//-----------------------------------------------------------------------------
bool MyGUISystem::init()
{
	if(!mGUIRender)
	{
		mGUIRender = &CEGUI::OgreRenderer::bootstrapSystem();
		mGUISystem = CEGUI::System::getSingletonPtr();
		//加载GUI主题, 设置默认参数
		CEGUI::Imageset::setDefaultResourceGroup("Imagesets");
		CEGUI::Font::setDefaultResourceGroup("Fonts");
		CEGUI::Scheme::setDefaultResourceGroup("Schemes");
		CEGUI::WidgetLookManager::setDefaultResourceGroup("LookNFeel");
		CEGUI::WindowManager::setDefaultResourceGroup("Layouts");
		CEGUI::SchemeManager::getSingleton().create("TaharezLook.scheme");
		CEGUI::FontManager::getSingleton().create("SimHei-14.font");
		mGUISystem->setDefaultFont("SimHei-14");
		/*
		 *	此处设置图片资源(Imageset)
		 */
		//设置默认鼠标样式
		setDefaultMouseCursor("TaharezLook", "MouseArrow");
		//设置GUI鼠标是否可见
		showGUICursor(true);
		return true;
	}
	return false;
}
//-----------------------------------------------------------------------------
void MyGUISystem::update(float timeSinceLastFrame)
{
	mGUISystem->injectTimePulse(timeSinceLastFrame);
}
//-----------------------------------------------------------------------------
void MyGUISystem::createImageset(const std::string& name, const std::string& filename)
{
	CEGUI::ImagesetManager::getSingleton().createFromImageFile(name, filename);
}
//-----------------------------------------------------------------------------
bool MyGUISystem::loadLayout(const std::string& layoutName)
{
	CEGUI::Window *guiSheet;
	// 检测给定layout的文件是否加载,没有加载则加载
	if(!getGUIWindowManager()->isWindowPresent(layoutName))
	{
		// 从 .layout脚本文件读取一个UI布局设计,并将其放置到GUI资源组中。
		guiSheet = getGUIWindowManager()->loadWindowLayout(layoutName + ".layout");
	}
	else
	{	
		// 如果已经加载则直接显示
		guiSheet = getGUIWindowManager()->getWindow(layoutName);
	}
	// 接下来我们告诉CEGUI显示哪份UI布局。当然我们可以随时更换显示的UI布局。
	mGUISystem->setGUISheet(guiSheet);
	//显示UI布局
	guiSheet->show();
	return true;
}
//-----------------------------------------------------------------------------
bool MyGUISystem::destroyWindow(const std::string& windowName)
{
	getGUIWindowManager()->destroyWindow(windowName);
	return true;
}
//-----------------------------------------------------------------------------
void MyGUISystem::subscribeEvent(const CEGUI::String& windowName,
	const CEGUI::String &eventName, const CEGUI::Event::Subscriber &subscriber)
{
	CEGUI::WindowManager::getSingleton().getWindow(CEGUI::String(windowName))
		->subscribeEvent(eventName,subscriber);
}
//-----------------------------------------------------------------------------
void MyGUISystem::setProperty(const std::string& windowName, 
	const std::string& key, const std::string& value)
{
	MyGUISystem::getSingletonPtr()->getWindow(windowName)->setProperty(key, value);
}
//-----------------------------------------------------------------------------

update中我们让GUI系统更新时间,如果你需要实现GUI的动画效果,那么这个方法必须在Ogre的每帧进行调用。

在init中我们设置了GUI的一些默认资源,其中的字体我使用的是黑体14号。这是一个中文字体,CEGUI本身是使用UTF-8编码的,那么理论上是可以显示中文的。但是还需要一些小小的步骤才行。

 

CEGUI中显示中文的步骤:

1. 将编辑好的layout文件使用VC Studio打开(不要使用记事本),然后在文件->高级保存选项中把文件保存为UTF-8。

2.从WINDOW/Fonts文件夹中找一个中文字体的文件, 比如我使用的simhei.ttf

3.新建一个xml字体文件, 比如SimHei-14.Font,然后写上:

<?xml version="1.0" ?>
<Font Name="SimHei-14" Filename="simhei.ttf" Type="FreeType" Size="14" NativeHorzRes="1024" NativeVertRes="768" AutoScaled="true"/>

Name就是我们需要在程序中使用的字体名。

4.之后可以直接在layout文件中 有Text属性的地方使用中文, 如果要在代码中设置Text的中文,需要这么使用:

CEGUI::String str = (CEGUI::utf8*)Ogre::UTFString(L"你需要的中文").asUTF8_c_str()

 

这个GUI框架的使用很简单, 在Ogre窗口配置好后,使用MyGUISystem::getSingletonPtr()->init()对GUI系统初始化, 在Ogre渲染循环里对GUI系统update, 然后就可以使用了。

 

下篇文章会使用这个框架做一个游戏里要找NPC对话, 点击NPC后镜头与NPC拉近,然后弹出GUI对话框, 如果要退出游戏按ESC弹出退出的GUI菜单,并且带有GUI的动画效果。

抱歉!评论已关闭.