Linux下基于C语言的贪吃蛇(共享内存)

本文详细介绍了一个使用C语言编写的经典贪吃蛇游戏。游戏采用多线程处理,通过共享内存实现父子进程间的通信,父进程负责检测方向键输入,子进程负责游戏逻辑和地图更新。游戏地图为17x17大小,蛇初始长度为1,玩家通过键盘控制蛇移动,吃到食物后蛇身增长。游戏还包括边界和自我碰撞检测。
摘要由CSDN通过智能技术生成

// gcc snake.c -lpthread
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define KEYCODE_U 0x41 // 向上按键
#define KEYCODE_D 0x42 // 向下按键
#define KEYCODE_L 0x44 // 向左按键
#define KEYCODE_R 0x43 // 向右按键

unsigned char map[17][17] = {0}; // 游戏地图
unsigned char snake[50] = {133}; // 初始化蛇坐标,游戏开始的时候蛇在(8,5)这个位置
unsigned char food = 67; // 食物的坐标,游戏开始的时候在(4,3)这个位置
int len = 1; // 保存蛇的当前长度

// 将 数字 转化为坐标系
void num_to_xy(unsigned char num, unsigned char *x, unsigned char *y)
{
*x = num >> 4;
*y = (unsigned char)(num << 4) >> 4;
}

// 更新地图数据
void update_map()
{
int i, j;
// 先初始化边界
for (i = 0; i < 17; i++)
{
for (j = 0; j < 17; j++)
{
if (i == 0 || i == 16 || j == 0 || j == 16) // 代表地图的边界
{
map[i][j] = ‘#’;
}
else
{
map[i][j] = ’ ';
}

	}
}
// 初始化食物
unsigned char  x,y;      // 坐标
num_to_xy(food, &x, &y); // 获取食物的坐标   (4,3)
map[y][x] = '!';         // 设置食物


// 初始化蛇
for (i = 0; i < len; i++)
{
	num_to_xy(snake[i], &x, &y);  // 获取蛇的第 i+1 节身体的坐标
	map[y][x] = '*';
}

}

// 打印地图
void print_map()
{
int i, j;
for (i = 0; i < 17; i++)
{
for (j = 0; j < 17; j++)
{
printf ("%c", map[i][j]);
}
printf ("\n");
}

usleep(500000/(len/4+1));           // 让程序睡眠1秒
system("clear");    // 清屏

}

// 生成食物
unsigned char generate_food()
{
srand ((unsigned int)time(NULL)); // 生成一个随机数的种子
unsigned char new_food;
unsigned char x,y;
int insnake = 0; // 标志生成的食物有没有在蛇的身体,默认是不在
do
{
insnake = 0;
new_food = rand() % 256; // 产生一个新的食物
num_to_xy(new_food, &x, &y);

	int i;
	for (i = 0; i < len; i++)
	{
		if (snake[i] == new_food)
		{
			insnake = 1;    // 1代表在蛇的身体上
			break;
		}
	}	
}while (x == 0 || x == 16 || y == 0 || y == 16 || insnake);

return new_food;

}

// 移动蛇
void move_snake(char dir)
{
unsigned char x,y; // 坐标
num_to_xy(snake[0], &x, &y); // 获取蛇头的坐标

// 判断移动方向
switch (dir)
{
	case 'w':   // 向上移动
		y--;
		break;
	case 's':   // 向下移动
		y++;
		break;
	case 'a':   // 向左移动
		x--;
		break;
	case 'd':   // 向右移动
		x++;
		break;
}
unsigned char last = snake[0];    // 保存原蛇头的值
snake[0] = (unsigned char)(x << 4) + y;  // 更新蛇头坐标

int i;
// 移动蛇的身体
unsigned char current;
for (i = 1; i < len; i++)
{
	current  = snake[i];
	snake[i] = last;
	last = current;
}

// 如果蛇头和食物的坐标重合,证明蛇吃到食物
// len 是蛇的长度 0 -- len-1 snake[len]
if (snake[0] == food)
{
	// 蛇要长一节身体
	snake[len] = last;
	len++;
	
	// 重新生成食物
	food = generate_food();
}

}

// 判断蛇是否应该存活,如果返回值是0代表应该存活,1代表不应该存活
int isalive()
{
unsigned char x,y;
num_to_xy(snake[0], &x, &y); // 获取蛇头的坐标

// 判断蛇头有没有碰到边界
if (x == 0 || x == 16 || y == 0 || y == 16)
{
	return 1;
}

// 判断蛇头有没有咬到它自己
int i;
for (i = 1; i < len; i++)
{
	if (snake[0] == snake[i])
	{
		return 1;
	}
}

return 0;

}

// 父进程工作: 检测方向键
int father_do()
{

char dir;   // 方向

char buf[100];
printf (“aaaaa\n”);
// 1、创建 或者 获取一块共享内存
int shmid = shmget((key_t)9876, sizeof(char), IPC_CREAT);
if (shmid == -1)
{
perror(“shmget”);
return -1;
}

// 2、映射,获取指向共享的指针
char* ps = (char *)shmat(shmid, NULL, 0);
if (ps == (char *) -1)
{
	perror("shmat");
	return -1;
}
while (1)
{
	fgets(buf, 100, stdin);
	*ps=buf[0];
}	

}

// 子进程工作:负责游戏运行
int child_do()
{
// you do

char dir;   // 方向

// 1、创建 或者  获取一块共享内存
int shmid = shmget((key_t)9876, sizeof(char), IPC_CREAT);
if (shmid == -1)
{
	perror("shmget");
	return -1;
}
printf ("iiii\n");
// 2、映射,获取指向共享的指针
char* ps = (char *)shmat(shmid, NULL, 0);
if (ps == (char *) -1)
{
	perror("shmat");
	return -1;
}
while (1)
{
	char ch = *ps;
update_map();
print_map();
move_snake(ch);
//print_map();
//update_map();
if (isalive() == 1)
{
	printf ("Game Over\n");
	break;
}
shmdt(ps);
return 0;

}

int main()
{

pid_t pid = fork();
switch(pid)
{
	case 0:  
		child_do();
		break;
	case -1:  
		perror("子进程创建失败");
		break;
	default: 
		printf ("yyy\n");
		father_do();
		break;
}
printf ("游戏结束\n");
return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值