[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永远指向蛇尾,提高追加节点的效率。

转载于:https://www.cnblogs.com/git-pizcai/p/4262957.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值