1. 程式人生 > >基於OpenGL的C版貪食蛇(簡陋版)

基於OpenGL的C版貪食蛇(簡陋版)

終於找到一個合適的圖形庫,比之前一個DOS視窗的好多了,DOS視窗版刷屏不給力,就算是一個sleep()下去是毫秒級的精度,等屏上資訊刷出來,黃花菜都涼了。

介紹下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

執行截圖: