C语言 基于Ncurse库的贪吃蛇游戏项目

news2024/9/25 1:19:57

为了敲键盘及时响应,需要用到ncurse

测试代码: ncurse1.c

/* ncurse1.c */
#include <curses.h> //ncurse的头文件。

int main()
{
        char c;
        int i = 0;

		//ncurse界面的初始化函数。
        initscr(); 
        for(i=0;i<=2;i++)
        {
                c = getch();
                printw("\n");
                //ncurse下的打印函数。
                printw("Input: %c\n",c); 
        }
        //等待用户的输入,没有该函数程序会直接退出,看不到printw()的结果。
        getch(); 
        //调用程序退出函数,恢复shell终端的显示,没有该函数终端可能会乱码。 
        endwin(); 
        return 0;
}
//输入指令测试 gcc ncurse1.c -lcurses

 游戏的规划实现步骤

  1. Ncurse 函数初始化
  2. 边框图像设置 (for循环)
  3. 贪吃蛇身子节点    (结构体:行,列,下一个节点)
  4. 第一个节点  (静态设置)
  5. 设的整的身子  (静态设置)
  6. 改进 4,5蛇身子的问题, (采用结构体指针指向下一个,尾插法的方式)
  7. 蛇身子向右移动 move(0,0)光标界面不乱,通过按键key来向右行驶, 尾部加节点,注意必须要释放头节点来达到平衡。
  8. 贪吃蛇撞壁  
  9. 主动向右行驶,不需要按键key ,边框图像然后refresh()刷新界面。
  10. 方向键控制蛇变化 , key按键与dir配合,如果key向下,dir就变化,并switch选择增加往那个方向加节点。
  11. 主函数采用linux两个线程,(按键与自动)同时移动,并且都不退出。
  12. 贪吃蛇随机位置的设定。
  13. 咬死自己。

代码:

#include <curses.h>
#include <stdlib.h>
 
#define UP     1
#define DOWN  -1
#define LEFT   2
#define RIGHT -2
 
struct Snake
{
	int row;
	int line;
	struct Snake* next;
};
 
struct Snake* head = NULL;
struct Snake* tail = NULL;
int key;
int dir;
 
struct Snake food;
 
void initFood()//初始化食物节点
{
	int x = rand() % 20;//随机出现位置
	int y = rand() % 20;
	food.row = x;
	food.line = y;
}
 
void initNcurse()//初始化curses图形库
{
	initscr();
	keypad(stdscr,1);//使用keypad可以在stdscr中接受键盘的功能键
	noecho();//对于输出的功能键的值不做出回应,以免界面溢出
}
 
int hasSnakeNode(int i,int j)//传参:行号,列号
{
	struct Snake* p;
	p = head;
	while(p != NULL){
		if(p->row==i && p->line==j){
			return 1;//gamePic中打印一个节点"[]"
		}
		p=p->next;
	}
	return 0;
}
 
int hasFood(int i,int j)//打印食物
{
    if(food.row==i && food.line==j){
        return 1;
    }
    return 0;
}
 
void gamePic()//打印图形界面
{
	int row;
	int line;
	move(0,0);
	for(row=0;row<20;row++){
		//第0行为20个"--"
		if(row==0){
			for(line=0;line<20;line++){
				printw("--");
			}
			printw("\n");
		}
		//第0-19行为左右两边一个"|",中间21个"  "(空格)为了对齐第一行
		if(row>=0 && row<=19){//一共打印20行
			for(line=0;line<=20;line++){
				if(line==0 || line==20){
                    printw("|");//打印两边
                }else if(hasSnakeNode(row,line)){
					printw("[]");//打印蛇的身体
				}else if(hasFood(row,line)){
					printw("##");//打印食物
				}
				else{
                    printw("  ");//打印中间
                }
            }
            printw("\n");
		}
		//打印第19行,与第一行一样
		if(row==19){
            for(line=0;line<20;line++){
                printw("--");
            }
            printw("\n");
			printw("by Andy,key = %d\n",key);//打印作者名字以及方向键的值
        }
	}
}
 
