游戏引擎学习第109天
回顾目前进展
在这一期中,讨论了游戏开发中的一个重要问题——如何处理Z轴值的表示,尤其是在一个3D游戏中,如何更好地表示和存储这些值。上次的进展中,已经解决了透视投影的问题,意味着渲染部分的Z轴代码基本上已经完成,但仍然有一个待解决的关键问题,就是如何在游戏中处理不同的楼层(z-levels)。
在3D游戏中,通常可以将各个层次视作相同的对象进行处理,但在Tschudi类型的游戏中,需要做更多的调整,考虑如何以一种有趣且健壮的方式处理这些层次。由于没有标准的答案,决定直接面对这个技术问题,展示如何在代码中做出折衷,以便找到一个合理的解决方案。
目前的主要任务是明确如何存储和处理这些Z轴的数值,确保它们能够有效表示世界中的多个层级,进而为进一步的开发工作奠定基础。
更深入地看一下透视投影
现在的目标是检查透视投影的设置,并重新思考世界的表示方式以及它应如何呈现。当前的投影参数可能并不完全现实,尤其是如果将其视作建筑物的楼层时,楼层之间的间隔看起来可能不够大。因此,调整的参数可能有些保守,尽管效果还可以,但仍显得有些不自然。
为了改善这一点,决定将楼层的高度调整为更合适的值,比如三米,这大约是建筑物楼层的标准高度,而不是像教堂那样的高天花板。这种调整看起来更符合实际,能够使得游戏中的世界呈现出更加合理的比例。
在查看这些参数时,有一个不太直观的地方需要注意:当前的设置中,摄像机到目标的距离被设定为与焦距相同。虽然这看起来合理,但也有些疑惑,因为这种设置并不完全符合预期的效果。通常当看到与预期不符的情况时,值得再三检查一下,确保所有设置都如预期工作。
虽然作为一个程序员,长期从事三维图形开发,可能会有一些特定的预期,但在二维游戏中,由于艺术风格和效果的不同,可能需要做出不同的调整。因此,虽然对这些设定有些疑虑,但也认识到这可能是一个学习的过程,最终可能会发现这种设置更适合二维游戏的表现方式。为了确保没有问题,仍然希望深入了解这些设置背后的原理。
黑板:透视方程的组成部分
现在讨论的是透视投影中的一些细节。基本上,场景中有一个世界和一些树木,这些树木分布在不同的层面上,形成一个环形结构。每个层面上都有树木,且树木环绕整个区域。在这个场景的中心,有一个虚拟的目标点,摄像机正朝这个目标点看过去。摄像机沿着Z轴上升,想要俯视这些物体。
原本期望在这个设置中使用一些参数来表示摄像机和虚拟显示器的关系。例如,假设有一个表示显示器的参数,距离显示器的焦距可以用来做透视计算,同时还有一个表示摄像机到目标点距离的参数,这些参数共同决定了透视效果。
然而,意识到的一个问题是,至今为止并没有定义显示器的实际大小。最初设定了一个“MetersToPixels”的转换值,但这个值是在当初使用正射投影时随便指定的,并没有根据显示器的实际物理尺寸来定义。这就导致了这些参数的值可能并不符合预期,可能是“MetersToPixels”的值本身设置错误,从而影响了最终的显示效果。
因此,决定今天要重新审视显示器的实际大小,明确它应该如何与世界单位(比如米)进行换算,并弄清楚像素在世界单位中的实际尺寸。这有助于更好地理解透视投影的原理,避免之前的误差。
确定我们的显示器大小
“MetersToPixels”(meters to pixels)转换的设置。最初,设定一个像素等于42毫米,意味着1米等于42像素。然而,问题在于这一设定可能并不合理,特别是在使用透视投影时。之前,使用正射投影时,像素的表示是直观的,但在透视投影中,像素的定位变得复杂了。
如果设定1米等于42像素,那么接下来需要确认显示器的大小。通过查看创建窗口时设定的分辨率(1204x800像素),可以计算出显示器的实际尺寸。经过计算,发现显示器的宽度约为28.666米,高度为19米,这相当于一个非常大的“虚拟显示器”,甚至比常规的显示器大约十倍。这个尺寸显然不符合实际,导致“MetersToPixels”的转换值完全不准确。
因此,怀疑当前的“MetersToPixels”转换值并不反映实际情况,需要重新修正这个设定,确保它能正确地与世界坐标系对接。接下来的任务是修正这一值,以使其适应正确的显示尺寸。
考虑 MetersToPixels 和分辨率独立性
目前,MetersToPixels
(meters to pixels)转换主要用于两个地方:一个是透视投影的计算,这个地方需要使用它;另一个是在计算位图偏移时需要用到,因为位图的偏移是以像素为单位的。由于计算位图偏移时依赖像素,使用这个转换就显得有些麻烦。
为了简化这一过程,可以尝试将MetersToPixels
的转换从整个流程中去除。具体来说,可以将目前需要的数值转换成其他单位,这样就能让透视变换成为唯一一个需要考虑像素和世界单位如何互动的地方,其他部分的代码就不需要再处理像素了。这样做的好处是,游戏的其他部分不再直接依赖像素单位,这使得支持多分辨率变得更简单,不需要复杂的调整。举例来说,如果需要从当前分辨率切换到1920x1080分辨率时,处理起来会更直接,不需要每个部分都考虑像素,最终实现分辨率独立性,从而提高灵活性和可扩展性。
将我们的热点编码为与位图大小成比例
当前的计划是将热区(hot spots)编码为位图大小的比例,而不是使用MetersToPixels
的转换。这意味着,位图不再包含与MetersToPixels
相关的任何信息,也不再依赖该概念。通过这种方式,位图的尺寸可以以百分比表示,而不是直接与物理单位(如米或像素)相关联。
具体来说,将原来以像素为单位的对齐操作,改为以百分比表示对齐位置。这样,无论是使用像素、米,还是其他单位,百分比都能保持一致性,因为距离的百分比是独立于单位的。通过这种方法,位图的对齐点会依据位图宽度和高度的百分比来计算,从而避免了直接依赖MetersToPixels
的转换。
在代码实现上,需要对位图宽度和高度进行处理,计算出合适的对齐百分比。首先,定义一个align
变量来表示对齐位置,并使用位图宽度和高度来计算该位置。接下来,修改现有的对齐逻辑,使其支持百分比的对齐方式。最后,确保在所有涉及对齐的地方都采用这种新的百分比方式,而不是像素值。
经过修改后,代码中的偏移计算应该会正常工作,且所有的对齐操作都会根据位图的相对尺寸来进行,而不再依赖于像素或米之间的转换。这一改动不仅解决了原来的问题,还为将来支持多分辨率提供了更好的灵活性。
出现段错误
从编码调用中去除 MetersToPixels
目前,尽管通过将对齐操作改为使用百分比的方式,已经消除了米到像素
的转换,但在存储实际的生产数据时,依然使用了位图的宽度和高度。这意味着,米到像素
的转换仍然在编码过程中被直接使用,仍未完全摆脱这一依赖。
为了解决这个问题,计划引入一个新的概念:位图本身应该具有一个原生的缩放值,用于表示位图的缩放比例(即原生缩放比例)。通过这个缩放值,可以避免直接使用米到像素
的转换,使位图的存储和处理更加灵活和独立于像素和米之间的转换。
这种方法的目的是将位图的原生缩放比例与其实际宽度和高度分离,从而彻底摆脱原来基于像素的依赖,使得整个系统更加独立于分辨率和单位的转换。
黑板:我们将指定尺寸为米
目标是将物体的尺寸从像素单位转换为实际的米单位。当表示物体的高度时,将直接以米为单位进行定义。例如,在某一维度(如Y轴)上指定物体的高度,之后会通过计算来确定X轴的值。这个计算是基于精灵的宽高比(即其横向像素宽度与纵向像素高度的比例)来进行的。
该宽高比将作为一个比例因子存储在位图中,这样就可以消除“像素”这一单位的干扰。通过这种方法,宽高比将不再依赖于具体的像素尺寸,而是成为一个无单位的比率,这使得整个系统能够在处理过程中脱离像素和世界单位之间的转换。
通过这样的调整,系统将转向一个“像素中立”的方式来定义和处理物体的尺寸,进一步简化并标准化了对物体尺寸的处理。
引入 WidthOverHeight 并指定我们的预期大小
每次加载位图时,需要计算其宽高比(即宽度除以高度),并将这个比例存储下来。计算这个比例非常简单,只是一个基本的比率计算。计算完后,位图的宽高比将用于推算其他维度,确保无论传入的是多大的值,能够根据这个比例推算出相应的宽度或高度。
为了实现这一点,在加载位图时,可以将计算得到的宽高比存储为一个永久的值。具体来说,宽度与高度的比例会通过将结果宽度与结果高度相除来得到。
在进行位图推送调用时,传统的“米到像素”的转换机制将不再适用。取而代之的是,直接定义期望的物体尺寸(以米为单位)。如果希望保持当前的方式,可以在加载位图时,根据原有的“米到像素”比例来计算物体的尺寸。例如,可以通过位图的原始高度值与米到像素的转换值相结合,继续基于原来的像素尺寸来推算物体在物理空间中的尺寸,但这种做法并不是最理想的。
每当我们进行读取时
每次读取位图时,需要指定像素到米的转换值。通过这种方式,位图加载程序将成为唯一一个关心像素到米转换的地方。具体实现时,位图加载函数中将插入像素到米的比例,类似于“每42个像素等于1米”的转换关系。
然而,这个像素到米的比例可能需要进一步调整,因为目前的值可能并不完全符合预期尺寸。具体的值是否合理还需进一步确认,并可能需要根据实际需求进行修改。
在没有管道中任何值的情况下做这件事
目前的目标是清除不再需要的像素到米的转换,并且使整个过程更加简洁。在进行位图推送时,尺寸计算会根据位图的原始高度进行调整,同时确保每个对象都可以单独指定其高度,而不是通过固定的转换比例来计算。
在这过程中,像素到米的转换不再需要在渲染和存储过程中使用,只保留在与位图加载相关的部分。其他部分的代码则需要清理掉与像素到米转换相关的内容,确保所有计算都可以直接在米为单位的基础上进行。
之后,所有的渲染操作都将基于米来进行,而最终的像素计算将通过屏幕分辨率的转换因子来处理,这样可以确保无论分辨率如何变化,渲染效果都保持一致。这将使得系统更灵活,且避免了不必要的转换步骤,简化了代码。
黑板:单位立方体
在讨论二维和三维图形渲染时,提到两种常见的处理方式,一种是将它们融合为一个乘法操作,另一种是将其转换为单位立方体进行进出处理。尽管后者涉及更复杂的步骤,但由于对三维的兴趣,还是会简要提及这一方法。
在二维图形处理中,裁剪是一个相对简单的操作,几乎不容易出错,通常会使用一种称为“守卫带裁剪”的技术。这种技术在二维空间中是直接有效的,不会遇到复杂的边界问题。而在三维图形处理中,裁剪则变得复杂,通常需要借助“单位立方体”和四维单位齐次立方体来进行裁剪。
单位立方体是一个三维空间的表示,可以被看作是三维世界的“缩小版”。假设整个世界被压缩并映射到一个单位立方体内,裁剪的过程就是将这个单位立方体与世界空间的视锥体进行匹配。视锥体是由摄像机确定的可视区域,包含近裁剪面和远裁剪面。通过将这个视锥体映射到单位立方体,裁剪过程就可以在这个简化的空间内进行,最终筛选出正确的可视图像片段。
在这个过程中,三维坐标通常被映射到[-1, 1]的范围内,无论是X、Y还是Z坐标。这一过程通过投影矩阵完成,GPU负责将这些坐标从单位立方体空间转换到屏幕坐标。这通常会涉及一个额外的转换步骤,将坐标映射到实际像素坐标。
然而,对于某些简单场景,我们并不需要进行这两步处理(单位立方体到屏幕坐标的转换),因为可以直接将世界坐标转换为像素坐标,这样就省略了将坐标映射到单位立方体的过程。通过直接将世界单位(例如米)转换为像素单位,我们可以简化整个渲染流程,避免不必要的复杂性。
在这种情况下,使用一个从世界单位到像素单位的比例值就足够了,而不需要像三维渲染管线那样进行多重变换。
最后做 MetersToPixels 投影
可以将世界坐标直接转换为像素坐标,而无需经历单位立方体的转换步骤。尽管这种简化处理在当前情况下有效,但在未来如果转向OpenGL等框架时,可能需要更对称地处理转换,具体问题可以在需要时再解决。
在实际操作中,首先是将坐标从世界单位(米)转换为像素单位。这个转换是当前流程中唯一需要进行的,之后在渲染时,只需要确保这些转换正确应用即可。在代码中,这一过程涉及将世界坐标与像素坐标映射,并在相应的地方进行适当的投影处理。
在进行转换时,遇到了一些细节问题,比如不希望某个部分继续执行不必要的操作,或者在进行渲染资源分配时出现不符合预期的行为。虽然这些问题暂时不会影响主要流程,但在进一步开发时需要注意。
此外,在代码中还调整了一些变量名称,以便更清晰地反映它们的功能。例如,改进了与比例缩放有关的命名,以便更好地与原始尺寸相关联,并避免混淆。
整体来说,主要的目标是简化当前的处理过程,避免不必要的复杂步骤,同时确保每个转换环节都能按照预期的方式执行。
在游戏中查看它γ
目前的进展接近完成目标,但仍需调试最近的修改。尽管在去除“米到像素”的转换方面取得了进展,问题依然存在,特别是当对象变得非常小并快速移动时,表现出一些意外的行为。下一步需要专注于调试这些细节,以确保一切按预期运行。
调试它
在当前的实现中,基础缩放的计算看起来是正确的,基础缩放的作用是处理透视变换,确保最终的投影 x 和 y 坐标输出符合预期。问题出在缺少了正确的缩放值,特别是 Z 坐标的计算。为了正确生成像素级别的大小,必须在计算结果时适当缩放,确保最终的显示尺寸正确。
检查它并让 PushBitmap 开始指定它认为物体应该的尺寸
目前的目标是为位图推送(push bitmap)添加缩放功能,不仅仅是位置偏移,还要包括世界高度。通过这样做,可以确保图形元素的大小与实际世界中的物体高度相匹配。为了实现这一点,首先调整了位图推送的API,使其接受额外的高度参数,来指定物体在世界中的实际高度。
目前正在调试角色的高度。设定角色的高度为1.2米,这是大致的人物身高,同时需要为其他对象如阴影、树木和剑设定合适的尺寸。虽然这些值还不确定,目的是在之后调整和调试过程中细化。
一开始,位图的高度可能没有完全对齐角色的实际身高,因为位图的显示并不一定精确到角色的头顶。需要进一步检查和调整,特别是在计算角色身高时,考虑位图的实际占用空间。这可能是当前存在的一个问题,需要进一步的调试。
方便缩放
在 GIMP 中查看位图δ
在查看位图时,发现角色的位图尺寸存在问题。位图顶部和底部有很大的空白区域,这意味着角色的实际大小并没有正确匹配位图中的尺寸。具体来说,角色的躯干部分虽然在位图中,但上方和下方都留有空白,导致角色在显示时并不符合预期的尺寸。因此,当前角色的位图并未正确地表示其实际大小,需要进一步调整和修正。
合成地缩放 HeroBitmaps
目前,角色的尺寸需要在位图中进行合成缩放,以便使其看起来更接近实际的大小。角色的实际尺寸似乎比预期要小,大约缺少三分之一的高度。经过缩放后,角色相对于树木的大小看起来更加合理。然而,仍然不完全满意角色与树木的比例,认为它们之间的大小关系可能需要微调。为了达到更符合二维游戏美学的效果,可能需要引入一个大小系数来调整角色与树木的尺寸比例,以便更符合视觉需求。
查看并调整相机数值
目前,角色的大小已经调整到与树木相对较为合适的比例。接下来,需要调整视角的焦距以便更好地呈现场景。焦距的值看起来需要比之前的小一些,但考虑到要显示整个房间,可能需要较长的焦距。尽管这样,焦距的调整仍显得有些不自然,因此决定继续调整这些参数,直到获得更合适的视野。
对于角色的大小,尽管实际尺寸不应与树木相等,但为了更符合游戏的视觉效果,认为将角色大小设置为大致与树木相同会更合适。通过这种调整,角色的大小看起来更合理,并且感觉与环境更加匹配。最后,计划清理和优化相关代码,以便更好地实现这些调整。
清理这些东西
当前,角色的碰撞尺寸需要与角色的实际大小对齐,这个问题需要尽快处理。同时,已决定去除“NativeHeight”部分,因为它在当前阶段并不需要,直接移除可以简化代码。
接着,需要对渲染部分进行调整,确保渲染使用的是世界坐标,而不是像素坐标。在渲染函数中,所有的输入应该是世界坐标,如果某些特殊情况下必须使用像素,才会明确标注。这样可以减少像素坐标的使用,保持一致性。
在渲染过程中,涉及到从世界坐标转换到像素坐标的步骤时,想要基于屏幕的实际尺寸来处理输出目标。因此,想要传入屏幕尺寸信息,并根据屏幕尺寸来计算相应的屏幕中心。这样可以避免固定值,确保在不同的显示器上都能正确计算。
基于 ScreenDim.x 进行 MetersToPixels
目前,想要通过屏幕尺寸来确定每米对应的像素数量。为了实现这一点,决定通过计算显示器在世界坐标空间中的实际大小来确定像素与世界单位之间的比例。这意味着需要计算显示器在世界空间中的宽度,以此推算每米对应多少像素。
此外,还考虑在特定的距离下,如何在屏幕上呈现该显示器的大小,可能会涉及到一个百分比的屏幕尺寸来做调节。这将帮助确定每米与屏幕尺寸的映射关系。
最终,目标是使这个转换尽可能独立于分辨率,即无论使用什么分辨率,都能得到一致的显示效果。通过这种方式,可以确保显示的尺寸和世界空间之间的比例关系更加合理,不受分辨率的影响。
演示分辨率独立性
在设置分辨率时,目标是确保无论分辨率如何变化,显示在屏幕上的内容保持一致。例如,假设显示器的分辨率是1920x1080,而场景中有一排树,显示的数量依赖于分辨率。如果分辨率变化,树的数量应保持相同,确保不论分辨率如何,显示的内容都能适应屏幕。
为了解决这个问题,决定根据屏幕的实际大小来调整显示内容,避免分辨率变化时发生不一致。通过计算“每米到像素”的比例,可以确保无论分辨率设置如何,显示的内容都能按照预期的比例显示。这种方法使得显示内容与分辨率独立,确保在不同分辨率下,显示的物体数量和位置不会出现偏差。
此外,还需要计算“像素到米”的转换,这样可以确保屏幕尺寸和世界空间单位之间的关系是一致的。通过这种方式,可以在不同的分辨率和显示条件下,保持统一的显示效果,确保内容适应各种屏幕尺寸和分辨率设置。
最后,目标是让外部渲染系统能够统一获取这些值,以便其他部分不需要单独计算这些转换,从而提高代码的整洁性和一致性。
英雄/树的大小不应该由艺术分辨率决定吗?即为了保持恒定的像素密度?
在高分辨率的游戏中,并不需要追求像素级的精确度,尤其是像1920x1080这样的分辨率。过于追求像素精确可能会导致失去很多灵活性和艺术上的表现空间,因此,决定不将游戏中的英雄树的大小固定为与分辨率相适应的像素尺寸。相反,树木的大小可以根据不同的因素动态调整,这种调整方式有助于增加视觉上的多样性和趣味性。
不追求像素完美是为了允许更多的灵活性和艺术效果。例如,可以通过缩放来增加树木的大小差异,使得每棵树看起来都不一样,这样做能带来更丰富的视觉效果,而不需要严格控制像素的精确度。对于像素艺术而言,精确的像素可能更为重要,但一旦分辨率达到一定水平后,像素的精准度就不再那么重要。
相比之下,允许图形略微模糊,并且在一定范围内进行缩放,能带来更多的视觉趣味。尽管如果有人希望坚持像素精度,也可以这么做,但由于像素的摆放本身就有些许模糊(如总是介于两个像素值之间),因此过于强调像素的准确性可能会适得其反,甚至影响画面的流畅性。
总结来说,在高分辨率下,不必过分强调像素精确度,而是应当关注如何在艺术上提供更大的表现空间,增加画面的吸引力。
如果你想让游戏全屏,如何处理不同宽高比的屏幕?
在处理不同纵横比的屏幕时,仍需做出决策。例如,在全屏模式下,如果屏幕比例是4:3而非16:9,应该如何处理?一种选择是让玩家看到更少的屏幕内容,接受这一限制,并告知他们如果想要更广阔的视野,需要更大的屏幕;另一种选择是为屏幕加上黑条,形成类似信箱式的显示效果。
目前,虽然这一决策非常重要,但它并不会直接影响渲染过程。因此,可以在未来根据需要自由调整,而不必在当前阶段对其进行过多考虑。总之,纵横比问题可在将来灵活处理,不会对当前的渲染产生实质性影响。
问:宝宝伙伴
计划中将会添加一些“小型宝宝版”的伙伴角色,它们会跟随玩家并提供帮助。这一功能已经被记录,并计划加入待办事项清单。这是一个被认为必要的元素,大家都认同这个方向。
小阴影看起来很有趣
目前发现影子的大小有些问题,调整后影子的尺寸看起来更合适。尽管一些元素,如伙伴的大小,可能还需要调整,但当前的效果还算可以接受。此外,还注意到某些角色的缩放比例有问题,特别是伙伴角色。虽然这些问题还没有完全解决,但整体来说,调整后的效果已经不算差。同时,也考虑到可以将一些角色,例如躯体怪兽,放大,营造更加威胁的感觉。
问:如果树木跨越多个 Z 轴层级,那会很有趣。我们风格下能否实现?
考虑到让更大的树木跨越多个层级的想法,虽然这个概念看起来很有趣,但实际操作起来可能会遇到一些困难。因为如果树木跨越多个层级,这意味着玩家需要在树上上下攀爬,而树木本身在视觉上的表现也需要调整。具体如何实现,还不完全确定,可能需要设计一些小坡或者其他机制来实现这种跨层级的效果。
游戏现在支持缩放到任意分辨率了吗?
目前,游戏已经支持动态缩放到任意分辨率,能够在不同的分辨率下正常工作。虽然可以切换到更高的分辨率,但在渲染优化之前,最好避免使用过高的分辨率。即使渲染得到优化,也不建议在大多数机器上使用过高的分辨率,除非机器性能非常强大。因为要在像1920x1080或更高的分辨率下运行,可能需要使用GPU渲染,而不是CPU渲染。CPU渲染虽然可以支持高分辨率,但在性能上可能不理想。
在引入GPU后,才可以实现较高分辨率下的流畅帧率,CPU渲染主要是为了验证和了解整个渲染流程,而不是真正用于高效的玩家体验。因此,虽然CPU渲染支持高分辨率,但不适合在性能上有较高要求的情况下使用。
你能解释一下 #if #endif 这段代码的用途和何时/如何使用它吗?
if
语句和 #if 0
等预处理指令是用来有条件地启用或禁用某些代码段的工具。通常情况下,这种方法用于暂时关闭某些代码块,便于逐步开发和调试。
有两种常见的使用场景:
-
分阶段调试和开发:当进行代码更改时,特别是当修改的部分影响较多时,可以先将一部分代码注释掉,专注于处理当前需要关注的部分。通过使用
#if 0
等指令,可以暂时禁用一部分代码,这样可以让开发人员在进行更大更复杂的修改时,确保能够逐步验证功能是否正常,避免一次性更改带来大量未知问题。 -
快速开关某些功能:当有些功能代码是可选的,例如调试代码、测试功能等,可以通过
#if
来快速启用或禁用。这种方式可以不需要删除或手动注释掉代码块,只需切换开关即可方便地控制功能是否生效,而不会影响其他部分的开发工作。
总体来说,这种方法使得开发过程中能够灵活地管理不同功能块的启用状态,特别是在进行大范围的修改或调试时,可以保持代码清晰,并且减少不必要的重复工作。
楼梯的顶部和底部会有不同的艺术设计吗?如果是的话,如何使它们无缝连接?每一步的艺术设计是否会根据高度不同?
对于楼梯的艺术设计,考虑到它们可能会有不同的上下部分,设计思路是将楼梯的图形以位图的形式统一处理。在楼梯所在的楼层及位置,楼梯的图形会始终出现在正确的地方,这样就不需要为每个层级单独绘制不同的艺术作品。
至于如何使上下楼梯的视觉效果无缝连接,可以通过让楼梯成为不同楼层之间的过渡区域来处理。考虑到楼梯的图形在不同高度上展示是一样的,可以避免需要为不同的高度设计不同的艺术作品。然而,可能需要一些处理方法来使过渡效果更自然,例如调整楼梯在Z轴上的高度,或者在两个不同层级之间逐渐淡化切换的效果,但目前看来这种处理可能不必强制执行。
虽然这种处理方式看似可行,但由于这是一个涉及连续在不同Z轴高度之间移动的游戏,还没有看到其他游戏采用类似的设计,因此还需进一步验证效果。如果发现这种方式太复杂,或许可以考虑将视角切换为正交视图,这样只需要停止进行除法运算就能轻松实现,并且依然能够保持Z轴的功能。
我们能不能至少加入一些简单的 MS Paint 程序员风格的楼梯,而不是黄色方块?
目前考虑到楼梯的设计,虽然不希望使用黄色块作为占位符,至少可以考虑使用一些简陋的图形(例如用“画图”程序做的楼梯图形)来替代这些块状物,暂时填补楼梯的视觉设计空缺,直到最终的艺术设计完成。这种简陋的图形可以作为临时解决方案,让视觉效果看起来更完整一些。
楼梯的速度提升功能去哪了?
关于楼梯的速度提升效果,似乎目前没有明确讨论过这个问题,也不清楚曾经提到过这种速度提升。可能之前并没有专门提到过楼梯与速度提升相关的内容,或者这个功能还没有被实现或记录下来。
在打包时,是否会展示压缩方法和如何将所有资产打包成一个文件?
在打包资产时,计划将所有的艺术资产打包成一个文件,可能使用一种基础的压缩方法,比如采用类似 zlib 的压缩方式。然而,压缩方法不会进行深入讨论,也不会介绍复杂的压缩技术。计划使用的压缩工具是基本的 LZ 压缩器。至于是否会处理三维艺术和不对称图形,项目中采用的是类似于 TTR 艺术风格的三维方式,即允许世界在三维空间中运作,目的是展示如何在程序中健壮地实现三维功能,并帮助人们理解如何编写相关的三维程序。
英雄在楼梯上是不是应该变小?
英雄在楼梯上发生缩小的原因是因为当前位置的 Z 坐标更新与相机的位置更新存在一帧的延迟。这个问题出现在角色的 Z 坐标在移动时被计算出来,而相机的位置是在渲染后才更新的,导致角色在一帧内移动,而相机紧随其后更新。因此,角色的移动位置和相机的位置不同步,造成了一帧的延迟,表现为缩小的现象。
为了解决这个问题,需要确保更新过程中的各个部分按正确的顺序进行,特别是要确保渲染时相机的位置已经更新。在进行模拟计算时,需要将相机的更新放在正确的位置,避免由于相机位置滞后于角色位置而产生的延迟。可以通过适当的更新策略来确保相机和角色的同步,从而解决这一问题。
双分号!
关于双分号的问题,对它不满,认为它可能是不必要的或者不喜欢它的表现形式。提出如果不喜欢双分号,可以考虑使用三分号,认为这是更好的选择。这种讨论似乎带有一些幽默成分,表达了对语法细节的轻松探讨。
相关文章:
游戏引擎学习第109天
回顾目前进展 在这一期中,讨论了游戏开发中的一个重要问题——如何处理Z轴值的表示,尤其是在一个3D游戏中,如何更好地表示和存储这些值。上次的进展中,已经解决了透视投影的问题,意味着渲染部分的Z轴代码基本上已经完…...
npm、yarn、pnpm 的异同及为何推荐 pnpm
文章目录 一、引言二、npm 介绍(一)工作原理和特点(二)优势与不足 三、yarn 介绍(一)诞生背景和特性(二)与 npm 的主要区别 四、pnpm 介绍(一)核心优势和创新…...
基于遗传算法排课系统
一、遗传算法介绍: 遗传算法核心的任务是要通过编码体系,给出解决方案的染色体表现规则,首先需要随机初始化一定数量的种群(population),而种群则由一定数目的个体(individual)构成。每个个体实际上是染色体…...
Windows 图形显示驱动开发-GpuMmu 示例方案
本文介绍常见使用方案以及实现这些方案所需的操作顺序。 更新进程的页表条目 下面是更新页表条目以将属于进程 (P) 的分配映射到物理内存的操作序列。 假定页表分配已驻留在图形处理单元中GPU)内存段。 视频内存管理器在分页进程上下文中为进程 P 的根页表分配分配虚拟地址范…...
【Linux AnolisOS】关于Docker的一系列问题。尤其是拉取东西时的网络问题,镜像源问题。
AnolisOS 8中使用Docker部署(全)_anolis安装docker-CSDN博客 从在虚拟机安装龙蜥到安装docker上面这篇文章写的很清晰了,我重点讲述我解决文章里面问题一些的方法。 问题1: docker: Get https://registry-1.docker.io/v2/: net/h…...
策略+适配器模式详解
文章目录 1.策略模式1.目录结构2.Strategy.java 策略接口3.StrategyA.java 策略A4.StrategyB.java 策略B5.StrategyC.java 策略C6.Context.java 策略上下文7.Client.java 客户端8.小结 2.适配器模式1.目录结构2.CustomPaymentProcessor.java 自己的支付接口3.PayPalPaymentServ…...
Vue中事件名的命名规范
Vue中事件名的命名规范 起因: 本人之前不太写vue的项目,最近接触了vue的代码,在学习的过程中同时也会伴随着一点疑惑。比如一以下面的父子组件的事件传递为例: 父组件: 显然,父组件有个自定义事件refre…...
云计算架构学习之Ansible-playbook实战、Ansible-流程控制、Ansible-字典循环-roles角色
一、Ansible-playbook实战 1.Ansible-playbook安装软件 bash #编写yml [rootansible ansible]# cat wget.yml - hosts: backup tasks: - name: Install wget yum: name: wget state: present #检查playbook的语法 [rootansible ansible]…...
背包dp与数位dp
背包dp 介绍 动态规划实际上就是将复杂问题分解成若干个子问题,并通过子问题的解逐步发展成整体问题的解的算法思想。(我感觉这个解释就跟递归的思想一样) 背包问题分为01背包(物体只能使用一次),完全背包(物体可以使用无数次)&…...
【linux】更换ollama的deepseek模型默认安装路径
【linux】更换ollama的deepseek模型默认安装路径 文章目录 【linux】更换ollama的deepseek模型默认安装路径Ollama 默认安装路径及模型存储路径迁移ollama模型到新的路径1.创建新的模型存储目录2.停止ollama3.迁移现有模型4.修改 Ollama 服务配置5.重启ollama6.验证迁移是否成功…...
【紫光同创国产FPGA教程】——FPGA开发工具使用
本原创文章由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处(www.meyesemi.com) 一:实验简介 实验目的:了解PDS软件的使用,在线Debugger工具的使用请看第八章uart实…...
面试技术分享:MySQL死锁与事务等待超时的临时解决方案
📝 面试技术分享:MySQL死锁与事务等待超时的临时解决方案 1. 问题背景 某电商系统在促销高峰期出现库存更新失败,日志报错: Lock wait timeout exceeded; try restarting transaction (errno 1213)现象:多个事务因争…...
6.3 k8s的事件event和kube-scheduler中的事件广播器
什么是k8s的events k8s的events是向您展示集群内部发生的事情的对象 例如调度程序做出了哪些决定或者为什么某些 Pod 从节点中被逐出 哪些组件可以产生events 所有核心组件和扩展(操作符)都可以通过 API Server 创建事件k8s 多个组件均会产生 event …...
OAI 平台 4G(LTE)基站 、终端、核心网 端到端部署实践(一)
本系列文章,基于OAI LTE代码搭建端到端运行环境,包含 eNB,EPC,UE三个网元。本小节先介绍系统总体架构,硬件平台及驱动安装方法。 1. Overview 系统总体架构如下图所示。 2 Machine setup 2.1 Machine specs Distributor ID: Ubuntu Description: Ubuntu 18.04.5 LTS…...
t113修改串口
1 sys_config.fex [uart_para] uart_debug_port 0 uart_debug_tx port:PE02<6><1><default><default> uart_debug_rx port:PE03<6><1><default><default> 2 uboot修改启动参数 3 修改env.cfg启动地址和传输 #ear…...
「软件设计模式」桥接模式(Bridge Pattern)
深入解析桥接模式:解耦抽象与实现的艺术 一、模式思想:正交维度的优雅解耦 桥接模式(Bridge Pattern)通过分离抽象(Abstraction)与实现(Implementation),使二者可以独立…...
“地质环境体检”辅助智慧地质,服务工程建设、城市用地规划
随着社会经济的高速发展,各类工程建设也在加快筹建中。在工程项目的快速推进中,如何保障工作安全和工程建设的质量,是国家和社会普遍关注的一个问题。地质环境条件是影响工程建设、城市用地规划的重要因素,加强地质风险系统性研究…...
TMS320F28335二次bootloader在线IAP升级
F28335总共ABCDEFGH个区域,每个32K*16bits,即64K字节。 bootloader代码占用A区,地址0x338000~0x33FF7F,cmd文件中SECTIONS部分,需要添加Flash28_API相关信息,具体下载Flash28335_API_V210的demo࿰…...
java:用Guava的TypeToken优雅处理通配符类型(WildcardType): ? extends Number
在日常开发中我们经常会遇到泛型和通配符类型(WildcardType),比如当我们需要处理List<? extends Number>这样的类型时,如何优雅地创建这样的类型表示?本文将重点介绍如何通过Guava的TypeToken来实现通配符类型的…...
ROS-相机话题-获取图像-颜色目标识别与定位-目标跟随-人脸检测
文章目录 相机话题获取图像颜色目标识别与定位目标跟随人脸检测 相机话题 启动仿真 roslaunch wpr_simulation wpb_stage_robocup.launch rostopic hz /kinect2/qhd/image_color_rect/camera/image_raw:原始的、未经处理的图像数据。 /camera/image_rectÿ…...
Zabbix——Rocky9安装zabbix相关步骤记录
安装Zabbix 安装MariaDB 这里用MariaDB演示 https://mariadb.org/download/?trepo-config&dRedHatEnterpriseLinux9&v10.11&r_mneusoft 通过这个网址获得连接 选择对应的repo 根据系统版本和要安装的版本选择对应的repo 安装 新建一个repo文件,例…...
三轴云台之姿态测量篇
一、姿态测量的基本原理 三轴云台通过内置的传感器实时感知其姿态变化。这些传感器主要包括陀螺仪、加速度计和磁力计(在某些高级系统中)。 陀螺仪:用于检测云台的角速度变化,即绕三个轴的旋转速度。陀螺仪提供的数据是姿态测量的…...
Kotlin 2.1.0 入门教程(二十三)泛型、泛型约束、协变、逆变、不变
out(协变) out 关键字用于实现泛型的协变。协变意味着如果 B 是 A 的子类型,那么 Producer<B> 可以被视为 Producer<A> 的子类型。这里的 Producer 是一个使用泛型类型参数的类或接口,并且该泛型类型参数被标记为 ou…...
VSCode 中使用 Snippets 设置常用代码块
背景 在开发中,有很多代码片段是重复的,例如:vue文件中的模版,react 中的模版,打印的 log 等等,很多很多。对于这些重复性的工作,vscode 官方提供了解决方案-Snippets in Visual Studio Code&a…...
在conda虚拟环境中安装jupyter lab-----deepseek问答记录
在 Conda 虚拟环境中安装 Jupyter Lab 的步骤如下: 1. 创建并激活 Conda 虚拟环境 如果你还没有创建虚拟环境,可以使用以下命令创建一个新的虚拟环境并激活它: conda create -n myenv python3.x # 将 myenv 替换为你的环境名称࿰…...
单元测试整理
在国外软件开发中,单元测试必不可少,但是国内并不太重视这一块,一个好的单元测试可以提前发现很多问题,也减去和测试battle的时间 Spring单元测试 JUnit4 RunWith 指明单元测试框架 e.g. RunWith(SpringJUnit4ClassRunner.cla…...
计算机毕业设计hadoop+spark旅游景点推荐 旅游推荐系统 旅游可视化 旅游爬虫 景区客流量预测 旅游大数据 大数据毕业设计
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Java虚拟机面试题:内存管理(下)
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
【贝克街迷宫疑云:用侦探思维破解Java迷宫算法】
贝克街迷宫疑云:用侦探思维破解Java迷宫算法 "华生,把煤气灯调亮些。"福尔摩斯用放大镜仔细端详着桌上的羊皮纸,“这个案子比表面上看起来要复杂得多——它是个三维的思维迷宫。” 第一幕:离奇委托 1895年秋的伦敦笼…...
网络安全示意图 网络安全路线图
其实网络安全本身的知识点并不算难,但需要学的东西比较多,如果想要从事网络安全领域,肯定是需要系统、全面地掌握清楚需要用到的技能的。 自学的方式基本是通过看视频或者相关的书籍,不论是什么方法,都是很难的&#…...
ubuntu22.04离线安装K8S
1. 准备离线安装包 参考教程离线包准备教程 2. 准备环境 2.1. 准备主机 主机名ip系统k8s-master192.168.38.128ubuntu22.04k8s-node192.168.38.131ubuntu22.04 2.2. 设置host 修改 /etc/hosts 文件,添加master和node节点,需要和主机名保持一致 2…...
985本硕,网络安全方向,走算法还是走开发?
今天给大家分享的是一位粉丝的提问,985本硕,网络安全方向,走算法还是走开发? 接下来把粉丝的具体提问和我的回复分享给大家,希望也能给一些类似情况的小伙伴一些启发和帮助。 同学提问: 985本硕ÿ…...
如何清理 Linux 缓存 ?
和其他操作系统一样,Linux 使用缓存来优化系统性能。随着时间的推移,这些缓存可能会累积起来,尽管 Linux 擅长管理内存,但在某些情况下,手动清除可能是有益的,例如用于系统诊断、应用程序性能测试或其他特定…...
cv2库的使用及图像预处理02
目录 八,图像缩放 1. 图像缩放操作 2. 插值方法 (1)最邻近插值(cv2.INTER_NEAREST) (2)双线性插值(cv2.INTER_LINEAR) 3. 显示缩放结果 4. 目标尺寸 5. 总结 九,线性灰度变…...
硬件学习笔记--45 电磁兼容试验-9 无线电干扰抑制试验介绍
目录 电磁兼容试验- 无线电干扰抑制试验 1.试验目的 2.试验方法 3.判定依据及意义 电磁兼容试验- 无线电干扰抑制试验 驻留时间是在规定频率下影响量施加的持续时间。被试设备(EUT)在经受扫频频带的电磁影响量或电磁干扰的情况下&a…...
P1464 Function(记忆化递归)
#include <bits/stdc.h> using namespace std;#define ll long longll dp[21][21][21]; // dp数组,用来记忆已经计算过的结果ll w(ll a, ll b, ll c) {if (a < 0 || b < 0 || c < 0) {return 1;}if (a > 20 || b > 20 || c > 20) {return …...
OpenCV机器学习(7)人工神经网络 定义模型训练过程中参数的搜索范围cv::ml::ParamGrid 类
OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::ml::ParamGrid 类是 OpenCV 机器学习模块中的一个辅助类,用于定义模型训练过程中参数的搜索范围。它通常被用作某些机器学习算法(如支持向量机 SVM&…...
STL —— 洛谷字符串(string库)入门题(蓝桥杯题目训练)(一)
目录 一、B2109 统计数字字符个数 - 洛谷 算法代码: 1. 引入库和命名空间 2. 主函数 3. 读取输入 4. 变量初始化 5. 遍历字符串 6. 输出结果 7. 返回值 总结 评测记录: 二、B2110 找第一个只出现一次的字符 - 洛谷 方法一:算法代…...
游戏引擎学习第107天
仓库:https://gitee.com/mrxiao_com/2d_game_2 回顾我们之前停留的位置 在这段内容中,讨论了如何处理游戏中的三维效果,特别是如何处理额外的“Z层”。由于游戏中的艺术资源是位图而不是3D模型,因此实现三维效果变得非常具有挑战性。虽然可…...
网页制作01-html,css,javascript初认识のhtml的基本标记
一、 Html简介 英文全称是 hyper text markup language,超文本标记语言,是全球广域网上描述网页内容和外观的标准. Html作为一款标记语言,本身不能显示在浏览器中.标记语言经过浏览器的解释和编译,才能正确地反映html标记语言的内容. 1.html 的基本标记 1)头部标…...
WebSocket在分布式环境中的局限性及解决方案
WebSocket 在分布式环境中存在一些局限性,特别是当系统需要扩展多个服务实例时,单个 WebSocket 连接的管理和消息推送就变得比较复杂。因此,必须采取一些额外的措施来确保 WebSocket 能在多个服务实例之间正确工作。 WebSocket 在分布式环境…...
Windows日志分析
查看服务日志文件 windows下我们可以通过时间查看器来查看windows系统下服务,应用,系统等产生的事件以及日志 1.打开方式是: winr 输入eventvwr.msc 2.控制面板--系统与安全--事件查看器 事件类型分为5种 错误:标识问题很严重…...
青少年编程与数学 02-009 Django 5 Web 编程 20课题、测试
青少年编程与数学 02-009 Django 5 Web 编程 20课题、测试 一、软件测试二、自动化测试三、单元测试四、Django 单元测试(一)、创建测试用例(二)、运行测试(三)、常用测试功能 课题摘要: 本文全面介绍了软件…...
WPF 中为 Grid 设置背景图片全解析
WPF 中为 Grid 设置背景图片全解析 在 WPF(Windows Presentation Foundation)开发中,界面的美观度是吸引用户的重要因素之一。而添加背景图片是提升界面视觉效果的常见手段。今天,我们就来深入探讨在 WPF 里如何为 Grid 设置背景…...
3.10 实战Hugging Face Transformers:从文本分类到模型部署全流程
实战Hugging Face Transformers:从文本分类到模型部署全流程 一、文本分类实战:IMDB电影评论情感分析 1.1 数据准备与预处理 from datasets import load_dataset from transformers import AutoTokenizer # 加载IMDB数据集 dataset = load_dataset("imdb") …...
Android中获取so文件来源于哪个库
Android app中可能有很多的.so文件,有时我们不确定这些.so文件都是来源于哪些库的,可以通过在build.gradle中添加代码来统计。具体方法如下: 1.在com.android.application模块的build.gradle文件最后添加如下代码: // 获取所有的…...
地面沉降监测,为地质安全保驾护航
地面沉降,不容忽视的城市隐患 随着城市化进程的加速,大规模的工程建设、地下水过度开采等因素,导致地面沉降现象日益严重。地面沉降不仅会使建筑物开裂、倾斜,影响其使用寿命和安全性,还会破坏地下管线,引…...
宝塔docker 安装oracle11G
1、拉取镜像 sudo docker pull iatebes/oracle_11g #iatebes为用户名2、查看镜像 sudo docker images3、创建并运行容器 docker run -d --privileged --name oralce11g -p 1521:1521 iatebes/oracle_11g4、登录到容器 5、进入容器并修改system用户密码 docker exec -it orac…...
unity学习39:连续动作之间的切换,用按键控制角色的移动
目录 1 不同状态之间的切换模式 1.1 在1个连续状态和一个连续状态之间的transition,使用trigger 1.2 在2个连续状态之间的转换,使用bool值切换转换 2 至少现在有2种角色的移动控制方式 2.1 用CharacterController 控制角色的移动 2.2 用animator…...
DeepSeek等大模型功能集成到WPS中的详细步骤
记录下将**DeepSeek功能集成到WPS中**的步骤,以备忘。 1. 下载并安装OfficeAI插件 访问OfficeAI插件下载地址:https://www.office-ai.cn/,下载插件(目前只支持windows系统)。 注意,有两个插件࿰…...