C语言用面向对象的思想写贪吃蛇
大概一年前这时候,接触C语言一个月,那时候知之甚少,对面向对象只觉”可远观而不可亵玩“,而且会看到很多言论说C语言就是面向过程的语言,C++就是面向对象的语言。不过,不记得什么时候在网上看到过一篇博文,大概是说如何优雅的写C语言。其中颇有印象的就是通过结构的函数指针模拟C++中的类。
今天粗略尝试了一下,写的是之前写过的贪吃蛇。的确,用面向对象的思维写让我的思维变的更加清晰,因为这个游戏(以及大多数显示事物)的天然属性就是对象。
此外,这次从最关键最核心的写起,如此写起来真是越写越轻松。因为如果关键部分写不出来,其他写的再好也没用。所以这次的顺序大概是:能移动的蛇--->能吃食物并变长--->能判断自己是否死亡--->其他修饰功能。
最后,调试无误后。在发布代码前写了写注释。发现自己现在命名编码规范了不少,所以注释也并不多。曾经看到一种观点就是,注释关键部分就足够了,最好的注释就是良好的命名习惯、编码风格和清晰的逻辑。
不过,由于没有太多的规划,都是自己在路上零散构思的,代码还是不够紧凑,逻辑还可以优化。
头文件
#ifndef _HEAD_H_
#define _HEAD_H_
#include <stdio.h>
#include <windows.h>//
int Score = -;
typedef struct node1
{
int x;
int y;
struct node1 *next;
}SnakeBody;
typedef struct node2
{
int x;
int y;//location
char Status;
char Direction;
void (*MoveUp)(struct node2 *);
void (*MoveDown)(struct node2 *);
void (*MoveRight)(struct node2 *);
void (*MoveLeft)(struct node2 *);
void (*GrowUp)(struct node2 *);
int (*IsDie)(struct node2 *);
SnakeBody *next;
}SnakeHead;
void HideCursor()
{
CONSOLE_CURSOR_INFO cursor_info = { , };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
void SetPosition(int x, int y)
{
COORD pos;
HANDLE hOutput;
pos.X = x;
pos.Y = y;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, pos);
}
void Print(SnakeHead *H)
{
SetPosition(H->x, H->y);
printf("@");//mean snake head
SnakeBody *temp = H->next;
while(NULL != temp)
{
SetPosition(temp->x, temp->y);
printf("+");//means snake body
temp = temp->next;
}
}
void Move(SnakeHead *H)
{
SnakeBody *temp = H->next;
while (NULL != temp->next->next)
{
temp = temp->next;
}
temp->next->next = H->next;
H->next = temp->next;
SetPosition(temp->next->x, temp->next->y);
printf(" ");
temp->next = NULL;
H->next->x = H->x;
H->next->y = H->y;
}
void _MoveUp(SnakeHead *H)
{
Move(H);
H->y--;
}
void _MoveDown(SnakeHead *H)
{
Move(H);
H->y++;
}
void _MoveRight(SnakeHead *H)
{
Move(H);
H->x++;
}
void _MoveLeft(SnakeHead *H)
{
Move(H);
H->x--;
}
void _GrowUp(SnakeHead *H)
{
SnakeBody *temp = (SnakeBody *)malloc(sizeof(SnakeBody));
temp->x = H->x;
temp->y = H->y;
temp->next = H->next;
H->next = temp;
switch (H->Direction)
{
case 'U':
{
H->y--;
break;
}
case 'D':
{
H->y++;
break;
}
case 'L':
{
H->x--;
break;
}
case 'R':
{
H->x++;
break;
}
default:
{
break;
}
}
Print(H);
}
const int Left = ;
const int Right = ;
const int Top = ;
const int Bottom = ;
void BuildWall()
{
for (int x = Left; x <= Right; x++)
{
SetPosition(x, Top);
printf("-");
SetPosition(x, Bottom);
printf("-");
}
for (int y = Top; y <= Bottom; y++)
{
SetPosition(Left, y);
printf("|");
SetPosition(Right, y);
printf("|");
}
//some hint
SetPosition(, );
printf("Snake");
SetPosition(, );
printf("zhaoyu");
SetPosition(, );
printf("F1:Slow Down");
SetPosition(, );
printf("F2:Speed Up");
SetPosition(, );
printf("F3:Speed Up++");
SetPosition(, );
printf("Score:");
}
void CreateFood(int *x, int *y, SnakeHead *H)
{
int flag = ;
int i = , j = ;
//make sure in the wall && not on snake
SnakeBody *temp = H->next;
while ( == flag)
{
i = rand()%;
i += ;
j = rand()%;
j += ;
flag = ;
if (i == H->x && j == H->y)
{
flag = ;
continue;
}
temp = H->next;
while (NULL != temp)
{
if (i == temp->x && j == temp->y)
{
flag = ;
break;
}
temp = temp->next;
}
} *x = i;
*y = j;
SetPosition(i, j);
printf("$");//dollar mead food!
SetPosition(, );
//once food created ,score plus 1
printf("%d", ++Score);
}
int Die(SnakeHead *H)
{
//out the wall will die
if (H->x <= Left || H->x >= Right || H->y >= Bottom || H->y <= Top)
{
return ;//die
}
// crush into itself will die
SnakeBody *temp = H->next;
while (NULL !=temp)
{
if (H->x == temp->x && H->y == temp->y)
{
return ;
}
temp = temp->next;
}
// 0 mean not die
return ;
}
#endif
源文件
#include "head.h" void StartGame()
{
//Create a snake
SnakeBody *temp = (SnakeBody *)malloc(sizeof(SnakeBody));
SnakeHead *Head = (SnakeHead *)malloc(sizeof(SnakeHead));
Head->Direction = 'L';
Head->Status = ;
Head->x = ;
Head->y = ;
//assign some functions to snake
Head->MoveUp = _MoveUp;
Head->MoveDown = _MoveDown;
Head->MoveRight = _MoveRight;
Head->MoveLeft = _MoveLeft;
Head->GrowUp = _GrowUp;
Head->IsDie = Die;
temp->x = ;
temp->y = ;
temp->next = NULL;
Head->next = temp;
// create snake body
for (int i = ; i < ; i++)
{
SnakeBody *move = (SnakeBody *)malloc(sizeof(SnakeBody));
move->x = temp->x + ;
move->y = temp->y;
temp->next = move;
temp = move;
move->next = NULL;
}
//Init food
int Foodx = , Foody = ;
CreateFood(&Foodx, &Foody, Head);
int Speed = ;
while ( == Head->Status)
{
//print the snake
Print(Head);
//judge is or not die
if((*Head->IsDie)(Head))
{
break;
}
//get direction
if(GetAsyncKeyState(VK_UP) && 'D' != Head->Direction)
{
Head->Direction = 'U';
}
else if (GetAsyncKeyState(VK_DOWN) && 'U' != Head->Direction)
{
Head->Direction = 'D';
}
else if (GetAsyncKeyState(VK_RIGHT) && 'L' != Head->Direction)
{
Head->Direction = 'R';
}
else if (GetAsyncKeyState(VK_LEFT) && 'R' != Head->Direction)
{
Head->Direction = 'L';
}
//move
switch (Head->Direction)
{
case 'U':
{
//judge is there a food
if (Head->x == Foodx && Head->y - == Foody)
{
(*Head->GrowUp)(Head);
CreateFood(&Foodx, &Foody, Head);
}
else//Just move
{
(*Head->MoveUp)(Head);
}
break;
}
case 'D':
{
if (Head->x == Foodx && Head->y + == Foody)
{
(*Head->GrowUp)(Head);
CreateFood(&Foodx, &Foody, Head);
}
else
{
(*Head->MoveDown)(Head);
}
break;
}
case 'R':
{
if (Head->x + == Foodx && Head->y == Foody)
{
(*Head->GrowUp)(Head);
CreateFood(&Foodx, &Foody, Head);
}
else
{
(*Head->MoveRight)(Head);
} break;
}
case 'L':
{
if (Head->x - == Foodx && Head->y == Foody)
{
(*Head->GrowUp)(Head);
CreateFood(&Foodx, &Foody, Head);
}
else
{
(*Head->MoveLeft)(Head);
}
break;
}
default:
{
break;
}
}
//control
if (GetAsyncKeyState(VK_F1) && Speed > )
{
Speed -= ;
}
else if (GetAsyncKeyState(VK_F2) && Speed < )
{
Speed += ;
}
else if (GetAsyncKeyState(VK_F3))
{
Speed += ;
}
if ('L' == Head->Direction ||'R' == Head->Direction)
{
Sleep(/Speed);
}
else
{
Sleep(/Speed);
}
}
}
int main(int argc, char const *argv[])
{
//init
system("cls");
system("mode con cols=50 lines=30");//no space around equal sign
BuildWall();
HideCursor();
StartGame();
SetPosition(, );
printf("Enter to exit!");
getchar();
return ;
}
运行:
后记:
1、函数指针与函数名
函数名与函数指针都是一样的,即都是函数指针。函数名是一个函数指针常量,而函数指针是一个函数数指针变量。
一般的C语言书籍都不会谈及这些近乎奇淫技巧的东东。
2、GetAsyncKeyState函数
这个函数按下之后其状态会一直存在,我在写俄罗斯方块就大受其害。以下面代码为例。你只需要按一下F1就可以跳出循环了,而不是1000下。因为按下一次之后其状态就始终为真了,除非你按下别的键。
#include <stdio.h>
#include <windows.h>
int main(int argc, char const *argv[])
{
int i = ;
while ()
{
if (GetAsyncKeyState(VK_F1))
{
i++;
}
if (i >= )
{
break;
}
}
printf("%d\n", i);
return ;
}
C语言用面向对象的思想写贪吃蛇的更多相关文章
- JS高级---面向对象的编程思想(贪吃蛇梳理)
面向对象的编程思想(贪吃蛇梳理) 模拟贪吃蛇游戏,做的项目 地图: 宽,高,背景颜色,因为小蛇和食物都是相对于地图显示的, 这里小蛇和食物都是地图的子元素, 随机位置显示, 脱离文档流的, 地图也需要 ...
- JavaScript面向对象编程小游戏---贪吃蛇
1 面向对象编程思想在程序项目中有着非常明显的优势: 1- 1 代码可读性高.由于继承的存在,即使改变需求,那么维护也只是在局部模块 1- 2 维护非常方便并且成本较低. 2 这个demo是采用了 ...
- 用python+pygame写贪吃蛇小游戏
因为python语法简单好上手,前两天在想能不能用python写个小游戏出来,就上网搜了一下发现了pygame这个写2D游戏的库.了解了两天再参考了一些资料就开始写贪吃蛇这个小游戏. 毕竟最开始的练手 ...
- 【Java并发基础】利用面向对象的思想写好并发程序
前言 下面简单总结学习Java并发的笔记,关于如何利用面向对象思想写好并发程序的建议.面向对象的思想和并发编程属于两个领域,但是在Java中这两个领域却可以融合到一起.在Java语言中,面向对象编程的 ...
- pygame写贪吃蛇
python小白尝试写游戏.. 学了点pygame不知道那什么练手好,先拿贪吃蛇开刀吧. 一个游戏可以粗略的分为两个部分: 数据(变量) 处理数据(函数,方法) 设计变量 首先预想下,画面的那些部分需 ...
- 用原生Canvas写贪吃蛇及问题解决
为了学习Canvas,写了这个小游戏贪吃蛇供自己和大家学习 Github: https://github.com/zhiyishou/Gsnake Play On: http://zhiyishou. ...
- 用Js写贪吃蛇
使用Javascript做贪吃蛇小游戏, 1.自定义地图宽高,蛇的初始速度 2.食物随机出现 3.蛇的样式属性 4.贪吃蛇玩法(吃食物,碰到边界,吃食物后加速,计分,) <!DOCTYPE ht ...
- 一步步教你怎么用python写贪吃蛇游戏
目录 0 引言 1 环境 2 需求分析 3 代码实现 4 后记 0 引言 前几天,星球有人提到贪吃蛇,一下子就勾起了我的兴趣,毕竟在那个Nokia称霸的年代,这款游戏可是经典中的经典啊!而用Pytho ...
- javascript写贪吃蛇游戏(20行代码!)
<!doctype html> <html> <body> <canvas id="can" width="400" ...
随机推荐
- NOI2018准备 Day11
今天7点半到9点我都不知道自己在干啥, 一共A了3道题,2道钻石,1道大师. 下午调一道线段树3个小时没调出来,一个单调栈2小时没搞出来...... 学了个算法:求极大子矩阵. 昨天定的目标是学指针, ...
- checkbox页面全选
http://pan.baidu.com/s/1tfzSa
- sFlow
http://www.sflow.org/developers/specifications.php http://www.inmon.com/technology/index.php sFlow s ...
- 流量工程 traffic engineering (TE)
什么是流量工程 流量工程是指根据各种数据业务流量的特性选取传输路径的处理过程.流量工程用于平衡网络中的不同交换机.路由器以及链路之间的负载. [编辑] 流量工程的内容 流量工程在复杂的网络环境中,控制 ...
- 虚拟机VirtualBox 5.1.0|VBOX
Oracle VM VirtualBox是一款免费.开源的虚拟机软件,现属于Oracle旗下产品.可以安装Windows.Linux.IBM OS/2.Solaris.BSD等操作系统,具有远端桌面协 ...
- [AJAX系列]$.get(url,[data],[fn],[type])
$.get(url,[data],[fn],[type]) 概述 通过远程HTTP GET请求载入信息 参数 url:待载入页眉的URL地址 data:待发送key/value参数 callback: ...
- IOS -- 获取本地图片和网络图片的大小size
// 获取图片的size CGSize size = [UIImage imageNamed:@"regStep2_sex"].size; 获取网络图片的尺寸: // 根据图片ur ...
- Beta版冲刺Day1
会议讨论: 628: 已经成功实现了文件的上传功能,但是按钮的布局有点不好看.未完成的功能有:修改老师信息时候弹出小窗口进行修改. 601: 目前还在解决剩下的问题,比如将 ...
- JavaIO流文件的操作总结
IO流的分类 1.根据数据的流向: 输入流:用来读数据,如从外界设备读数据到内存中: 输出流:用来写数据,如从内存输出数据到外界存储设备: 2.根据数据流的格式: 字节流:一般用于声音或者秃瓢等二进制 ...
- java进程CPU飙高
因为这段时间一直在弄监控,但是工作还是在进行中 因为机器不多,所以今天早上巡检了一下,看到一台生产机器上的CPU飙高 top