游戏引擎学习第36天
仓库 :https://gitee.com/mrxiao_com/2d_game
回顾之前的内容
在这个程序中,目标是通过手动编写代码来从头开始制作一个完整的游戏。整个过程不使用任何库或现成的游戏引擎,这样做的目的是为了能够全面了解游戏执行的每一个细节。开发过程中,关注的不仅是游戏的最终效果,还包括理解计算机在运行时所做的每一个操作。
目前,项目已经进入了较为深入的阶段,已经完成了一个构建,并设计了一个瓦片地图存储系统。这个系统已经开始得到一些研究,开发者正在努力理解如何设计引擎的架构,以便能够开始实现游戏的具体功能。尽管目前系统还没有完全成型,但开发者已经在此过程中积累了许多有价值的经验。
在开发过程中,有一项重要的编程实践被强调,那就是在进行设计之前应该先进行实验和探索。这是一种非常有效的方式,通过探索来产生设计,而不是先做出设计再试图强迫其实现。当事先没有足够的了解时,强行设计可能会导致不理想的结果。
在目前的阶段,开发者对现有的平铺地图系统已经非常满意,接下来会将其打包起来,准备进入开发的下一个阶段。除了城镇相关的部分,游戏的其他内容也在考虑之中,这些内容也是完成游戏所不可或缺的部分。
加载 BMP 文件的介绍
接下来将开始使用之前下载的测试资源,目标是将它们加载到屏幕上并显示出来。首先会写一个非常简单的小系统,用来加载位图文件并将其显示在屏幕上。这个过程将帮助开始处理游戏的显示部分,但它还不是真正的渲染,因为渲染是一个庞大而复杂的过程,涉及到大量的数学运算和技术细节,需要逐步讲解。在当前阶段,重点是通过简单的矩形显示内容,为后续的更复杂渲染工作打下基础。
随着项目进展,工程架构将会逐渐完善,而此时的矩形显示将为之后的工作提供基础,帮助更好地理解和决定如何组织和管理其他图形和资产。为了在家中跟进这一部分工作,确保已经下载了测试资产包。未来,如果有新的资产发布,会及时通知,通常这些更新不频繁,但会在重要的阶段进行资产批量更新。
在 BMP 加载器之前处理玩家上下“楼梯”的动作
接下来的目标是处理玩家如何在不同层次之间移动,特别是在有上下楼梯或门的场景中。为了实现这一点,设计了两个时间平面,分别表示上层和平层,以便能够让玩家在这些平面之间上下移动。这将通过引入一个z分量来实现,允许多个平面堆叠在一起,并且处理这些平面时需要一个通用的系统。
要实现这一功能,首先需要对玩家代码进行修改。目前的玩家代码只负责检查玩家是否能够移动到指定的位置,并将其移动到正确的位置,但没有处理玩家在不同平面之间切换的逻辑。为了实现这一点,计划引入一个新的函数来检测玩家是否移动到了新的平面,即新的城镇或不同的地砖。当玩家位置发生变化时,通过一个谓词函数来检查玩家是否仍然在原来的地砖上。如果玩家移动到了新的地砖,就会触发相应的操作。
目前,正在使用一种基本的检查方法,比较玩家的当前位置与目标位置的不同,以便确定是否需要做出响应。未来,随着玩家移动逻辑的进一步开发,将会采用更正式的方式处理这一问题,包括处理玩家进入不同地砖后的具体行为。
上下文切换成本
在开发过程中,有时会编写一些临时的"胶水代码",其主要目的是将不同系统或模块连接起来,以便于进行测试和实验。这些代码通常不是最终代码,也不会出现在最终的项目中。其存在的目的是让开发者能够快速推进实验,而不必过多关注如何精确地设计或实现代码。
为了避免浪费时间,开发者倾向于在处理问题时,将注意力集中在当前的任务上,而不是在不合时宜的时间里纠结于代码的细节或质量问题。尽管某些代码可能是低质量的或者未完全实现,但只要它能推动当前任务的进展,且开发者清楚其临时性和不必要性,就可以继续使用。这种方式有助于集中精力,避免频繁切换任务,因为频繁的上下文切换会浪费大脑的处理能力,就像虚拟内存系统那样,会导致系统的效率降低。
因此,开发者会优先关注当前任务,尽可能提高集中度,而不花太多时间去考虑细节或完美代码的实现,特别是在暂时不必要的情况下。最终,这些临时代码会被替换掉,只要能达到当前的工作目标,其他问题就会暂时搁置。
实现上下楼梯的动作
在开发过程中,需要处理玩家的移动和位置更新。为了确保玩家可以顺利地移动到新的位置,代码会检查玩家的当前位置,并根据该位置的不同类型值来决定玩家的行为。如果玩家的当前位置是门(例如,值为3或4),他们会被引导到上方或下方的不同平面。
为了实现这一点,代码会首先获取玩家的当前位置,并通过一个函数获取该位置的瓦片值。然后,根据瓦片值的不同,采取不同的行动。如果玩家移动到一个门上,程序会根据设定的规则引导玩家向上或向下移动。对于门和其他空白区域,代码会检查是否有合法的移动路径,并执行相应的操作。
此外,代码中的一些功能,例如获取瓦片值的函数,被设计成"代理"函数,用来简化重复调用的过程。这样开发者不必每次都手动处理复杂的细节,而是通过更简化的调用来实现相同的功能。
开发过程中,临时代码(例如“懒代码”)是不可避免的,这些代码并不追求完美,而是帮助开发者快速推进任务。虽然这种方式有效,但开发者也意识到,频繁的上下文切换和处理多个任务时的困难,会使得集中精力变得更为挑战。最终,所有临时性或“懒”代码会在项目成熟时被替换或优化。
瓦片地图系统与瓦片地图定位系统的区别
在开发过程中,有一些代码涉及到定位和几何问题,但它们与瓦片地图本身无关。开发者意识到这些部分应该从当前的城市地图系统中剥离出来,可能应该被移到一个更适合的几何文件中。定位和几何细节本质上并不直接影响城市的瓦片地图,而更关乎瓦片的实际大小等信息。
因此,开发者计划将这些与瓦片地图无关的部分标记出来,并移到适当的位置。这些定位相关的部分,虽然在某些情况下可能看似和瓦片地图有关,但其实它们与地图的存储、瓦片布局并无直接关联,反而可能是更广泛的几何或定位问题。
接下来,开发者回到项目的核心,继续处理瓦片地图的位置,并计划确定如何处理这两个位置:位置A和位置B。这些位置将有助于进一步推动开发进程,特别是在处理城市地图系统的细节时。
// 检查玩家当前位置是否与新的目标位置在同一块瓦片上
if (!AreOnSameTile(&GameState->PlayerP, &NewPlayerP)) {// 获取新目标位置的瓦片值uint32 NewTileValue = GetTileValue(TileMap, NewPlayerP);// 如果瓦片值为 3,则表示当前瓦片有向上的楼梯// 玩家需要移动到上一层(AbsTileZ 增加)if (NewTileValue == 3) {++NewPlayerP.AbsTileZ;}// 如果瓦片值为 4,则表示当前瓦片有向下的楼梯// 玩家需要移动到下一层(AbsTileZ 减少)else if (NewTileValue == 4) {--NewPlayerP.AbsTileZ;}
}
注释说明:
-
AreOnSameTile
的作用:- 用于检查玩家当前位置和目标位置是否在同一个瓦片上。
- 如果玩家没有离开当前瓦片,则不需要进一步处理移动逻辑。
-
GetTileValue
的作用:- 返回目标位置瓦片的值。
- 不同的瓦片值表示不同的功能或场景,例如楼梯、障碍等。
-
瓦片值的含义:
3
表示该瓦片是向上的楼梯。4
表示该瓦片是向下的楼梯。
-
更新玩家的层级(
AbsTileZ
):- 如果瓦片值为
3
,玩家沿楼梯向上,层级增加。 - 如果瓦片值为
4
,玩家沿楼梯向下,层级减少。
- 如果瓦片值为
整体逻辑:
此代码实现了一个楼层切换机制,玩家移动到楼梯瓦片时,可以根据楼梯的方向(向上或向下)更新其所在的楼层,确保玩家能够跨层移动。
修复生成代码
1. 瓦片是否相同
- 当物体位于相同瓦片上时,讨论如何判断瓦片数据是否不同。这可能是为了避免在逻辑中忽略某些关键信息(例如瓦片属性差异)。
- 在同一瓦片上,所有瓦片的部分数据通常是相同的,除非明确标记了不同属性。因此,判断这些差异是为了逻辑严谨。
2. 房间布局与门的生成逻辑
- 房间的门在生成时,需要考虑合理性:
- 一个房间最多应该有两个出口(一个是进入的门,另一个是离开的门)。
- 当前程序逻辑中,门的生成过程可能出错,导致过多的门被添加到房间中。
3. 逻辑的主要问题与修复方法
问题描述:
- 门的重复切换:
- 如果存在上下的门(
door up
或door down
),程序在处理门的状态时,会多次切换其状态,导致门无限制地添加。
- 如果存在上下的门(
- 生成门的条件控制:
- 门的生成过程未明确限制条件,比如没有明确判断当前是否已经存在门。
修复步骤:
-
避免重复添加门:
- 在生成门时,检查当前是否已存在
door up
或door down
状态。 - 如果已存在,则不再生成新门。
- 在生成门时,检查当前是否已存在
-
记住门的生成状态:
- 使用标志位(如
createdVerticalDoor
)记录当前是否生成了门。 - 如果生成了门,再进入下一房间时对其状态进行切换;否则保持原样。
- 使用标志位(如
-
修正门与房间的逻辑关系:
- 如果当前房间有
door up
或door down
,需要保证下一房间的门与之对应。 - 例如,当前房间的
door up
对应下一房间的door down
。
- 如果当前房间有
4. 门切换逻辑优化
- 在门的切换逻辑中,明确区分
z门
(上下门)和其他类型的门:- 如果当前生成了
z门
,下一步需要生成其反向门。 - 如果当前未生成
z门
,则无需考虑反向切换,只需保持当前门状态。
- 如果当前生成了
5. 总结改进后的核心逻辑
- 检查现有状态:在生成门前,检查当前状态是否允许生成新门。
- 设置状态标志:使用标志位(如
createdVerticalDoor
)记录门的生成情况。 - 优化切换过程:只在需要切换状态时执行逻辑,避免不必要的重复操作。
- 保持合理性:确保每个房间有合理数量的门,并且与房间布局一致。
实现效果
修复后,程序能够:
- 正确判断是否生成新门。
- 避免门的重复生成问题。
- 维持房间布局的逻辑合理性,实现动态楼层切换与房间连通性。
实现完成,工作中的瓦片地图系统
-
瓷砖地图生成与楼梯设计
地图的设计和生成由一系列随机决定的因素控制,例如是否生成楼梯(Z门)或其他门的方向。随机数表用于生成门的选择,每次循环会检查当前楼层是否有楼梯,并且根据条件决定是否生成向上的或向下的楼梯。地图的绘制包括墙壁和门的判断,通过这些判断确定不同的瓷砖类型(例如墙壁、可行走区域)。 -
楼梯与门的交替生成
在每轮迭代中,生成不同类型的门(右侧、顶部或楼梯)。如果生成了楼梯,那么下一次迭代会调整楼梯的方向。如果没有生成楼梯,则确保两个楼梯的状态都关闭。特别是当随机选择为生成楼梯时,会根据当前楼层的状态切换楼梯的方向,可能是从上到下,或者反之。 -
地牢的探索与反思
游戏环境被描述为地牢,玩家可能会在其中探索,虽然此时地牢内没有具体的战利品或路径。尽管如此,地图生成的过程本身就是游戏设计的一部分,且逐步推进。随着设计的推进,开发者认为已经达到了一个相当不错的地牢地图。 -
未来的发展方向
一旦地图的生成完成,接下来的工作是使得游戏具备更多功能,例如玩家的运动与碰撞检测。这是为了使游戏变得可玩并为未来的开发奠定基础。此外,还考虑了图形显示的改进,尽管当前的地图显示是基本的,但未来会通过加载位图来提升视觉效果。 -
关于开发过程的探索
在开发过程中,重点在于逐步改进和修改已有的设计。开发者表达了对当前工作进展的满意,并且承认随着时间的推移,可能会需要做进一步的修改和调整。这些修改的目标是使得游戏更具可玩性和吸引力。 -
逐步推进开发目标
在实现基础功能后,开发者计划继续探索更复杂的功能,比如处理玩家的运动、碰撞检测以及游戏中的动画效果。更长远的目标是提高游戏的图形表现,使其在视觉上更具吸引力。 -
实现和改进
随着游戏逐步开发,开发者认识到,接下来的任务是解决如何在屏幕上呈现合理的图形,确保地图和游戏元素的表现是合理的。为了做到这一点,开发者考虑了加载位图和改进图形代码的需求。 -
未来方向与图形优化
接下来,开发者计划通过加载和优化位图来提升游戏的视觉效果,使得游戏在实际发布时能够提供更高质量的图形表现。这包括替换玩家运动代码以使其更加真实,以及在开发过程中逐步优化和改进游戏的各个方面。
总结:整个开发过程涉及多个步骤,从地牢地图的生成到玩家运动、碰撞检测的处理,再到图形优化。开发者通过逐步实验和调整,尝试找到合理的方案来实现一个既有趣又可玩的游戏。通过这一过程,开发者不断反思和改进设计,目标是最终实现一个具备完整功能的游戏。
加载 BMP 文件
今天的目标是把一张地图放到屏幕上。目标很简单,就是从一个文件中加载位图图像并显示在屏幕上,这为之后的原型设计提供基础。
需要加载一个位图文件作为示例。例如,可以选择一个测试背景,它包含一些树、蘑菇,以及草地背景。这是一个很合适的例子,能够帮助演示位图加载的基础工作流程。
该背景图像的分辨率为 1024x576。这需要与窗口大小对齐。在代码部分,可以根据图像尺寸和显示窗口的具体设置,完成加载和显示过程。
总结来说,重点是实现位图从文件加载并渲染到屏幕上的功能,为后续开发提供基础支持。
讨论游戏屏幕分辨率
-
屏幕分辨率目标:
- 目标分辨率是 1920x1080(典型的高清分辨率)。
- 为了便于处理并减少计算负担,考虑以一半的分辨率运行(960x540)。
-
调整为 2 的幂:
- 许多图形处理单元(GPU)偏好纹理大小为 2 的幂(如 1024x1024 或 2048x2048),因此在设计纹理时通常会考虑这些尺寸。
- 对于 1920 宽的屏幕,接近的 2 的幂是 2048,但这会浪费 128 像素。
- 对于 1080 高的屏幕,接近的 2 的幂是 1024 或 2048,但 2048 高浪费太多空间,因此选择 1024 并为顶部和底部添加 128 的缓冲带。
-
缓冲和屏幕抖动:
- 为支持屏幕抖动和溢出效果,增加了缓冲区域,比如在宽度上左右各 64 像素,在高度上上下各 36 像素。
-
内存利用效率:
- 选择的纹理尺寸(如 1152 (1024+128) 高或 2048 宽)既能容纳整个屏幕,也能支持额外的缓冲区域,尽可能减少浪费。
-
设计逻辑:
- 这一选择背后的逻辑是将图像资源设计为稍大于目标屏幕尺寸,以便于 GPU 的处理和动画效果的实现。
- 尽管这种方法可能并非最优,但它在实现时相对简单且足够灵活。
实现加载器
我们需要加载一些图像,并将它们显示在屏幕上,以确保一切正常运行。目标是通过绘制矩形的方式,将图像内容渲染到屏幕上。然而,这里不是直接填充纯色,而是通过矩形将完整的图像数据呈现到屏幕上。
绘制矩形的核心思想是用实际的图像内容替代简单的颜色填充。最终目标是实现图像渲染的基本功能,使图像可以正确显示在指定位置的矩形区域内。
为了实现这一功能,需要编写代码来加载图像文件。这里的初步实现并不是最终工业级的,而是为了快速完成一个可以运行的版本。稍后会对这些功能进行更详细的优化和改进。
加载图像需要读取位图文件的数据。可以利用现有的文件读取功能,将整个文件内容读取到内存中。通过一个函数调用,这些数据将被存储在内存缓冲区中,供后续操作使用。
这个读取功能依赖于一个已经实现的读取整个文件的工具。它接受一个线程上下文和文件名作为参数,完成文件内容的加载。位图文件的数据会被完整地传入内存中,以便进一步处理。
最后一步是解析文件中的位图数据,确保这些数据能够以正确的方式用于屏幕上的渲染。虽然这里的代码仅展示了初步实现,但它为后续更复杂的图像处理和优化奠定了基础。
我们需要加载一些图像,并将它们显示在屏幕上,以确保一切正常运行。目标是通过绘制矩形的方式,将图像内容渲染到屏幕上。然而,这里不是直接填充纯色,而是通过矩形将完整的图像数据呈现到屏幕上。
绘制矩形的核心思想是用实际的图像内容替代简单的颜色填充。最终目标是实现图像渲染的基本功能,使图像可以正确显示在指定位置的矩形区域内。
为了实现这一功能,需要编写代码来加载图像文件。这里的初步实现并不是最终工业级的,而是为了快速完成一个可以运行的版本。稍后会对这些功能进行更详细的优化和改进。
加载图像需要读取位图文件的数据。可以利用现有的文件读取功能,将整个文件内容读取到内存中。通过一个函数调用,这些数据将被存储在内存缓冲区中,供后续操作使用。
这个读取功能依赖于一个已经实现的读取整个文件的工具。它接受一个线程上下文和文件名作为参数,完成文件内容的加载。位图文件的数据会被完整地传入内存中,以便进一步处理。
最后一步是解析文件中的位图数据,确保这些数据能够以正确的方式用于屏幕上的渲染。虽然这里的代码仅展示了初步实现,但它为后续更复杂的图像处理和优化奠定了基础。
快速学习如何读取文件格式
以下是关于读取文件格式的快速入门概述。
要读取一种文件格式,首先需要对该格式有一定了解。可以通过在网络上搜索文件格式的名称和相关文档来获取信息。通常,搜索“bmp file format”可以找到相关的技术细节和结构说明。
一旦找到合适的资源,可以根据文件组织结构来理解数据布局。例如,对于位图文件(BMP),一般会有如下结构:
- 文件头:包含文件的基本信息,例如文件大小和偏移量。
- 位图头:包含位图数据的具体信息,例如宽度、高度和色彩深度。
- 调色板(可选):存储颜色信息,通常仅在文件使用索引颜色模式时存在。
- 位图数据:图像的实际像素数据。
如果确定文件存储的是RGB数据而非索引颜色,就可以跳过调色板部分,仅处理文件头、位图头和位图数据。
BMP(Bitmap)文件格式是一种无压缩的图像文件格式,用于存储位图数字图像,尤其是在 Windows 操作系统中被广泛使用。以下是 BMP 文件格式的详细介绍:
BMP 文件结构
BMP 文件由多个部分组成,每个部分有特定的用途。以下是 BMP 文件的主要结构:
1. 文件头 (File Header)
- 大小:14 字节
- 描述:文件的基本信息,包括文件大小、文件类型等。
- 字段:
- 文件标志 (
bfType
):2 字节,固定为BM
(0x4D42),表示这是一个 BMP 文件。 - 文件大小 (
bfSize
):4 字节,文件总大小(以字节为单位)。 - 保留字段 (
bfReserved1
和bfReserved2
):各 2 字节,通常为 0。 - 位图数据偏移量 (
bfOffBits
):4 字节,从文件开头到位图数据开始的偏移量。
- 文件标志 (
2. 位图信息头 (Bitmap Info Header)
- 大小:40 字节(常见的版本);不同版本的 BMP 文件可能扩展。
- 描述:图像的详细信息,如宽度、高度、颜色深度等。
- 字段:
- 结构大小 (
biSize
):4 字节,信息头的大小,通常为 40 字节。 - 图像宽度 (
biWidth
):4 字节,图像的宽度(以像素为单位)。 - 图像高度 (
biHeight
):4 字节,图像的高度(以像素为单位)。正值表示自下而上存储,负值表示自上而下存储。 - 颜色平面数 (
biPlanes
):2 字节,始终为 1。 - 位深度 (
biBitCount
):2 字节,每个像素的颜色位数(1、4、8、16、24、32)。 - 压缩方式 (
biCompression
):4 字节,图像数据的压缩方法:- 0:BI_RGB(无压缩)。
- 1:BI_RLE8(8 位 RLE 压缩)。
- 2:BI_RLE4(4 位 RLE 压缩)。
- 3:BI_BITFIELDS(每像素指定颜色掩码)。
- 图像大小 (
biSizeImage
):4 字节,位图数据的大小(可能为 0,如果未压缩)。 - 水平分辨率 (
biXPelsPerMeter
):4 字节,水平分辨率(像素/米)。 - 垂直分辨率 (
biYPelsPerMeter
):4 字节,垂直分辨率(像素/米)。 - 颜色索引数量 (
biClrUsed
):4 字节,调色板中使用的颜色数(0 表示使用所有颜色)。 - 重要颜色索引数量 (
biClrImportant
):4 字节,重要颜色的数量(0 表示所有颜色都重要)。
- 结构大小 (
3. 调色板 (Color Table) (仅限 1、4、8 位色深的 BMP 文件)
- 大小:可变
- 描述:存储颜色索引,定义图像的调色板。
- 字段:
- 每种颜色通常占用 4 字节:红色、绿色、蓝色和保留字段。
4. 像素数据 (Pixel Data)
- 大小:可变
- 描述:图像的实际像素数据,从左下角开始,逐行存储。每行的大小需要对齐到 4 字节的倍数(即填充字节)。
- 格式:
- 如果是 24 位色,每个像素占用 3 字节(B、G、R 顺序)。
- 如果是 32 位色,每个像素占用 4 字节(B、G、R、A 顺序)。
BMP 文件示例
示例文件头和信息头 (24 位色无压缩)
字节偏移量 | 长度(字节) | 字段名称 | 示例值 | 描述 |
---|---|---|---|---|
0 | 2 | bfType | BM (0x4D42) | BMP 文件标志 |
2 | 4 | bfSize | 0x00036E | 文件大小 |
6 | 2 | bfReserved1 | 0x0000 | 保留字段 |
8 | 2 | bfReserved2 | 0x0000 | 保留字段 |
10 | 4 | bfOffBits | 0x36 | 位图数据偏移量 |
14 | 4 | biSize | 0x28 | 信息头大小 |
18 | 4 | biWidth | 0x00000200 | 图像宽度 |
22 | 4 | biHeight | 0x00000200 | 图像高度 |
26 | 2 | biPlanes | 0x01 | 颜色平面数 |
28 | 2 | biBitCount | 0x18 (24 位色) | 每像素位数 |
30 | 4 | biCompression | 0x00 (BI_RGB) | 压缩方式 |
34 | 4 | biSizeImage | 0x00000000 | 图像数据大小(未压缩可为 0) |
BMP 文件的特点
- 优点:
- 结构简单,易于解析。
- 无压缩格式保留了图像的完整质量。
- 缺点:
- 文件体积大(特别是高分辨率图像)。
- 不支持现代图像功能(如透明度或高效压缩)。
解析 BMP 文件时的注意事项
- 字节顺序:BMP 文件采用小端序存储数据。
- 像素对齐:每行像素的字节数需要是 4 的倍数,不足的部分需要填充字节。
- 支持的色深:1 位、4 位、8 位、16 位、24 位和 32 位。
实现加载功能
编写代码时,可以利用现有的文件读取工具来读取整个文件。例如,使用一个函数将文件完全加载到内存中。加载后,文件数据将以缓冲区的形式存储,可以进行解析。
加载步骤:
- 读取文件内容:通过调试工具或自定义的文件读取函数,将文件加载为内存缓冲区。
- 解析文件头和位图头:根据文件格式文档,读取文件的元数据,例如图像尺寸、偏移量等。
- 读取位图数据:跳转到文件的位图数据部分,将其解析为实际像素信息。
调试与验证
加载文件后,可以通过调试工具查看加载的数据,以验证文件格式是否正确解析。通过观察文件内容的前几字节,可以判断使用的具体文件格式版本。
测试案例:
- 使用预先保存的BMP文件测试加载功能。
- 确保程序能够正确读取文件头、位图头以及图像数据。
- 验证加载的数据是否符合预期的像素信息。
代码示例
在初始化阶段,调用加载函数并传入文件路径。以下是示例逻辑:
- 调用文件读取函数,将文件内容加载到内存。
- 检查文件头和位图头的格式,以确保解析的准确性。
- 使用调试工具输出加载的数据,用于验证文件内容。
通过这些步骤,可以快速实现一个基础的文件加载功能,为后续的图像处理或渲染奠定基础。
在内存中调试 BMP 文件
清理屏幕时涉及的对话内容包括对文件的读取过程、文件格式的解释以及调试步骤的详细说明。涉及的关键点包括:
-
文件读取和验证:
- 确认文件是否成功读取,检查文件大小和内容是否一致。
- 在调试过程中查看文件内容,看它的格式是否如预期的那样,包括 BMP 文件的标头、文件大小和偏移量。
-
文件格式解析:
- 解释 BMP 文件的结构,如文件头的前 2 个字节标识文件类型,文件大小的 4 个字节、偏移量等。
- 解释这些数据的意义,例如文件头的大小和具体的位图数据位置。
-
调试步骤:
- 在调试中检查文件内容,确保每一步都符合预期。
- 将文件内容从未压缩格式处理和读取,以便进行进一步分析和处理。
这些对话展示了如何使用调试工具来解析和理解文件内容,如何检查文件头和数据的各个部分,并确保在处理过程中每个步骤都是正确的。
处理 BMP 文件头
打包结构体以避免填充
我们遇到一个问题,这个问题之前讲过很多次。为了巩固这件事,可能有些人对这类事情不熟悉。当我们试图读取一个文件,查看其中的内容时,你会发现它看起来不像我们预期的那样。我们期望看到文件的大小和内容像预期的一样,但事实是,它们可能会看起来不正确。这是因为在布局数据时,C++ 并不一定会紧紧地打包这些结构体。换句话说,C++ 在安排内存时,不会按照数据的实际大小紧密排列,而是可能会跳过一些字节,把数据安排到一个边界上。即使我们在声明了结构后告诉编译器要紧紧包裹这些结构,编译器可能依然会使用默认的包装方式。这导致了我们在读取文件时可能会遇到数据错位的问题。
为了解决这个问题,我们可以使用 #pragma pack
指令来告诉编译器把结构体紧紧包裹起来。这个指令可以指定打包的水平,使得结构体中的字段以最紧凑的方式排列。然而,这样做的一个问题是我们无法确定是否在其他地方的代码中已经使用了这种打包方式。因此,为了确保我们不会影响到其他地方,编译器提供了一个push
和pop
的机制。使用 #pragma pack(push, 1)
可以把当前的打包设置推到堆栈上,并设置新的紧凑打包水平,然后在结束时使用 #pragma pack(pop)
恢复之前的打包设置。这样就可以在读取文件的过程中保持结构体数据的正确排列,从而避免数据错位问题。
通过这样做,我们可以确保读取的位图文件的实际数据大小、宽度和高度以及位深度都符合预期,从而正确处理文件中的位图数据。
处理 BMP 像素
在进行二进制文件解析时,我们了解到了一些关键的概念。这包括我们如何处理宽度和高度,数据的偏移量,以及如何确保内存中像素的正确对齐。我们知道了像素数据将会从位图偏移处读取,这个偏移量是相对于整个文件的起始位置的。这样,我们可以确保计算得到的像素指针能够正确地指向每个像素。
然而,存在一些问题,像是图像可能会出现剪切现象,颜色顺序可能不正确等。这些问题需要在调试和修复过程中逐一解决。下周我们将继续探讨如何将这些数据正确地展示到屏幕上,并解决这些问题。
总体来说,虽然我们现在已经基本理解了如何处理位图文件格式和内存布局,但仍有一些细节需要精确调整,特别是涉及到像素对齐和颜色顺序的问题。这是未来需要解决的重要挑战。
BitmapOffset
在位图文件格式中表示图像数据的偏移量,即从文件的开始位置到实际图像数据开始的字节数。它是文件头结构的一部分,用于指示图像数据在文件中的起始位置。
在 BitmapFileHeader
或 BitmapInfoHeader
结构中,BitmapOffset
是一个 uint32
类型的整数,它告诉解码程序从文件的开头开始读取多少个字节后才能开始解析位图图像数据。
具体作用
BitmapOffset
提供了从文件的开始位置到图像数据的起始位置的字节数。这对于读取二进制文件中的图像数据至关重要。- 它保证了解码程序从文件的正确位置开始解析图像数据,而不是从文件的开头开始读。
- 这个值通常会是文件头部分的大小加上图像信息头部分的大小。
举例
假设 BitmapOffset
值为 54
(字节数),则图像数据开始的字节是从文件的第 54 个字节开始。解析程序需要从文件的第 54 个字节开始读取图像数据并解码出来。
这个偏移量保证了解析程序能够正确地跳转到图像数据的位置,而不必从文件的开头逐个字节地进行读取,这大大提高了读取图像数据的效率。
我错过了你处理文件字节序的部分,还是位图格式始终相同?
就位图而言,我想说的是,我不确定它们是否可以在不同的系统上被保存。例如,如果他们在Mac上保存的位图,它们总是会是小端字节序的,因为现代计算机通常都使用小端字节序。因此,不论是在PC还是Mac上保存,位图文件都将保持一致。
对于其他格式,比如PSD文件,它们可能会包含不同的字节序(大端或者小端)。但对于位图而言,无论是在PowerPC、Mac 还是现代PC上,它们总是小端格式保存。这就意味着,不论在哪个系统上保存或加载位图,位图数据格式都不会改变。
你更喜欢 #pragma pack 还是 gcc 风格的注解?
可能是gcc喜欢注释,并且这种注释方式虽然看起来有点丑,但我并不介意。它更像是简单直接的表达方式,就像是包装一样,这种注释方式更直观。例如,gcc和某些工具也有类似的属性。尽管如此,这通常不是一个大问题,因为这并不是经常需要的功能,也就是说,它通常不是那么重要。
在将多个参数放入一个结构体之前,你对函数参数数量的阈值是什么?
我没有一个具体的阈值来决定是否将所有函数参数放入一个单一的结构中。这主要取决于是否有很多人会频繁地传递同样的一组数据。 如果一组内容被多个函数频繁使用,我会将它们整合到一个结构中,以便更简洁地管理代码。然而,如果一个函数只包含一组独特的数据,即使是多个参数,我不介意把它们保持为独立的参数。关键在于这些数据是否能够被整合在一起,允许更高效的代码结构和管理。
为什么不使用函数模板,将原始字节读取到任何结构体中,一次读取一个基本类型,而不是使用编译器注解?
该解释围绕一种稀疏地图存储的概念,特别是在游戏引擎中的基于网格的世界中的应用。以下是关键点的中文翻译:
-
两级数组方案:地图组织成一个三维数组,其中:
- Z轴表示世界中的层级或深度。
- Y轴表示网格中的垂直层。
- X轴表示横向网格中的层。
-
稀疏存储:而不是存储整个地图的每个网格内的每个层(这将非常低效),引擎使用一个稀疏方案:
- 只存储实际使用的网格。
- 未使用的区域标记为零,表示不存在任何网格。
- 这显著减少了内存占用,因为只存储了地图中的活跃部分,而不是整个世界。
-
网格:网格的概念允许将一组网格以紧凑的、可管理的格式存储:
- 每个网格是一个平面的密集的二维数组(16x16网格),存储实际的数据。
- 这个平面数组只在稀疏的三维地图中存储必要的部分。
- 网格通过其坐标(x, y, z)进行索引,这些坐标表示它们在地图中的位置,使得引擎能够仅在需要时获取必要的数据。
-
效率:稀疏地图允许通过仅存储实际使用的世界局部,来高效地使用内存。这样可以避免存储大量空白或未使用的数据,否则在一个完全密集的地图中必须存在。
-
代码实现:
- 代码涉及从文件中读取所需的网格,并在需要时动态重建它们到活跃的地图中。
- 使用基本的数据类型来读取特定类型的数据(如头部或指针),允许引擎动态拼接地图,而不是在游戏开始时存储所有可能的数据。
- 这种方法减少了游戏过程中的计算开销,因为它避免了处理不必要的数据,优化了内存使用和处理效率。
这种方法提供了一种灵活且高效的处理大型游戏世界的方式,确保了在任何给定时间只使用和存储所需的内容。
你能解释一下如何处理平台特定数据吗?
在处理内存时,当读取文件时,我们会避免将文件中的所有数据都加载到内存池中,这样做会浪费内存。相反,我们采用资源流的概念,使得仅在需要时,按需读取文件。这种方法有助于优化内存使用,因为我们只会读取并解压缩那些确实需要的部分,并且把它们直接放入合适的位置。
这种方法最大限度地减少了加载时的内存开销。通过预先处理并将数据转换为一个易于流式处理的格式,我们能够尽可能快速地加载资源,即使数据已经被压缩。这个过程包括仅从文件中读取、解压缩和存储需要的数据块,从而避免了加载时处理不必要的文件内容。这些处理都在一个临时的缓冲区中进行,以便反复使用,从而最大限度地提高资源的加载效率。
在设计平台特定的行为时,我们通常会将平台特定的数据存储在线程环境的一个额外空间中。这些数据在传递给游戏时,会被合并到通用的线程上下文中。因此,当游戏代码回调时,我们可以从这个合并的结构中提取所需的数据。这种方法能够最小化平台数据的传递次数,从而减少代码中的往返调用,并提高代码的效率。
实现一个通用稀疏数组来解决瓦片地图问题会很容易吗(可能通过重载)?
在实现一个通用的稀疏数组来解决这个问题时,可能会比较复杂。使用一个哈希表可能是更合适的选择,因为它提供了更快的索引和访问速度,而稀疏数组可能会显得效率较低,并且需要更多的内存操作。一个哈希表能够更好地处理动态数据的插入和删除,不像稀疏数组那样必须预先分配所有可能的索引空间。
虽然稀疏数组可以用来存储稀疏的数据,但在大多数情况下,这种方法可能会慢于使用哈希表,因为它要求不断地进行内存访问和索引计算。而且,稀疏数组的通用性可能不是必需的,因为它需要一个通用的哈希函数,这可能不是最适合特定需求的。
因此,基于当前情况,我们可能会选择更具体的解决方案,如使用四叉树或类似的数据结构。这些方法虽然可能更复杂,但可以根据特定应用的要求进行优化,提供更高的效率。
总的来说,选择合适的数据结构取决于具体的应用需求。如果内存开销或访问速度是关键因素,哈希表可能是更好的选择。而如果需要更复杂的存储方式,像四叉树这样的结构可能更合适。
所以我们有世界块和瓦片,是不是也有屏幕?
在这个架构中,屏幕并不是一个明确的存储或结构对象,而是一个游戏构造。它们只是游戏中用于管理视角和可见区域的抽象概念。实际上,屏幕只是一种在游戏中进行显示和滚动的方式。摄像头固定在一个屏幕上,使玩家能够在特定区域内移动,而不需要显式地管理或存储这些屏幕对象。它们只是游戏的表现和行为的一部分,通过游戏的机制自动管理和标记。
为什么在前面提到的例子中不使用函数模板?
在开发过程中,如果涉及到使用模板,很多人会感到不适,因为他们的语法被认为很复杂且容易引发编译器问题。模板可能会导致错误消息变得难以理解,使调试过程更加复杂。这种情况尤其普遍,当模板用于复杂的代码结构时,例如在数据处理或抽象层次较深的情况下。代码的可读性和可维护性也会受到影响,特别是当模板泛化程度高时,需要处理各种类型的特殊情况。
从某种程度上说,使用模板可能是一种过度的尝试,用来实现一种弱元编程,而不是利用更强大的语言特性来解决问题。大多数时候,写一些实际的函数或类,更易于理解和调试。这些函数可以根据需要被调用,而不必担心模板所带来的复杂性和潜在的错误消息问题。
综上所述,模板可能在特定情况下节省时间和代码量,但它们引入的复杂性通常不值得。对很多开发者来说,这种复杂性可能远远超过了模板带来的代码简化效果,尤其是在需要处理大量特殊情况时。因此,他们更倾向于使用实际的函数或类来替代模板。
你会编写资源导出/导入工具来将资源转换为高效格式,还是依赖资源创建者的工具?
在编写资产导入程序时,主要关注的是如何将外部资源(如图像或音频文件)打包并转换为游戏所需的格式。虽然直接使用艺术工具生成的数据可能会被忽略,但将这些资源包装成一个统一的文件格式可以方便地集成到游戏中。基本上,这个过程涉及到对资源的整理和优化,以符合游戏的需求。
虽然不会直接依赖艺术工具生成的数据,但在实际开发中,使用一些元编程技术来自动化生成C代码,对于提升效率和简化代码是有帮助的。这种方式可以有效地生成必要的代码片段,从而避免手动编写重复的代码。
对于未来的开发计划,期待能够将资源正确地呈现在屏幕上,并构建出一个吸引人的游戏体验。这包括如何组织地图屏幕和处理游戏中的视觉效果。这些内容将在下一次的直播中继续讨论,并最终实现,使得游戏能够更具吸引力和互动性。
总结来说,编写资产导入程序的关键在于将资源打包和转换,并在游戏中有效利用这些资源,而不是依赖于艺术工具直接输出的数据。
相关文章:
游戏引擎学习第36天
仓库 :https://gitee.com/mrxiao_com/2d_game 回顾之前的内容 在这个程序中,目标是通过手动编写代码来从头开始制作一个完整的游戏。整个过程不使用任何库或现成的游戏引擎,这样做的目的是为了能够全面了解游戏执行的每一个细节。开发过程中࿰…...
数仓技术hive与oracle对比(一)
准备 包括软硬件环境、数据、测试数据三方面的准备内容。 环境 虚拟机软件virtualbox7,同样的虚拟机配置:内存2G、cpu一核,物理主机同一台macbookpro(13-2020款),所以硬盘IO读写速度一致。 综上&#x…...
LeetCode题集-5 - 最长回文子串(一)
题目:给你一个字符串 s,找到 s 中最长的回文子串。 这一题作为中等难度,常规解法对于大多数人应该都没有难度。但是其中也有超难的解决办法,下面我们就一起由易到难,循序渐进地来解这道题。 01、暴力破解法 对于大多…...
A3026 Java+jsp+servlet+mysql高校学生请假管理系统
高校学生请假管理系统 1.摘要2. 绪论3.功能结构4.界面展示5.源码获取 1.摘要 高校学生请假管理系统 摘要:随着计算机的发展与不断进步,各个领域都出现了新的技术,曾经各种规模之间的竞争已经发展成为技术之间的竞争,管理和人才之…...
LDO低压差线性稳压器
1. 简介 LDO 是 “Low Dropout Regulator” 的缩写,中文称为“低压差线性稳压器”。LDO 稳压器是一种用于电压调节的电子设备,它的主要特点是输出电压和输入电压之间的压差非常低。这种特性使得 LDO 在许多应用场景中非常有用,特别是在需要高…...
Angular由一个bug说起之十一:排序之后无法展开 Row
问题现象 在使用 Material Table 时,排序功能触发了一个奇怪的 Bug:表格的 Row 无法展开。最终排查发现,问题的根源在于 trackBy 的错误使用。trackBy 方法接受两个参数:index(数据索引)和 row(…...
wlanapi.dll丢失怎么办?有没有什么靠谱的修复wlanapi.dll方法
在遇到各种系统文件错误当中,其中之一就是“wlanapi.dll文件丢失”的问题。这种问题通常发生在Windows操作系统上,特别是当系统试图执行与无线网络相关的任务时。wlanapi.dll是一个重要的系统文件,它负责处理Windows无线网络服务的许多功能。…...
redis安装和使用教程【保姆级】
1.下载 通过网盘分享的文件:redis 链接: https://pan.baidu.com/s/1Tu1KZkf33YJFdul8s6SzqQ?pwd8888 提取码: 8888 2.启动 进入根目录,使用redis-server redis.windows.conf命令启行启动Redis服务, 如下图所示为启动成功,默认…...
Github 2024-12-01 开源项目月报 Top20
根据Github Trendings的统计,本月(2024-12-01统计)共有20个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10TypeScript项目9Go项目2HTML项目1Shell项目1Jupyter Notebook项目1屏幕截图转代码应用 创建周期:114 天开发语言:TypeScript, Py…...
C总结(C语言知识点,深化重难点)
C语言 1.使用C语言的7个步骤2.ASCII码3.提高程序可读性的机巧4.如何使用多种整形5.打印多种整形6.课移植类型:stdint.h和inttypes.h7.浮点数常量8.浮点值的上溢和下溢9.使用数据类型11.常量和C预处理器12.转换说明的意义12.1转换不匹配13.副作用和序列点14.数组简介…...
[Collection与数据结构] 位图与布隆过滤器
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
Redis与缓存
目录 缓存 缓存优缺点 缓存更新策略 超时剔除 先删缓存再更新数据库 旁路缓存(先更新数据库,再删缓存) 先更新数据库,再更新缓存 读写穿透 编辑 异步缓存写入模式 缓存常见问题 缓存穿透 缓存雪崩 缓存击穿 缓存 在业务开发…...
Ubuntu Linux 文件、目录权限问题(五)
本文为Ubuntu Linux操作系统- 第五弹 此文是在上期文件目录的内容操作基础上接着讲权限问题 上期回顾:Ubuntu Linux 目录和文件的内容操作 文件访问者身份与文件访问权限 Linux文件结构 所有者(属主)所属组(属组)其他…...
AI 名人堂:Jeff Dean
Jeff Dean,谷歌的高级研究员和人工智能领域的领军人物,以其在大规模分布式计算系统和人工智能系统的杰出贡献而闻名。 谷歌AI掌门人 TensorFlow项目负责人 美国工程院院士 2AGI.NET AI 名人堂 AI 名人堂:Jeff DeanAI 名人堂:Je…...
基础排序算法详解:冒泡排序、选择排序与插入排序
引言 上一章,我们聊到了排序的基本概念和常见算法的分类。这一次,我们从基础开始,深入剖析三种常见的O(n) 排序算法:冒泡排序、选择排序 和 插入排序。 它们是学习排序算法的入门神器,不仅实现简单,还能帮…...
Flink如何基于数据版本使用最新离线数据
业务场景 假设批量有一张商户表,表字段中有商户名称和商户分类两个字段。 批量需要将最新的商户名称和分类的映射关系推到hbase供实时使用。 原实现方案 a.原方案内容 为解决批量晚批问题,批量推送hbase表时一份数据产生两类rowkey:T-1和…...
什么是反向代理?作用、原理和实例详解
🚀 什么是反向代理?作用、原理和实例详解 在现代的网络架构中,反向代理(Reverse Proxy)无处不在。无论是负载均衡、加速缓存,还是WebSocket 支持,反向代理都是必不可少的工具。 这篇文章将带您…...
国产GPU中,VLLM0.5.0发布Qwen2.5-14B-Instruct-GPTQ-Int8模型,请求返回结果乱码
概述 国产GPU: DCU Z100 推理框架: vllm0.5.0 docker容器化部署 运行如下代码: python -m vllm.entrypoints.openai.api_server --model /app/models/Qwen2.5-14B-Instruct-GPTQ-Int8 --served-model-name qwen-gptq --trust-remote-code --enforce…...
Stable Diffusion本地部署:从零开始的完整指南
1、引言 Stable Diffusion是计算机视觉领域的一个生成式大模型,能够进行文生图(txt2img)和图生图(img2img)等图像生成任务。它利用深度学习技术,特别是RealisticVision v2.0模型,能够创造出接近…...
隐式神经网络实现低光照图像增强
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...
Flutter动画(三)内建显式动画Widget
常见的内建显式动画Widget: ListenableBuilder: AnimatedBuilder AnimatedWidget AlignTransition DecoratedBoxTransition DefaultTextStyleTransition PositionedTransition RelativePositionedTransition RotationTransition ScaleTransiti…...
springSecurity自定义登陆接口和JWT认证过滤器
下面我会根据该流程图去自定义接口: 我们需要做的任务有: 登陆:1、通过ProviderManager的方法进行认证,生成jwt;2、把用户信息存入redis;3、自定义UserDetailsService实现到数据库查询数据的方法。 校验&a…...
Spring Boot日志:从Logger到@Slf4j的探秘
写在前面 Hello大家好,今日是2024年的第一天,祝大家元旦快乐?? 2024第一篇文章从SpringBoot日志开始 文章目录 一、前言二、日志有什么用?三、日志怎么用?四、自定义日志打印 ?? 常见日志框架说明4.1 在程序中得到?志对象【…...
使用 LabVIEW 与 PLC 通信的方式
要将 PLC 与 LabVIEW 或其他 NI 产品进行通信,首先需要明确 PLC 支持的通信协议和接口类型。NI 提供了多种方案,包括 OPC 服务器、Modbus、Ethernet/IP 和其他工业通信协议。下面将详细介绍这些方法,并进行比较分析,帮助你选择最适…...
python录制鼠标键盘操作循环播放
依赖 pip install pynput 程序: from pynput import mouse, keyboard import time import threading# 用于存储录制的鼠标和键盘事件 mouse_events [] keyboard_events []# 定义事件处理函数# 处理鼠标事件 def on_move(x, y):mouse_events.append((move, x, y))def on_cl…...
开发者如何使用GCC提升开发效率Opencv操作
看此篇前请先阅读 https://blog.csdn.net/qq_20330595/article/details/144134160?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_20330595/article/details/144134160?spm=1001.2014.3001.5502 https://blog.csdn.net/qq_20330595/article/details/144216351?spm=1001…...
异常与文件
目录 1.异常 1.1.概念 1.2.常见异常 1.3.异常处理方式 1.3.1.try except 1.3.2.try except else 1.3.3.try except else finally 2.文件 2.1.文件分类 ps:python 程序的数据保存在哪里? 2.2.常见的文件类型 2.3.python 操作文件的函数 2.3.1.读取文件…...
【C语言】完成程序设计填空
文章目录 1、请阅读下面的程序,在空白处填写正确的代码,要求各在一行从头开始输出m和n的值。2、求100~599之间的所有水仙花数,即各位数字的立方和恰好等于该数本身的数。3、以下程序的功能是:将值为三位正整数的变量x中的数值按照个位、十位、百位的顺序 拆分并输出。请填空…...
西湖大学:LLM零样本推理任务校准
📖标题:Task Calibration: Calibrating Large Language Models on Inference Tasks 🌐来源:arXiv, 2410.18764 🌟摘要 🔸大型语言模型(LLM)在推理任务上表现出令人印象深刻的零样本…...
windows下Qt5自动编译配置QtMqtt环境(11)
文章目录 [toc]1、概述2、准备1.1 下载源码1.2 配置环境1.3 解释原理 3、编译4、验证5、参考6、视频 更多精彩内容👉内容导航 👈👉Qt网络编程 👈 1、概述 Qt默认是不包含mqtt库的,如果需要使用到mqtt库就只能自己编译配…...
每天五分钟深度学习:神经网络的前向传播的计算(多样本)
本文重点 前面我们学习了单样本的前向传播,本文我们学习多样本的前向传播,我们先来回忆一下,神经网络的单样本的前向传播的向量化的方式: m个样本依次进行前向传播 这里我们说明一下符号: 我们使用(m)表示第m个样本,用[m]表示神经网络的第m层 a[2](i) 表示第i个样本计…...
基于 NXP S32K312+FS23 的汽车通用评估板方案
S32K3 系列是 NXP 推出的面向汽车电子和工业应用的微控制器,基于 ARMCortex-M7 内核,支持单核、双核和锁步内核配置。S32K3 系列具有内核、内存和外设数量方面的可扩展性,符合 ISO26262 标准,能达到 ASIL B/D 安全等级,…...
11进阶篇:专业课论文阅读方向指南(2025版)
文章目录 第一个检索式:图情档核心期刊(北大 + CSSCI)发文情况研究方法类关键词研究主题类关键词论文阅读建议第二个检索式:川大公共管理学院在核心期刊(北大 + CSSCI)的发文情况研究方法类关键词研究主题类关键词特点关键词与2024年972(现815)两道题目的映射情况815信…...
Qt之第三方库QXlsx使用(三)
Qt开发 系列文章 - QXlsx(三) 目录 前言 一、Qt开源库 二、QXlsx 1.QXlsx介绍 2.QXlsx下载 3.QXlsx移植 4.修改项目文件.pro 三、使用技巧 1.写入数据 2.读出数据 总结 前言 Qt第三方控件库是指非Qt官方提供的、用于扩展Qt应用程序功能的控件…...
第145场双周赛: 使数组的值全部为 K 的最少操作次数、破解锁的最少时间 Ⅰ、使两个整数相等的位数操作、统计最小公倍数图中的连通块数目
Q1、使数组的值全部为 K 的最少操作次数 1、题目描述 给你一个整数数组 nums 和一个整数 k 。 如果一个数组中所有 严格大于 h 的整数值都 相等 ,那么我们称整数 h 是 合法的 。 比方说,如果 nums [10, 8, 10, 8] ,那么 h 9 是一个 合法…...
AJAX三、XHR,基本使用,查询参数,数据提交,promise的三种状态,封装-简易axios-获取省份列表 / 获取地区列表 / 注册用户,天气预报
一、XMLHttpRequest基本使用 XMLHttpRequest(XHR)对象用于与服务器交互。 二、XMLHttpRequest-查询参数 语法: 用 & 符号分隔的键/值对列表 三、XMLHttpRequest-数据提交 核心步骤 : 1. 请求头 设置 Content-Type 2. 请求体 携带 符合要求 的数…...
Android期末复习题
1.如何搭建Android开发环境? 答案:搭建Android开发环境需要以下几个步骤: (1)下载和安装JDK (2)配置PATH环境变量 (3)下载和安装Android Studio (4)创建A…...
《蓝桥杯比赛规划》
一、比赛简介 蓝桥杯全国软件和信息技术专业人才大赛是一项具有较高影响力的编程竞赛,旨在促进软件和信息技术领域专业技术人才的培养,提升高校毕业生的就业竞争力。比赛涵盖了多个编程语言和专业方向,包括 C/C、Java、Python 等。 二、目标…...
三、Zookeeper
Zookeeper 三、Zookeeper3.1什么是zookeeper?3.2为什么需要zookeeper3.3Zookeeper基本运行流程3.4Zookeeper数据模型3.5Zookeeper主要角色3.6Zookeeper工作原理3.7Zookeeper节点数据操作流程三、Zookeeper 3.1什么是zookeeper? ZooKeeper是一个分布式的,开放源码的分布式应…...
Wireshark数据抓包分析之传输层协议(TCP协议)
根据实验环境,本实验的步骤如下: 1.在测试环境使用发包工具和Wireshark抓取TCP三次握手和四次断开的数据包。 2.详细分析TCP协议的三次握手以及四次断开。 任务描述:安装发包工具,并配置TCP客户端,服务端࿰…...
用ai做机器视觉的事情
cnn(卷积神经网络)是典型的ai算法。 我们已经cnn实现像机器视觉中形状匹配的功能,因为使用了roi抠图匹配,所以就叫做roicnn,以区分整图匹配。下面是roicnn笔记总结: 20241022,roicnn搞定&…...
LLM - 开源视觉多模态 LLaVA-CoT(o1) 深度推理模型 测试与源码 教程
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/144304351 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 LLaVA-…...
qtcanpool 知 10:包管理雏形
文章目录 前言痛点转机雏形实践后语 前言 曾听闻:C/Qt 没有包管理器,开发起来太不方便。这是一个有过 node.js 开发经验的人对 Qt 的吐槽。 确实,像 python、golang、node.js 这些编程语言都有包管理器,给用户带来了极佳的开发体…...
[保姆式教程]使用目标检测模型YOLO11 OBB进行旋转目标检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)
之前写了一个基于YOLOv8做旋转目标检测(OBB)的文章,内容写得不够好,内容也有些杂乱无序。现如今YOLO已经更新到11了,数据集也集齐了无人机和卫星的农业大棚,所以这次就写一个基于YOLO11 OBB的农业大棚旋转检…...
MySQL 权限管理分配详解
MySQL 权限管理分配详解 MySQL权限系统的工作原理权限表的存取用户通过权限认证、进行权限分配的流程账号管理我们常用的授权all privileges到底有哪些权限呢?以及带来的安全隐患有哪些?创建账户的时候最好分配指定的权限,这样子安全也高管理…...
【期末速成】《微机原理与接口技术》知识点总结
文章目录 前言第一、二章 接口技术概述1. 接口的定义*2. 接口功能特点*3. 接口的分类*4. 接口中的传输信息及其组成5. 接口的编址与译码*6. CPU 与外设之间的数据传送方式* 第三章 总线1. 总线(BUS)的定义*2. 总线的标准3. 采用标准总线的优点*4. 总线的…...
华为、华三交换机纯Web下如何创关键VLANIF、操作STP参数
华为交换机WEB操作 使用的是真机S5735,目前主流的版本都适用(V1R5~V2R1的就不在列了,版本太老了,界面完全不一样,这里调试线接的console口,电脑的网络接在ETH口) 「模拟器、工具合集」复制整段内…...
【Elasticsearch】初始化默认字段及分词
1、添加分词插件 1)在线安装 执行命令 需要指定相同的版本 bin/elasticsearch-plugin.bat install https://get.infini.cloud/elasticsearch/analysis-ik/7.17.24 2)离线安装 将安装包解压到 /plugins 目录下 安装包可以从对应的资源处下载 启动成…...
asdf-java配置
asdf list all java 无结果 asdf list all java 显示结果 No compatible versions available 解决方案 参考 执行 cp ~/.asdf/plugins/java/data/jdk-macosx-x86_64-ga.tsv $TMPDIR/asdf-java-$(whoami).cache/releases-macosx-x86_64.tsv 在此执行 asdf list all java 就可…...
2-2-18-14 QNX系统架构之 TCP/IP 网络
阅读前言 本文以QNX系统官方的文档英文原版资料为参考,翻译和逐句校对后,对QNX操作系统的相关概念进行了深度整理,旨在帮助想要了解QNX的读者及开发者可以快速阅读,而不必查看晦涩难懂的英文原文,这些文章将会作为一个…...