本文介绍: windows作为开发系统程序员提供的一些函数接口,用以实现一些功能。注:只在windows系统中可用。

1.需要实现基本功能:

1.地图绘制

2.上下左右键控制蛇的动作

3.蛇撞墙死亡;

4.蛇撞自己死亡;

5.计算得分;

6.蛇加速,减速;

7.暂停游戏

2.Win32 API:

2.1.介绍

windows作为开发系统程序员提供的一些函数接口,用以实现一些功能。

注:只在windows系统中可用。

2.2.控制台程序

cmd的程序—终端/控制台程序—运行起来的黑框

2.2.1.mode—可控制黑框大小
mode con cols=100 lines=30
#include<stdlib.h>

int main()
{
	system("mode con cols=50 lines=20");//这个函数就能执行系统命令
	printf("hehen");
	return 0;
}
2.2.2.title—可修改黑框名字
title 贪吃蛇
system("title 贪吃蛇");
2.2.3.pause—可使程序暂停:
system("pause");

注:会自动打印 “ 请按任意键继续. . . ”。

2.2.4.cls—可清理屏幕内容
system("cls");

2.3.控制台屏幕上的坐标—COORD:

1.需包含<window.h>

2.COORD为描述坐标所需结构体。

3.横轴向右为x轴正方向,纵轴向下为y轴正方向

COORD pos = { 3,5 };

2.4.获得句柄:GetStdHandle

GetStdHandle一个API函数。它用于一个特定的标准设备标准输入标准输出标准错误中取一个句柄设备控制权限),用来操作设备

HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出句柄

2.5.设置光标大小和可见性:

2.5.1.GetConsoleCursorInfo

检索有关指定控制台屏幕缓冲区光标大小和可见性信息

注:结构体:CONSOLE_CURSOR_INFO :

包含了有关控制台光标信息

typedef struct _CONSOLE_CURSOR_INFO {
	DWORD dwSize;
	BOOL bVisible;
}CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO;

dwSize:此值介于1到100之间。光标外观发生变化,从完全填充单元底部的水平线条
bVisible:光标的可见性。

例:隐藏光标

cursor_info.bVisible = false;
2.5.2.SetConsoleCursorInfo

设置有关指定控制台屏幕缓冲区光标大小和可见性信息

e.g

int main()
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出的句柄
	CONSOLE_CURSOR_INFO cursor_info;
	GetConsoleCursorInfo(handle,&cursor_info);
    cursor_info.dwSize = 1;
	SetConsoleCursorInfo(handle,&cursor_info);	
	return 0;
}

2.6.设置光标位置:SetConsoleCursorPosition:

设置有关指定控制屏幕缓冲区光标位置

用法:将坐标信息放在COORD类型pos中,调用SetConsoleCursorPosition函数将光标位置设置指定位置

例:封装一个SetPos函数用来设置光标位置

void SetPos(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);
}

2.7.获取按键情况:GetAsyncKeyState:

1.功能:获取按键情况。

上下左右键对应虚拟代码

VK_LEFT—0x25 ; VK_UP—0x26 ; VK_RIGHT—0x27 ; VK_DOWN—0x28 ;

2.返回值

short类型。最高位:1为按下,0为抬起;最低位:1为按下过,0为未按过。

例:封装一个检测vk这个虚拟键值对应按键是否被按过的宏:

#define PRESS_KET(vk)(GetAsyncKeyState(vk)&0x1?1:0)

3.贪吃蛇游戏设计分析

3.1.地图

由于贪吃蛇墙体,蛇身等字块为宽字符,而c语言默认包含字符,故需要locale上进行修改

3.1.1.locale是什么

locale是c语言针对不同地区字符区别,所提供的标准当前地区的语言设置

如想输出字符,需将locale改为Chinese。

3.1.2.类项:

程序员指定部分设置进行地区修改,各部分称为类项。

3.1.3.setlocale函数

char* setlocale ( int category , const chat* locale )

第一个参数为修改类项;

