基於OpenGL的C版貪食蛇(簡陋版)
阿新 • • 發佈:2019-02-03
終於找到一個合適的圖形庫,比之前一個DOS視窗的好多了,DOS視窗版刷屏不給力,就算是一個sleep()下去是毫秒級的精度,等屏上資訊刷出來,黃花菜都涼了。
snake.c
snake.h
執行截圖:
介紹下GLUT,OpenGL Utility Toolkit,即OpenGL應用工具包,是一套可用於所有主流平臺的支援函式庫。提供瞭解決如視窗、選單和裝置輸入等基本問題的方法,同時還保持了對作業系統平臺的獨立性。
Windows環境下在VS裡安裝GLUT步湊如下:
解壓所得五個檔案如圖
對於VS2008,把glut.h複製到./Microsoft/Visual Studio 9.0/VC/include/GL資料夾中,如果沒有GL這個資料夾則可以自己新建一個。
glut.lib和glut32.lib放到靜態函式庫所在資料夾(即與include並排的lib資料夾下)。
glut.dll和glut32.dll放到作業系統目錄下面的system32資料夾內。(典型的位置為:C:/Windows/System32)
OpenGL入門知識,可以參考:點選開啟連結
直接貼程式碼了,好多都寫在註釋裡
main.c
/* *Classic snake game, based on OpenGL and C language. * by simon、xia * 2013.10.10 Meng Day */ #include<stdio.h> #include<stdlib.h> #include<windows.h> #include"GL/glut.h" #include"snake.h" //#include "resource.h" //int main(int argc, char *argv[]) int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev,//去掉Dos視窗 PSTR CmdLine, int iCmdShow) { int argc = 1; char *argv[] = {"snake"}; //傳入引數,去掉Dos視窗 init_snake(); glutInit(&argc, argv); //初始化 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//顯示方式,其中GLUT_RGB表示使用RGB顏色,GLUT_SINGLE表示使用單緩衝 glutInitWindowPosition(200, 100); //設定視窗在螢幕中的位置。左邊距,上邊距 glutInitWindowSize(800, 600); //設定視窗的大小。沒有單位,僅用數值客觀表示 glutCreateWindow("**********************************Simon's Snake***********************************"); //建立視窗。注意:視窗被建立後,並不立即顯示到螢幕上。 //需要呼叫glutMainLoop才能看到視窗 glClearColor(0.0,0.0,0.0,0.0); //視窗背景為黑色 glMatrixMode(GL_PROJECTION); //把視窗投影到矩陣上 gluOrtho2D(0.0,400.0,0.0,300.0); //引數依次為左下角x座標,右上角x座標,左下角y座標,右上角y座標——座標全相對於視窗左下角-原點 create_food(); glutDisplayFunc(display_all); glutSpecialFunc(get_direction); glutTimerFunc(SPEED,snake_timer,1); glutMainLoop(); return 0; }
snake.c
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> #include<windows.h> #include"GL/glut.h" #include"snake.h" //extern int direction; #define WIN32_LEAN_AND_MEAN int direction = GLUT_KEY_RIGHT; node* head = NULL; void init_snake() { int i = 0, x = COL / 2, y = ROW / 2, first = 1; node * temp, *ptr; for(; i < 80; i++, x--) { temp = (struct node*)malloc(sizeof(node)); temp -> spos_r = y; temp -> spos_c = x; if(first) { head = temp; first = 0; ptr = head; // CA } else { ptr -> next = temp; ptr = temp; } } ptr -> next = NULL; } void show_snake() { node * temp = head; glBegin(GL_POINTS); while( temp != NULL ) { glVertex2i(temp -> spos_c, temp -> spos_r); temp = temp -> next; } glEnd(); glFlush();//保證前面的OpenGL命令立即執行(而不是讓它們在緩衝區中等待)。其作用跟fflush(stdout)類似。 } void create_food() { int flag = 0; node *temp = head; srand((unsigned)time(NULL)); food_x = rand() % COL ; food_y = rand() % ROW ; while( temp != NULL ) { if((food_x == temp -> spos_c) && (food_y == temp -> spos_r)) { flag = 1; break; } temp = temp -> next; } if(flag) create_food(); else return; } void show_food() { glBegin(GL_POINTS); glVertex2i(food_x, food_y); glEnd(); glFlush(); } void get_direction(int key, int x, int y) { if( (key != direction) && abs(key - direction) != 2 &&(key == GLUT_KEY_LEFT || key == GLUT_KEY_RIGHT || key == GLUT_KEY_UP || key == GLUT_KEY_DOWN)) { direction = key; } else return; } void snake_move() { int i = head->spos_r, j = head->spos_c; node* temp, *p, *p_pre; temp = (struct node*)malloc(sizeof(node)); switch(direction) { case GLUT_KEY_RIGHT: { temp -> spos_r = i; temp -> spos_c = ++j; break; } case GLUT_KEY_UP: { temp -> spos_r = ++i; temp -> spos_c = j; break; } case GLUT_KEY_LEFT: { temp -> spos_r = i; temp -> spos_c = --j; break; } case GLUT_KEY_DOWN: { temp -> spos_r = --i; temp -> spos_c = j; break; } } temp -> next = head; head = temp; p = head; while(p -> next != NULL) { p_pre = p; p = p -> next; } p_pre -> next = NULL; free(p); } void snake_timer(int i) { snake_move(); glutTimerFunc(SPEED,snake_timer,1); glutPostRedisplay(); } void eat() { node * temp , *p = head, *p_pre = head; int x1, y1, x2, y2, flag = 0; if(head -> spos_c == food_x && head -> spos_r == food_y) { while(p -> next != NULL) { p_pre = p; p = p -> next; } y1 = p_pre -> spos_r; //通過末尾兩點座標,判斷蛇尾增長方向 x1 = p_pre -> spos_c; y2 = p -> spos_r; x2 = p -> spos_c; temp = (struct node*)malloc(sizeof(node)); if(x1 == x2) if(y1 < y2) { temp -> spos_r = x2; temp -> spos_c = ++y2; } else { temp -> spos_r = x2; temp -> spos_c = --y2; } else { if(x1 > x2) { temp -> spos_r = --x2; temp -> spos_c = y2; } else { temp -> spos_r = ++x2; temp -> spos_c = y2; } } p -> next = temp; temp -> next = NULL; flag = 1; } if(flag) { create_food(); flag = 0; } } int is_dead() { node * temp = head -> next; if(head -> spos_r < 0 || head -> spos_r > ROW || head -> spos_c < 0 || head -> spos_c > COL ) return 1; while(temp -> next != NULL) { if(temp -> spos_r == head -> spos_r && temp -> spos_c == head -> spos_c ) return 1; temp = temp -> next; } return 0; } void restart() { init_snake(); direction = GLUT_KEY_RIGHT; } void display_all() //顯示設定放到這裡防止多次重新整理 { if(is_dead()) { //exit(0); MessageBox(NULL,"\tHeHe\t","Game Over",NULL); restart(); //return ; } glClear(GL_COLOR_BUFFER_BIT);//把整個視窗清除為當前的清除顏色 glColor3f(1.0,0.0,0.0); //指定顏色,紅色 glPointSize(PIX); //設定點的寬度,單位畫素 show_snake(); eat(); show_food(); }
snake.h
#ifndef _SNAKE_H_
#define _SNAKE_H_
#define ROW 300
#define COL 400
#define SPEED 20 //重新整理間隔(ms)
#define PIX 8 //畫素大小
typedef struct
{
int spos_r;
int spos_c;
struct node* next;
}node;
int food_x, food_y;
void init_snake();
void show_snake();
void show_food();
void eat();
int is_dead();
extern void display_all(); //回撥函式要宣告
extern void snake_timer();
extern void get_direction();
#endif
執行截圖: