OpenGL初探 - 简易贪吃蛇

本文内容包括:
1、mac中新建openGL工程
2、绘制一个简单图形
3、键盘控制
4、定时器
5、文字绘制

这次是初次学习openGL,所以用了第一版的OpenGL,用的是固定片元着色器。

代码仓库:贪吃蛇

游戏截图:

游戏截图

一、工程新建

1、首先是新建一个mac OS的APP工程

新建工程

2、添加三个库,GLUT和OpenGL是系统库,可直接添加,libGLTools是第三方库,可以从我的项目中获取并拖拽到新建的项目中,注意需要把include目录下的头文件也一并添加进去

引入三个库
头文件引入

3、这次是使用C++来编写,所以需要把新建项目中的AppDelegate.h,AppDelegate.m,main.m,ViewController.m,ViewController.h删除,并新建main. cpp文件

代码目录结构

到此为止,一个空项目创建完成,可以试试是否能编译成功。

二、OpenGL绘制简单方形

1、绘制一个简单图形需要哪些元素?比如一个三角形

a、顶点,要确定一个三角形,必须得知道三角形的三个顶点坐标

b、颜色,以什么颜色来绘制

2、这次项目使用的是GLUT库来绘制,GLUT是OpenGL Utility Toolkit,是一个处理openGL程序的工具库。

//设置当前工作目录,针对MAC OS X
    gltSetWorkingDirectory(argv[0]);
    //初始化GLUT库
    glutInit(&argc, argv);
    /*初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
     
     双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    //GLUT窗口大小,标题窗口
    glutInitWindowSize(800,600);
    glutCreateWindow("贪吃蛇");
    //注册回调函数
    glutReshapeFunc(ChangeSize);//窗口改变大小
    
    glutDisplayFunc(RenderScene);//绘制刷新
    glutKeyboardFunc(OnKeyTap);//键盘监听
    glutTimerFunc(speed,timerFunc,1);//定时回调,第一个参数是定时间隔,单位毫秒,第二个回调方法指针,第三个是回调ID,会透传给回调方法的参数
    
    //驱动程序的初始化中没有出现任何问题。
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
        return 1;
    }
    //调用SetupRC
    SetupRC();
    glutMainLoop(); //启动runloop

代码比较简单,思路就是初始化GLUT库,创建窗口,设置背景色,绘制图形,事件监听,看代码都有注释,不多说。

三、贪吃蛇的思路

1、以链表存放蛇块,每吃一个食物方块,链表尾部加1

//新建一个蛇块,并添加到链表后面
void newASnake(Point point, GLfloat *color) {
    SnakeObject snake = SnakeObject();
    snake.points = (GLfloat*)malloc(sizeof(GLfloat) * 12);
    snake.color = (GLfloat*)malloc(sizeof(GLfloat) * 4);
    for (int i=0; i< 4; i++) {
        snake.color[i] = color[i];
    }
    createBlock(snake.points, blockSize);
    moveTo(snake.points, point);
    snake.triangleBatch = new GLBatch();
    snake.triangleBatch->Begin(GL_TRIANGLE_FAN,4);
    snake.triangleBatch->CopyVertexData3f(snake.points);
    snake.triangleBatch->End();
    SnakeNode *newNode = (SnakeNode *)malloc(sizeof(SnakeNode));
    if (objectCount == 0) {
        SnakeHead = newNode;
    }else {
        SnakeNode *lastNode = SnakeHead;
        while (lastNode->next) {
            lastNode = lastNode->next;
        }
        lastNode->next = newNode;
    }
    newNode->snake = snake;
    newNode->next = NULL;
    
    objectCount++;
}

2、移动:以复杂度最低的方式移动,即把尾块移动到即将移动的点,这样只需移动一个块就可以达到移动的效果,而不需要把所有的块都绘制一遍。这也是为什么选用单向链表做数据结构的原因。


向右移动
向下移动

要想自动移动,还要配合定时器的使用,改方法只会调用一次,所以再执行完之后需要继续调用,达到循环调用的效果

glutTimerFunc(speed,timerFunc,1);
//定时回调,第一个参数是定时间隔,单位毫秒,第二个回调方法指针,第三个是回调ID,会透传给回调方法的参数
//定时方法
void timerFunc(int nTimerID) {
    move();
    glutTimerFunc(speed,timerFunc,1);//继续调用
}

3、碰撞检测:主要是检测两个块的顶点是否有相交


碰撞检测
//两个点是否碰到
bool isTouch(GLfloat *v, GLfloat *t) {
    Point vxy = getPoint(v);
    Point txy = getPoint(t);
    GLfloat size = blockSize*ScreenWidth*2;
    bool hTouch = vxy.x > txy.x && vxy.x < txy.x + size || vxy.x + size > txy.x && vxy.x+ size < txy.x + size;
    bool vTouch = vxy.y > txy.y && vxy.y < txy.y + size || vxy.y + size > txy.y && vxy.y+ size < txy.y + size;
    return hTouch && vTouch;
}

4、键盘监听

glutKeyboardFunc(OnKeyTap);//键盘监听
//键盘监听
void OnKeyTap(unsigned char key, int x, int y) {
    Direction nextDirection = currentDirection;
    if (key == 'w') {
        nextDirection = Up;
    }else if (key == 'd') {
        nextDirection = Right;
    }else if (key == 's') {
        nextDirection = Down;
    } else if (key == 'a') {
        nextDirection = Left;
    }
    //方向相反无法操作
    if (nextDirection == Left && currentDirection == Right || nextDirection == Right && currentDirection ==Left
        || nextDirection == Up && currentDirection == Down || nextDirection == Down && currentDirection == Up) {
        return;
    }
    currentDirection = nextDirection;
}

5、文字绘制

//打印文字
void glutPrint(float x, float y, char *text)
{
    glRasterPos2f(x,y);
    glColor3f(0, 0, 0);
    for (int i=0; text[i]; i++){
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, text[i]);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,277评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,777评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,946评论 0 245
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,271评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,636评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,767评论 1 221
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,989评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,733评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,457评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,674评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,155评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,518评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,160评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,114评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,898评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,822评论 2 280
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,705评论 2 273

推荐阅读更多精彩内容