大概一年前这时候,接触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语言用面向对象的思想写贪吃蛇的更多相关文章

  1. JS高级---面向对象的编程思想(贪吃蛇梳理)

    面向对象的编程思想(贪吃蛇梳理) 模拟贪吃蛇游戏,做的项目 地图: 宽,高,背景颜色,因为小蛇和食物都是相对于地图显示的, 这里小蛇和食物都是地图的子元素, 随机位置显示, 脱离文档流的, 地图也需要 ...

  2. JavaScript面向对象编程小游戏---贪吃蛇

    1 面向对象编程思想在程序项目中有着非常明显的优势: 1- 1 代码可读性高.由于继承的存在,即使改变需求,那么维护也只是在局部模块 1- 2 维护非常方便并且成本较低. ​ 2 这个demo是采用了 ...

  3. 用python+pygame写贪吃蛇小游戏

    因为python语法简单好上手,前两天在想能不能用python写个小游戏出来,就上网搜了一下发现了pygame这个写2D游戏的库.了解了两天再参考了一些资料就开始写贪吃蛇这个小游戏. 毕竟最开始的练手 ...

  4. 【Java并发基础】利用面向对象的思想写好并发程序

    前言 下面简单总结学习Java并发的笔记,关于如何利用面向对象思想写好并发程序的建议.面向对象的思想和并发编程属于两个领域,但是在Java中这两个领域却可以融合到一起.在Java语言中,面向对象编程的 ...

  5. pygame写贪吃蛇

    python小白尝试写游戏.. 学了点pygame不知道那什么练手好,先拿贪吃蛇开刀吧. 一个游戏可以粗略的分为两个部分: 数据(变量) 处理数据(函数,方法) 设计变量 首先预想下,画面的那些部分需 ...

  6. 用原生Canvas写贪吃蛇及问题解决

    为了学习Canvas,写了这个小游戏贪吃蛇供自己和大家学习 Github: https://github.com/zhiyishou/Gsnake Play On: http://zhiyishou. ...

  7. 用Js写贪吃蛇

    使用Javascript做贪吃蛇小游戏, 1.自定义地图宽高,蛇的初始速度 2.食物随机出现 3.蛇的样式属性 4.贪吃蛇玩法(吃食物,碰到边界,吃食物后加速,计分,) <!DOCTYPE ht ...

  8. 一步步教你怎么用python写贪吃蛇游戏

    目录 0 引言 1 环境 2 需求分析 3 代码实现 4 后记 0 引言 前几天,星球有人提到贪吃蛇,一下子就勾起了我的兴趣,毕竟在那个Nokia称霸的年代,这款游戏可是经典中的经典啊!而用Pytho ...

  9. javascript写贪吃蛇游戏(20行代码!)

    <!doctype html> <html> <body> <canvas id="can" width="400" ...

随机推荐

  1. hashset hastable dictionary concurrentdictionary区别

    1.HashTable 哈希表(HashTable)表示键/值对的集合.在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现 ...

  2. windows mysql提示:1045 access denied for user 'root'@'localhost' using password yes 解决方案

    win7 MySql5.6.17提示:1045 access denied for user 'root'@'localhost' using password yes 从网上找到的解决方法,以此博客 ...

  3. java:使用匿名类直接new接口

    java中的匿名类有一个倍儿神奇的用法,见下面代码示例: package contract; public interface ISay { void sayHello(); } 上面是一个简单的接口 ...

  4. 一款炫酷的幻灯片播放框架介绍(附demo及使用方法)

    废话不多说,先上demo(建议在chrome下打开 F键全屏 esc退出全屏): 我的demo-博客园简介 官网demo 更多demo 今天为大家介绍一款基于css3和JavaScript的幻灯片播放 ...

  5. 用TypeScript开发Vue——如何通过vue实例化对象访问实际ViewModel对象

    用TypeScript开发Vue--如何通过vue实例化对象访问实际ViewModel对象 背景 我个人很喜欢TypeScript也很喜欢Vue,但在两者共同使用的时候遇到一个问题. Vue的实例化对 ...

  6. Scala入门之函数进阶

    /** * 函数式编程进阶: * 1,函数和变量一样作为Scala语言的一等公民,函数可以直接赋值给变量: * 2, 函数更长用的方式是匿名函数,定义的时候只需要说明输入参数的类型和函数体即可,不需要 ...

  7. 关于Hibernate的sequence diagram

  8. LVS+MYCAT读写分离+MYSQL同步部署手册(第三版)

    1      配置MYSQL主备同步 1.1    测试环境 mysql版本:5.6.24: 操作系统内核版本:Linux-3.13-0-32 主数据库IP:192.168.10.3: 主数据库名:d ...

  9. LINUX中简单的字符命令

    1. ls 查看目录中的内容 -a 查看隐藏文件 -l 显示文件的详细信息 -d 显示目录属性 -h 人性化显示文件大小 -i 显示ID号 2. 目录操作 创建目录 mkdir [-p](递归) di ...

  10. springmvc中实现quartz定时任务

    1.maven项目添加如下两个jar包,当然也需要相应的spring 的Jar <!-- Spring Quartz定时器 begin --> <dependency> < ...