我们将在周末继续进行有关3D射击游戏的讨论。 如果有的话,我想提醒您,这是下半年:
正如我所说,我尽最大努力支持学生渴望用自己的双手做某事。 尤其是,当我讲授关于编程入门的课程时,作为实际练习,我几乎给了他们完全的自由。 只有两个限制:编程语言(C ++)和项目主题,这应该是电子游戏。 这是我的新生制作的数百种游戏之一的示例:
不幸的是,大多数学生选择诸如2D平台游戏之类的简单游戏。 我写这篇文章的目的是表明,创造一个三维世界的错觉并不比克隆马里奥·布鲁斯困难。
我提醒您,我们在一个允许您对墙壁进行纹理化的阶段停止了工作:

阶段13:在地图上绘制怪物
我们游戏中的怪物是什么? 这些是其坐标和纹理编号:
struct Sprite { float x, y; size_t tex_id; }; [..] std::vector<Sprite> sprites{ {1.834, 8.765, 0}, {5.323, 5.365, 1}, {4.123, 10.265, 1} };
定义了几个怪物之后,我们首先将它们绘制在地图上:
您可以在此处看到更改。

阶段14:用黑色方块代替3D怪物
现在我们将在3D窗口中绘制精灵。 为此,我们需要确定两件事:精灵在屏幕上的位置及其大小。 这是代替每个子画面绘制一个黑色正方形的函数:
void draw_sprite(Sprite &sprite, FrameBuffer &fb, Player &player, Texture &tex_sprites) {
让我们弄清楚它是如何工作的。 这是图表:

在第一行中,我们考虑sprite_dir的绝对角度(从播放器到Sprite的方向与横坐标之间的角度)。 精灵与注视方向之间的相对角度显然可以通过简单地减去两个绝对角度来获得:sprite_dir-player.a。 从播放器到子画面的距离很难计算,子画面的大小是屏幕大小除以距离的简单划分。 好吧,以防万一,我从顶部切了两千个,以免得到巨大的正方形(顺便说一下,这段代码很容易被零除)。 h_offset和v_offset给出屏幕上精灵的左上角的坐标; 然后一个简单的双循环用黑色填充我们的正方形。 用笔和一张纸检查是否正确计算了h_offset和v_offset,在我的提交中有一个(非严重)错误,请相信本文中的代码:)好吧,存储库中的最新代码也已修复。
您可以在此处看到更改。

第15步:深度图
我们的正方形奇迹般地好,但是只有一个问题:遥远的怪物在拐角处偷看,并且正方形被完全绘制。 如何成为 很简单 绘制墙壁
后 ,我们绘制精灵。 因此,对于屏幕的每一列,我们都知道到最近的墙的距离。 我们将这些距离保存到512个值的数组中,并将该数组传递给sprite渲染函数。 精灵也会逐列绘制,因此对于精灵的每一列,我们都将其距离与深度数组中的值进行比较。
您可以在此处看到更改。

阶段16:精灵问题
他们变成了伟大的怪物,不是吗? 但是在此阶段,我将不添加任何功能,相反,我将通过添加另一个怪物来破坏一切:
您可以在此处看到更改。

阶段17:对精灵进行排序
怎么了 问题是我可以随意绘制绘画精灵,对于每个精灵,我都将其与墙的距离进行比较,但与其他精灵进行比较,因此远处的生物爬到了最近的生物上。 是否可以使用深度图适应解决方案来绘制精灵?
隐藏文字正确的答案是“可以”。 但是如何? 在评论中写。
我将采取另一种方式,在额头上愚蠢地解决问题。 我将绘制从最远到最远的所有精灵。 也就是说,我将按距离的降序对精灵进行排序,并按该顺序绘制它们。
您可以在此处看到更改。

步骤18:SDL时间
SDL的时机已到。 有很多不同的跨平台窗口库,我完全不了解它们。 就个人而言,我喜欢
imgui ,但是由于某种原因,我的学生更喜欢SDL,因此我将其链接。 此阶段的任务非常简单:创建一个窗口并显示上一阶段的图像:
您可以在此处看到更改。 我不再提供指向gitpod的链接,因为 浏览器中的SDL尚未学会启动:(
更新:学习! 您可以在浏览器中一键运行代码!
步骤19:事件处理和清理
我不会描述对按键的反应甚至不好笑。 添加SDL时,我删除了对stb_image.h的依赖。 它很漂亮,但是编译时间太长。
对于那些不了解的人,
这里是第十九阶段的来源。 好吧,这是一个典型的表现:
结论
目前,我的代码仅包含486行,但同时我根本没有保存它们:
haqreu@daffodil:~/tinyraycaster$ cat *.cpp *.h | wc -l 486
我没有舔我的代码,故意扔了脏衣服。 是的,我这样写(而不仅仅是我)。 一个星期六早上,我刚坐下来写下了这个:)
我没有完成游戏,我的任务只是为您发挥想象力提供初步动力。 编写自己的代码,可能会比我的代码更好。 共享您的代码,共享您的想法,发送请求请求。