[C入门 - 游戏编程系列] 贪吃蛇篇(六) - 蛇实现
这一篇是关于设置蛇的属性的,接上一篇(五)。
设置蛇的速度,很简单,只要不是负数就行了。
void SNK_SetSnakeSpeed(Snake *snake, int speed)
{
if (snake != ) snake->speed = SDL_abs(speed);
}
设置蛇的方向有些复杂,玩过贪吃蛇的都知道,蛇向前移动时,它无法向后转弯;向左移动时,它无法向右转弯。所以,我也要做些这样的判断。
void SNK_SetSnakeDirection(Snake *snake, int direction)
{
if (snake != && (direction & (SNAKE_UP | SNAKE_DOWN | SNAKE_LEFT | SNAKE_RIGHT)))
{
if (snake->direction & (SNAKE_UP | SNAKE_DOWN))
{
if (direction & (SNAKE_LEFT | SNAKE_RIGHT))
snake->direction = direction;
}
else
{
if (direction & (SNAKE_UP | SNAKE_DOWN))
snake->direction = direction;
}
}
}
这样就能保证方向是对的,而且具有正确的转弯行为。
最后设置蛇的颜色,这个就没什么好说的了。
void SNK_SetSnakeColor(Snake *snake, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
if (snake != )
{
snake->color.r = r;
snake->color.g = g;
snake->color.b = b;
snake->color.a = a;
}
}
到此,蛇的实现代码就写完了。整个游戏最核心的部分也就这些了,接下来就是弄个美观的界面了。
以下是snk-snake.c文件的完整源码:
#include "snk-snake.h" #define INIT_SNAKE(world, size, x, y) \
snake->world = (world); \
snake->x = (SDL_abs(x) > (world)->w) ? : SDL_abs(x); \
snake->x = (size) ? ((snake->x / SDL_abs(size)) * SDL_abs(size)) : ; \
snake->y = (SDL_abs(y) > (world)->h) ? : SDL_abs(y); \
snake->y = (size) ? ((snake->y / SDL_abs(size)) * SDL_abs(size)) : ; \
snake->size = (size) ? SDL_abs(size) : ; \
snake->color.r = snake->color.g = snake->color.b = snake->color.a = ; \
snake->speed = ; \
snake->length = ; \
snake->direction = SNAKE_UP; \
snake->body = ; #define MOVE_SNAKE(body) do { \
switch ((body)->direction) \
{ \
case SNAKE_UP: (body)->y -= snake->size; break; \
case SNAKE_DOWN: (body)->y += snake->size; break; \
case SNAKE_LEFT: (body)->x -= snake->size; break; \
case SNAKE_RIGHT:(body)->x += snake->size; break; \
} \
} while () #define APPEND_BODY(last, body) do { \
if ((last)->direction & (SNAKE_UP | SNAKE_DOWN)) { \
(body)->x = (last)->x; \
if ((last)->direction & SNAKE_UP) \
(body)->y = (last)->y + snake->size; \
else \
(body)->y = (last)->y - snake->size; \
} else { \
if ((last)->direction & SNAKE_LEFT) \
(body)->x = (last)->x + snake->size; \
else \
(body)->x = (last)->x - snake->size; \
(body)->y = (last)->y; \
} \
(body)->direction = (last)->direction; \
(body)->next = (snake->body != ) ? snake->body : ; \
snake->body = (body); \
++snake->length; \
} while () #define REMOVE_BODY(body) do { \
snake->body = (body)->next; \
SDL_free(body); \
(body) = snake->body; \
} while (body) Snake * SNK_CreateSnake(World *world, int size, int x, int y)
{
Snake *snake; if (world == ) return ; if ((snake = (Snake *)SDL_malloc(sizeof(Snake))) == ) return ; INIT_SNAKE(world, size, x, y);
SNK_GrowSnake(snake); return snake;
} void SNK_DestroySnake(Snake *snake)
{
struct Body *body; if (snake != )
{
if ((body = snake->body)) REMOVE_BODY(body); SDL_free(snake);
snake = ;
}
} void SNK_MoveSnake(Snake *snake)
{
struct Body *body; if (snake != )
{
MOVE_SNAKE(snake); for (body = snake->body; body; body = body->next)
{
MOVE_SNAKE(body);
body->direction = (body->next != ) ? body->next->direction : snake->direction;
}
}
} void SNK_DrawSnake(Snake *snake)
{
SDL_Rect rect;
struct Body *body; if (snake != )
{
rect.x = snake->x;
rect.y = snake->y;
rect.w = rect.h = snake->size; if (((snake->world != ) ? (snake->world->render != ) : ))
{
SDL_SetRenderDrawColor(snake->world->render,
snake->color.r, snake->color.g,
snake->color.b, snake->color.a);
SDL_RenderDrawRect(snake->world->render, &rect); for (body = snake->body; body; body = body->next)
{
rect.x = body->x;
rect.y = body->y;
SDL_RenderDrawRect(snake->world->render, &rect);
}
}
}
} void SNK_GrowSnake(Snake *snake)
{
struct Body *body; if (snake != )
{
if ((body = (struct Body *)SDL_malloc(sizeof(struct Body))) == ) return; if (snake->body == )
{
APPEND_BODY(snake, body);
}
else
{
APPEND_BODY(snake->body, body);
}
}
} int SNK_HasIntersection(Snake *snake, SDL_Rect rect)
{
SDL_Rect bodyrect;
struct Body *body; if (snake != )
{
bodyrect.w = bodyrect.h = snake->size; for (body = snake->body; body; body = body->next)
{
bodyrect.x = body->x;
bodyrect.y = body->y; if (SDL_HasIntersection(&bodyrect, &rect) != )
return ;
}
} return ;
} int SNK_GetSnakeStatus(Snake *snake)
{
SDL_Rect headrect; if (((snake != ) ? (snake->world != ) : ))
{
headrect.w = (snake->x > && snake->x < snake->world->w);
headrect.h = (snake->y > && snake->y < snake->world->h); if (headrect.w && headrect.h)
{
headrect.x = snake->x;
headrect.y = snake->y;
headrect.w = headrect.h = snake->size; if (SNK_HasIntersection(snake, headrect) != )
return SNAKE_DIED; return SNAKE_MOVABLE;
}
else
{
switch (snake->direction)
{
case SNAKE_UP:
headrect.x = (snake->y > );
break;
case SNAKE_DOWN:
headrect.x = ((snake->y + snake->size) < snake->world->h);
break;
case SNAKE_LEFT:
headrect.x = (snake->x > );
break;
case SNAKE_RIGHT:
headrect.x = ((snake->x + snake->size) < snake->world->w);
break;
} return ((headrect.x != ) ? SNAKE_MOVABLE : );
}
} return ;
} void SNK_SetSnakeSpeed(Snake *snake, int speed)
{
if (snake != ) snake->speed = SDL_abs(speed);
} void SNK_SetSnakeDirection(Snake *snake, int direction)
{
if (snake != && (direction & (SNAKE_UP | SNAKE_DOWN | SNAKE_LEFT | SNAKE_RIGHT)))
{
if (snake->direction & (SNAKE_UP | SNAKE_DOWN))
{
if (direction & (SNAKE_LEFT | SNAKE_RIGHT))
snake->direction = direction;
}
else
{
if (direction & (SNAKE_UP | SNAKE_DOWN))
snake->direction = direction;
}
}
} void SNK_SetSnakeColor(Snake *snake, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
if (snake != )
{
snake->color.r = r;
snake->color.g = g;
snake->color.b = b;
snake->color.a = a;
}
}
宏INIT_SNAKE中snake->x和snake->y重复了两次,主要是为了将蛇的位置和蛇的大小对齐。
APPEND_BODY用于追加链表节点,并设置snake->body永远指向蛇尾,提高追加节点的效率。
[C入门 - 游戏编程系列] 贪吃蛇篇(六) - 蛇实现的更多相关文章
- [C入门 - 游戏编程系列] 贪吃蛇篇(三) - 蛇定义
蛇是这个游戏的主角,要实现的功能也是最复杂的一个.因为蛇不止有属性,还有行为.它会动,还会吃东西,还会长大!而且还会死!这是很要命的.我一向看不懂复杂的代码,也写不出复杂的代码.所以对于蛇,我很纠结, ...
- [C入门 - 游戏编程系列] 贪吃蛇篇(一) - 世界定义
每个游戏都有一个很明确的目的或者说游戏主题,贪吃蛇的目的很明确:蛇找到并吃掉食物.只有目的是很无聊的,算不上一个好游戏.所以设计者增加了创意:1. 吃掉食物后蛇会增长:2. 吃掉食物后分数会增加.有些 ...
- [C入门 - 游戏编程系列] 贪吃蛇篇(四) - 食物实现
由于食物是贪吃蛇游戏中最简单的一部分,而且和其他部分关联性不强,基本上是一个独立的部分,所以我打算先实现它. 我的想法是食物必须在世界中才能被创造出来,也就是说,先有世界再有食物,所以我得先判断世界是 ...
- [C入门 - 游戏编程系列] 贪吃蛇篇(二) - 食物定义
游戏中的食物没有那么多复杂属性,特别是贪吃蛇游戏中,我把食物看待的很简单: 1. 它必须属于世界,才能出现在世界.不可能一个不属于世界的食物,出现在世界中:但是可能存在着一个食物,它属于世界,但是却没 ...
- [C入门 - 游戏编程系列] 贪吃蛇篇(五) - 蛇实现
因为已经写了食物的实现,所以我不知道到底是该先写世界的实现还是蛇的实现.因为世界就是一个窗口,可以立刻在世界中看到食物的样子,对于大多数人来说,如果写完代码立刻就能看到效果,那就再好不过了.可是,我最 ...
- [C入门 - 游戏编程系列] 序言篇
记得学习C语言的时候,看着别人能写各种各样的小游戏和小软件,甚是羡慕.而自己,虽然说语法都会,但是真正上手写个几百行的代码,就显得力不从心.曾经一度很是郁闷,看过一些书,大都处于教语法的层面,有些涉及 ...
- [C入门 - 游戏编程系列] 环境篇
这一系列笔记的代码都是在Ubuntu 14.04下编码并测试的,原因无他,因为我笔记本电脑只装了一个Ubuntu系统,其中唯一使用的第三方库SDL也是开源并且跨平台的.所以即使你用的是Windows或 ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用[2]--Aop PostSharp篇
上一篇我们使用了一个通用JSON协议约定来进行达到远程调用的目的.但是从实现上,我们需要不断的在所有的方法上添加拦截,并且判断拦截,然后执行,这就达到了一个比较繁琐的目的. 之前我们尝试过使用代码生成 ...
- 游戏编程系列[2]--游戏编程中RPC与OpLog协议的结合--序
在系列[1]中,我们展示了RPC调用协议的定义以及演示,通过方法定义以及协议约定,进行了协议约定以及调用过程的约定.然而,实际上在游戏中,调用过程之后,需要传输相对多的数据给服务端. 常用场景,客户端 ...
随机推荐
- 我和小美的撸码日记(2)之第一个基于MVC+Jqgrid的列表页面
一.前言 “尼玛哥,上周你教我改了下OA系统UI,黄总看了很满意呀.” “不错不错,看来小美进步很大,可以提前结束试用期,到时候加工资别忘了请我吃饭呀!” “尼玛哥,你有女朋友了吗?” “ ...
- 有时summary的状态和details是否有open属性有关
用过mac的同学对这个界面一定很熟悉,因为这个界面和我们今天要说的details有很多相近的地方,首先,其有折叠效果,用户可以自己选择打开或关闭哪一个,其次,当我们直接打开的时候,默认会有几个标签是打 ...
- dos下修复硬盘损坏的文件
点击开始-->运行-->输入cmd,出现DOS状态对话框.在光标处输入有损坏文件的磁盘盘符后回车(如文件夹在D盘就输入D:然后回车),再输入“CHKDSK”,回车即可看到相关检测信息.“C ...
- Spinner 实现key value 效果
在使用Spinner进行下拉列表时,我们一般都会使用字符串数组的方式加ArrayAdapter,取到的列表值就是我们所看到的Text.如果我们想实现网页中select <option value ...
- 面试题 43 n 个骰子的点数
; void printfProbability(int number) { ) return; ]; p[] = ]; p[] = ]; memset(p[], , )); memset(p[], ...
- LeetCode_Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...
- Android文件下载(实现断点续传)
本文将介绍在android平台下如何实现多线程下载,大家都知道,android平台使用java做为开发语言,所以java中支持的多线程下载方式在android平台下都支持,其中主要有两种方式可以实现多 ...
- jQuery实现置顶和置底特效
原文地址:http://www.jqueryba.com/3403.html <script src="jquery.min.js" type="text/java ...
- virtIO驱动安装
- javascript笔记5之流程控制语句
/* var box = 100; //单行语句 var age = 20; //另一条单行语句 { //用花括号包含的语句集合,叫做复合语句,单位一个 //一对花括号,表示一个复合语句,处理时候,可 ...