void addNode()//加节点
{
	struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新节点空间
	new->next = NULL;
	switch(dir){//根据用户按的功能键的方向来决定如何添加一个节点
		case UP://列不变,行减一的位置添加
			new->row = tail->row - 1;
		    new->line = tail->line;
			break;
		case DOWN:
            new->row = tail->row + 1;
            new->line = tail->line;
            break;
		case LEFT:
            new->row = tail->row;
            new->line = tail->line - 1;
            break;
		case RIGHT:
            new->row = tail->row;
            new->line = tail->line + 1;
            break;
	}
	tail->next = new;
	tail = new;//新节点变成尾部
}
 
void deleteNode()//删除节点
{
	struct Snake* p;
	p = head;
	head = head->next;
	free(p);
}
 
void initSnake()//初始化蛇的身体
{
	struct Snake* p;//使用链表
	dir = RIGHT;//初始化方向为右
	while(head != NULL){
		p = head;
		head = head->next;
		free(p);//遍历节点,释放空节点内存
	}
	initFood();//初始化食物
	head = (struct Snake*)malloc(sizeof(struct Snake));//为头节点开辟空间
	head->row = 1;//第一行
	head->line = 1;//第一列
	head->next = NULL;//防止野指针
	tail = head;//头插法
	addNode();//加4个节点
	addNode();
	addNode();
	addNode();
}
 
int ifSnakeDie()//蛇死亡的条件
{
	struct Snake* p;
	p = head;
	if(tail->row < 0 || tail->line == 0 || tail->row == 20 || tail->line == 20){//四个边界
        return 1;
    }
	while(p->next != NULL){
		if(p->row == tail->row && p->line == tail->line){//头咬到尾巴
			return 1;
		}
		p = p->next;
	}
	return 0;
}
 
void moveSnake()//蛇的移动
{
	addNode();
	if(hasFood(tail->row,tail->line)){
		initFood();
	}
	else{
		deleteNode();
	}
	if(ifSnakeDie()){
		initSnake();
	}
}
 
void* refreshBox()//刷新界面
{
	while(1){
        moveSnake();//蛇移动
        gamePic();//重新打印界面
        refresh();//刷新覆盖原界面
        usleep(100000);//0.1s
    }
}
 
void turn(int direction)//绝对值解决方向问题
{
	if(abs(dir) != abs(direction)){
		dir = direction;
	}
}
 
void* changeDir()//根据用户按的功能键走位
{
	while(1){
        key = getch();
        switch(key){
            case KEY_DOWN:
                turn(DOWN);//转向
                break;
            case KEY_UP:
                turn(UP);
                break;
            case KEY_LEFT:
                turn(LEFT);
                break;
            case KEY_RIGHT:
                turn(RIGHT);
                break;
        }
    }
}
 
int main()
{
	initNcurse();//第一步:搭建curses环境
	initSnake();//第三步:打印蛇的身体
	gamePic();//第二步:打印图形界面
	pthread_t th1;//线程1
	pthread_t th2;//线程2
	pthread_create(&th1,NULL,refreshBox,NULL);//运行线程1:不断刷新界面
	pthread_create(&th2,NULL,changeDir,NULL);//运行线程2:不断改变方向
	while(1);//让线程一直进行
	getch();//让程序一直重复输入功能键还能执行
	endwin();//curses函数
	return 0;
}

还需要不断改进。。。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/356496.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一起学 pixijs(2):修改图形属性

大家好&#xff0c;我是前端西瓜哥。 我们做动画、游戏、编辑器&#xff0c;需要根据用户的交互等操作&#xff0c;去实时地改变图形的属性&#xff0c;比如位置&#xff0c;颜色等信息。今天西瓜哥带大家来看看在 pixijs 怎么修改图形的属性。 因为 pixijs 的底层维护了图形…

