栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

运行于linux终端的c语言编写的贪食蛇详解(游戏逻辑篇)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

运行于linux终端的c语言编写的贪食蛇详解(游戏逻辑篇)

文章目录
      • 概述
      • 采用的库
      • 功能规划
        • 最初规划
        • 已完成功能
      • 游戏界面
      • 代码实现
        • 规划中的数据结构
        • 具体实现

概述

 为了熟悉linux下的c语言编程,所以尝试做的,具体功能及实现有可能会慢慢更改。
仓库地址

采用的库

 图形化将采用curses库,存储存档及得分榜采用ndbm库,利用groff编写manpage,编译及安装采用make。

功能规划 最初规划

  使用命令行启动游戏,利用命令行参数可以打印版本信息、帮助信息,初始化得分榜,开启作弊模式(碰到自身或墙壁不算游戏失败)。如果不带参数则直接启动游戏。
  开始界面右侧窗口显示得分榜,左侧显示新游戏、载入存档、删除存档、退出游戏四个选项。顶上一行显示标题,最底下一行显示临时状态。
  游戏界面左边窗口为游戏窗口,右上窗口显示操作指南,右下窗口显示当前得分及速度等级。

已完成功能
  • 参数模式打印版本、帮助信息
  • 开始界面新游戏、退出游戏
  • 游戏界面正常游戏
  • 游戏界面显示操作指南
  • 游戏界面显示当前得分及速度等级
游戏界面

  游戏将有两个界面,即主界面和游戏界面。

  1. 主界面:
        主界面将要完成开启新游戏、载入存档和删除存档的任务,及循环显示得分榜。

  2. 游戏界面:
        主要分为左、右上、右下三个板块,游戏区域,操作说明区域,当前得分及速度的显示区域。

  3. 流程图:
    这是最初规划的流程图,实际实现会有一定的增删。

代码实现 规划中的数据结构
  1. 蛇的身体:
      将实现为一个结构体数组,数组长度为整个游戏区的格数,数组中每个结构体含有x,y两个成员,即身体每个点的坐标。
  2. 蛇的身体的当前长度:
      由一个全局变量保存
  3. 当前未占用的格子:
      维护一个全局的二维布尔数组,每次更新蛇的身体的同时,将蛇的身体所占用的格子对应的这个布尔数组的成员设为false。这个数组所有为true的成员即代表对应的格子允许生成食物。
  4. 现存的食物:
      与蛇的身体一样的结构体。
  5. 当前得分:
      与蛇的身体的总长相关
  6. 游戏者姓名:
      一个字符数组保存
  7. 当前速度:
      根据蛇身体的总长变化,每一次刷新的间隔,其区间将是1000ms~50ms。
  8. 存储文件
      存档文件,每条数据由一个编号,一个姓名,蛇身体长度,蛇的身体的数组组成。
      得分榜文件,每条数据由姓名及得分组成。
具体实现

data.h

#ifndef _DATA_H
#define _DATA_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define WINDOW_WIDTH 40
#define WINDOW_HEIGHT 20
#define TOTLE_POINT ((WINDOW_WIDTH-2)*(WINDOW_HEIGHT-2))
#define SPEED_MAX 1000
#define STR_LEN 38

#define VERSION ("1.00")


typedef struct
{
	int x;
	int y;
}node;
typedef node food;
typedef node direct;
typedef node *snake;

//存档数据和得分榜数据处理函数



//游戏逻辑函数
void init_status(WINDOW *win_ptr,direct *d_ptr,food *f_ptr,snake greedy,char *name);
void destory_status(snake greedy);
void end_game(WINDOW *win_ptr,char *string);
//用于参数模式的函数
int command_mode(int argc,char *argv[]);

//用于开始界面的函数
void draw_base_window(void);
void draw_select_window(WINDOW *win_ptr,char *options[],int current_highlight,int start_row,int start_col);
void clear_start_screen(void);
int getchoice(WINDOW *win_ptr,char *choices[]);

//用于游戏界面的函数
void Checkmap(snake greedy);
void draw_snake_window(WINDOW *win_ptr,snake greedy,food f1);
void draw_status_window(WINDOW *win_ptr,char *name);
void update_snake(snake greedy,direct d,bool *eated);
void init_keyboard(WINDOW *w_ptr);
void get_key(direct *d);
void close_keyboard(WINDOW *w_ptr);
bool Eatfood(snake greedy,food f1);
bool Isover(snake greedy);
bool Iswin(void);
void Createfood(food *fd);
#endif

