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

  由于食物是贪吃蛇游戏中最简单的一部分,而且和其他部分关联性不强,基本上是一个独立的部分,所以我打算先实现它。

我的想法是食物必须在世界中才能被创造出来,也就是说,先有世界再有食物,所以我得先判断世界是否存在,存在的话才可以创建食物。

Food * SNK_CreateFood(World *world, int size)
{
    Food *food;

    if (world == 0) return 0;

    if ((food = (Food *)SDL_malloc(sizeof(Food))) == 0) return 0;

    INIT_FOOD(world, size);

    return food;
}

对于指针变量,我总是显式地将它和数值比较,这有助于避免某些隐藏的错误。宏INIT_FOOD用来初始化Food结构体,在最后的完整源码中可以看到定义。

由于food是用SDL_malloc函数分配的,所以销毁食物只要释放内存就可以了。在C语言中,释放后的指针并不为零, 一个好的习惯是:每次释放指针后,显式的将指针置为零。我总是会遵循这个习惯,除非释放指针后程序也立刻退出,否则我总是将释放后的指针置为零。

void SNK_DestroyFood(Food *food)
{
    SDL_free(food);
    food = 0;
}

我对食物的美或丑没有任何概念,所以我这里所谓的食物仅仅只是一个矩形。在画食物这里可以有很多创意,画一个奇葩的食物可以令人耳目一新。不过我只力求简洁,意思到了就可以了。

void SNK_DrawFood(Food *food)
{
    SDL_Rect rect;

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

        if (((food->world != 0) ? (food->world->render != 0) : 0))
        {
            SDL_SetRenderDrawColor(food->world->render,
                                   food->color.r, food->color.g,
                                   food->color.b, food->color.a);
            SDL_RenderDrawRect(food->world->render, &rect);
        }
    }
}

设置食物位置的函数定义的很简单,给一个食物和坐标就可以了。但是内部实现起来我还是做了一点判断和处理,为了保证两方面的可行性:1. 确保坐标是正数且在世界范围内。2. 食物坐标要为食物大小的整数倍。尽管不是整数倍也能行,不过我是打算将食物和蛇设置为相同大小的,如果不是整数倍,就会发生蛇还没吃完食物,食物就消失了的情况。

void SNK_SetFoodPosition(Food *food, int x, int y)
{
    if (((food != 0) ? (food->world != 0) : 0))
    {
        if (SDL_abs(x) > food->world->w)
            x = food->world->w;

        if (SDL_abs(y) > food->world->h)
            y = food->world->h;

        if (food->size != 0)
        {
            food->x = (SDL_abs(x) / food->size) * food->size;
            food->y = (SDL_abs(y) / food->size) * food->size;
        }
    }
}

最后就是设置食物颜色了,这个很简单,依次赋值就行了。

void SNK_SetFoodColor(Food *food, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
    if (food != 0)
    {
        food->color.r = r;
        food->color.g = g;
        food->color.b = b;
        food->color.a = a;
    }
}

以下是snk-food.c文件的完整内容:

#include "snk-food.h"

#define INIT_FOOD(world, size)                                          \
    food->world = (world);                                                  food->x = food->y = 0;                                                  food->size = (size) ? SDL_abs(size) : 0;                                food->color.r = food->color.g = food->color.b = food->color.a = 0;

Food * SNK_CreateFood(World *world, int size)
{
    Food *food;

    if (world == 0) return 0;

    if ((food = (Food *)SDL_malloc(sizeof(Food))) == 0) return 0;

    INIT_FOOD(world, size);

    return food;
}

void SNK_DestroyFood(Food *food)
{
    SDL_free(food);
    food = 0;
}

void SNK_DrawFood(Food *food)
{
    SDL_Rect rect;

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

        if (((food->world != 0) ? (food->world->render != 0) : 0))
        {
            SDL_SetRenderDrawColor(food->world->render,
                                   food->color.r, food->color.g,
                                   food->color.b, food->color.a);
            SDL_RenderDrawRect(food->world->render, &rect);
        }
    }
}

void SNK_SetFoodPosition(Food *food, int x, int y)
{
    if (((food != 0) ? (food->world != 0) : 0))
    {
        if (SDL_abs(x) > food->world->w)
            x = food->world->w;

        if (SDL_abs(y) > food->world->h)
            y = food->world->h;

        if (food->size != 0)
        {
            food->x = (SDL_abs(x) / food->size) * food->size;
            food->y = (SDL_abs(y) / food->size) * food->size;
        }
    }
}

void SNK_SetFoodColor(Food *food, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
    if (food != 0)
    {
        food->color.r = r;
        food->color.g = g;
        food->color.b = b;
        food->color.a = a;
    }
}
时间: 2024-11-05 15:53:01

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

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

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

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

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

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

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

[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

Qt小游戏开发:贪吃蛇

周末没事,手写小游戏继续~ 预览 步骤 1 定义数据结构 逻辑与界面分离,游戏场景是个二维数组区域,贪吃蛇是若干个连续的坐标点集合,用动态链表维护,果实是一个随机坐标点. const int BLOCK_SIZE=25; //单个方块单元的边长 const int MARGIN=5; //场景边距 const int AREA_ROW=15; //场景行数 const int AREA_COL=15; //场景列数 QPoint foodPoint; //果实出现坐标 QList<QPoint>

Love2D游戏引擎制作贪吃蛇游戏

代码地址如下:http://www.demodashi.com/demo/15051.html Love2D游戏引擎制作贪吃蛇游戏 内附有linux下的makefile,windows下的生成方法请查看: for windows 预览游戏 love2d游戏引擎重要函数 详情: love2d wiki love.load:当游戏开始时被调用且仅调用一次 love.draw:回调函数,每帧更新一次游戏画面 love.update:回调函数,每帧更新一次游戏状态 love.keypressed:回调函

Linux Curses编程实现贪吃蛇

curses库 简单而言,提供UNIX中多种终端 操作光标和显示字符 的接口.我们常见的vi就是使用curses实现的.现在一般都用ncurses库. Linux下curses函数库    Linux curses库使用      这两篇文章很详细地介绍了curses,在此就不重复了. ubuntu安装curses函数库 >sudo apt-get install ncurses-dev 用curses库,编译程序: gcc program.c -o program -lcurses 2.工作原