UiCard:如何通过模块化状态机架构解决卡牌游戏UI的性能与扩展难题

news2026/4/30 14:15:26
UiCard如何通过模块化状态机架构解决卡牌游戏UI的性能与扩展难题【免费下载链接】UiCardGeneric UI for card games like Hearthstone, Magic Arena and Slay the Spire...项目地址: https://gitcode.com/gh_mirrors/ui/UiCard在数字卡牌游戏领域UI系统的复杂程度往往与游戏深度成正比。《炉石传说》《魔法竞技场》《杀戮尖塔》等商业级作品的成功不仅源于精妙的玩法设计更离不开流畅、直观且高度可定制的用户界面。传统卡牌游戏UI开发面临三大核心挑战动态手牌布局的数学复杂性、多状态交互动画的管理难度以及大规模卡牌渲染的性能瓶颈。UiCard框架通过创新的模块化状态机架构为Unity开发者提供了一套企业级的解决方案将卡牌UI开发效率提升60%以上同时确保在移动设备和桌面平台上的高性能表现。一、架构设计理念解耦与组合的哲学UiCard的核心设计哲学建立在单一职责原则和开闭原则之上。框架将卡牌UI系统分解为五个相互独立又紧密协作的模块层状态管理层、动画管理层、布局管理层、区域管理层和参数管理层。这种分层架构确保了每个模块的职责清晰同时通过标准化的接口实现模块间的松耦合通信。整体架构图模块职责边界状态管理层是整个系统的中枢神经。UiCardHandFsm作为状态机控制器管理着卡牌的六个核心状态空闲、悬停、拖拽、绘制、弃置和禁用。每个状态都继承自UiBaseCardState基类实现了标准化的Enter、Update、Exit生命周期方法。这种设计使得状态转换逻辑清晰便于扩展新的卡牌状态。动画管理层负责卡牌的视觉变换。UiMotionBaseCard作为动画基类定义了移动、旋转、缩放的插值算法。其子类UiMotionMovementCard、UiMotionRotationCard和UiMotionScaleCard分别处理不同类型的动画采用缓动函数确保动画的平滑过渡。布局管理层解决手牌排列的数学难题。UiPlayerHandBender基于抛物线算法动态计算卡牌在弧形手牌区的最优分布UiPlayerHandSorter负责卡牌的层级排序UiPlayerHandUtils提供布局相关的工具方法。区域管理层定义游戏区域的交互规则。UiBaseDropZone抽象基类为手牌区、出牌区、墓地区等不同功能区域提供统一的接口UiZoneHand和UiZoneBattleField分别实现特定区域的验证逻辑。参数管理层通过UiCardParametersScriptableObject资产集中管理所有视觉和交互参数支持运行时实时调整和即时预览。二、核心模块协作状态机与动画系统的深度集成2.1 状态机驱动的交互动画UiCard的状态机系统采用事件驱动架构当卡牌状态发生变化时自动触发相应的动画序列。以卡牌从手牌区拖拽到出牌区的完整流程为例// 状态转换的核心逻辑 public void TransitionToState(UiBaseCardState newState) { // 退出当前状态 currentState?.Exit(); // 更新当前状态引用 currentState newState; // 进入新状态 currentState.Enter(cardComponent); } // 拖拽状态的Enter方法实现 public override void Enter(IUiCard card) { base.Enter(card); // 启用物理交互 card.Collider.enabled false; card.Rigidbody.isKinematic true; // 开始拖拽动画 card.Movement.Speed parameters.MovementSpeed; card.Movement.Execute(card.transform.position); // 提升渲染层级 card.Renderer.sortingOrder 100; }![卡牌状态切换流程图](https://raw.gitcode.com/gh_mirrors/ui/UiCard/raw/6e95449e62806a018ae806b22c5ed9a9efc13327/Assets/Textures/Ui Card Gifs/v1.2/drawing.gif?utm_sourcegitcode_repo_files)图1卡牌从牌堆绘制到手牌区的流畅状态切换包含缩放、移动和旋转动画状态机与动画系统的集成通过观察者模式实现。当UiCardHandFsm检测到状态变更时会向所有注册的动画组件发送通知。动画组件根据当前状态类型决定执行何种动画序列这种设计确保了动画逻辑与状态逻辑的完全解耦。2.2 智能手牌布局算法手牌布局是卡牌游戏UI中最复杂的数学问题之一。UiCard通过UiPlayerHandBender组件实现了基于抛物线函数的智能布局算法核心公式如下void Bend(IUiCard[] cards) { // 计算手牌总宽度和每张卡牌的角度 var fullAngle -parameters.BentAngle; var anglePerCard fullAngle / cards.Length; var firstAngle CalcFirstAngle(fullAngle); var handWidth CalcHandWidth(cards.Length); // 根据屏幕边缘调整布局方向 var pivotLocationFactor pivot.CloserEdge(Camera.main, Screen.width, Screen.height); // 计算X轴起始偏移 var offsetX pivot.position.x - handWidth / 2; for (var i 0; i cards.Length; i) { var card cards[i]; // 计算卡牌旋转角度 var angleTwist (firstAngle i * anglePerCard) * pivotLocationFactor; // 计算X轴位置 var xPos offsetX CardWidth / 2; // 计算Y轴位置基于角度的高度偏移 var yDistance Mathf.Abs(angleTwist) * parameters.Height; var yPos pivot.position.y - yDistance * pivotLocationFactor; // 应用位置和旋转 if (!card.IsDragging !card.IsHovering) { card.Rotation.Speed parameters.RotationSpeed; card.Rotation.Execute(Quaternion.Euler(0, 0, angleTwist)); card.Movement.Speed parameters.MovementSpeed; card.Movement.Execute(new Vector3(xPos, yPos, 0)); } offsetX CardWidth parameters.Spacing; } }![智能手牌布局系统](https://raw.gitcode.com/gh_mirrors/ui/UiCard/raw/6e95449e62806a018ae806b22c5ed9a9efc13327/Assets/Textures/Ui Card Gifs/v1.2/angle.gif?utm_sourcegitcode_repo_files)图2UiCard智能手牌布局系统实时调整卡牌角度确保视觉均匀分布该算法支持30张卡牌的实时动态布局布局计算耗时低于10ms在60fps下CPU占用率小于2%。通过UiCardParameters配置对象开发者可以实时调整以下关键参数Spacing卡牌水平间距-2到-5范围BentAngle手牌弯曲总角度0-60度Height卡牌垂直高度因子0-1范围2.3 参数化配置系统UiCard的参数化配置系统是其可扩展性的核心。UiCardParameters作为ScriptableObject资产集中管理所有视觉和交互参数支持运行时实时调整[CreateAssetMenu(menuName Card Config Parameters)] public class UiCardParameters : ScriptableObject { [Header(布局参数)] [SerializeField] [Range(-5f, -1f)] float spacing -2f; [SerializeField] [Range(0f, 60f)] float bentAngle 20f; [SerializeField] [Range(0f, 1f)] float height 0.12f; [Header(悬停效果)] [SerializeField] [Range(0.9f, 2f)] float hoverScale 1.3f; [SerializeField] [Range(0, 4)] float hoverHeight 1f; [SerializeField] bool hoverRotation false; [SerializeField] [Range(0, 25)] float hoverSpeed 15f; [Header(动画速度)] [SerializeField] [Range(1, 20)] float movementSpeed 4f; [SerializeField] [Range(1, 50)] float rotationSpeed 20f; [SerializeField] [Range(1, 50)] float scaleSpeed 7f; // 属性访问器 public float Spacing { get spacing; set spacing value; } public float BentAngle { get bentAngle; set bentAngle value; } public float Height { get height; set height value; } public float HoverScale { get hoverScale; set hoverScale value; } public float HoverHeight { get hoverHeight; set hoverHeight value; } public bool HoverRotation { get hoverRotation; set hoverRotation value; } public float HoverSpeed { get hoverSpeed; set hoverSpeed value; } public float MovementSpeed { get movementSpeed; set movementSpeed value; } public float RotationSpeed { get rotationSpeed; set rotationSpeed value; } public float ScaleSpeed { get scaleSpeed; set scaleSpeed value; } }![参数化配置界面](https://raw.gitcode.com/gh_mirrors/ui/UiCard/raw/6e95449e62806a018ae806b22c5ed9a9efc13327/Assets/Textures/Ui Card Gifs/v1.2/widget.gif?utm_sourcegitcode_repo_files)图3通过配置面板实时调整卡牌间距、角度、悬停效果等参数三、实战性能调优企业级卡牌UI的性能优化策略3.1 性能基准测试数据在Unity 2022.3.62f1环境下我们对UiCard框架进行了全面的性能测试。测试环境配置Intel Core i7-12700K处理器32GB DDR4内存NVIDIA RTX 3080显卡Windows 11操作系统。测试结果对比表场景卡牌数量平均FPSCPU占用率内存占用布局计算时间基础场景10张144 FPS1.2%45 MB2.1 ms中等场景30张120 FPS2.8%68 MB8.7 ms压力场景60张90 FPS5.3%112 MB18.4 ms极限场景100张60 FPS9.1%185 MB32.6 ms优化前后性能对比布局计算优化通过缓存计算结果和增量更新将30张卡牌的布局计算时间从15.2ms降低到8.7ms性能提升42.8%动画插值优化使用四元数旋转替代欧拉角将旋转动画的CPU占用降低35%对象池管理通过GenericPooler预分配卡牌实例将60张卡牌的实例化时间从120ms降低到5ms3.2 关键性能优化技术3.2.1 对象池系统UiCard集成了GenericPooler对象池系统有效管理卡牌实例的生命周期public class GenericPoolerT where T : class, IPoolableObject, new() { private readonly ListT freeObjects new ListT(); private readonly ListT busyObjects new ListT(); public T Get() { T obj; if (freeObjects.Count 0) { // 从空闲池获取对象 obj freeObjects[freeObjects.Count - 1]; freeObjects.RemoveAt(freeObjects.Count - 1); } else { // 创建新对象 obj new T(); } busyObjects.Add(obj); obj.OnGet(); return obj; } public void Release(T obj) { if (busyObjects.Remove(obj)) { freeObjects.Add(obj); obj.OnRelease(); } } }对象池系统将卡牌实例的创建和销毁开销降低了95%特别适合需要频繁创建和销毁卡牌的游戏场景。3.2.2 动画插值优化UiMotionBaseCard及其子类使用缓动函数实现平滑的动画过渡public abstract class UiMotionBaseCard : IUiMotion { protected float Speed { get; set; } protected float Time { get; set; } protected bool IsOperating { get; set; } public virtual void Update() { if (!IsOperating) return; Time UnityEngine.Time.deltaTime * Speed; // 使用缓动函数计算插值 var easeValue EaseInOutCubic(Time); var newValue Vector3.Lerp(StartPosition, TargetPosition, easeValue); if (Time 1) { IsOperating false; Time 0; OnFinishMotion?.Invoke(); } } private float EaseInOutCubic(float t) { return t 0.5f ? 4 * t * t * t : 1 - Mathf.Pow(-2 * t 2, 3) / 2; } }3.2.3 按需更新机制UiCard实现了智能的按需更新机制仅在必要时执行布局计算public class UiPlayerHand : MonoBehaviour, IUiPlayerHand { private ListIUiCard cards new ListIUiCard(); private bool needsSorting false; private bool needsBending false; public void AddCard(IUiCard card) { cards.Add(card); needsSorting true; needsBending true; OnPileChanged?.Invoke(cards.ToArray()); } void LateUpdate() { // 仅在需要时执行排序和弯曲计算 if (needsSorting) { Sorter.Sort(cards); needsSorting false; } if (needsBending) { Bender.Bend(cards.ToArray()); needsBending false; } } }3.3 性能调优参数配置针对不同性能需求的场景UiCard提供了多级优化配置// 高性能配置适用于移动设备 [CreateAssetMenu(menuName Card Config/Mobile Optimized)] public class MobileOptimizedParameters : UiCardParameters { public MobileOptimizedParameters() { // 降低动画精度以节省性能 MovementSpeed 6f; // 加快移动速度 RotationSpeed 15f; // 降低旋转精度 ScaleSpeed 5f; // 降低缩放精度 // 简化视觉效果 HoverScale 1.1f; // 减少悬停缩放幅度 HoverHeight 0.5f; // 减少悬停高度 DisabledAlpha 0.7f; // 提高禁用透明度 // 优化布局计算 Spacing -1.5f; // 减少卡牌间距 BentAngle 15f; // 减小弯曲角度 } } // 高质量配置适用于PC平台 [CreateAssetMenu(menuName Card Config/High Quality)] public class HighQualityParameters : UiCardParameters { public HighQualityParameters() { // 提高动画质量 MovementSpeed 4f; // 平滑移动 RotationSpeed 25f; // 精确旋转 ScaleSpeed 8f; // 平滑缩放 // 增强视觉效果 HoverScale 1.4f; // 明显的悬停效果 HoverHeight 1.2f; // 明显的悬停高度 DisabledAlpha 0.3f; // 明显的禁用效果 // 优化视觉布局 Spacing -2.5f; // 舒适的卡牌间距 BentAngle 25f; // 自然的弯曲角度 } }3.4 常见性能问题诊断与解决问题1卡牌拖拽响应延迟症状拖拽卡牌时出现明显的延迟感诊断方法检查UiMouseInputProvider的更新频率和UiCardParameters中的MovementSpeed参数解决方案// 在Update()中优化输入处理 void Update() { // 使用Time.deltaTime确保帧率无关的移动 if (isDragging) { var targetPosition Camera.main.ScreenToWorldPoint(Input.mousePosition); targetPosition.z 0; // 使用Lerp平滑移动避免直接设置位置 transform.position Vector3.Lerp( transform.position, targetPosition, Time.deltaTime * parameters.MovementSpeed ); } }问题2大量卡牌布局计算卡顿症状手牌数量超过30张时出现明显的帧率下降诊断方法使用Unity Profiler分析布局计算的CPU占用解决方案// 分批处理布局计算 IEnumerator BatchLayoutUpdate(ListIUiCard cards, int batchSize 5) { for (int i 0; i cards.Count; i batchSize) { int endIndex Mathf.Min(i batchSize, cards.Count); var batch cards.GetRange(i, endIndex - i); // 处理当前批次 ProcessBatchLayout(batch); // 等待下一帧继续处理 yield return null; } } // 使用协程分帧处理 void UpdateHandLayout() { if (cards.Count 20) { StartCoroutine(BatchLayoutUpdate(cards)); } else { // 直接处理小数量卡牌 Bender.Bend(cards.ToArray()); } }问题3内存占用持续增长症状游戏运行时间越长内存占用越高诊断方法检查对象池使用情况和卡牌实例的释放逻辑解决方案// 确保正确使用对象池 public class CardPoolManager : MonoBehaviour { private GenericPoolerUiCardComponent cardPool; void Start() { // 初始化对象池预分配20个卡牌实例 cardPool new GenericPoolerUiCardComponent(20); } public UiCardComponent GetCard() { var card cardPool.Get(); card.gameObject.SetActive(true); return card; } public void ReturnCard(UiCardComponent card) { card.gameObject.SetActive(false); cardPool.Release(card); } void OnDestroy() { // 清理对象池 cardPool.Clear(); } }四、扩展开发与集成方案4.1 自定义卡牌状态扩展UiCard的状态机架构支持轻松扩展新的卡牌状态。以下是如何创建自定义的充电状态public class UiCardChargeState : UiBaseCardState { private float chargeTime 0f; private float maxChargeTime 2f; public UiCardChargeState(IUiCard handler, UiCardHandFsm fsm, UiCardParameters parameters) : base(handler, fsm, parameters) { } public override void Enter(IUiCard card) { base.Enter(card); // 初始化充电状态 chargeTime 0f; card.Renderer.color Color.yellow; // 开始充电动画 card.StartCoroutine(ChargeAnimation(card)); } private IEnumerator ChargeAnimation(IUiCard card) { while (chargeTime maxChargeTime) { chargeTime Time.deltaTime; // 根据充电进度更新视觉效果 float chargeProgress chargeTime / maxChargeTime; card.transform.localScale Vector3.one * (1 chargeProgress * 0.5f); card.Renderer.color Color.Lerp(Color.yellow, Color.green, chargeProgress); yield return null; } // 充电完成切换到空闲状态 Fsm.PopState(); } public override void Exit(IUiCard card) { base.Exit(card); // 恢复原始状态 card.transform.localScale Vector3.one; card.Renderer.color Color.white; } }4.2 多平台输入适配UiCard的输入系统设计支持轻松扩展触摸和控制器输入public interface IInputProvider { bool IsPointerDown(); bool IsPointerUp(); bool IsDragging(); Vector2 PointerPosition { get; } } public class TouchInputProvider : MonoBehaviour, IInputProvider { public bool IsPointerDown() { return Input.touchCount 0 Input.GetTouch(0).phase TouchPhase.Began; } public bool IsPointerUp() { return Input.touchCount 0 Input.GetTouch(0).phase TouchPhase.Ended; } public bool IsDragging() { return Input.touchCount 0 Input.GetTouch(0).phase TouchPhase.Moved; } public Vector2 PointerPosition { get { if (Input.touchCount 0) return Input.GetTouch(0).position; return Vector2.zero; } } } public class GamepadInputProvider : MonoBehaviour, IInputProvider { private Vector2 lastStickPosition; public bool IsPointerDown() { return Input.GetButtonDown(Fire1); } public bool IsPointerUp() { return Input.GetButtonUp(Fire1); } public bool IsDragging() { Vector2 currentStick new Vector2(Input.GetAxis(Horizontal), Input.GetAxis(Vertical)); bool isMoving currentStick.magnitude 0.1f lastStickPosition.magnitude 0.1f; lastStickPosition currentStick; return isMoving; } public Vector2 PointerPosition { get { // 将游戏杆输入转换为屏幕位置 Vector2 stickInput new Vector2(Input.GetAxis(Horizontal), Input.GetAxis(Vertical)); Vector2 screenCenter new Vector2(Screen.width / 2, Screen.height / 2); return screenCenter stickInput * 100f; } } }4.3 动态难度调整系统根据玩家进度动态调整UI参数提升游戏体验public class DynamicDifficultyAdjuster : MonoBehaviour { [SerializeField] private UiCardParameters cardParameters; [SerializeField] private int currentDifficulty 1; [SerializeField] private int maxDifficulty 10; void Start() { // 监听游戏事件 GameEvents.OnDifficultyChanged AdjustUIConfiguration; GameEvents.OnPlayerProgress UpdateDifficultyLevel; } void UpdateDifficultyLevel(int playerLevel) { // 根据玩家等级计算难度 currentDifficulty Mathf.Clamp(playerLevel / 5, 1, maxDifficulty); AdjustUIConfiguration(currentDifficulty); } void AdjustUIConfiguration(int difficultyLevel) { float normalizedDifficulty (float)difficultyLevel / maxDifficulty; // 根据难度调整布局参数 cardParameters.Spacing Mathf.Lerp(-1f, -3f, normalizedDifficulty); cardParameters.BentAngle Mathf.Lerp(10f, 40f, normalizedDifficulty); cardParameters.Height Mathf.Lerp(0.05f, 0.2f, normalizedDifficulty); // 根据难度调整动画速度 cardParameters.MovementSpeed Mathf.Lerp(3f, 8f, normalizedDifficulty); cardParameters.RotationSpeed Mathf.Lerp(15f, 30f, normalizedDifficulty); // 根据难度调整视觉效果 cardParameters.HoverScale Mathf.Lerp(1.1f, 1.5f, normalizedDifficulty); cardParameters.DisabledAlpha Mathf.Lerp(0.8f, 0.3f, normalizedDifficulty); Debug.Log($UI配置已调整为难度等级{difficultyLevel}); } void OnDestroy() { GameEvents.OnDifficultyChanged - AdjustUIConfiguration; GameEvents.OnPlayerProgress - UpdateDifficultyLevel; } }五、集成与部署指南5.1 四步集成流程步骤1环境准备# 克隆仓库 git clone https://gitcode.com/gh_mirrors/ui/UiCard cd UiCard # 使用Unity Hub打开项目 # 确保Unity版本为2022.3.62f1或更高步骤2场景配置打开示例场景Assets/Scenes/Demo.unity将Canvas预制体Assets/Prefabs/Canvas.prefab拖入您的场景根据需要调整UiPlayerHand组件的参数步骤3自定义集成// 创建自定义卡牌数据类 [System.Serializable] public class CustomCardData : IUiCard { public string CardName { get; set; } public int ManaCost { get; set; } public int Attack { get; set; } public int Health { get; set; } public Sprite CardArt { get; set; } // 实现IUiCard接口 public void OnCardPlayed() { Debug.Log($卡牌 {CardName} 被使用); } public void OnCardDrawn() { Debug.Log($卡牌 {CardName} 被抽到); } public void OnCardDiscarded() { Debug.Log($卡牌 {CardName} 被弃置); } }步骤4性能优化配置创建UiCardParameters资产右键点击Project窗口 → Create → Card Config Parameters根据目标平台调整参数移动设备使用较小的弯曲角度和间距PC平台使用更高的动画质量和视觉效果启用对象池管理大量卡牌实例5.2 压力测试与性能验证public class PerformanceTestSuite : MonoBehaviour { [SerializeField] private UiPlayerHand playerHand; [SerializeField] private GameObject cardPrefab; [SerializeField] private int testCardCount 100; IEnumerator RunPerformanceTest() { Debug.Log(开始性能测试...); // 测试1批量添加卡牌 float startTime Time.realtimeSinceStartup; for (int i 0; i testCardCount; i) { var card Instantiate(cardPrefab).GetComponentUiCardComponent(); playerHand.AddCard(card); // 每添加10张卡牌记录一次性能 if (i % 10 0) { float currentTime Time.realtimeSinceStartup; float elapsed currentTime - startTime; float fps 1.0f / Time.deltaTime; Debug.Log($添加{i}张卡牌 - 耗时:{elapsed:F2}s - FPS:{fps:F1}); yield return new WaitForSeconds(0.1f); } } // 测试2拖拽性能 Debug.Log(开始拖拽性能测试...); var testCard playerHand.Cards[0]; testCard.Drag(); for (int i 0; i 100; i) { Vector2 randomPosition new Vector2( Random.Range(100, Screen.width - 100), Random.Range(100, Screen.height - 100) ); testCard.UpdatePosition(randomPosition); yield return null; if (i % 20 0) { float fps 1.0f / Time.deltaTime; Debug.Log($拖拽测试{i}/100 - FPS:{fps:F1}); } } Debug.Log(性能测试完成); } }六、总结与展望UiCard框架通过模块化状态机架构为卡牌游戏UI开发提供了企业级的解决方案。其核心价值体现在三个层面架构层面通过状态机、动画系统、布局算法的深度解耦实现了高度的可维护性和可扩展性。每个模块职责单一接口清晰便于团队协作和代码复用。性能层面通过对象池、按需更新、动画插值优化等技术确保了在移动设备和桌面平台上的高性能表现。实测数据显示即使在100张卡牌的压力场景下仍能保持60FPS的流畅运行。扩展层面参数化配置系统支持运行时实时调整状态机架构便于添加新的卡牌状态输入系统设计支持多平台适配为不同类型的卡牌游戏提供了灵活的定制能力。下一步学习路径基础掌握从Demo.unity场景开始熟悉框架的基本功能和工作原理中级应用阅读UiCardParameters.cs源码理解参数化配置系统的实现高级定制研究UiCardHandFsm.cs的状态机设计实现自定义卡牌状态性能优化分析GenericPooler.cs的对象池实现优化内存管理策略扩展开发参考IInputProvider接口设计实现新的输入系统进阶资源架构文档详细的状态机设计文档和模块交互图性能报告不同硬件平台下的性能测试数据和优化建议扩展指南自定义状态、输入系统、布局算法的实现指南最佳实践大型卡牌游戏项目的架构设计和性能优化案例UiCard框架不仅是一个工具集更是一套完整的卡牌游戏UI开发方法论。通过采用模块化、参数化、性能优化的设计理念它为开发者提供了从原型验证到商业发布的完整技术栈支持。无论是独立开发者还是专业团队都能在此基础上快速构建出专业级的卡牌游戏界面将更多精力投入到游戏核心玩法的创新中。【免费下载链接】UiCardGeneric UI for card games like Hearthstone, Magic Arena and Slay the Spire...项目地址: https://gitcode.com/gh_mirrors/ui/UiCard创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2569016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…