c语言第一个小游戏:贪吃蛇小游戏04

贪吃蛇向右移动(原理就是删一个头节点,添加一个新节点)

#include <curses.h>

#include <stdlib.h>

struct snake{

int hang;

int lie;

struct snake *next;

};

struct snake *head;

struct snake *tail;

void initNcurse()

{

initscr();

keypad(stdscr,1);

}

int hasSnakeNode(int i,int j)

{

struct snake *p;

p = head;

while(p != NULL){

if(p->hang==i && p->lie==j){

return 1;

}

p=p->next;

}

return 0;

}

void gamepic()

{

int hang;

int lie;

move(0,0);

for(hang=0;hang<20;hang++){

if(hang == 0){

for(lie=0;lie<20;lie++){

printw("--");

}

printw("\n");

}

if(hang>=0 && hang<=19){

for(lie=0;lie<=20;lie++){

if(lie==0||lie==20){

printw("|");

}else if(hasSnakeNode(hang,lie)){

printw("[]");

}

else{

printw(" ");

}

}

printw("\n");

}

if(hang == 19){

for(lie=0;lie<20;lie++){

printw("--");

}

printw("\n");

}

}

printw("by shijintao");

printw("\n");

}

void addNode()//程序每调用一次这个函数就会新搞个new,开辟一个新的内存给new

{

struct snake *new;

new =(struct snake *)malloc(sizeof(struct snake));

new->hang=tail->hang;

new->lie=tail->lie+1;

tail->next = new;

tail = new;

new->next = NULL;

}

void initSnake()

{

head = (struct snake *)malloc(sizeof(struct snake));

head->hang=2;

head->lie=2;

head->next=NULL;

tail = head;

addNode();

addNode();

}

void deleteNode()

{

struct snake *p;//这个p是为了释放旧节点,避免内存泄漏

p = head;

head = head->next;

free(p);

}

void moveSnake()

{

addNode();

deleteNode();

}

int main()

{

int con;

initNcurse();

initSnake();

gamepic(); //这边都还是初始化贪吃蛇,就是游戏刚进入有个默认的小蛇

while(1){

con = getch();

if(con == KEY_RIGHT){

moveSnake();

gamepic(); //这个是刷新地图的效果,就是重新捕获地图

}

}

getch();

endwin();

return 0;

}

知识点:

这个是ncurse的特性

  • move(y, x) 用于将光标移动到屏幕上的指定坐标位置
  • (0, 0) :表示屏幕的左上角(第一行、第一列)。

这边有个move(0,0)函数添加到了gamepic函数中,是因为这个ncurse程序输出时候光标在最尾巴,所以我们按-->方向键的时候,内容随着光标位置显示地图,就像这样

如何解决?才能像我们需要的效果

那么ncurse里面有个函数叫做move可以改变光标的位置,我们肯定是想要得到一个图的,然后我们使用move函数相当于覆盖了之前的地图,达到了我们的效果

move函数要放在gamepic函数的循环遍历前面

我们实现蛇向右走的原理其实就是按-->的时候,把头节点删掉,然后尾巴后面增加新节点。然后利用ncurse的move函数将光标重置随后生成的图覆盖之前的图,就达到了看上去的按-->键往右移动的效果

这个就是按右方向键可以获得响应到相关代码:

调用这个moveSnake()函数后其实链表已经发生了变化,但是要重新扫描一下地图才会显示,所以有 gamepic();这个函数的再次调用

while(1){

con = getch();

if(con == KEY_RIGHT){

moveSnake();

gamepic();

}

}

贪吃蛇撞墙

人想的蛇头是我们链表的尾节点,这点要分清楚

如果尾节点的hang和lie与边界的行和列重合就表示撞墙了

撞墙就是判断链表尾节点的行和列是否等于地图边界的行和列的值,如果等于了,那么就释放内存,重新初始化成刚开始head还是NULL的时候

#include <curses.h>

#include <stdlib.h>

struct snake{

int hang;

int lie;

struct snake *next;

};

struct snake *head=NULL;

struct snake *tail=NULL;

void initNcurse()

{

initscr();

keypad(stdscr,1);

}

