前言(重点,考试要考)
有的时候,想把一件事情完完整整的做完,但是又不知道背后的动力何在,我发现,写写博客还是能激励自己做下去的,不知道最后能获得什么,但是至少看到了博客数目多起来了,阅读量多起来了,自己的努力有了可视的收获,心里着实踏实不少。这其中也包含着我一直以来都想做的事情,就是自己写一个游戏,不管什么游戏,像样点就行,我琢磨了好久,用什么工具来写(C++还是JAVA还是U3D等等),最后我在DirectX和OpenGL之间开始抉择,可能是本人有点愚笨,U3D愣是没上手明白,感觉不太适应,倒是OpenGL和DX用着比较舒服,后来经过查询资料,发现OpenGL好像可以跨平台,DirectX似乎只能在windows下,或者说是微软那套东西下(应该还有xbox360什么的),我一想,只能在windows下多不爽,那就OpenGL吧,那时我还对OpenGL一无所知,真的,因为刚开始我还在天真的去找什么OpenGL库或者源码去编译,可是后来我发现,哪里是什么库啊,就是一个图形接口,人家早就在显卡驱动里实现了,我需要一些辅助的库去调用和建立环境,就这样我开始学习,发现入了坑,这东西完全没有想象中容易上手,光是乱七八糟的状态机一般的机制就让我着实摸不到头脑,不过经过一段艰辛的探索和适应,我终于能用其写出可以运行的程序了(^_^),就这样,我带着探索和分享的精神,来完成此系列的博客(此处有BGM:HandClap)。
进入正题
这篇系列有些奇怪,因为我一上来就讲如何制作按钮,没有直接进入游戏制作,原因是我只是觉得,我想从这里开始写,毕竟这些东西的写法又没有个规定和条条框框,随意喜欢怎么写就怎么写了,对了看我的博客最好一个字一个字的看,看的太快可能会遗漏什么重要信息。游戏中肯定要使用各种控件,最基本的就是按钮了,这个控件实现了别的也都差不多,因为我之前没有写个游戏,所以看着各种游戏里面花花绿绿的按钮我个人觉得应该不是MFC和Qt那样直接拖上去的按钮,虽然配合OpenGL使用的控件有现成写好的,但是既然已经到了这一步,都没用U3D了,干脆就啥也别用了,白手起家更扎实。还有,要先配置好GLFW,GLEW,GLM。写按钮之前,我们先从基本的窗体开始。
这里面肯定会涉及GL部分的代码,如果没有接触过GL的,我这里也不会说让你单独去学了,我会在相应的地方小小的展开说明一下相关知识的。由于本人写代码功夫仍然需要提升,所以思前想后,还是决定选择C++写能容易一些。我在windows下写代码,用的是CodeLite,用什么IDE读者可以根据自己的喜好,操作系统的话我目前没有在linux和mac(没有mac电脑。。)下试验代码和环境,所以需要自己探索一下了。(补充:拿魔塔游戏来作为开发目标)
创建一个新的GL项目
新建一个OpenGL空白程序,我封装了一个GLWindow类,这个类中包含的就是创建窗体的流程。我设置成了抽象类,目的是方便在上面添加各种新的功能,从而不影响大局的设计思想,因为最后写好游戏后,一个简单的游戏框架也随之成型。代码下载会附在后面。
class GLWindow
{
protected:
GLFWwindow * window;
//窗口设置函数,可以继承
virtual void WindowSetting()=0;
//设置回调函数
virtual void SetCallBack()=0;
//鼠标按键回调函数
virtual void mouse_buttoncallback(GLFWwindow* window, int button, int action, int mods)=0;
//鼠标移动回调函数
virtual void mouse_movecallback(GLFWwindow* window, double xpos, double ypos)=0;
public:
GLWindow();
//创建窗口
bool CreateGLWindow(const char * name,unsigned long window_width,unsigned long window_height,unsigned long view_width,unsigned long view_height);
//窗口循环渲染
virtual void Run()=0;
~GLWindow();
};
类就是这个样子,需要键盘事件函数可以再加上,但是目前不需要。
这里对CreateGLWindow函数进行了实现。其中WindowSetting是我们自己写的函数。
bool GLWindow::CreateGLWindow(const char * name,unsigned long window_width,unsigned long window_height,unsigned long view_width,unsigned long view_height)
{
//初始化glfw
glfwInit();
//窗口设置
WindowSetting();
//创建一个窗口
window = glfwCreateWindow(window_width, window_height, name, nullptr, nullptr);
if(window == nullptr)
return false;
//设置窗口上下文
glfwMakeContextCurrent(window);
//glew初始化
if (glewInit() != GLEW_OK)
return false;
//设置视觉范围
glViewport(0, 0, view_width, view_height);
SetCallBack();
cout << glGetString(GL_VERSION) << endl;
cout << glGetString(GL_RENDERER) << endl;
}
这个类是抽象类,不能实例化,所以我们需要创建一个继承它的类,GameWindow
class GameWindow : public GLWindow
{
public:
GameWindow();
//窗口设置
virtual void WindowSetting();
virtual void SetCallBack();
//运行
virtual void Run();
//渲染函数
//void Render();
//鼠标按键回调函数
virtual void mouse_buttoncallback(GLFWwindow* window, int button, int action, int mods);
//鼠标移动回调函数
virtual void mouse_movecallback(GLFWwindow* window, double xpos, double ypos);
~GameWindow();
};
这里只是写了暂时需要用的几个函数。后面我们会有更多的。先将WindowSetting函数实现,Run函数实现
void GameWindow::WindowSetting()
{
//设置OpenGL版本
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//OPENGL核心模式
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
//窗口大小不可调整
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
}
void GameWindow::Run()
{
while(!glfwWindowShouldClose(window))
{
//渲染等函数
cout<<"I am running"<<endl;
}
}
main函数很简单。以后我们的main函数几乎不会有什么变动。
int main()
{
GameWindow window;
window.CreateGLWindow("GL",800,600,800,600);
window.Run();
return 0;
}
运行的效果就是窗口什么都不显示,一片白色,控制台输出I am runing 。现在渲染处什么都没写,也没有窗口响应函数,所以我们的窗口处于未响应状态,关掉控制台就都关掉了。
结束语
这部分是封装好一个GL窗口类,后面我们还会封装更多的东西,下一篇就是封装按钮。
源代码
本次的全部源码都在这里。