2023年美赛C题Wordle预测问题三、四建模及Python代码详细讲解

更新时间:2023-2-19 16:30 相关链接 &#xff08;1&#xff09;2023年美赛C题Wordle预测问题一建模及Python代码详细讲解 &#xff08;2&#xff09;2023年美赛C题Wordle预测问题二建模及Python代码详细讲解 &#xff08;3&#xff09;2023年美赛C题Wordle预测问题三、四建模…

Android 基础知识4-2.8 TableLayout(表格布局)详解

一、TableLayout的概述 表格布局是以行数和列数来确定位置进行排列。就像一间教室&#xff0c;确定好行数与列数就能让同学有序入座。 注意&#xff1a;我们需要先添加<TableRow容器&#xff0c;每添加一个就会多一行&#xff0c;然后再往<TableRow容器中添加其它组件。…

研报精选230219

目录 【行业230219山西证券】煤炭行业周报&#xff1a;复工改善&#xff0c;港口价格企稳反弹【行业230219中航证券】农林牧渔行业周观点&#xff1a;一号文件落地&#xff0c;生物育种超势不改【行业230219华西证券】汽车行业周报&#xff1a;新车密集上市 自主转型提速【个股…

[vue3] pinia的基本使用

使用Pinia npm install piniastore文件里index.js import { createPinia } from piniaconst pinia createPinia()export default piniamain.js导入并引用 import { createApp } from vue import App from ./App.vue import pinia from ./storescreateApp(App).use(pinia).m…

「技术选型」深度学习软件如何选择?

深度学习(DL, Deep Learning)是机器学习(ML, Machine Learning)领域中一个新的研究方向&#xff0c;它被引入机器学习使其更接近于最初的目标——人工智能(AI, Artificial Intelligence)。 深度学习是学习样本数据的内在规律和表示层次&#xff0c;这些学习过程中获得的信息对…

【Flutter入门到进阶】Dart进阶篇---DartVM单线程设计原理

1 虚拟机的指令执行设计 1.1 虚拟机的分类 基于栈的虚拟机&#xff0c;比如JVM虚拟机 基于寄存器的虚拟机&#xff0c;比如Dalvik虚拟机 1.2 虚拟机的概念 首先问一个基本的问题&#xff0c;作为一个虚拟机&#xff0c;它最基本的要实现哪些功能&#xff1f; 他应该能够模拟…

使用uni-app框架中uni.chooseAddress()接口,获取不到用户收货地址

错误描述 在我们使用uni-app框架或微信原生开发微信小程序时&#xff0c;使用到uni.chooseAddress(OBJECT)接口获取用户收货地址时&#xff0c;无法跳转到收货地址页面获取。 打印接口返回信息&#xff0c;显示 "chooseAddress:fail the api need to be declared in the …

LeetCode-17. 电话号码的字母组合

题目来源 17. 电话号码的字母组合 题目思路 从示例上来说&#xff0c;输入"23"&#xff0c;最直接的想法就是两层for循环遍历了吧&#xff0c;正好把组合的情况都输出了。 如果输入"233"呢&#xff0c;那么就三层for循环&#xff0c;如果"2333"…

接口测试(Fiddler工具)

目录 1.Fiddler是什么&#xff1f; 2.Fiddler的原理 3.Fiddler安装 4.Fiddler界面 4.1.常用工具 4.2 会话列表 4.3 状态栏 4.4 内容显示区 1.Fiddler是什么&#xff1f; Fiddler是客户端与服务器之间的HTTP代理&#xff0c;是当前最常用的HTTP协议抓包工具。 主要功能&a…

NSDT可编程3D场景【兼容Three.js】

NSDT编辑器简化了WebGL 3D应用的开发&#xff0c;完全兼容Three.JS生态。本文介绍如何在自己的应用中嵌入使用NSDT编辑器搭建的3D场景&#xff0c;并通过JS API与场景进行交互。 在自己的应用中嵌入3D场景只需要三个步骤&#xff1a; 在NSDT编辑器中搭建3D场景在自己的前端应…