int hasSnakeNode(int i,int j)

{

struct snake *p;

p = head;

while(p != NULL){

if(p->hang==i && p->lie==j){

return 1;

}

p=p->next;

}

return 0;

}

void gamepic()

{

int hang;

int lie;

move(0,0);

for(hang=0;hang<20;hang++){

if(hang == 0){

for(lie=0;lie<20;lie++){

printw("--");

}

printw("\n");

}

if(hang>=0 && hang<=19){

for(lie=0;lie<=20;lie++){

if(lie==0||lie==20){

printw("|");

}else if(hasSnakeNode(hang,lie)){

printw("[]");

}

else{

printw(" ");

}

}

printw("\n");

}

if(hang == 19){

for(lie=0;lie<20;lie++){

printw("--");

}

printw("\n");

}

}

printw("by shijintao");

printw("\n");

}

void addNode()

{

struct snake *new;

new =(struct snake *)malloc(sizeof(struct snake));

new->hang=tail->hang;

new->lie=tail->lie+1;

tail->next = new;

tail = new;

new->next = NULL;

}

void initSnake()

{

struct snake *p;

while(head != NULL){//如果这个游戏第一次运行,head是空的,不会运行这个代码

p=head;

head=head->next;

free(p);

}

head = (struct snake *)malloc(sizeof(struct snake));

head->hang=2;

head->lie=2;

head->next=NULL;

tail = head;

addNode();

addNode();

}

void deleteNode()

{

struct snake *p;

p = head;

head = head->next;

free(p);

}

void moveSnake()

{

addNode();

deleteNode();

if(tail->hang==0||tail->hang==20||tail->lie==20||tail->lie==0){

initSnake();

}

}

int main()

{

int con;

initNcurse();

initSnake();

gamepic();

while(1){

con = getch();

if(con == KEY_RIGHT){

moveSnake();

gamepic();

}

}

getch();

endwin();

return 0;

}

代码优化点:

initSnake()这段函数添加了while()这段代码,作用是用于释放链表内存的,因为游戏死亡后,贪吃蛇会重新回到初始位置上,那么我们要将旧的链表的每一项节点拿去释放掉,避免内存泄漏,当然第一次玩的时候head是空的,不会运行while这段代码,只有死后head才会不为NULL,才会运行。

void initSnake()

{

struct snake *p;

while(head != NULL){//如果这个游戏第一次运行,head是空的,不会运行这个代码

p=head;

head=head->next;

free(p);

}

head = (struct snake *)malloc(sizeof(struct snake));

head->hang=2;

head->lie=2;

head->next=NULL;

tail = head;

addNode();

addNode();

}

主要的算法在这:用于判断是否到边界

void moveSnake()

{

addNode();

deleteNode();

if(tail->hang==0||tail->hang==20||tail->lie==20||tail->lie==0){

initSnake();//如果值相等了,说明蛇撞墙死了,然后蛇复活,调用这个函数就是从新开 始,让蛇的坐标回到初始位置

}

}

相关推荐
weixin_472339465 小时前
高效处理大体积Excel文件的Java技术方案解析
java·开发语言·excel
枯萎穿心攻击6 小时前
响应式编程入门教程第二节:构建 ObservableProperty<T> — 封装 ReactiveProperty 的高级用法
开发语言·unity·c#·游戏引擎
Eiceblue7 小时前
【免费.NET方案】CSV到PDF与DataTable的快速转换
开发语言·pdf·c#·.net
m0_555762908 小时前
Matlab 频谱分析 (Spectral Analysis)
开发语言·matlab
学不动CV了8 小时前
ARM单片机启动流程(二)(详细解析)
c语言·arm开发·stm32·单片机·51单片机
浪裡遊8 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
lzb_kkk9 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
好开心啊没烦恼9 小时前
Python 数据分析:numpy,说人话,说说数组维度。听故事学知识点怎么这么容易?
开发语言·人工智能·python·数据挖掘·数据分析·numpy
猫猫的小茶馆10 小时前
【STM32】通用定时器基本原理
c语言·stm32·单片机·嵌入式硬件·mcu·51单片机
简佐义的博客10 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang