[C入门 - 游戏编程系列] 贪吃蛇篇(三) - 蛇定义

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

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

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毫秒,表示蛇的速度,它是时间值,而不是移动的距离。

时间: 2024-08-01 15:05:12

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

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

这一篇是关于设置蛇的属性的,接上一篇(五). 设置蛇的速度,很简单,只要不是负数就行了. void SNK_SetSnakeSpeed(Snake *snake, int speed) { if (snake != 0) snake->speed = SDL_abs(speed); } 设置蛇的方向有些复杂,玩过贪吃蛇的都知道,蛇向前移动时,它无法向后转弯:向左移动时,它无法向右转弯.所以,我也要做些这样的判断. void SNK_SetSnakeDirection(Snake *snake,

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

由于食物是贪吃蛇游戏中最简单的一部分,而且和其他部分关联性不强,基本上是一个独立的部分,所以我打算先实现它. 我的想法是食物必须在世界中才能被创造出来,也就是说,先有世界再有食物,所以我得先判断世界是否存在,存在的话才可以创建食物. Food * SNK_CreateFood(World *world, int size) { Food *food; if (world == 0) return 0; if ((food = (Food *)SDL_malloc(sizeof(Food))) =

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

游戏中的食物没有那么多复杂属性,特别是贪吃蛇游戏中,我把食物看待的很简单: 1. 它必须属于世界,才能出现在世界.不可能一个不属于世界的食物,出现在世界中:但是可能存在着一个食物,它属于世界,但是却没有出现在世界中(即食物的颜色和世界的颜色相同,因此看不见食物).这就像鬼一样,它可能存在于这个世界上,但我们看不到它. 2. 一个属于世界的食物,具有在这个世界中的位置. 3. 它有颜色和大小. 因此,食物的结构体定义就显而易见了! typedef struct Food { World *worl

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

因为已经写了食物的实现,所以我不知道到底是该先写世界的实现还是蛇的实现.因为世界就是一个窗口,可以立刻在世界中看到食物的样子,对于大多数人来说,如果写完代码立刻就能看到效果,那就再好不过了.可是,我最后还是选择了先写蛇的实现这篇笔记.如果先写世界的实现,我就无法按照现在的思路完完整整的写下去,因为没有蛇,世界部分的代码就不完整,看完食物的效果后,我还是得写蛇的实现,然后又得修改世界部分的代码,来查看蛇的效果.反反复复,实在折腾不起.所以我打算把食物和蛇的实现都写完,最后统一看运行效果. 蛇和食物

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

记得学习C语言的时候,看着别人能写各种各样的小游戏和小软件,甚是羡慕.而自己,虽然说语法都会,但是真正上手写个几百行的代码,就显得力不从心.曾经一度很是郁闷,看过一些书,大都处于教语法的层面,有些涉及到软件设计,但是对于几百行代码都驾驭不了的我,看了也是等于白看,完全领悟不到设计中蕴含的哲学和精髓. 所以,本来盘算着第一个月学完语法,第二个月写出自己所谓的“软件”的这个美好愿望,被无情的打破了.现实是,语法确实在一个月学完了,但是坑爹的是,除了在群里或者论坛中增加了一点谈论或者说冒充“大神”的资

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

这一系列笔记的代码都是在Ubuntu 14.04下编码并测试的,原因无他,因为我笔记本电脑只装了一个Ubuntu系统,其中唯一使用的第三方库SDL也是开源并且跨平台的.所以即使你用的是Windows或Mac,也能运行所有的代码. 1. 安装SDL库及其扩展 Ubuntu: sudo apt-get install libsdl2-dev sudo apt-get install libsdl2-gfx-dev sudo apt-get install libsdl2-image-dev sudo

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

前言 本篇继续玩转模块的内容,关于索引在SQL Server的位置无须多言,本篇将分析如何利用Hint引导语句充分利用索引进行运行,同样,还是希望扎实掌握前面一系列的内容,才进入本模块的内容分析. 闲言少叙,进入本篇的内容. 技术准备 数据库版本为SQL Server2012,利用微软的以前的案例库(Northwind)进行分析,部分内容也会应用微软的另一个案例库AdventureWorks. 相信了解SQL Server的朋友,对这两个库都不会太陌生. 一.并行Hint提示 (MAXDOP N

游戏编程系列[1]--游戏编程中RPC协议的使用

RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据.在OSI网络通信模型中,RPC跨越了传输层和应用层.RPC使得开发包括网络分布式多程序在内的应用程序更加容易.RPC采用客户机/服务器模式.请求程序就是一个客户机,而服务提供程序就是一个服务器. 首先,客户机调用进程发送一个有进程参数的调用信息到服务进

编程系列之——资源篇

jdk下载在这里jdk的我给官方的地址:http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html java文档资料:链接:http://pan.baidu.com/s/1boGUz4V 密码:km36 Android环境搭建:链接:http://pan.baidu.com/s/1miEQ0fI 密码:3i4l After Effects CC 2015:链接:http://pan.baidu.com