蛇是这个游戏的主角,要实现的功能也是最复杂的一个。因为蛇不止有属性,还有行为。它会动,还会吃东西,还会长大!而且还会死!这是很要命的。我一向看不懂复杂的代码,也写不出复杂的代码。所以对于蛇,我很纠结,如何才能简单的实现它。

  毫无质疑的一点是,食物具有的属性,蛇也具有。蛇必须存在于世界中,有大小和位置以及颜色。这样最起码可以推测出一个蛇的简单定义。但是这还远远不够,蛇是活的,它能动,就必须有速度和方向,它能吃,就必须能长大。所以,抛开其它的一切,它最简单的形式起码也得这样:

typedef struct Snake
{
World *world;
int x, y, size;
SDL_Color color;
int speed, length, direction; struct Body
{
int x, y;
int direction;
struct Body *next;
} *body;
} Snake;

而我要的就是简单,于是乎,一咬牙一跺脚,就它了!

  既然选择了创造这样的一条蛇,那我也只能接受创造它了。

extern Snake * SNK_CreateSnake(World *world, int size, int x, int y);
extern void SNK_DestroySnake(Snake *snake);

  这样的蛇,要操控它的属性,就必须实现多个函数。而由于属性之间的相互联系,就得实现更多的函数。例如,改变蛇的方向,会有两种结果:1. 能动,2. 会死!吃掉食物,也有两种结果:1. 能长大,2. 被撑死。所以,我把这些函数一一细分,分为属性函数、行为函数以及附加函数。

属性相关函数:

extern void SNK_SetSnakeSpeed(Snake *snake, int speed);
extern void SNK_SetSnakeDirection(Snake *snake, int direction);
extern void SNK_SetSnakeColor(Snake *snake, Uint8 r, Uint8 g, Uint8 b, Uint8 a);

行为相关函数:

extern void SNK_MoveSnake(Snake *snake);
extern void SNK_GrowSnake(Snake *snake);

附加函数:

extern int SNK_HasIntersection(Snake *snake, SDL_Rect rect);
extern int SNK_GetSnakeStatus(Snake *snake);

  当这样一条蛇被完完整整的创造出来,我就可以毫无顾虑的让它暴露在世界之中。

extern void SNK_DrawSnake(Snake *snake);

  这是我目前所能想到的最简单的方式去实现一条蛇了。对,只是蛇!你会发现,从头到位,贪吃蛇游戏都是蛇在吃食物,但是我并没有在蛇的定义中,包含任何和食物相关的函数或变量, 我只是站在一个造物主的角度去创建生命罢了。蛇吃什么不是我要关心的,我创造了它,并制作了规则,让它去适应世界。

以下是snk-snake.h文件中的完整蛇定义:

#ifndef SNK_SNAKE_H_HEADER
#define SNK_SNAKE_H_HEADER #define SNAKE_UP (1 << 0)
#define SNAKE_LEFT (1 << 1)
#define SNAKE_DOWN (1 << 2)
#define SNAKE_RIGHT (1 << 3) #define SNAKE_DIED (1 << 4)
#define SNAKE_MOVABLE (1 << 5) #define SNAKE_INIT_COLOR 0, 0xff, 0, 0xff
#define SNAKE_DIED_COLOR 0xff, 0, 0, 0xff
#define SNAKE_CTMV_COLOR 0xff, 0xff, 0, 0xff #define SNAKE_INIT_SPEED 900 #include "snk-world.h" typedef struct Snake
{
World *world;
int x, y, size;
SDL_Color color;
int speed, length, direction; struct Body
{
int x, y;
int direction;
struct Body *next;
} *body;
} Snake; extern Snake * SNK_CreateSnake(World *world, int size, int x, int y);
extern void SNK_DestroySnake(Snake *snake); extern int SNK_HasIntersection(Snake *snake, SDL_Rect rect); extern void SNK_MoveSnake(Snake *snake);
extern void SNK_DrawSnake(Snake *snake);
extern void SNK_GrowSnake(Snake *snake); extern int SNK_GetSnakeStatus(Snake *snake); extern void SNK_SetSnakeSpeed(Snake *snake, int speed);
extern void SNK_SetSnakeDirection(Snake *snake, int direction);
extern void SNK_SetSnakeColor(Snake *snake, Uint8 r, Uint8 g, Uint8 b, Uint8 a); #endif

最开始的几行宏定义是蛇的方向,然后是蛇的状态:已死或者可以移动。最下面几行宏只是为了提供方便,仅在设置属性时使用。SNAKE_INIT_SPEED设置为900毫秒,表示蛇的速度,它是时间值,而不是移动的距离。