Nonebot2官网插件nonebot-plugin-chatgpt让自己的QQ聊天机器人不再呆头呆脑

前言 如果你会使用Nonebot2搭建QQ聊天机器人&#xff0c;那么你一定会使用Nonebot官网上插件商店发布的插件&#xff0c;今天这篇博客记录一下使用插件时遇到的错误&#xff0c;最终如何解决的错误。在开始之前先看一下效果图吧&#xff01; 瞬间我们的QQ机器人就高大上了起…

Java serialVersionUID 作用和自动生成设置

一、由来 最近在做一个军工的项目&#xff0c;代码提交后&#xff0c;军方用代码安全扫描工具&#xff0c;对代码进行全局扫描&#xff0c;提示一个漏洞&#xff0c;导致原因是实体类实现了Serializable接口&#xff0c;未对serialVersionUID手动赋值&#xff0c;java机制里&am…

Zero-shot(零次学习)简介

zero-shot基本概念 首先通过一个例子来引入zero-shot的概念。假设我们已知驴子和马的形态特征&#xff0c;又已知老虎和鬣狗都是又相间条纹的动物&#xff0c;熊猫和企鹅是黑白相间的动物&#xff0c;再次的基础上&#xff0c;我们定义斑马是黑白条纹相间的马科动物。不看任何斑…

枚举类的使用方法

一、理解枚举类型 枚举类型是Java 5中新增特性的一部分&#xff0c;它是一种特殊的数据类型&#xff0c;之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束&#xff0c;但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。下面先来看看如何写…

如何用一句话感动测试工程师?产品和技术都这么说!

测试工程师在公司里的地位一言难尽&#xff0c;产品挥斥苍穹&#xff0c;指引产品前路&#xff1b;开发编写代码实现功能&#xff0c;给产品带来瞩目成就。两者&#xff0c;一个是领航员&#xff0c;一个是开拓者&#xff0c;都是聚光灯照耀的对象&#xff0c;唯独团队中的保障…

换脸方法大汇总:生成对抗网络GAN、扩散模型等

1、One-Shot Face Video Re-enactment using Hybrid Latent Spaces of StyleGAN2StyleGAN的高保真人像生成&#xff0c;已逐渐克服了单样本面部视频驱动重现的低分辨率限制&#xff0c;但这些方法至少依赖于以下其中之一&#xff1a;明确的2D/3D先验&#xff0c;基于光流作为运…

Android 基础知识4-2.5View与VIewGroup的概念、关系与区别

1.概念&#xff1a; Android里的图形界面都是由View和ViewGroup以及他们的子类构成的&#xff1a; View&#xff1a;所有可视化控件的父类,提供组件描绘和时间处理方法 ViewGroup&#xff1a; View类的子类&#xff0c;可以拥有子控件,可以看作是容器 Android UI中的控件都是…

Java【七大算法】算法详细图解,一篇文章吃透

文章目录一、排序相关概念二、七大排序1&#xff0c;直接插入排序2&#xff0c;希尔排序3&#xff0c;选择排序4&#xff0c;堆排序5&#xff0c;冒泡排序5.1冒泡排序的优化6&#xff0c;快速排序6.1 快速排序的优化7&#xff0c;归并排序三、排序算法总体分析对比总结提示&…

K8s学习(一)从零开始搭建kubernetes集群环境(虚拟机/kubeadm方式)

文章目录1 Kubernetes简介&#xff08;k8s&#xff09;2 安装实战2.1 主机安装并初始化2.2 安装docker2.3 安装Kubernetes组件2.4 准备集群镜像2.5 集群初始化2.6 安装flannel网络插件3 部署nginx 测试3.1 创建一个nginx服务3.2 暴漏端口3.3 查看服务3.4 测试服务1 Kubernetes简…