第二个参数只有两个取值:“C”和“ ”(本地模式

3.1.4.打印字符
#include<locale.h&gt;
int main()
{
	setlocale(LC_ALL, "");
	wchar_t ch1 = L'几';//宽字符类型
	wchar_t ch2 = L'个';

	printf("abn");

	wprintf(L"%lcn", ch1);//打印字符
	wprintf(L"%lcn", ch2);
	wprintf(L"%lcn", ch1);
	wprintf(L"%lcn", ch2);
	return 0;
}

3.1.5.地图坐标:

x轴坐标需为偶数,其他详见2.3 。

3.2.数据结构的设计:

enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};

enum GAME_STATUS
{
	OK,
	END_NORMAL,
	KILL_BY_WALL,
	KILL_BY_SELF
};

//贪吃蛇节点
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode,*pSnakeNode;

//贪吃蛇的结构
typedef struct Snake
{
	pSnakeNode _psnake;//指向贪吃蛇节点指针
	pSnakeNode _pFood;//指向食物节点指针
	int _Score;//贪吃蛇积累的总分
	int _FoodWeight;//一个食物的分数
	int _SleepTime;//每走一步休息的时间,时间越短速度越快
	enum DIRECTION _Dir;//描述蛇的方向
	enum GAME_STATUS _Status;//游戏状态:正常,退出,撞墙,撞到自己
}Snake,*pSnake;

4.具体实现:

头文件:snake.h

#pragma once
#include<locale.h&gt;
#include<stdlib.h>
#include<windows.h>
#include<stdbool.h>
#include<stdio.h>
#include<time.h>

#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'

#define POS_X 24
#define POS_Y 5

#define PRESS_KET(vk)(GetAsyncKeyState(vk)&amp;0x1?1:0)

enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};

enum GAME_STATUS
{
	OK,
	END_NORMAL,
	KILL_BY_WALL,
	KILL_BY_SELF
};

//贪吃蛇的节点
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;
}SnakeNode,*pSnakeNode;

//贪吃蛇的结构
typedef struct Snake
{
	pSnakeNode _psnake;//指向贪吃蛇头节点指针
	pSnakeNode _pFood;//指向食物节点指针
	int _Score;//贪吃蛇积累的总分
	int _FoodWeight;//一个食物的分数
	int _SleepTime;//每走一步休息的时间,时间越短速度越快
	enum DIRECTION _Dir;//描述蛇的方向
	enum GAME_STATUS _Status;//游戏状态:正常,退出,撞墙,撞到自己
}Snake,*pSnake;

//1.游戏开始 - 初始化游戏
void GameStart(pSnake ps);
void WelcomeToGame();//游戏开始的欢迎界面
void CreateMap();//打印地图
void InitSnake(pSnake ps);//初始化void CreateFood(pSnake ps);//创建食物
//2.游戏运行 
void GameRun(pSnake ps);
void PrintHelpInfo();//打印辅助信息
void SnakeMove(pSnake ps);//蛇的移动
int NextIsFood(pSnake ps, pSnakeNode pNext);//判断下一个位置是否是食物
void KillByWall(pSnake ps);//蛇是否撞墙
void  KillBySelf(pSnake ps);//蛇是否自杀
//3.游戏结束 
void GameEnd(pSnake ps);

源文件:snake.c

#include"snake.h"

//1.游戏开始 - 初始化游戏
void SetPos(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(handle, pos);
}

void WelcomeToGame()
{
	//定位光标
	SetPos(40, 15);
	printf("欢迎来到贪吃蛇小游戏!");
	SetPos(40, 25);
	system("pause");
	system("cls");
	SetPos(25, 15);
	printf("使用↑.↓.←.→控制蛇的移动,F3是加速,F4是减速");
	SetPos(40, 25);
	system("pause");
	system("cls");
}

void CreateMap()
{
	//上
	SetPos(0, 0);
	int i = 0;
	for (i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//下
	SetPos(0, 26);
	for (i = 0; i <= 56; i += 2)
	{
		wprintf(L"%lc", WALL);
	}
	//左
	for (i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	//右
	for (i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}

void InitSnake(pSnake ps)
{
	pSnakeNode cur = NULL;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("InitSnake()::malloc()");
			return;
		}
		cur->x = POS_X + 2 * i;
		cur->y = POS_Y;
		cur->next = NULL;

		//头插法
		if (ps->_psnake == NULL)
		{
			ps->_psnake = cur;
		}
		else
		{
			cur->next = ps->_psnake;
			ps->_psnake = cur;
		}
	}
	//打印蛇身
	cur = ps->_psnake;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	ps->_Status = OK;
	ps->_Score = 0;
	ps->_pFood = NULL;
	ps->_SleepTime = 200;
	ps->_FoodWeight = 10;
	ps->_Dir = RIGHT;
}

void CreateFood(pSnake ps)
{
	int x;
	int y;
	again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);

	//坐标不能和蛇的身体冲突
	pSnakeNode cur = ps->_psnake;
	if (cur->x == x &amp;&amp; cur->y == y)
	{
		goto again;
	}
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("CreateFood()::malloc()");
		return;
	}
	pFood->x = x;
	pFood->y = y;
	ps->_pFood = pFood;

	//打印食物
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
}

void GameStart(pSnake ps)
{
	//控制窗口的设置
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	
	//光标隐藏
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出的句柄
	CONSOLE_CURSOR_INFO cursor_info;
	GetConsoleCursorInfo(handle, &amp;cursor_info);
	cursor_info.bVisible = false;
	SetConsoleCursorInfo(handle, &amp;cursor_info);
	
	//打印欢迎界面
	WelcomeToGame();
	//创建地图
	CreateMap();	
	//初始化贪吃蛇
	InitSnake(ps);
	//创建食物
	CreateFood(ps);
}

//2.游戏运行 

void PrintHelpInfo()//打印辅助信息
{
	SetPos(64, 15);
	printf("1.不能撞墙,不能咬自己。");
	SetPos(64, 16);
	printf("2.使用↑、↓、←、→控制蛇的移动。");
	SetPos(64, 17);
	printf("3.F3加速,F4减速。");
	SetPos(64, 18);
	printf("4.ESC退出空格暂停。");
	SetPos(64, 20);
	printf("几个几个@版权");
}

int NextIsFood(pSnake ps, pSnakeNode pNext)//判断下一个位置是否是食物
{
	if (ps->_pFood->x == pNext->x &amp;&amp; ps->_pFood->y == pNext->y)
		return 1;
	else return 0;
}

void KillByWall(pSnake ps)//蛇是否撞墙
{
	if (ps->_psnake->x == 0 || ps->_psnake->x == 56 || ps->_psnake->y == 0 || ps->_psnake->y == 26)
	{
		ps->_Status = KILL_BY_WALL;
	}
}
void  KillBySelf(pSnake ps)//蛇是否自杀
{
	pSnakeNode cur = ps->_psnake->next;
	while (cur)
	{
		if (ps->_psnake->x == cur->x &amp;&amp; ps->_psnake->y == cur->y)
		{
			ps->_Status = KILL_BY_SELF;
		}
		cur = cur->next;
	}
}

