从零开始的太空入侵者 - 第 5 部分

从零开始的太空入侵者 - 第 5 部分

首页枪战射击太空入侵者重生更新时间:2024-04-24

在本系列文章中,我将使用 C 创建经典街机游戏太空入侵者的克隆,仅使用几个依赖项。 在本系列的最后一篇文章中,我将处理评分并添加用于绘制文本和其他 UI 元素的例程。

没有分数就没有高分

当电子游戏勇敢地迈出第一步进入这个世界时,事情很简单,它们通常没有最终目标,而是使用“分数”作为衡量玩家成功或失败的手段。评分还为玩家提供了一种在“击败”他们的“高分”时相互挑战的方法,因此游戏制造商可以在更长的时间内利用玩家,尽管游戏可以提供的娱乐量有限,当然,这是这是当时硬件限制的直接后果。

太空侵略者只有一个阶段。当你击败所有外星人时,舞台重新开始,外星人重新生成。清除阶段后唯一保持不变的是玩家的生命和他的得分。所以我要做的第一件事是声明一个变量来跟踪分数,

size_t score = 0;

当玩家击中外星人时分数会增加一定的数量,我选择根据外星人类型给予10到40分,就像这样,

score = 10 * (4 - game.aliens[ai].type);

当我们检测到子弹击中外星人时,它被插入到主循环中。

使用这一点代码,我们可以跟踪玩家的得分。但是,在屏幕上显示它有点复杂。

您现在可以创建一个文本编辑器

我们将像我们游戏中的任何其他精灵一样处理绘制文本和数字。 出于这个原因,我们定义了一个包含 65 个 5x7 ASCII 字符精灵的新 spritesheet,从 'space' 开始,它的 ASCII 值是 32,直到字符 '`',它的 ASCII 值是 96。请注意,我们只包括大写字母 和一些特殊字符。 我不打算包含整个 spritesheet,因为它太大了,但是您可以随意查看本周的代码。

为了绘制文本,我们定义了一个新函数,

void buffer_draw_text( Buffer* buffer, const Sprite& text_spritesheet, const char* text, size_t x, size_t y, uint32_t color) { size_t xp = x; size_t stride = text_spritesheet.width * text_spritesheet.height; Sprite sprite = text_spritesheet; for(const char* charp = text; *charp != '\0'; charp) { char character = *charp - 32; if(character < 0 || character >= 65) continue; sprite.data = text_spritesheet.data character * stride; buffer_draw_sprite(buffer, sprite, xp, y, color); xp = sprite.width 1; } }

它获取一段文本并在缓冲区中以指定的坐标和指定的颜色绘制它,就像我们对精灵所做的那样。 该函数简单地遍历文本中的所有字符,直到遇到空字符,即字符串终止字符,并使用 buffer_draw_sprite 绘制每个字符。 棘手的部分是从 spritesheet 中获取正确的字符并正确地从左到右正确地绘制字符,间隔正确。 我们通过 (c - 32) * stride 将字符索引到 spritesheet 中来实现第一个,其中 stride 是一个字符 sprite 的大小,即 7×5 = 35。字符绘制位置 xp 由 sprite 移动 宽度增加 1。

我们定义了最后一个用于绘制数字的函数。 这里最简单的方法是使用 snprintf 之类的东西将数字(分数)转换为字符串,然后使用 buffer_draw_text 绘制数字,但让我们自己尝试将数字分成数字,

void buffer_draw_number( Buffer* buffer, const Sprite& number_spritesheet, size_t number, size_t x, size_t y, uint32_t color) { uint8_t digits[64]; size_t num_digits = 0; size_t current_number = number; do { digits[num_digits ] = current_number % 10; current_number = current_number / 10; } while(current_number > 0); size_t xp = x; size_t stride = number_spritesheet.width * number_spritesheet.height; Sprite sprite = number_spritesheet; for(size_t i = 0; i < num_digits; i) { uint8_t digit = digits[num_digits - i - 1]; sprite.data = number_spritesheet.data digit * stride; buffer_draw_sprite(buffer, sprite, xp, y, color); xp = sprite.width 1; } }

请注意,number_spritesheet 只是对从精灵位置 16 开始的 text_spritesheet 的引用。函数的第二部分与 buffer_draw_text 的函数非常相似。 获取数字的数字是在 do-while 循环中完成的。 我们基本上通过除以 10 的余数(模运算)来找到数字的最后一位,然后我们进行整数乘法以基本上将数字向右移动,并重复直到我们一无所有。 尽管我们本可以选择 snprintf 解决方案,但最好了解其中一些基本操作是如何工作的。

在主循环中,清除缓冲区后,我们绘制文本“SCORE”,

buffer_draw_text( &buffer, text_spritesheet, "SCORE", 4, game.height - text_spritesheet.height - 7, rgb_to_uint32(128, 0, 0) );

再向右一点,我们画出分数,

buffer_draw_number( &buffer, number_spritesheet, score, 4 2 * number_spritesheet.width, game.height - 2 * number_spritesheet.height - 12, rgb_to_uint32(128, 0, 0) );

虽然我们在 Space Invaders 游戏中不使用积分,但为了新奇,我们还在缓冲区底部绘制了文本“CREDIT 00”,

buffer_draw_text( &buffer, text_spritesheet, "CREDIT 00", 164, 7, rgb_to_uint32(128, 0, 0) );

作为画龙点睛的一笔,我们在信用文本上方画了一条水平线。

for(size_t i = 0; i < game.width; i) { buffer.data[game.width * 16 i] = rgb_to_uint32(128, 0, 0); }

这是最终的结果,

结论

正如您可能已经意识到的那样,游戏并不完整。 仍然缺少的是外星子弹和外星子弹播放器和子弹-子弹碰撞检测。 而且,在原版游戏中,外星人显然不是静止的,而是从左到右,从右到左向玩家移动。 创建一篇关于添加所有这些功能的博客文章不会有指导意义。 我们已经实现了所需的所有必需工具,因此您可以完成自己的游戏版本,甚至可以完全更改逻辑,您可以将 Space Invaders 与 Breakout 结合起来。

在本系列的最后一篇文章中,我们设置了用于在游戏中绘制文本和数字的代码。 通过我们实现的所有这些代码,我们已经可以创建许多不同的游戏,甚至是使用您自己的自定义字体的文本冒险。 这就是编程的好处,当你获得更多经验时,你会开发出一套工具/可重用的代码片段,它们会随着时间的推移而发展。 这种正反馈循环允许您创建越来越复杂的程序。 与传统的游戏引擎相比,您必须付出更多的初始努力才能从头开始学习编程游戏,但您获得的灵活性值得坚持下去。 希望这个系列也让您相信这样做会很有趣!

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved