这一篇是关于设置蛇的属性的,接上一篇(五)。

设置蛇的速度,很简单,只要不是负数就行了。

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入门 - 游戏编程系列] 贪吃蛇篇(六) - 蛇实现的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. 游戏编程系列[1]--游戏编程中RPC协议的使用[2]--Aop PostSharp篇

    上一篇我们使用了一个通用JSON协议约定来进行达到远程调用的目的.但是从实现上,我们需要不断的在所有的方法上添加拦截,并且判断拦截,然后执行,这就达到了一个比较繁琐的目的. 之前我们尝试过使用代码生成 ...

  9. 游戏编程系列[2]--游戏编程中RPC与OpLog协议的结合--序

    在系列[1]中,我们展示了RPC调用协议的定义以及演示,通过方法定义以及协议约定,进行了协议约定以及调用过程的约定.然而,实际上在游戏中,调用过程之后,需要传输相对多的数据给服务端. 常用场景,客户端 ...

随机推荐

  1. js 简单倒计时插件和使用方法

    // 倒计时插件 (function (){ function countdown(config){ var startDate = config.start ? new Date(config.st ...

  2. iTween_ValueTo函数

    ValueTo:返回一个插值在两件值之间的值供回调函数使用; 网上没找到例子,自己试了下,直接看代码就明白了. , 0, 0),// gameObject.transform.position为0.0 ...

  3. Keil 3光标问题 以及汉字问题

    初次使用keil3,光标总是定位不准,修改十分麻烦,google后解决问题,修改tools.ini如下(蓝色为加入项): NAME="YGLenovo User", "a ...

  4. zabbix 发送邮件配置

    Administration->Users->User name->Media <img src="http://img.blog.csdn.net/20160919 ...

  5. Mybatis 开发中遇见的异常及处理

    1 异常信息: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.Bin ...

  6. hdu 5423 Rikka with Tree(dfs)

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

  7. [MongoDB] Remove, update, create document

    Remove: remove the wand with the name of "Doom Bringer" from our wandscollection. db.wands ...

  8. Android调用系统邮件类应用的正确实现方法

    Android应用开发中,很多情况下免不了要调用手机上的邮件类应用,实现邮件发送的功能,这一般是通过调用系统已有的Intent来实现的.看到网上很多邮件发送都是调用action为android.con ...

  9. JS高级程序设计学习笔记之RegExp类型

    创建正则表达式: 字面量形式定义正则表达式: Var expression = / pattern /flags ;pattern部分可以使任意简单或复杂的正则表达式.每个正则表达式可以带有一个或多个 ...

  10. React数据传递

    React基础概念 React是基于组件化的开发,通过组件的组合,让web应用能够实现桌面应用的效果. React更有利于单页应用的开发. 并非MVC框架,只能算是V 具有单项数据流的特点 优势:代码 ...