void SnakeMove(pSnake ps)//蛇的移动
{
	pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pNext == NULL)
	{
		perror("SnakeMove()::malloc()");
		return;
	}
	pNext->next = NULL;
	switch (ps->_Dir)
	{
	case UP:
		pNext->x = ps->_psnake->x;
		pNext->y = ps->_psnake->y - 1;
		break;
	case DOWN:
		pNext->x = ps->_psnake->x;
		pNext->y = ps->_psnake->y + 1;
		break;	
	case LEFT:	
		pNext->x = ps->_psnake->x - 2;
		pNext->y = ps->_psnake->y;
		break;
	case RIGHT:
		pNext->x = ps->_psnake->x + 2;
		pNext->y = ps->_psnake->y;
		break;
	}

	//判断下一个位置是否是食物
	if (NextIsFood(ps, pNext))//是
	{
		//头插
		pNext->next = ps->_psnake;
		ps->_psnake = pNext;
		//打印蛇身
		SetPos(ps->_psnake->x, ps->_psnake->y);
		wprintf(L"%lc", BODY);
		//处理食物
		free(ps->_pFood);
		ps->_Score += ps->_FoodWeight;
		CreateFood(ps);
	}
	else//不是
	{
		//头插
		pNext->next = ps->_psnake;
		ps->_psnake = pNext;
		//删除最后节点并打印蛇身
		SetPos(ps->_psnake->x, ps->_psnake->y);
		wprintf(L"%lc", BODY);
		pSnakeNode cur = ps->_psnake;
		while (cur->next->next)
		{
			cur = cur->next;
		}
		SetPos(cur->next->x, cur->next->y);
		printf("  ");
		free(cur->next);
		cur->next = NULL;
	}

	//蛇是否撞墙
	KillByWall(ps);
	//蛇是否自杀
	KillBySelf(ps);
}

void GameRun(pSnake ps)
{
	PrintHelpInfo();
	do
	{
		//打印按键得分
		SetPos(64, 10);
		printf("得分:%05d", ps->_Score);
		SetPos(64, 11);
		printf("每个食物的分数:%2d", ps->_FoodWeight);

		//判断按键情况
		if (PRESS_KET(VK_UP) && ps->_Dir != DOWN)
		{
			ps->_Dir = UP;
		}		
		else if (PRESS_KET(VK_DOWN) && ps->_Dir != UP)
		{
			ps->_Dir = DOWN;
		}		
		else if (PRESS_KET(VK_LEFT) && ps->_Dir != RIGHT)
		{
			ps->_Dir = LEFT;
		}		
		else if (PRESS_KET(VK_RIGHT) && ps->_Dir != LEFT)
		{
			ps->_Dir = RIGHT;
		}		
		else if (PRESS_KET(VK_ESCAPE))
		{
			ps->_Status = END_NORMAL;
		}		
		else if (PRESS_KET(VK_SPACE))
		{
			while (1)
			{
				Sleep(100);
				if (PRESS_KET(VK_SPACE))
				{
					break;
				}
			}
		}		
		else if (PRESS_KET(VK_F3))//加速
		{
			if (ps->_SleepTime >= 80)
			{
				ps->_SleepTime -= 30;
				ps->_FoodWeight += 2;
			}
		}		
		else if (PRESS_KET(VK_F4))//减速
		{
			if (ps->_SleepTime <= 320)
			{
				ps->_SleepTime += 30;
				ps->_FoodWeight -= 2;
			}
		}

		//蛇的移动
		Sleep(ps->_SleepTime);
		SnakeMove(ps);

	} while (ps->_Status == OK);
}

//3.游戏结束 
void GameEnd(pSnake ps)
{
	SetPos(20, 12);
	switch (ps->_Status)
	{
	case END_NORMAL:
		printf("退出游戏n");
		break;	
	case KILL_BY_SELF:
		printf("撞自己了,游戏结束。n");
		break;	
	case KILL_BY_WALL:
		printf("撞墙了,游戏结束。n");
		break;
	}
	SetPos(0, 27);
	//释放蛇身节点
	pSnakeNode cur = ps->_psnake;
	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
	ps->_psnake = NULL;
}

main函数:main.c

#include"snake.h"
#include<stdio.h>

#include<locale.h>

int main()
{
	//设置程序适应本地环境
	setlocale(LC_ALL, "");
	srand(time(NULL));
	Snake snake = { 0 };
	//1.游戏开始 - 初始化游戏
	GameStart(&snake);
	//2.游戏运行 
	GameRun(&snake);
	//3.游戏结束 
	GameEnd(&snake);
	return 0;
}

c语言学习收关,撒花

原文地址:https://blog.csdn.net/2301_78922485/article/details/134361907

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_24720.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注