当前位置: 首页 > news >正文

游戏引擎学习第23天

实时代码编辑功能的回顾

当前实现的实时代码编辑功能已经取得了显著的成功,表现出强大的性能和即时反馈能力。该功能允许开发者在修改代码后几乎立即看到变化在运行中的程序中体现出来,极大提升了开发效率。尽管目前的演示内容较为简单,呈现的是一个玩具性质的小程序,而不是一个完整的游戏,但已能清晰展示实时反馈的效果。

目前,工作的重心主要放在平台代码的开发和支持游戏在Windows平台上运行的相关功能上。因此,尚未进入具体游戏内容的开发阶段。接下来的工作将转向开发一个更复杂、更完整的游戏系统,随着每个阶段的推进,游戏内容的实现将逐步完善。

然而,当游戏开发进入实际阶段时,情况将会变得更加复杂。例如,玩家输入(如角色移动)将引入更多动态的交互,这可能会影响实时反馈的效果。游戏的运行逻辑和系统复杂性可能会对实时代码编辑功能的表现带来一定的限制。因此,计划创建一个小型的演示,以直观展示在更复杂环境下实时代码编辑的实际表现,并分析可能会遇到的挑战。

这些挑战并非源自实时代码编辑功能本身,而是游戏系统本身复杂性带来的自然结果。尽管如此,当前的实现已经在质量和性能上达到了非常高的水准,并且相比市面上的其他类似工具,毫不逊色,甚至表现得更加出色。

构建一个演示来展示游戏调整工作流

整体目标是通过此次演示展示当前技术的巨大潜力,并为未来在更加复杂的应用环境中应用该技术做好准备。

目前的代码编辑状态已经很好,但目标是进一步改进,让它变得更出色。希望能够达到一种效果,使用者看到之后,可能再也不愿意使用其他工具。

为了演示这个改进的效果,首先需要通过一些用户输入来进行展示。目标是通过这种方式来观察系统如何响应并进行调整。

计划是在现有的游戏代码框架中增加一个非常简单的功能,模拟一个玩家在某个位置的情景。可以通过随机选择一个位置来初始化玩家的位置,而不去深思熟虑,目的是简单地展示效果。

接着,开发者将继续利用现有的控制器代码,处理非模拟的输入。通过模拟控制器的输入,玩家的行为会根据输入值做出响应,甚至不关心实际的细节,只是计算结果并进行渲染。

此时,尽管渲染代码还未完善,演示代码会使用一个临时的渲染函数,称为“渲染玩家”。这个函数会展示一个简单的图形(如矩形),代表玩家的位置,目的是确保画面上有元素显示出来。

尽管当前代码结构相当草率且不完美,但它能够帮助演示预期效果,并且为后续的渲染功能奠定基础。最初的代码逻辑并不复杂,只是通过简单的轴循环来调整位置,快速地在屏幕上绘制出代表玩家的矩形图形,展示玩家是否按预期行为移动。

目前,代码并未完善,可能会在玩家移动超出窗口范围时崩溃,但这不影响整体目的,因为最终目标是通过代码的逐步调整和完善,确保系统能够有效应对更复杂的输入与渲染需求。

在这里插入图片描述

添加跳跃功能

为了实现一个简单的跳跃机制,可以按照以下流程进行:

  1. 初始状态和条件设定
    创建一个表示跳跃状态的变量,例如JumpTimerPlayerVelocity,用于跟踪玩家的跳跃时间或速度。这些变量将帮助确定玩家是否正在跳跃以及跳跃的持续时间。

  2. 跳跃触发逻辑
    在按下跳跃按钮时设置相关状态。例如,将JumpTimer设置为特定值(如1秒),或者将PlayerVelocity设置为初始向上的速度。

  3. 跳跃的动态效果
    在每帧中更新这些状态:

    • 如果使用JumpTimer,每帧减少其值,直到归零。
    • 如果使用PlayerVelocity,根据帧时间逐渐减少速度(模拟重力)。
  4. 屏幕更新
    玩家的位置会根据这些状态在每帧更新。例如,如果使用PlayerVelocity,则每帧增加玩家的Y坐标(向上或向下移动)。

  5. 重力作用
    在每帧中模拟重力效果,使玩家能够自然地从跳跃到达的最高点回到地面。

  6. 边界处理
    检查玩家是否落到地面,并在到达地面时重置状态,例如将JumpTimer清零或将PlayerVelocity设为零。

实现跳跃的简单代码示例:

以下是一个基于上述逻辑的伪代码:

