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

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

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

void SNK_SetSnakeSpeed(Snake *snake, int speed)
{
    if (snake != 0) snake->speed = SDL_abs(speed);
}

设置蛇的方向有些复杂,玩过贪吃蛇的都知道,蛇向前移动时,它无法向后转弯;向左移动时,它无法向右转弯。所以,我也要做些这样的判断。

void SNK_SetSnakeDirection(Snake *snake, int direction)
{
    if (snake != 0 && (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 != 0)
    {
        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) ? 0 : SDL_abs(x);                      snake->x = (size) ? ((snake->x / SDL_abs(size)) * SDL_abs(size)) : 0;       snake->y = (SDL_abs(y) > (world)->h) ? 0 : SDL_abs(y);                      snake->y = (size) ? ((snake->y / SDL_abs(size)) * SDL_abs(size)) : 0;       snake->size = (size) ? SDL_abs(size) : 0;                                   snake->color.r = snake->color.g = snake->color.b = snake->color.a = 0;      snake->speed = 0;                                                           snake->length = 1;                                                          snake->direction = SNAKE_UP;                                                snake->body = 0;

#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 (0)

#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 != 0) ? snake->body : 0;                        snake->body = (body);                                                       ++snake->length;                                                        } while (0)

#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 == 0) return 0;

    if ((snake = (Snake *)SDL_malloc(sizeof(Snake))) == 0) return 0;

    INIT_SNAKE(world, size, x, y);
    SNK_GrowSnake(snake);

    return snake;
}

void SNK_DestroySnake(Snake *snake)
{
    struct Body *body;

    if (snake != 0)
    {
        if ((body = snake->body)) REMOVE_BODY(body);

        SDL_free(snake);
        snake = 0;
    }
}

void SNK_MoveSnake(Snake *snake)
{
    struct Body *body;

    if (snake != 0)
    {
        MOVE_SNAKE(snake);

        for (body = snake->body; body; body = body->next)
        {
            MOVE_SNAKE(body);
            body->direction = (body->next != 0) ? body->next->direction : snake->direction;
        }
    }
}

void SNK_DrawSnake(Snake *snake)
{
    SDL_Rect rect;
    struct Body *body;

    if (snake != 0)
    {
        rect.x = snake->x;
        rect.y = snake->y;
        rect.w = rect.h = snake->size;

        if (((snake->world != 0) ? (snake->world->render != 0) : 0))
        {
            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 != 0)
    {
        if ((body = (struct Body *)SDL_malloc(sizeof(struct Body))) == 0) return;

        if (snake->body == 0)
        {
            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 != 0)
    {
        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) != 0)
                return 1;
        }
    }

    return 0;
}

int SNK_GetSnakeStatus(Snake *snake)
{
    SDL_Rect headrect;

    if (((snake != 0) ? (snake->world != 0) : 0))
    {
        headrect.w = (snake->x > 0 && snake->x < snake->world->w);
        headrect.h = (snake->y > 0 && 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) != 0)
                return SNAKE_DIED;

            return SNAKE_MOVABLE;
        }
        else
        {
            switch (snake->direction)
            {
            case SNAKE_UP:
                headrect.x = (snake->y > 0);
                break;
            case SNAKE_DOWN:
                headrect.x = ((snake->y + snake->size) < snake->world->h);
                break;
            case SNAKE_LEFT:
                headrect.x = (snake->x > 0);
                break;
            case SNAKE_RIGHT:
                headrect.x = ((snake->x + snake->size) < snake->world->w);
                break;
            }

            return ((headrect.x != 0) ? SNAKE_MOVABLE : 0);
        }
    }

    return 0;
}

void SNK_SetSnakeSpeed(Snake *snake, int speed)
{
    if (snake != 0) snake->speed = SDL_abs(speed);
}

void SNK_SetSnakeDirection(Snake *snake, int direction)
{
    if (snake != 0 && (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 != 0)
    {
        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永远指向蛇尾,提高追加节点的效率。

时间: 2024-08-06 15:35:49

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

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

蛇是这个游戏的主角,要实现的功能也是最复杂的一个.因为蛇不止有属性,还有行为.它会动,还会吃东西,还会长大!而且还会死!这是很要命的.我一向看不懂复杂的代码,也写不出复杂的代码.所以对于蛇,我很纠结,如何才能简单的实现它. 毫无质疑的一点是,食物具有的属性,蛇也具有.蛇必须存在于世界中,有大小和位置以及颜色.这样最起码可以推测出一个蛇的简单定义.但是这还远远不够,蛇是活的,它能动,就必须有速度和方向,它能吃,就必须能长大.所以,抛开其它的一切,它最简单的形式起码也得这样: typedef str

[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

【python游戏编程之旅】第六篇---pygame中的Sprite(精灵)模块和加载动画

本系列博客介绍以python+pygame库进行小游戏的开发.有写的不对之处还望各位海涵. 直到现在我们已经学了很多pygame基础知识了,从这篇博客开始我们将会学习pygame中高级部分,更多和精灵模块,冲突检测相关的知识. 一.Sprite模块.sprite对象 在pygame.sprite模块里面包含了一个名为Sprite类,他是pygame本身自带的一个精灵.但是这个类的功能比较少,因此我们新建一个类对其继承,在sprite类的基础上丰富,以方便我们的使用. 首先来了解一下如何使用spr

游戏编程系列[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