[C入门 - 游戏编程系列] 贪吃蛇篇(三) - 蛇定义的更多相关文章

  1. [C入门 - 游戏编程系列] 贪吃蛇篇(一) - 世界定义

    每个游戏都有一个很明确的目的或者说游戏主题,贪吃蛇的目的很明确:蛇找到并吃掉食物.只有目的是很无聊的,算不上一个好游戏.所以设计者增加了创意:1. 吃掉食物后蛇会增长:2. 吃掉食物后分数会增加.有些 ...

  2. [C入门 - 游戏编程系列] 贪吃蛇篇(六) - 蛇实现

    这一篇是关于设置蛇的属性的,接上一篇(五). 设置蛇的速度,很简单,只要不是负数就行了. void SNK_SetSnakeSpeed(Snake *snake, int speed) { ) sna ...

  3. [C入门 - 游戏编程系列] 贪吃蛇篇(四) - 食物实现

    由于食物是贪吃蛇游戏中最简单的一部分,而且和其他部分关联性不强,基本上是一个独立的部分,所以我打算先实现它. 我的想法是食物必须在世界中才能被创造出来,也就是说,先有世界再有食物,所以我得先判断世界是 ...

  4. [C入门 - 游戏编程系列] 贪吃蛇篇(二) - 食物定义

    游戏中的食物没有那么多复杂属性,特别是贪吃蛇游戏中,我把食物看待的很简单: 1. 它必须属于世界,才能出现在世界.不可能一个不属于世界的食物,出现在世界中:但是可能存在着一个食物,它属于世界,但是却没 ...

  5. [C入门 - 游戏编程系列] 贪吃蛇篇(五) - 蛇实现

    因为已经写了食物的实现,所以我不知道到底是该先写世界的实现还是蛇的实现.因为世界就是一个窗口,可以立刻在世界中看到食物的样子,对于大多数人来说,如果写完代码立刻就能看到效果,那就再好不过了.可是,我最 ...

  6. [C入门 - 游戏编程系列] 序言篇

    记得学习C语言的时候,看着别人能写各种各样的小游戏和小软件,甚是羡慕.而自己,虽然说语法都会,但是真正上手写个几百行的代码,就显得力不从心.曾经一度很是郁闷,看过一些书,大都处于教语法的层面,有些涉及 ...

  7. [C入门 - 游戏编程系列] 环境篇

    这一系列笔记的代码都是在Ubuntu 14.04下编码并测试的,原因无他,因为我笔记本电脑只装了一个Ubuntu系统,其中唯一使用的第三方库SDL也是开源并且跨平台的.所以即使你用的是Windows或 ...

  8. SQL Server调优系列玩转篇三(利用索引提示(Hint)引导语句最大优化运行)

    前言 本篇继续玩转模块的内容,关于索引在SQL Server的位置无须多言,本篇将分析如何利用Hint引导语句充分利用索引进行运行,同样,还是希望扎实掌握前面一系列的内容,才进入本模块的内容分析. 闲 ...

  9. SQL Server 调优系列玩转篇三(利用索引提示(Hint)引导语句最大优化运行)

    前言 本篇继续玩转模块的内容,关于索引在SQL Server的位置无须多言,本篇将分析如何利用Hint引导语句充分利用索引进行运行,同样,还是希望扎实掌握前面一系列的内容,才进入本模块的内容分析. 闲 ...

随机推荐

  1. IIC 概述之用IO模拟

    最近做的一个项目,是基于IIC总线通信的传感器系统.由于另外一个传感器使用的是类IIC协议,而不是标准IIC,所以MCU不能与其通信,最后没有办法,只有通过I/O口模拟的方式实现IIC的总线通信.具体 ...

  2. 编写Swift代码的其他工具

    Swift程序不能在Windows其他平台编译和运行,有人提供了一个网站swiftstub.com,左栏是代码编辑窗口,右栏是运行结果窗口.可以在任何平台下编译和运行Swift程序.

  3. 3D打印论坛

    3D打印论坛:http://www.3done.cn http://www.03dp.com www.qjxxw.net/ http://www.3ddayin.net http://oa.zol.c ...

  4. hdu 5422 Rikka with Graph(简单题)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  5. MySql 查询表字段数

    MySql 查询表字段数 SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='test_cases' AND tab ...

  6. IOS UIlabel设置文本距离边框距离

    自定义UILabel 继承 UILabel 重写drawTextInRect 方法具体如下: CGRect rect = CGRectMake(rect.origin.x + 5, rect.orig ...

  7. java如何从方法返回多个值

    本文介绍三个方法,使java方法返回多个值. 方法1:使用集合类 方法2:使用封装对象 方法3:使用引用传递 示例代码如下: import java.util.HashMap; import java ...

  8. [Redux] Redux: Extracting Container Components -- AddTodo

    Code to be refactored: const AddTodo = ({ onAddClick }) => { let input; return ( <div> < ...

  9. IPMITOOL常用操作指令

    一.开关机,重启 1. 查看开关机状态: ipmitool -H (BMC的管理IP地址) -I lanplus -U (BMC登录用户名) -P (BMC 登录用户名的密码) power statu ...

  10. verilog 实现加法器

    半加器 如果不考虑来自低位的进位将两个1二进制数相加,称为半加. 实现半加运算的逻辑电路称为半加器. 真值表 逻辑表达式和 \begin{align}\notag s = a{b}' + {a}'b ...