// 初始化玩家状态
float PlayerY = 0;          // 玩家当前的 Y 坐标
float PlayerVelocity = 0;   // 玩家当前的速度
bool IsJumping = false;     // 玩家是否正在跳跃// 在按下跳跃键时触发
void OnJumpButtonPressed() {if (!IsJumping) {       // 确保玩家没有处于跳跃状态PlayerVelocity = -10.0f; // 初始跳跃速度,负值表示向上IsJumping = true;       // 设置为跳跃状态}
}// 每帧更新逻辑
void Update(float DeltaTime) {if (IsJumping) {// 更新位置,根据速度移动玩家PlayerY += PlayerVelocity * DeltaTime;// 应用重力影响PlayerVelocity += 9.8f * DeltaTime;// 碰到地面时停止跳跃if (PlayerY >= 0) {PlayerY = 0;       // 确保位置在地面上IsJumping = false; // 重置跳跃状态}}
}

流程中的思考:

  • 初始跳跃速度可以调整以实现更高或更低的跳跃。
  • 重力加速度影响玩家回落的速度,可以进行调试以达到所需的平滑效果。
  • 可以添加额外的动画或粒子效果,使跳跃更加生动。

代码调试与迭代:

  1. 确保跳跃键的输入响应正确。
  2. 调整跳跃参数(如速度、重力),获得更合理的跳跃轨迹。
  3. 处理边界情况(如地面检测、防止跳出屏幕)。

总结:

这种方法将跳跃实现分解为触发、动态更新和状态检查三个主要步骤,逐步优化,实现自然的跳跃体验。
在这里插入图片描述

总结与复述:

为了实现更好的游戏体验,代码需要解决玩家越界的问题,并优化跳跃逻辑。在开发过程中,遇到了多个挑战,包括确保玩家在屏幕范围内运动、实现准确的跳跃效果以及简化测试和调试的流程。以下是逐步进行的尝试和优化:


1. 防止玩家越界:
  • 当玩家移动到屏幕边界之外时,需要确保不会发生越界错误。
  • 添加了逻辑来检测玩家的位置是否超出屏幕范围(上下左右),如果超出范围,就将玩家位置调整到屏幕内对应的位置。
2. 简化代码以避免内存错误:
  • 修改了像素指针的逻辑,确保任何写入操作都在有效的缓冲区范围内。
  • 引入了缓冲区大小的限制条件,计算时使用了屏幕宽度、高度和每像素字节数,避免越界访问内存。

3. 调试跳跃逻辑:
  • 跳跃通过一个定时器变量控制,模拟玩家的垂直运动曲线。
  • 添加了条件逻辑:
    • 仅在跳跃定时器 (tJump) 大于零时执行跳跃相关逻辑。
    • 防止定时器未初始化或跳跃状态不符合预期导致的异常行为。
  • 修复了跳跃方向的错误(例如跳跃向下而非向上),通过检查符号并更改对应的逻辑实现正确的运动效果。

4. 测试中的挑战:
  • 调试需要频繁切换代码和游戏测试:
    • 修改代码后需要重新加载程序。
    • 使用手柄测试行为,观察跳跃或其他动作是否按预期工作。
    • 若某些状态(如敌人或道具)在测试中被破坏,则需重新初始化或手动恢复相关状态。
  • 这种测试流程复杂且繁琐,尤其当多个状态需要同时被验证时。

5. 提出优化解决方案:
  • 为提高开发效率,建议构建类似音乐编辑工具中的循环编辑器:
    • 允许开发者录制一次操作,并重复播放操作。
    • 在调试代码时,自动执行这些操作,使得调试更加流畅。
    • 避免手动恢复测试状态或重复执行相同的测试步骤。

通过这些优化,代码的鲁棒性和测试效率可以显著提升,使开发过程更加直观和高效,同时减少不必要的错误和重复劳动。

更新方块的位置和边界检查

  // 更新方块的水平位置,根据手柄的左右摇杆输入GameState->PlayerX += (int)(4.0f * Controller->StickAverageX);// 更新方块的垂直位置,根据手柄的上下摇杆输入GameState->PlayerY -= (int)((4.0f * Controller->StickAverageY));// 如果方块当前垂直位置大于0,模拟跳跃的垂直运动if (GameState->PlayerY > 0) {GameState->PlayerY -= (int)(10.0f * sinf(GameState->tJump));  // 向上跳跃} else {GameState->PlayerY += (int)(10.0f * sinf(GameState->tJump));  // 向下移动,处理边界情况}// 如果跳跃按钮被按下,重置跳跃时间计时器if (Controller->ActionDown.EndedDown) {GameState->tJump = 1.0;  // 重置跳跃时间,开始新的跳跃}// 减少跳跃时间,控制跳跃曲线的时间步长GameState->tJump -= 0.033f;// 处理水平位置越界情况,使方块从另一侧回到屏幕内if (GameState->PlayerX < 0) {GameState->PlayerX += Buffer->Width;  // 从屏幕左侧越界后移到右侧}if (GameState->PlayerX > Buffer->Width) {GameState->PlayerX -= Buffer->Width;  // 从屏幕右侧越界后移到左侧}// 处理垂直位置越界情况,使方块从另一侧回到屏幕内if (GameState->PlayerY < 0) {GameState->PlayerY += Buffer->Height;  // 从屏幕顶部越界后移到底部}if (GameState->PlayerY > Buffer->Height) {GameState->PlayerY -= Buffer->Height;  // 从屏幕底部越界后移到顶部}}// 渲染渐变效果,根据蓝色和绿色偏移量调整颜色RenderWeirdGradient(Buffer, GameState->BlueOffset, GameState->GreenOffset);// 渲染方块RenderPlayer(Buffer, GameState->PlayerX, GameState->PlayerY);std::cout << "GameState->PlayerY = " << GameState->PlayerY << "DELTA"<< Buffer->Height - GameState->PlayerY << std::endl

为代码创建一个循环编辑器

总结与复述:

构建一个类似于循环编辑器的工具,用于代码开发和调试,是为了简化复杂的调试流程。这种工具的核心思想是记录和重复输入数据,使开发者能够高效地测试代码,而无需手动重现所有的操作。


工具设计的核心概念:
  1. 游戏架构的简化:

    • 游戏逻辑集中在一个主要函数中,该函数负责更新和渲染。
    • 主要依赖三个输入:
      • 游戏状态(从内存中读取)。
      • 当前帧的输入(如按键、手柄状态)。
      • 绘制目标缓冲区(用于渲染输出)。

    这种模块化设计使得任何修改或测试只需关注函数的输入和输出,避免了不必要的复杂性。

  2. 输入的记录与反馈:

    • 每帧的输入数据(例如控制器状态或按键)被记录下来,保存在一个队列或数组中。
    • 调试时,可以通过回放这些记录的输入数据来复现操作,而无需实时操作手柄或键盘。
  3. 减少声音模块的干扰:

    • 为了专注于核心游戏逻辑的调试,声音输出被隔离。
    • 仅保留更新和渲染的逻辑部分,用于测试和优化,声音部分可以稍后独立测试。

实现的基本思路:
  1. 输入记录模块:

    • 在每次调用更新函数前,记录输入数据(如控制器状态、鼠标移动、按键)。
    • 通过一个数据结构(如数组、链表)存储这些输入帧。
  2. 回放机制:

    • 在调试过程中,将记录的输入数据依次回放。
    • 通过模拟的输入流代替实时的物理输入,将这些数据传递给更新函数。
  3. 循环执行:

    • 工具能够不断重复回放这些记录的输入帧,从而让开发者专注于调试代码逻辑,而无需手动操作手柄或键盘。
    • 如果需要调整输入,可以修改记录的输入数据,甚至可以插入或删除帧。

优点:
  • 高效测试: 通过循环回放相同的操作序列,可以快速调试复杂逻辑,避免手动重复操作。
  • 可追溯性: 每一帧的输入都被完整记录,可以随时回溯,发现问题的根源。
  • 扩展性强: 这种记录和回放机制可以用于调试其他模块(如物理模拟、AI行为)。

通过这样的工具,代码开发过程变得更加流畅和高效,可以更好地定位和修复问题,同时减少了繁琐的重复性劳动。

储存输入流到内存的简便性

总结与复述:

为了实现代码调试中高效的输入记录与回放机制,可以通过简单的结构化设计来捕获和管理输入数据。这一设计旨在确保调试过程顺畅,同时易于实现和扩展。


输入记录机制的核心:
  1. 输入数据的捕获:

    • 将输入数据(例如按键状态、控制器动作)设计成一个平面化的结构。
    • 简化数据类型和格式,使其适合直接存储和操作。
  2. 结构化记录:

    • 引入一个输入流结构来保存输入信息。该结构可能包括:
      • 输入数组,用于存储所有记录的输入。
      • 输入计数器,跟踪当前存储了多少帧的输入。
  3. 记录过程:

    • 在每帧更新中,将输入数据捕获并存储到输入流结构中。
    • 例如,输入流会逐帧记录按键或控制器状态,将其依次填入输入数组。
  4. 回放机制:

    • 当需要重现输入时,从输入流中逐一提取记录的数据。
    • 以逐帧的方式将这些输入重新传递给游戏逻辑,使游戏状态与记录时一致。

输入记录与回放的实现:
  • 定义结构:

    • 设计一个结构体来存储输入流和计数器,例如:
      struct InputStream {InputType Inputs[MAX_INPUTS]; // 输入数组int InputCount;              // 已存储输入的数量
      };
      
  • 记录输入:

    • 在游戏的更新函数中,每帧采集输入信息,并存储到 InputStream 的数组中,同时更新计数器。
      if (InputStream.InputCount < MAX_INPUTS) {InputStream.Inputs[InputStream.InputCount++] = CurrentInput;
      }
      
  • 回放输入:

    • 当需要重现操作时,从 InputStream 的数组中提取数据,并依次传递给更新函数。
      if (ReplayIndex < InputStream.InputCount) {CurrentInput = InputStream.Inputs[ReplayIndex++];
      }
      

优点:
  1. 简单高效:
    • 记录和回放机制只涉及基本的数据存储和读取操作,易于实现且运行高效。
  2. 灵活性高:
    • 可以根据需求扩展输入流的功能,例如添加暂停、快进或编辑输入数据的能力。
  3. 调试友好:
    • 重现复杂场景的能力简化了调试工作,让开发者能够快速验证和调整逻辑。

通过这样的方法,可以大幅优化开发过程中的调试体验,使得开发者能够更高效地发现问题并进行调整。

在这里插入图片描述

将输入写入磁盘

总结与复述:

在实现输入记录与回放的功能时,结合文件 I/O 提供更灵活和持久的解决方案。以下是详细设计和思路:


文件 I/O 的引入:
  1. 记录到文件:

    • 输入数据不仅可以存储在内存中,也可以直接记录到文件中。
    • 通过文件保存,记录的数据可以在程序关闭后仍然可用,从而实现永久保存。
  2. 文件的读写:

    • 利用基本的文件 I/O 操作,可以将输入流保存到磁盘上,随后在需要时从文件中加载回放。
    • 这种方式避免了内存占用过多的问题,同时提供了更灵活的调试和分析能力。

实现方案:
  1. 记录和回放的状态管理:

    • 设置变量来管理记录和回放的状态,例如:
      • RecordingIndex:表示当前是否处于记录状态。
      • PlayingIndex:表示当前是否处于回放状态。
    • 当这些变量为零时,表示未进行记录或回放;非零值则指向当前记录或回放的槽位。
  2. 数据流管理:

    • 在记录时,将每帧的输入数据写入文件,形成连续的输入流。
    • 在回放时,从文件中逐帧读取记录的数据,模拟真实的输入。
  3. 伪代码实现:

    • 记录逻辑:
      if (RecordingIndex > 0) {WriteToFile(RecordingFile, CurrentInput);
      }
      
    • 回放逻辑:
      if (PlayingIndex > 0) {CurrentInput = ReadFromFile(PlaybackFile);
      }
      
    • 状态切换:
      if (StartRecording) {RecordingIndex = 1; // 开始记录OpenFileForWrite(RecordingFile);
      }
      if (StartPlayback) {PlayingIndex = 1; // 开始回放OpenFileForRead(PlaybackFile);
      }
      

优点与扩展:
  1. 灵活性:

    • 文件 I/O 方式不仅支持调试,还可以用于存储预定义的输入序列,例如用于自动测试或重现问题。
  2. 可扩展性:

    • 支持多条记录流,通过不同的槽位 (RecordingIndexPlayingIndex) 管理多个文件。
    • 例如,可以同时记录玩家的操作和游戏的输出。
  3. 简易实现:

    • 设计清晰,逻辑简单,易于在现有框架中集成。

通过这种方法,可以高效地记录和回放输入数据,并利用文件持久化特性为开发和调试提供更大的便利和支持。

创建一个可以传递的 win32_state 结构

总结与复述:

在设计和组织代码时,尝试将一些处理逻辑集中化,以便提高代码的清晰性和可维护性,同时减少冗余和重复。这主要涉及以下几个方面的思路:


键盘处理的集中化:
  1. 当前问题:

    • 键盘处理逻辑散布在代码的不同部分,导致结构零散,不易管理。
    • 想要将这些逻辑整合起来,使其能够集中影响相关的全局状态。
  2. 解决方案:

    • 引入一个统一的数据结构(如 struct),将键盘处理相关的状态和逻辑封装到一个模块中。
    • 这样可以在程序中更方便地传递和管理这些状态,同时简化接口设计。

数据结构设计:
  1. 封装状态:

    • 创建一个结构体(如 StateStruct),其中包含:
      • 全局键盘输入状态。
      • 其他可能的全局属性,例如窗口状态或鼠标输入。
  2. 模块化的好处:

    • 统一管理: 将相关的全局属性整合到一个结构体中,便于维护和扩展。
    • 简化传递: 通过一个结构体参数,可以避免多个函数调用时传递过多的独立参数。
  3. 伪代码示例:

    struct StateStruct {KeyboardState keyboard; // 键盘输入状态MouseState mouse;       // 鼠标输入状态(如果需要)GlobalFlags flags;      // 其他全局标志
    };// 初始化全局状态
    StateStruct AppState;// 在键盘处理函数中,更新状态
    void ProcessKeyboardInput(StateStruct* state) {state->keyboard = GetKeyboardInput();
    }// 在其他模块中,直接使用封装的状态
    void Render(StateStruct* state) {if (state->flags.someCondition) {DrawSomething();}
    }
    

代码清理与传递:
  1. 目的:

    • 将所有相关的处理逻辑封装起来,使得代码的功能分布更加明确,同时便于扩展和重用。
  2. 实现方式:

    • 定义一个统一入口函数,用于初始化并更新全局状态。
    • 在需要的地方直接传递封装的 StateStruct,避免重复调用和分散管理。
  3. 示例逻辑:

    • 集中化操作:

      void UpdateState(StateStruct* state) {ProcessKeyboardInput(state);ProcessMouseInput(state); // 如果需要处理鼠标UpdateFlags(state);       // 更新全局标志
      }
      
    • 使用状态:

      void MainLoop() {UpdateState(&AppState);Render(&AppState);
      }
      

总结:

通过引入统一的状态结构体,可以有效解决逻辑分散的问题,并提高代码的可读性、可扩展性和模块化程度。这种方法适用于需要管理复杂状态的场景,尤其是在处理多输入、多模块交互时,能够显著优化程序的整体结构。

按 “L” 键开始录制

总结与复述

在代码设计中,为了实现通过按键操作来录制和回放输入,设计了一个简单的输入管理机制,核心思路如下:


功能目标:
  1. 输入录制与回放:

    • 允许通过按键切换录制状态,并将输入记录到特定的存储槽中。
    • 实现通过简单的按键操作开始或停止录制,同时可以回放录制的内容。
  2. 基本按键交互逻辑:

    • 按下某键(如 L)后,进入录制模式。
    • 按下数字键(如 1)选择要录制到的槽。
    • 再次按下 L 停止录制。
    • 按下对应的数字键开始回放选定槽的内容。

逻辑实现:
  1. 状态管理:

    • 使用一个变量(如 input_recording_index)来记录当前录制的槽索引。
      • 初始值为 0,表示未在录制模式。
      • 值为 1(或其他槽编号)时,表示录制正在进行,目标为对应槽。
    • 当录制结束时,将索引值重置为 0
  2. 按键事件的处理:

    • 按下 L 键:
      • 如果当前未录制(input_recording_index == 0),进入录制模式并设置槽索引。
      • 如果当前正在录制(input_recording_index != 0),停止录制。
    • 按下数字键(如 1):
      • 选择目标槽开始录制或回放。
    • 状态切换为“录制”或“回放”时,程序会根据状态进行逻辑处理。
  3. 伪代码示例:

    // 状态变量
    int input_recording_index = 0; // 当前录制槽索引
    int input_playback_index = 0; // 当前回放槽索引// 按键事件处理
    void HandleKeyPress(int key) {if (key == 'L') {if (input_recording_index == 0) {input_recording_index = 1; // 开始录制到槽1} else {input_recording_index = 0; // 停止录制}}else if (key >= '1' && key <= '9') {int slot = key - '0'; // 获取按下的数字键对应的槽编号if (input_recording_index != 0) {// 开始录制到对应槽StartRecording(slot);} else {// 开始回放对应槽StartPlayback(slot);}}
    }
    
  4. 逻辑流程:

    • 按下 L:切换录制状态。
    • 按下数字键:在录制模式下,指定目标槽;在非录制模式下,开始回放对应槽的输入。

改进与扩展:
  1. 结构封装:

    • 使用结构体(如 InputState)管理录制与回放相关的变量,便于扩展和代码组织:
      struct InputState {int recording_index; // 当前录制槽索引int playback_index;  // 当前回放槽索引bool is_recording;   // 是否处于录制状态bool is_playing;     // 是否处于回放状态
      };InputState state;
      
  2. 增加其他功能:

    • 增加更多快捷键(如暂停、快进)。
    • 支持多个槽的独立管理。
    • 添加输入保存到文件的功能,便于长期存储或加载。

总结:

通过这种设计,可以实现一种简单直观的输入录制和回放机制。基于按键切换的逻辑,使得操作简单清晰,同时为未来扩展更多功能奠定了良好基础。

实现录制和回放功能

这是一段关于实现一个输入记录与回放系统的详细说明,涵盖了其基本逻辑、实现细节和相关流程。


输入记录与回放系统概述

1. 输入记录
  • 触发条件
    • 系统检测输入状态,例如“Win32State”(可能是某种状态标识),并检查是否有一个标志(如 on)表明录音功能已启用。
  • 记录操作
    • 在录功能启用时,调用特定函数(如“Win32RecordInput”)以记录当前输入数据。
    • 系统将记录刚刚收到的输入,将其存储在某个结构中(如文件或内存块)。
  • 覆盖逻辑
    • 如果有新的输入到来,将覆盖先前的记录数据。这确保输入记录总是最新的。

2. 输入回放
  • 触发条件
    • 检查系统状态,例如某种条件是否满足回放要求。
  • 回放操作
    • 系统从先前存储的输入流中读取历史数据,并将其设置为当前输入。
    • 此过程通过文件句柄或内存访问完成,将新输入替换为回放数据。

记录与回放的实现细节

写入逻辑
  1. 文件句柄初始化
    • 定义用于记录的文件句柄(如“记录句柄”)和用于回放的文件句柄(如“回放句柄”)。
    • 在操作前,确保文件句柄正确打开。
  2. 写入操作
    • 通过文件句柄将输入数据写入目标文件。
    • 输入数据的大小根据其结构动态确定。
    • 写入操作完成后无需关注写入字节数,因为即使失败也会被视为一个简单的调试问题。
读取逻辑
  1. 读取操作
    • 使用文件句柄从目标文件中读取数据。
    • 数据大小根据记录时的结构确定。
  2. 回放实现
    • 将读取的数据作为当前输入进行处理。
    • 回放逻辑与写入逻辑几乎相同,只是从文件读取而不是写入文件。

核心流程描述

  1. 记录输入

    • 检测是否有新输入到来。
    • 通过记录句柄将新输入数据写入文件。
    • 输入数据的大小由其结构定义,确保所有输入都被正确存储。
  2. 回放输入

    • 检测触发条件(例如某种状态标识)。
    • 使用回放句柄从文件中读取历史数据。
    • 读取的数据会覆盖当前输入,作为新的输入流。

系统功能总结

  • 模块化设计
    • 录音和回放被分为两个独立的逻辑单元。
  • 高效性
    • 写入和读取操作简单直接,利用文件句柄和动态内存大小进行高效数据处理。
  • 可扩展性
    • 逻辑设计支持对状态的进一步扩展,例如实现循环播放功能或多种状态切换。

此系统通过文件句柄的管理实现对输入的记录与回放,设计上追求简单高效,确保在实际操作中能够稳定运行。

处理录制输出文件的函数

这是描述如何实现一个用于记录和回放输入的系统,并细化了在实际操作中如何启动、停止录音和回放的过程。

关键功能与操作流程

1. 录音开始
  • 开始录音

    • 需要在开始录音时获取文件句柄。
    • 文件句柄的创建涉及到打开一个文件并赋予写入权限,确保系统可以将输入数据写入文件。
    • 通过文件句柄执行操作时,文件的名字和权限设置都非常重要,确保文件能够被正确打开和写入。
  • 命名与文件创建

    • 录音的文件名称需要一致性,虽然在命名时可能有些困惑,但最终会根据情况选择合适的命名方式。
    • 系统在每次开始录音时,都会创建或打开一个文件,并且需要为该文件分配一个唯一的标识符(如录音句柄)。
  • 写入数据

    • 在录音过程中,录音数据将通过文件句柄写入文件。系统需要处理数据的传输和文件操作,确保数据能够正确保存。
2. 停止录音并回放
  • 录音结束

    • 停止录音时,系统需要关闭文件句柄,确保录音操作的完整性,并保存数据。
    • 一旦停止录音,系统将通过执行 close handle 操作来关闭文件。
  • 回放操作

    • 如果需要回放,系统会从文件中读取先前保存的录音数据。回放操作与录音过程类似,但它是从文件中读取数据,而不是写入。
3. 状态管理
  • 录音与回放的状态切换

    • 当系统处于录音状态时,会开始记录输入。如果系统没有录音,用户可以发出命令让系统开始录音。
    • 如果系统已经在录音中,可以切换到回放模式,通过简单的状态管理切换输入模式。
  • 文件句柄的管理

    • 系统使用文件句柄来管理录音数据的存储和读取。在录音开始时创建文件句柄,在录音结束时关闭句柄。整个过程中,文件句柄确保了数据存取的正确性。
4. 过程总结
  • 系统通过打开和关闭文件句柄,管理录音和回放过程中的数据存储和读取。
  • 开始录音时,系统创建文件并赋予写入权限,输入数据通过文件句柄写入。结束时关闭文件句柄。
  • 回放时,从文件读取数据并进行回放,确保数据的流畅读取和处理。

主要步骤

  1. 创建文件句柄
    • 打开文件句柄并赋予写入权限。
  2. 开始录音
    • 系统开始录制输入数据并将其写入文件。
  3. 停止录音
    • 系统停止录音并关闭文件句柄。
  4. 回放
    • 系统通过文件句柄读取录音数据并进行回放。

通过这些步骤,系统能够实现录音与回放的基本功能,并能根据需要在两者之间切换,确保流程的简洁与高效。

处理读取录制文件的函数

在实现录音和回放功能时,需要处理两个核心功能:录音开始与停止以及回放的启动与操作。以下是详细的分解和总结。


功能实现概述

1. 文件句柄与命名风格的一致性
  • 文件句柄的创建和命名对于系统的整体一致性和代码可读性非常重要。
  • 存在命名风格的不一致问题,例如“Playback”和“PlayBack”可能同时出现,这会引发困惑和管理问题。
  • 需要定义明确的风格指南,特别是在涉及功能名称、变量或文件名的情况下。

2. 录音功能
  • 创建录音文件句柄

    • 为了开始录音,需要创建一个新的文件句柄并赋予写入权限。
    • 此文件句柄用于将输入数据实时保存到指定的录音文件中。
    • 使用 CreateFile 函数时,需要确保设置正确的写入权限。
  • 录音操作

    • 在开始录音时,输入的数据会通过录音文件句柄被写入文件中。
    • 录音结束时,需要关闭文件句柄以确保数据完整写入。

3. 回放功能
  • 打开回放文件句柄

    • 回放功能需要读取先前录制的文件,因此文件句柄必须以只读方式打开。
    • 打开回放文件句柄时,系统需要确保文件是存在的,否则将提示错误。
  • 回放操作

    • 回放过程中,数据从文件中逐步读取,并以某种形式(如流式传输)进行输出。
    • 由于读取的文件是只读的,因此无需担心数据被意外修改。

4. 状态切换
  • 录音与回放的切换

    • 按特定的触发条件(例如按下某个键)时,系统在录音和回放之间切换。
    • 如果当前在录音模式下,触发时会停止录音并关闭句柄,同时开始回放。
    • 如果当前在回放模式下,触发时会停止回放并重新进入录音模式。
  • 逻辑流程

    • 当触发录音时,系统初始化一个新的文件句柄并启动录音。
    • 当停止录音时,文件句柄被关闭,录音文件被锁定。
    • 当触发回放时,系统打开录音文件并读取内容以进行播放。

代码设计和操作流程

录音函数的实现
  • 函数名称BeginRecordingInput
    • 初始化录音操作,创建文件句柄,并将其赋予写入权限。
  • 主要逻辑
    • 检查文件句柄是否已被打开。
    • 如果未打开,则调用 CreateFile 创建一个新的文件句柄。
    • 开始录制输入数据并写入文件。
  • 停止录音
    • 通过关闭文件句柄结束录音操作。
回放函数的实现
  • 函数名称BeginPlaybackInput
    • 打开一个现有文件句柄,设置为只读权限,并准备进行数据读取。
  • 主要逻辑
    • 检查回放文件是否存在。
    • 如果存在,则打开文件并读取内容。
    • 按照回放逻辑将数据逐步输出。
  • 停止回放
    • 在读取完成或触发停止条件时关闭文件句柄。

示例流程

  1. 开始录音
    • 按下录音键,调用 BeginRecordingInput 创建文件句柄。
    • 开始写入数据。
  2. 停止录音
    • 按下停止键,关闭文件句柄,结束录音。
  3. 开始回放
    • 调用 BeginPlaybackInput 打开文件句柄并读取数据。
    • 将读取的内容逐步输出。
  4. 停止回放
    • 按下停止键,关闭文件句柄,结束回放。

总结

实现录音和回放功能的核心在于:

  • 通过文件句柄管理录音文件的读写操作。
  • 在录音和回放之间进行有效的状态切换。
  • 维护一致的命名风格,以提升代码的清晰度和可维护性。

这一切结合在一起,为录音与回放提供了一个稳健的实现基础。

添加代码以循环播放输入回放

在实现输入回放的功能时,需要重点解决循环回放的问题,以及当文件操作或回放操作失败时的处理方式。以下是详细的复述与总结。


功能描述与逻辑实现

1. 循环回放的核心逻辑
  • 在回放阶段,如果操作失败(例如到达文件末尾或读取出错),系统需要检测并处理。
  • 当回放失败时,如果启用了循环回放功能,系统需要关闭当前的回放文件句柄并重新开始回放。
  • 这种逻辑通过模拟停止和重新开始回放实现,目的是在技术上实现循环行为。

2. 输入回放的状态管理
  • 回放状态索引:系统需要一个变量(例如 inputPlayingIndex)来跟踪回放的当前进度。

  • 停止与重启的过程

    • 在回放失败时,模拟停止操作以清理资源(如关闭句柄)。
    • 然后重新开始操作,将状态重置到起点,实现循环。
  • 操作步骤

    1. 检查当前回放是否失败。
    2. 调用停止回放函数,关闭文件句柄。
    3. 调用重新开始回放函数,重新初始化句柄和状态。

3. 文件句柄的管理
  • 关闭与重置句柄
    • 当回放结束或停止时,需要确保相关句柄被正确关闭,避免资源泄漏。
    • 在重新开始时,需重新打开文件句柄。
  • 区分输入模式
    • 录音操作与回放操作对应不同的文件句柄与权限(写入权限用于录音,只读权限用于回放)。

4. 函数实现与逻辑优化
  • 终止回放操作

    • 停止回放时,需要将相关的状态变量(如 inputPlayingIndex)重置为初始值(通常为零)。
    • 同时关闭文件句柄以释放资源。
  • 重新启动回放

    • 调用初始化函数重新开始回放,并从起始点重新读取文件内容。
    • 这种处理方式确保回放能够循环进行。

5. 代码管理与一致性
  • 变量命名与风格

    • 对函数和变量的命名需要统一,避免出现混乱的风格(如 PlaybackPlayBack 的混用)。
    • 统一的命名风格能够提升代码的可读性和可维护性。
  • 清理冗余代码

    • 在实现过程中可能出现粘贴代码导致的多余操作,需要定期检查和清理。

示例逻辑与操作流程

  1. 回放阶段的逻辑

    • 系统检测当前是否正在回放输入数据。
    • 如果读取失败且启用了循环回放,则触发停止回放。
    • 重新调用开始回放函数,从文件起点重新开始。
  2. 停止回放操作

    • 调用结束回放函数,关闭相关句柄。
    • 将回放索引 inputPlayingIndex 重置为零。
  3. 重新开始回放

    • 重新初始化文件句柄和回放状态。
    • 开始从文件起点读取内容。

总结

通过以下步骤实现循环回放和错误处理:

  1. 检测回放失败的条件。
  2. 模拟停止并清理资源。
  3. 重新开始回放,从文件起点继续。

在此过程中,代码结构和命名的一致性对逻辑清晰度至关重要,需尽可能避免冗余和风格混乱。最终,这种实现为系统提供了稳定且可循环的输入回放功能。

测试录制和回放功能

在调试和验证输入记录与回放功能时,一些关键细节被逐步解决并完善。以下是详细复述和总结:


为了确保输入记录和回放正常工作,需要进一步分析整个过程。首先,通过断点调试,验证了输入被正确记录,并在游戏运行期间输出到文件。这一功能在实现时耗时很短,只需约十分钟。这说明,只要系统架构设计合理,这样的功能并不复杂。

对于实现记录与回放,以下步骤进行了详细操作:

  1. 输入记录

    • 当激活输入记录时,将当前输入数据写入到一个文件中。文件被成功创建后,输入每帧的字节数被准确写入。
  2. 回放机制

    • 触发回放后,系统读取输入文件的内容并模拟这些输入操作,表现出之前记录的行为。
  3. 关键问题修复

    • 调试时发现一个问题,即未能正确区分输入事件(按下或释放),导致录制和回放功能触发两次。通过添加对输入状态的判断逻辑,这一问题被解决。
  4. 循环逻辑

    • 为了实现输入循环,需要确保当文件读取到末尾时能够重新开始读取。这一功能通过检测文件读取状态并在必要时重置为初始位置来实现。
  5. 游戏状态保存

    • 除了输入,游戏的整体状态也需要在回放期间正确还原。为此,整个游戏的内存被分配到一个固定的虚拟地址块。这样,游戏状态的保存与恢复变得非常高效,仅需简单地存储或加载这一内存块即可。
  6. 架构的优势

    • 此设计的优势在于不需要复杂的序列化过程,也无需专门管理指针和数据的状态。由于虚拟地址块固定,指针仍然有效,所有的数据结构都能被正确恢复,完全无缝。

总结

这一系列操作展示了高效输入记录和回放系统的实现方式。核心在于简化存储和加载过程,利用固定的虚拟地址块以保持数据完整性,同时避免冗长的序列化流程。虽然过程看似简单,但背后体现了严谨的架构设计理念。这不仅提升了开发效率,也为系统功能扩展打下了坚实基础。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

透明窗口

在这里插入图片描述

在Windows应用程序中,WS_EX_TOPMOSTWS_EX_LAYERED 是窗口的扩展样式(extended styles),而 SetLayeredWindowAttributes 用于设置窗口的透明度和颜色透明度。下面是对这些概念的详细解释和它们如何一起工作:

1. WS_EX_TOPMOST (最顶层窗口样式)

  • 作用: 设置窗口为最顶层窗口,使该窗口始终位于其他所有非最顶层窗口之上。即使用户切换到其他程序或窗口,带有 WS_EX_TOPMOST 样式的窗口也会保持在最前面。
  • 使用场景: 适用于需要始终保持可见的窗口,例如任务栏、系统通知窗口等。
  • 使用方法:
    SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_TOPMOST);
    

2. WS_EX_LAYERED (分层窗口样式)

  • 作用: 使窗口成为分层窗口。分层窗口允许你控制窗口的透明度、透明颜色、混合模式等。通常,配合 SetLayeredWindowAttributes 函数使用,可以使窗口部分或完全透明。
  • 使用场景: 用于需要透明或半透明效果的窗口,如浮动工具栏、透明背景窗口等。
  • 使用方法:
    SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
    

3. SetLayeredWindowAttributes (设置分层窗口属性)

  • 作用: 用于设置分层窗口的透明度和颜色键。通过该函数,你可以设置窗口的透明度级别(alpha 值),以及指定一个透明颜色。SetLayeredWindowAttributes 需要在窗口启用了 WS_EX_LAYERED 样式之后才能调用。
  • 参数:
    • hwnd: 要设置的窗口句柄。
    • crKey: 颜色键,通常设置为 RGB(0, 0, 0)(黑色),意味着黑色区域将变得透明。
    • bAlpha: 透明度值(0 到 255),0 表示完全透明,255 表示完全不透明。
    • dwFlags: 控制透明度和颜色键的标志。常用的标志是 LWA_COLORKEYLWA_ALPHA
      • LWA_COLORKEY: 设置 crKey 为透明色。
      • LWA_ALPHA: 设置 bAlpha 为透明度。
  • 使用场景: 适用于使窗口部分透明、全透明或具有透明背景的情况。
  • 使用方法:
    SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 255, LWA_ALPHA);
    
    这里,RGB(0, 0, 0) 表示黑色,255 表示完全不透明,LWA_ALPHA 表示使用 bAlpha 来设置透明度。

组合使用的效果

  • WS_EX_TOPMOST + WS_EX_LAYERED:

    • 使用这两个扩展样式,你可以创建一个总是位于其他窗口之上的透明或半透明窗口。例如,可以使用这种方式实现一个总是显示在最前面且有一定透明度的窗口,如游戏界面和浮动工具栏等。
    • 示例:
      // 设置为最顶层窗口
      SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_TOPMOST);// 设置为分层窗口
      SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);// 设置透明度(例如透明度为50%)
      SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 128, LWA_ALPHA);
      
  • SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 255, LWA_ALPHA):

    • 这个调用将使窗口完全不透明。RGB(0, 0, 0) 表示透明颜色为黑色(通常不会影响窗口本身,因为我们设置的是不透明),而 255 表示完全不透明。

总结

  • WS_EX_TOPMOST 使窗口始终位于其他窗口之上。
  • WS_EX_LAYERED 使窗口支持透明效果。
  • SetLayeredWindowAttributes 控制窗口的透明度和颜色键,配合 WS_EX_LAYERED 使用。透明度通过 bAlpha 参数控制,颜色透明通过 crKeyLWA_COLORKEY 控制。

使用这三个功能组合,你可以创建具有透明效果并始终位于其他窗口之上的特殊窗口,这在许多应用场景(如透明桌面窗口、系统工具等)中非常有用。

相关文章:

游戏引擎学习第23天

实时代码编辑功能的回顾 当前实现的实时代码编辑功能已经取得了显著的成功&#xff0c;表现出强大的性能和即时反馈能力。该功能允许开发者在修改代码后几乎立即看到变化在运行中的程序中体现出来&#xff0c;极大提升了开发效率。尽管目前的演示内容较为简单&#xff0c;呈现…...

0基础学java之Day25

Vector /** 知识点&#xff1a;Vector独有的方法 理解&#xff1a; * Vector在JDK1.0开始就已经存在 -- 元老级别的集合类&#xff0c; * 集合框架的概念是JDK1.2开始才有的&#xff0c; * 开发人员为了将Vector保留下来&#xf…...

android集成FFmpeg步骤以及常用命令,踩坑经历

1、入坑第一步:首先集成的库必须正确。最好是有ndk的,FFmpeg有许多个版本,我才开始接触的时候随便选了一个,一般的 方法没有问题。但是涉及到需要使用libx264等条件进行编码时,老是报错,网上搜索资料也没有人说需要ndk的支持才行。这个问题困扰了好几天,怎么试不行,最后…...

Mac——鼠标增强插件Mos

功能说明&#xff1a; 能够解决鼠标断续、不灵敏等鼠标问题。 下载地址&#xff1a; Mac——鼠标增强插件Mos...

【c++篇】:解读Set和Map的封装原理--编程中的数据结构优化秘籍

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.set和map的初步封装1.树的节点封装修改2.Find()查找函数3.红…...

华为鸿蒙内核成为HarmonyOS NEXT流畅安全新基座

HDC2024华为重磅发布全自研操作系统内核—鸿蒙内核&#xff0c;鸿蒙内核替换Linux内核成为HarmonyOS NEXT稳定流畅新基座。鸿蒙内核具备更弹性、更流畅、更安全三大特征&#xff0c;性能超越Linux内核10.7%。 鸿蒙内核更弹性&#xff1a;元OS架构&#xff0c;性能安全双收益 万…...

ArcGIS API for Javascript学习

一、ArcGIS API for Javascript 介绍 ArcGIS API for Javascript 是由美国 Esri 公司推出&#xff0c;跟随ArcGIS 9.3 同时发布的&#xff0c;是Esri 基于dojo 框架和 REST 风格实现的一套编程接口。通过 ArcGIS API for Javascript可以对ArcGIS for Server 进行访问&#xff…...

LeetCode 3206.交替组 I:遍历

【LetMeFly】3206.交替组 I&#xff1a;遍历 力扣题目链接&#xff1a;https://leetcode.cn/problems/alternating-groups-i/ 给你一个整数数组 colors &#xff0c;它表示一个由红色和蓝色瓷砖组成的环&#xff0c;第 i 块瓷砖的颜色为 colors[i] &#xff1a; colors[i] …...

环形缓冲区

什么是环形缓冲区 环形缓冲区,也称为循环缓冲区或环形队列,是一种特殊的FIFO(先进先出)数据结构。它使用一块固定大小的内存空间来缓存数据,并通过两个指针(读指针和写指针)来管理数据的读写。当任意一个指针到达缓冲区末尾时,会自动回绕到缓冲区开头,形成一个"环"。…...

Maven 仓库

Maven 仓库对于管理构建 Java 项目所需的依赖和插件至关重要。 Maven 仓库主要有三种类型&#xff1a;本地仓库、中央仓库和远程仓库。 本文将探讨每种仓库的用途以及如何有效使用它们。 Maven 仓库类型 本地仓库 本地仓库是位于您本地机器上的一个目录&#xff0c;Maven 在…...

29.UE5蓝图的网络通讯,多人自定义事件,变量同步

3-9 蓝图的网络通讯、多人自定义事件、变量同步_哔哩哔哩_bilibili 目录 1.网络通讯 1.1玩家Pawn之间的同步 1.2事件同步 1.3UI同步 1.4组播 1.5变量同步 1.网络通讯 1.1玩家Pawn之间的同步 创建一个第三人称项目 将网络模式更改为监听服务器&#xff0c;即将房主作为…...

计算机网络习题解答--个人笔记(未完)

本篇文章为关于《计算机网络-自顶向下方法第七版》的阅读总结和课后习题解答(未完待续) 第二章&#xff1a; cookie&#xff1a;&#xff08;这里是比较老版本的HTTP&#xff0c;具体HTTPs是怎么实现的不是很清楚&#xff09;cookie的原理其实很简单。就是在HTTP消息头上又多…...

Unity图形学之雾Fog

1.设置雾化&#xff1a; 2.雾化变化曲线&#xff1a;FogMode &#xff08;1&#xff09;线性&#xff1a; &#xff08;2&#xff09;一次指数&#xff1a; &#xff08;3&#xff09;二次指数&#xff1a; Shader "Custom/FogTest" {Properties{_Color ("Color…...

ML 系列:第 36 节 — 统计学中的抽样类型

ML 系列&#xff1a;第 36 天 — 统计学中的抽样类型 文章目录 一、说明二、抽样方法三、简单随机抽样四、 Stratified Sampling分层抽样五、 Cluster Sampling 整群抽样六、Systematic Sampling系统抽样七、Convenience Sampling便利抽样八、结论 一、说明 统计学中的抽样类型…...

docker-compose部署java服务

文章目录 一、下载安装docker-compose二、编写Dockerfile文件三、编写docker-compose.yml文件配置说明 四、服务启动五、测试与验证 一、下载安装docker-compose 在安装docker时&#xff0c;并不会同时把docker-compose安装好&#xff0c;需要额外安装一下 下载docker-compos…...

ubuntu22开机自动登陆和开机自动运行google浏览器自动打开网页

一、开机自动登陆 1、打开settings->点击Users 重启系统即可自动登陆桌面 二、开机自动运行google浏览器自动打开网页 1、安装google浏览器 sudo wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo dpkg -i ./google-chrome-stable…...

java接口对接标准

概述 最近在跟许多外部平台对接&#xff0c;遇到了很多问题&#xff0c;在此记录一下接口的对接标准。 接口对接标准 确认环境&#xff0c;分别获取di和prd环境的接口信息&#xff0c;比如域名。确认不同环境的防火墙是否连通。接口校验&#xff0c;接口携带的token信息如何…...

训练的decoder模型文本长度不一致,一般设置为多大合适,需要覆盖最长的文本长度么

在训练解码器模型时,文本长度不一致是常见的情况,需要根据任务的特性和数据集的长度分布来设置合理的最大长度 (max_length)。以下是一些指导原则,帮助你设置合适的最大长度: 1. 是否需要覆盖最长文本长度 覆盖最长文本长度: 如果任务对完整性要求很高(例如生成数学公式、…...

安装MySQL服务

安装版本MySQL8的安装包 安装界面 在这里选择MySQL中的Server only 只安装服务器端 如果选择custom需要如下图 进入配置导向&#xff0c;点击ready to configure&#xff0c;点击next即可 采用默认形式 执行成功后&#xff0c;会出现自动选择项 点击next然后再点击Finish 启动…...

十二、正则表达式、元字符、替换修饰符、手势和对话框插件

1. 正则表达式 1.1 基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&g…...

Unreal从入门到精通之如何绘制用于VR的3DUI交互的手柄射线

文章目录 前言实现方式MenuLaser实现步骤1.Laser和Cursor2.移植函数3.启动逻辑4.检测射线和UI的碰撞5.激活手柄射线6.更新手柄射线位置7.隐藏手柄射线8.添加手柄的Trigger监听完整节点如下:效果图前言 之前我写过一篇文章《Unreal5从入门到精通之如何在VR中使用3DUI》,其中讲…...

如何提升编程能力第二篇

如何提升编程能力2 1. 引言2. 掌握理论基础2.1 理解编程语言的核心2.2 数据结构与算法2.3 计算机基础与系统设计3.1 多写代码3.2 参与开源项目3.3 开发自己的项目 4. 提高代码质量4.1 代码风格与可读性4.2 测试驱动开发 1. 引言 编程是推动现代科技发展的核心技能&#xff0c;…...

【AI日记】24.11.26 聚焦 kaggle 比赛

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 核心工作 1 内容&#xff1a;研究 kaggle 比赛时间&#xff1a;3 小时 核心工作 2 内容&#xff1a;学习 kaggle 比赛 Titanic - Machine Learning from Disaster时间&#xff1a;4 小时备注&#xff1a;这…...

计算机网络八股整理(一)

计算机网络八股文整理 一&#xff1a;网络模型 1&#xff1a;网络osi模型和tcp/ip模型分别介绍一下 osi模型是国际标准的网络模型&#xff0c;它由七层组成&#xff0c;从上到下分别是&#xff1a;应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff0c;…...

删除链表中的重复元素

删除链表中的重复元素 单链表的创建和使用删除链表中的重复元素 I题目描述解题思路代码实现 删除链表中的重复元素 II题目描述解题思路代码实现 单链表的创建和使用 使用vector结合单链表数据结构创建一个通用单链表。 #include <iostream> #include <vector>str…...

序列求和 牛客网

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 定义S(n) 12 22 … n2&#xff0c;输出S(n) % 1000000007。 注意&#xff1a;1 < n < 1e18。 输入描述: 多组输入&#xff0c;输入直到遇到EOF为止&#xff1b;第一行输…...

【Oracle11g SQL详解】 SELECT 语句的基础用法与示例

SELECT 语句的基础用法与示例 在 Oracle 11g 中&#xff0c;SELECT 语句是最常用的 SQL 语句&#xff0c;用于从数据库表中查询数据。本文将从语法结构、使用方法和常见示例出发&#xff0c;系统讲解 SELECT 语句的基础用法。 一、SELECT 语句的基本语法 SELECT 列名1, 列名2…...

编译以前项目更改在x64下面时报错:函数“PVOID GetCurrentFiber(void)”已有主体

win32下面编译成功&#xff0c;但是x64报错 1>GetWord.c 1>md5.c 这两个文件无法编译 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\winnt.h(24125,1): error C2084: 函数“PVOID GetCurrentFiber(void)”已有主体 1>C:\Program Files (x…...

【小白学机器学习36】关于独立概率,联合概率,交叉概率,交叉概率和,总概率等 概念辨析的例子

目录 1 先说结论 2 联合概率 3 边缘概率 4 (行/列)边缘概率的和 总概率1 5 条件概率 5.1 条件概率的除法公式 5.2 条件概率和联合概率区别 1 先说结论 关于独立概率&#xff0c;联合概率&#xff0c;交叉概率&#xff0c;交叉概率和&#xff0c;总概率 类型含义 …...

如何使用 Tailwind CSS 构建响应式网站:详细指南

文章目录 前言一、安装 Tailwind CSS二、配置 Tailwind CSS三、使用 Tailwind CSS 构建响应式网站四、优化和部署结语 前言 在当今的数字时代&#xff0c;网站不仅需要在桌面浏览器上看起来出色&#xff0c;还需要在移动设备和平板电脑上提供一致的用户体验。响应式设计成为了…...

LabVIEW发动机热磨合试验台

在汽车发动机的研发和质量控制中&#xff0c;发动机热磨合试验是关键环节。它能够检验发动机在实际运行条件下的性能&#xff0c;及时发现异响、振动、漏油等潜在问题。通过搭建基于LabVIEW的高效测试平台&#xff0c;可以显著提高发动机的可靠性和使用寿命。下面介绍LabVIEW开…...

【GPT】力量训练是什么,必要吗,有可以替代的方式吗

什么是力量训练&#xff1f; 力量训练是一种通过抵抗力&#xff08;如重量、阻力带、自身体重等&#xff09;来刺激肌肉收缩&#xff0c;从而提高肌肉力量、耐力和体积的运动形式。它包括以下常见形式&#xff1a; 自由重量训练&#xff1a;使用哑铃、杠铃、壶铃等。固定器械…...

pikachu文件上传漏洞通关详解

声明&#xff1a;文章只是起演示作用&#xff0c;所有涉及的网站和内容&#xff0c;仅供大家学习交流&#xff0c;如有任何违法行为&#xff0c;均和本人无关&#xff0c;切勿触碰法律底线 目录 概念&#xff1a;什么是文件上传漏洞一、客户端check二、MIME type三、getimagesi…...

java hashCode() 详解

hashCode() 是 Java 中 Object 类 提供的一个重要方法&#xff0c;它在 Java 集合框架中扮演着关键角色&#xff0c;特别是在使用哈希表相关的集合&#xff08;如 HashMap、HashSet 和 Hashtable&#xff09;时。以下是对 hashCode() 方法的详解&#xff0c;包括概念、用法、规…...

鸿蒙学习自由流转与分布式运行环境-价值与架构定义(1)

文章目录 价值与架构定义1、价值2、架构定义 随着个人设备数量越来越多&#xff0c;跨多个设备间的交互将成为常态。基于传统 OS 开发跨设备交互的应用程序时&#xff0c;需要解决设备发现、设备认证、设备连接、数据同步等技术难题&#xff0c;不但开发成本高&#xff0c;还存…...

JavaWeb

JavaWeb 一、JavaWeb 是什么&#xff1f;二、JavaWeb 发展阶段三、JavaWeb 常用架构Servlet JSP 架构SSH 架构SSM 架构SpringBoot架构SpringCloud架构 四、JavaWeb 项目结构&#xff08;带web.xml的&#xff09;五、如何打包六、war包部署1. Tomcat 介绍2. Tomcat目录结构3. 开…...

加快发展社会保障事业的必要性

题目 【2011年浙江公务员考试】&#xff08;二&#xff09;某市将召开一次加快发展社会保障事业的形势分析会。会上&#xff0c;某领导要就加快发展社会保障事业的必要性做主题发言。请结合给定资料7~8&#xff0c;为领导拟一份发言要点。&#xff08;25分&#xff09; 要求&a…...

责任链模式在spring security过滤器链中的应用

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许多个对象按照顺序处理请求&#xff0c;并且每个对象可以选择自己是否处理该请求或将其传递给下一个对象。 在Spring Security中&#xff0c;责任链模式得到了广泛应…...

Netty基本原理

目录 前言 原生NIO VS Netty 原生NIO存在的问题 Netty的优点 线程模型 传统阻塞 I/O (Blocking I/O) 2. 非阻塞 I/O (Non-blocking I/O) 3. 多路复用 I/O (Multiplexed I/O) 4. Reactor 模式 常见的 Reactor 模式的变体&#xff1a; Netty线程模型 工作原理 前言 N…...

图论入门编程

卡码网刷题链接&#xff1a;98. 所有可达路径 一、题目简述 二、编程demo 方法①邻接矩阵 from collections import defaultdict #简历邻接矩阵 def build_graph(): n, m map(int,input().split()) graph [[0 for _ in range(n1)] for _ in range(n1)]for _ in range(m): …...

Haproxy

一、haproxy简介 HAProxy 是法国开发者 威利塔罗 (Willy Tarreau) 在 2000 年使用 C 语言开发的一个开源软件 是一款具备高并发 ( 万级以上 ) 、高性能的 TCP 和 HTTP 负载均衡器 支持基于 cookie 的持久性&#xff0c;自动故障切换&#xff0c;支持正则表达式及 web 状态统…...

旋转磁体产生的场 - 实验视频资源下载

先发几个视频&#xff0c;是2019年所作的实验内容 更多视频&#xff0c;到某宝找我吧。注意&#xff1a;是收费的。 20190312-180244-旋转磁体产生的场造成激光功率减小 https://download.csdn.net/download/u014161757/90038058 20190313-090956-旋转磁体产生的场对真空介电…...

Java Map

在Java的集合框架中&#xff0c;Map接口用于存储键值对&#xff0c;提供了一种基于键进行查找和操作的数据结构。Map接口的实现类提供了丰富的方法来操作键值对&#xff0c;例如添加、删除、更新和查找。本文将详细介绍Java中的Map接口及其常见实现类&#xff0c;包括HashMap、…...

长三角文博会:Adobe国际认证体系推动设计人才评价新标准

2024年11月22日&#xff0c;由上海、江苏、浙江、安徽三省一市党委宣传部共同发起的第五届长三角文化博览会&#xff08;简称“长三角文博会”&#xff09;在上海国家会展中心盛大启幕。长三角文博会自2018年起已成功举办多届&#xff0c;已成为展示区域文化产业发展成果、推动…...

GoogleTest做单元测试

目录 环境准备GoogleTest 环境准备 git clone https://github.com/google/googletest.git说cmkae版本过低了&#xff0c;解决方法 进到googletest中 cmake CMakeLists.txt make sudo make installls /usr/local/lib存在以下文件说明安装成功 中间出了个问题就是&#xff0c;…...

CSDN 博客自动发布脚本(Python 含自动登录、定时发布)

文章目录 关于 csdn auto publisher使用 关于 csdn auto publisher 源码地址&#xff1a;https://github.com/ezscode/csdn_auto_publisher 使用 def test_simple_pub():file_path /Users/xx/Documents/xxx/tool.md article Article(file_path) article.tags [python] art…...

RL78/G15 Fast Prototyping Board Arduino IDE 平台开发过程

这是一篇基于RL78/G15 Fast Prototyping Board的Arduino IDE开发记录 RL78/G15 Fast Prototyping Board硬件简介&#xff08;背景&#xff09;基础测试&#xff08;方法说明/操作说明&#xff09;开发环境搭建&#xff08;方法说明/操作说明代码结果&#xff09;Arduino IDE RL…...

VsCode 插件推荐(个人常用)

VsCode 插件推荐&#xff08;个人常用&#xff09;...

零基础学安全--云技术基础

目录 学习连接 前言 云技术历史 云服务 公有云服务商 云分类 基础设施即服务&#xff08;IaaS&#xff09; 平台即服务&#xff08;PaaS&#xff09; 软件即服务&#xff08;SaaS&#xff09; 云架构 虚拟化 容器 云架构设计 组件选择 基础设施即代码 集成部署…...

docker如何安装redis

第一步 如果未指定redis&#xff0c;则安装的是最新版的 docker pull redis 创建一个目录 mkdir /usr/local/docker/redis 然后直接可以下载redis&#xff0c;这是方式确实不怎么好&#xff0c;应该找在官网上找对应的redis配置文件 wget http://download.redis.io/redis-stab…...