frontend.c

#define _GNU_SOURCE
#include "data.h"

//用于参数模式的函数声明
static void version(void);
static void help(void);
static void opt_error(char c);

//用于开始界面的函数声明


//用于参数模式的函数定义
static void version(void)
{
	fprintf(stdout,"greedy snake version %sn",VERSION);
}
static void help(void)
{
	fprintf(stdout,"Usage: snake [options]n");
	fprintf(stdout,"Options:n");
	fprintf(stdout,"t-v/--versiontdisplay the version informationn");
	fprintf(stdout,"t-h/--helptdisplay the help informationn");
	fprintf(stdout,"t-i/--inittinitialize the ranking listn");
	fprintf(stdout,"t-c/--cheattinto the cheat mode, you will not die until got full marksn");
}
static void opt_error(char c)
{
	fprintf(stderr,"unknown option: %cnplease use snake --help to get more informationn",c);
}
static void cheat(void)
{
	extern bool Cheat;
	Cheat=true;
}
int command_mode(int argc,char *argv[])
{
	extern bool Cheat;
	int result=0,opt;
	struct option longopts[]=
	{
		{"version",0,NULL,'v'},
		{"help",0,NULL,'h'},
		{"init",0,NULL,'i'},
		{"cheat",0,NULL,'c'},
		{0,0,0,0}
	};
	while((opt=getopt_long(argc,argv,":vhic",longopts,NULL))!=-1)
	{
		switch(opt)
		{
			case 'v':
				version();
				result=1;
				break;
			case 'h':
				help();
				result=1;
				break;
			case 'i':
				
				result=0;
				break;
			case 'c':
				cheat();
				result=0;
				break;
			case '?':
				opt_error(optopt);
				result=2;
				break;
		}
	}
	return result;
}
//用于游戏逻辑的函数定义
void init_status(WINDOW *win_ptr,direct *d_ptr,food *f_ptr,snake greedy,char *name)
{
	char *prompt[]=
	{
		"enter your name: ",
		0
	};
	extern int Current_len;
	int seed;
	seed=rand()%4;
	switch(seed)//随机产生初始方向
	{
		case 0:
			d_ptr->x=0;
			d_ptr->y=-1;
			break;
		case 1:
			d_ptr->x=0;
			d_ptr->y=1;
			break;
		case 2:
			d_ptr->x=-1;
			d_ptr->y=0;
			break;
		case 3:
			d_ptr->x=1;
			d_ptr->y=0;
			break;
	}
	Current_len=0;
	Checkmap(greedy);
	while(true)//产生一个不靠边框的蛇头
	{
		Createfood(&greedy[0]);
		if(greedy[0].x>1&&greedy[0].x1&&greedy[0].yx;
	greedy[1].y=greedy[0].y-d_ptr->y;
	Current_len=2;
	Checkmap(greedy);
	Createfood(f_ptr);
	move(LINES-2,1);
	clrtoeol();
	mvprintw(LINES-2,1,"touch enter to save your name.");
	refresh();
	draw_select_window(win_ptr,prompt,-1,WINDOW_HEIGHT/2-1,WINDOW_WIDTH/2-10);
	wgetnstr(win_ptr,name,STR_LEN-1);
}
void destory_status(snake greedy)
{
	free(greedy);
}
void end_game(WINDOW *win_ptr,char *string)
{
	wclear(win_ptr);
	box(win_ptr,ACS_VLINE,ACS_HLINE);
	mvwprintw(win_ptr,WINDOW_HEIGHT/2-1,WINDOW_WIDTH/2-10,"%s",string);
	wrefresh(win_ptr);
	
	sleep(2);
}
//用于开始界面的函数定义
void draw_base_window(void)
{
	clear();
	box(stdscr,ACS_VLINE,ACS_HLINE);
	mvprintw(1,COLS/2-7,"%s","Greedy Snake");
	refresh();
}
void draw_select_window(WINDOW *win_ptr,char *options[],int current_highlight,int start_row,int start_col)
{
	wclear(win_ptr);
	box(win_ptr,ACS_VLINE,ACS_HLINE);
	int current_row=0;
	char **option_ptr;
	char *txt_ptr;
	option_ptr=options;
	while(*option_ptr)
	{
		if(current_row==current_highlight)
			wattron(win_ptr,A_STANDOUT);
		txt_ptr=options[current_row];
		mvwprintw(win_ptr,start_row+current_row*2,start_col,"%s",txt_ptr);
		if(current_row==current_highlight)
			wattroff(win_ptr,A_STANDOUT);
		current_row++;
		option_ptr++;
	}
	wrefresh(win_ptr);
}
void clear_start_screen(void)
{
	clear();
	mvprintw(1,COLS/2-7,"%s","Greedy Snake");
	refresh();
}
int getchoice(WINDOW *win_ptr,char *choices[])
{
	static int selected_row=0;
	int max_row=0;
	int start_screenrow=WINDOW_HEIGHT/2-5,start_screencol=WINDOW_WIDTH/2-6;
	char **options;
	int selected;
	int key=0;
	options=choices;
	mvprintw(LINES-2,1,"Move highlight then press enter");
	refresh();
	while(*options)
	{
		max_row++;
		options++;
	}
	keypad(stdscr,true);
	cbreak();
	noecho();
	while(key!=KEY_ENTER&&key!='n')
	{
		if(key==KEY_UP)
		{
			if(selected_row==0)
				selected_row=max_row-1;
			else
				selected_row--;
		}
		if(key==KEY_DOWN)
		{
			if(selected_row==max_row-1)
				selected_row=0;
			else
				selected_row++;
		}
		selected=*choices[selected_row];
		draw_select_window(win_ptr,choices,selected_row,start_screenrow,start_screencol);
		key=getch();
	}
	keypad(stdscr,false);
	nocbreak();
	echo();
	return selected;
}


//用于游戏界面的函数定义
void draw_snake_window(WINDOW *win_ptr,snake greedy,food f1)
{
	extern int Current_len;
	wclear(win_ptr);
	box(win_ptr,ACS_VLINE,ACS_HLINE);
	mvwaddch(win_ptr,f1.y,f1.x,'@');
	for(int i=Current_len-1;i>=0;i--)
	{
		if(i==0)
			mvwaddch(win_ptr,greedy[i].y,greedy[i].x,'#');
		else
			mvwaddch(win_ptr,greedy[i].y,greedy[i].x,'*');
	}
	wrefresh(win_ptr);
}
void draw_status_window(WINDOW *win_ptr,char *name)
{
	extern int Current_len;
	int score=Current_len;
	char speed_string[STR_LEN];
	char score_string[STR_LEN];
	sprintf(score_string,"Current Score = %d",score);
	sprintf(speed_string,"Current Speed level = %d",(Current_len/35));
	wclear(win_ptr);
	box(win_ptr,ACS_VLINE,ACS_HLINE);
	mvwprintw(win_ptr,WINDOW_HEIGHT/9,WINDOW_WIDTH/4,"Hello %s",name);
	mvwprintw(win_ptr,WINDOW_HEIGHT/5,WINDOW_WIDTH/4,"%s",score_string);
	mvwprintw(win_ptr,WINDOW_HEIGHT/3,WINDOW_WIDTH/4,"%s",speed_string);
	wrefresh(win_ptr);
}
void Checkmap(snake greedy)
{
	extern bool Map[WINDOW_HEIGHT-2][WINDOW_WIDTH-2];
	extern int Current_len;
	int index_x,index_y,i;
	for(index_y=0;index_y0;i--)
	{
		greedy[i]=greedy[i-1];
	}
	greedy[0]=temp;
	Checkmap(greedy);
}
void init_keyboard(WINDOW *w_ptr)
{
	keypad(stdscr,true);
	noecho();
	cbreak();
	leaveok(w_ptr,true);
	timeout(SPEED_MAX);
}
void get_key(direct *d)
{
	int key;
	if((key=getch())!=ERR)
		{
			switch(key)
			{
				case 'A':
				case 'a':
				case KEY_LEFT:
					if(d->x!=1)
					{
						d->x=-1;
						d->y=0;
					}
					break;
				case 'D':
				case 'd':
				case KEY_RIGHT:
					if(d->x!=-1)
					{
						d->x=1;
						d->y=0;
					}
					break;
				case 'W':
				case 'w':
				case KEY_UP:
					if(d->y!=1)
					{
						d->x=0;
						d->y=-1;
					}
					break;
				case 'S':
				case 's':
				case KEY_DOWN:
					if(d->y!=-1)
					{
						d->x=0;
						d->y=1;
					}
					break;
			}
		}
}
void close_keyboard(WINDOW *w_ptr)
{
	keypad(stdscr,false);
	echo();
	timeout(-1);
	nocbreak();
	leaveok(w_ptr,false);
}
bool Eatfood(snake greedy,food f1)
{
	if(greedy[0].x==f1.x&&greedy[0].y==f1.y)
		return true;
	else
		return false;
}
bool Isover(snake greedy)
{
	extern int Current_len;
	bool flag=false;
	if(greedy[0].x==0||greedy[0].x==(WINDOW_WIDTH-1)||greedy[0].y==0||greedy[0].y==(WINDOW_HEIGHT-1))
		flag=true;
	for(int i=1;ix=index_x+1;
	fd->y=index_y+1;
}

main.c

#include 
#include 
#include 
#include 
#include "data.h"

bool Cheat=false;
int Current_len;
bool Map[WINDOW_HEIGHT-2][WINDOW_WIDTH-2];
int main(int argc,char *argv[])
{
	char *start_menu[]=
	{
		"new game",
		"load game",
		"delete data",
		"quit",
		0
	};
	char *instructions[]=
	{
		"use up/down/left/right",
		"or w/s/a/d",
		"to control the snake",
		"Esc to save/end the game",
		0
	};
	srand(time(0));
	snake greedy;
	greedy=malloc(sizeof(food)*TOTLE_POINT);
	bool eatedfood=false;
	int key;
	food f;
	direct d;
	char name[STR_LEN];
//参数处理
	int command_result;
	if(argc>1)
	{
		command_result=command_mode(argc,argv);
		if(command_result)
			exit(command_result);
	}
//开始界面
	initscr();
	draw_base_window();
	WINDOW *start_rank_win=newwin(WINDOW_HEIGHT,WINDOW_WIDTH,(LINES-WINDOW_HEIGHT)/2,COLS/2+3);
	WINDOW *select_win=newwin(WINDOW_HEIGHT,WINDOW_WIDTH,2,6);
	draw_select_window(start_rank_win,start_menu,-1,1,1);
	do
	{
		command_result=getchoice(select_win,start_menu);
		switch(command_result)
		{
			case 'n':
				
				init_status(select_win,&d,&f,greedy,name);
				command_result='g';
				break;
			case 'l':
				
				command_result='g';
				break;
			case 'd':
				
				break;
			case 'q':
				exit(EXIT_SUCCESS);
		}
	}while(command_result!='g');
	delwin(start_rank_win);
	draw_base_window();
//游戏界面
//现在select_win作为游戏窗口
	WINDOW *instructions_win=newwin(WINDOW_HEIGHT/2,WINDOW_WIDTH,(LINES-WINDOW_HEIGHT)/2,COLS/2+3);
	WINDOW *status_win=newwin(WINDOW_HEIGHT/2,WINDOW_WIDTH,LINES/2,COLS/2+3);
	draw_select_window(instructions_win,instructions,-1,1,WINDOW_WIDTH/4);

	init_keyboard(select_win);

	while(true)
	{
		timeout(SPEED_MAX-(Current_len/35)*50);//改变速度
		draw_status_window(status_win,name);
		draw_snake_window(select_win,greedy,f);
		if(Isover(greedy))
		{
			end_game(select_win,"Game Over!");
			break;
		}
		if(Iswin())
		{
			end_game(select_win,"You Win!");
			break;
		}
		if(Eatfood(greedy,f))
		{
			Createfood(&f);
			eatedfood=true;
		}
		get_key(&d);
		update_snake(greedy,d,&eatedfood);
	}

	close_keyboard(select_win);

	delwin(select_win);
	delwin(instructions_win);
	delwin(status_win);


	endwin();
	destory_status(greedy);
	exit(EXIT_SUCCESS);
}

注:现在的游戏逻辑已基本完善,接下来会更新数据存储,更新的代码在仓库内查看

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/599569.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号