Unity游戏开发:基于贝塞尔曲线与对象池的卡牌扇形展开动画实现
1. 项目概述与核心思路最近在复刻《杀戮尖塔》的战斗体验其中一个让我着迷的细节就是它的出牌动画。当玩家点击手牌时卡牌并非简单地消失或平移到目标位置而是会以一种非常优雅的扇形轨迹展开然后飞向敌人。这个看似简单的效果实际上融合了动画、物理和视觉反馈极大地提升了操作的“手感”和策略的“仪式感”。今天我们就来深度拆解如何用Unity实现这个“扇形开牌”效果的第一部分。这个效果的核心目标很明确模拟一叠卡牌在手中被“扇形展开”的视觉过程为后续的飞牌、命中反馈做铺垫。它不适合用简单的位移动画Transform.Translate或线性插值Lerp粗暴完成那样会显得生硬。我们需要的是一个有弧度的、带有一点随机性和物理感的展开动画。经过几轮尝试和优化我最终确定了一套结合贝塞尔曲线、对象池和动画状态机的方案在保证效果惊艳的同时也兼顾了性能即使在移动设备上同时展开十几张牌也毫无压力。2. 核心模块设计与原理拆解实现扇形开牌我们可以将其分解为几个核心的子问题如何计算每张牌的终点位置形成扇形如何让牌沿着一条优美的曲线运动如何管理大量卡牌对象以避免性能开销以及如何让整个动画过程可控且可交互2.1 扇形布局算法从一叠牌到一个弧面首先我们需要一个算法根据手牌数量计算出每张牌在屏幕上的最终展开位置。这个位置集合应该构成一个圆弧。一个直观的方法是使用极坐标。我们可以定义一个“展开中心点”通常是手牌区域底部中央一个“展开半径”以及一个“总展开角度”。每张牌根据其索引分配一个角度然后通过极坐标转直角坐标的公式计算出其世界坐标位置。核心公式如下假设总牌数为cardCount当前牌索引为i从0开始。 总展开角度为totalAngle例如60度那么每张牌之间的角度间隔为angleStep totalAngle / (cardCount - 1)如果只有一张牌则间隔为0。 当前牌的角度为currentAngle -totalAngle / 2 i * angleStep。这样计算可以保证牌组以中心对称的方式展开。 最后世界坐标targetPosition centerPoint Quaternion.Euler(0, 0, currentAngle) * Vector3.right * radius。这里有一个关键细节radius半径不宜是固定值。为了让展开效果更自然我们可以让半径随着牌的数量增加而略微增大模拟手牌较多时展开幅度更大的物理感觉。同时totalAngle也可以根据牌的数量动态调整。实操心得直接计算出的目标位置是“牌的中心点”的位置。在实际摆放时你需要根据卡牌的锚点Pivot进行调整。通常卡牌Sprite的Pivot在中心0.5, 0.5这样计算出来的位置就是牌的中心点。如果你希望牌的下边缘对齐某个基线则需要额外计算偏移。2.2 运动轨迹贝塞尔曲线的魅力确定了起点手牌堆叠处和终点扇形位置后我们需要一条路径让卡牌“飞”过去。直线运动太死板而贝塞尔曲线尤其是二次贝塞尔曲线提供了完美的解决方案。它只需要一个起点P0、一个终点P2和一个控制点P1就能定义一条平滑的弧线。控制点P1的设定是精髓所在。它决定了曲线的弯曲程度和方向。对于扇形展开我们希望牌有一个向上抛起的弧线感。因此控制点可以设置在起点和终点连线的中垂线方向上的某个点。一个简单的策略是P1 (P0 P2) / 2 Vector3.up * curveHeight。 这里的curveHeight是一个可调节的参数控制弧线的“高度”。你可以为每张牌赋予一个微小的随机高度偏移让展开动画更有层次感避免过于机械。运动过程就是对t时间比例从0到1进行插值。二次贝塞尔曲线的公式是B(t) (1-t)^2 * P0 2 * (1-t) * t * P1 t^2 * P2。 在Update函数中我们根据动画的已进行时间与总时间的比例得到t然后计算当前位置并赋值给卡牌的Transform。2.3 性能基石对象池管理在战斗中出牌是高频操作。如果每次展开都实例化Instantiate新的卡牌对象动画结束后又销毁Destroy很快就会产生大量的GC垃圾回收开销导致游戏卡顿。对象池Object Pool是解决这个问题的标准答案。其思想是预先创建或懒加载一定数量的卡牌游戏对象放入一个“池子”如ListGameObject或QueueGameObject中。当需要展示一张牌时从池子里取一个闲置的对象将其激活SetActive(true)并设置到起始位置。当动画结束牌被使用或收起时不是销毁它而是将其失活SetActive(false)并放回池子。我们需要为对象池设计一个简单的管理器它负责初始化池子预加载若干卡牌Prefab。提供GetCard()方法返回一个可用的卡牌对象。提供ReturnCard(GameObject card)方法回收卡牌对象。处理池子容量不足时的动态扩容。避坑指南回收卡牌时务必重置其状态这包括位置、旋转、缩放、以及任何可能影响下次使用的脚本变量例如动画进度t、运动速度等。一个常见的做法是在卡牌对象上挂载一个CardAnimationController脚本该脚本提供一个Reset()方法在回收前调用。忘记重置状态是对象池使用中最常见的Bug来源之一。2.4 动画控制与状态管理每张卡牌的展开动画是一个有生命周期的过程等待 - 开始移动 - 移动中 - 到达终点 - 等待点击。我们需要一个清晰的状态机来管理它。我通常使用一个枚举Enum来定义卡牌动画的状态public enum CardAnimationState { Idle, // 闲置在手中未展开 MovingToFan, // 正在向扇形位置运动 InFan, // 已到达扇形位置等待交互 MovingToTarget, // 被点击后飞向敌人这是下一篇的内容 Discarded // 已被使用等待回收 }在卡牌的控制脚本中有一个CurrentState变量。在Update()函数里根据不同的状态执行不同的逻辑。例如在MovingToFan状态就计算贝塞尔曲线路径并更新位置当位置非常接近目标点Vector3.Distance 0.01f时就将状态切换为InFan。这种状态机模式使得逻辑非常清晰易于扩展比如以后增加“被选中高亮”、“抖动警告”等状态也便于调试。3. 完整实现步骤与代码解析下面我将把上述模块组合起来给出一个可运行的、相对完整的实现方案。我们将创建几个核心脚本CardObjectPool、CardFanLayoutManager和CardController。3.1 第一步创建对象池CardObjectPool这个脚本可以挂在一个空的GameObject上比如叫“CardPoolManager”。using System.Collections.Generic; using UnityEngine; public class CardObjectPool : MonoBehaviour { public static CardObjectPool Instance; // 单例模式方便全局访问 public GameObject cardPrefab; // 卡牌的Prefab public int initialPoolSize 10; // 初始池大小 private QueueGameObject pool new QueueGameObject(); void Awake() { if (Instance null) Instance this; else Destroy(gameObject); InitializePool(); } // 初始化对象池 void InitializePool() { for (int i 0; i initialPoolSize; i) { CreateNewCard(); } } // 创建一张新卡牌并放入池中 private GameObject CreateNewCard() { GameObject card Instantiate(cardPrefab, transform); // 作为池管理器的子物体 card.SetActive(false); pool.Enqueue(card); return card; } // 从池中获取一张卡牌 public GameObject GetCard() { if (pool.Count 0) { // 池子空了动态扩容 CreateNewCard(); } GameObject card pool.Dequeue(); card.SetActive(true); // 获取卡牌控制器重置状态 CardController controller card.GetComponentCardController(); if (controller ! null) controller.ResetCard(); return card; } // 将卡牌归还池中 public void ReturnCard(GameObject card) { if (card null) return; card.SetActive(false); // 重置父物体方便管理 card.transform.SetParent(transform); pool.Enqueue(card); } }3.2 第二步扇形布局管理器CardFanLayoutManager这个脚本负责计算所有卡牌的扇形目标位置。它可以挂在场景中代表“手牌区域”的GameObject上。using System.Collections.Generic; using UnityEngine; public class CardFanLayoutManager : MonoBehaviour { public Transform fanCenter; // 扇形展开的中心点世界坐标 public float baseRadius 2.0f; // 基础半径 public float radiusIncrementPerCard 0.1f; // 每多一张牌增加的半径 public float baseTotalAngle 60f; // 基础总角度度 public float angleIncrementPerCard 5f; // 每多一张牌增加的总角度 // 计算指定索引卡牌的目标位置 public Vector3 CalculateFanPosition(int cardIndex, int totalCards) { if (totalCards 0) return fanCenter.position; if (totalCards 1) return fanCenter.position Vector3.right * baseRadius; // 动态计算半径和总角度 float dynamicRadius baseRadius (totalCards - 1) * radiusIncrementPerCard; float dynamicTotalAngle baseTotalAngle (totalCards - 1) * angleIncrementPerCard; // 限制最大角度避免过度展开 dynamicTotalAngle Mathf.Min(dynamicTotalAngle, 120f); float angleStep dynamicTotalAngle / (totalCards - 1); // 计算当前牌的角度从最左侧开始 float currentAngle -dynamicTotalAngle / 2 cardIndex * angleStep; // 将角度转换为弧度并计算位置 float rad currentAngle * Mathf.Deg2Rad; Vector3 offset new Vector3(Mathf.Cos(rad), Mathf.Sin(rad), 0) * dynamicRadius; return fanCenter.position offset; } // 一个便捷方法为一批卡牌计算所有位置 public ListVector3 CalculateAllFanPositions(int totalCards) { ListVector3 positions new ListVector3(); for (int i 0; i totalCards; i) { positions.Add(CalculateFanPosition(i, totalCards)); } return positions; } }3.3 第三步卡牌控制器CardController这是最重要的脚本挂载在每一张卡牌的Prefab上。它控制动画、状态和交互。using UnityEngine; using UnityEngine.EventSystems; public class CardController : MonoBehaviour, IPointerClickHandler { // 状态 private CardAnimationState currentState CardAnimationState.Idle; // 动画参数 private Vector3 startPosition; private Vector3 controlPoint; private Vector3 targetPosition; private float animationDuration 0.3f; // 展开动画时长 private float elapsedTime 0f; private float curveHeight 1.5f; // 贝塞尔曲线控制点高度 // 组件引用 private RectTransform rectTransform; // 假设是UI卡牌 void Awake() { rectTransform GetComponentRectTransform(); } void Update() { switch (currentState) { case CardAnimationState.MovingToFan: UpdateFanMovement(); break; // 其他状态的Update逻辑... } } // 外部调用开始扇形展开动画 public void StartFanAnimation(Vector3 fanTargetPos) { if (currentState ! CardAnimationState.Idle) return; currentState CardAnimationState.MovingToFan; startPosition rectTransform.anchoredPosition3D; // 如果是UI // startPosition transform.position; // 如果是3D物体 targetPosition fanTargetPos; // 计算控制点起点和终点的中点向上偏移 Vector3 midPoint (startPosition targetPosition) / 2; controlPoint midPoint Vector3.up * curveHeight; elapsedTime 0f; } // 更新扇形移动动画 private void UpdateFanMovement() { elapsedTime Time.deltaTime; float t Mathf.Clamp01(elapsedTime / animationDuration); // 使用二次贝塞尔曲线公式计算当前位置 Vector3 position CalculateBezierPoint(t, startPosition, controlPoint, targetPosition); rectTransform.anchoredPosition3D position; // UI // transform.position position; // 3D // 可选添加一点旋转效果让运动更生动 float rotationAngle Mathf.Lerp(0f, 5f, t); // 轻微旋转 rectTransform.localEulerAngles new Vector3(0, 0, rotationAngle); // 动画结束判断 if (t 1f) { currentState CardAnimationState.InFan; // 到达后可以加一个轻微的弹动效果使用DOTween或自己写 // OnReachedFanPosition(); } } // 二次贝塞尔曲线计算 private Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2) { float u 1 - t; float tt t * t; float uu u * u; return (uu * p0) (2 * u * t * p1) (tt * p2); } // 点击事件需要EventTrigger或实现IPointerClickHandler public void OnPointerClick(PointerEventData eventData) { if (currentState CardAnimationState.InFan) { Debug.Log($Card {name} clicked! Ready to play.); // 触发后续的出牌逻辑飞向敌人 // PlayCard(); } } // 重置卡牌状态供对象池调用 public void ResetCard() { currentState CardAnimationState.Idle; elapsedTime 0f; rectTransform.localEulerAngles Vector3.zero; // 重置其他可能修改的属性如缩放、颜色等 } // 获取当前状态 public CardAnimationState GetCurrentState() { return currentState; } }3.4 第四步整合与调用最后我们需要一个“出牌管理器”或“手牌管理器”来驱动整个过程。这个脚本可能在玩家回合开始时或者在抽牌后调用。using System.Collections.Generic; using UnityEngine; public class HandManager : MonoBehaviour { public CardFanLayoutManager layoutManager; private ListGameObject currentHandCards new ListGameObject(); private ListVector3 fanPositions; // 模拟抽牌并扇形展开 public void DrawAndFanCards(int cardCount) { // 1. 清空当前手牌模拟回合开始 ClearHand(); // 2. 从对象池获取卡牌 for (int i 0; i cardCount; i) { GameObject card CardObjectPool.Instance.GetCard(); card.transform.SetParent(transform); // 设为手牌管理器的子物体 // 设置卡的起始位置例如屏幕外下方 card.GetComponentRectTransform().anchoredPosition new Vector2(0, -500); currentHandCards.Add(card); } // 3. 计算所有卡牌的扇形目标位置 fanPositions layoutManager.CalculateAllFanPositions(cardCount); // 4. 为每张卡牌启动扇形展开动画可以错开时间更有层次感 for (int i 0; i currentHandCards.Count; i) { CardController controller currentHandCards[i].GetComponentCardController(); if (controller ! null) { // 延迟启动让牌一张张展开 float delay i * 0.05f; // 每张牌间隔0.05秒 StartCoroutine(StartFanWithDelay(controller, fanPositions[i], delay)); } } } private System.Collections.IEnumerator StartFanWithDelay(CardController controller, Vector3 targetPos, float delay) { yield return new WaitForSeconds(delay); controller.StartFanAnimation(targetPos); } // 清空手牌将牌归还对象池 private void ClearHand() { foreach (var card in currentHandCards) { CardObjectPool.Instance.ReturnCard(card); } currentHandCards.Clear(); } }4. 效果优化与进阶技巧基础功能实现后我们可以追求更极致的视觉效果和手感。4.1 视觉增强加入缓动与弹性直接使用线性变化的t来计算贝塞尔曲线运动看起来还是不够生动。我们可以对t应用一个缓动函数Easing Function。例如使用Mathf.SmoothStep或者更流行的OutBack、OutElastic等函数可以让卡牌在动画末尾有一个轻微的“过冲”和“回弹”模拟真实的物理惯性。Unity的DOTween插件是处理这类动画的利器它内置了大量缓动函数。如果不想引入插件也可以自己实现几个简单的函数。例如一个简单的OutBack缓动可以这样写float EaseOutBack(float t) { float c1 1.70158f; float c3 c1 1; return 1 c3 * Mathf.Pow(t - 1, 3) c1 * Mathf.Pow(t - 1, 2); }在UpdateFanMovement中计算位置时使用缓动后的t_easedfloat t Mathf.Clamp01(elapsedTime / animationDuration); float t_eased EaseOutBack(t); // 应用缓动 Vector3 position CalculateBezierPoint(t_eased, startPosition, controlPoint, targetPosition);4.2 性能优化避免每帧计算布局如果你的手牌数量在动画过程中是固定的那么CalculateAllFanPositions只需要在开始展开时计算一次然后将位置列表缓存起来。避免在每一帧都为每张牌重新计算扇形位置尤其是在卡牌数量较多时。此外CardController的Update函数在MovingToFan状态时才会执行计算一旦进入InFan状态就应该停止不必要的计算。这通过状态机已经自然实现了。4.3 交互反馈悬停与选中高亮当卡牌处于InFan状态时我们可以为其添加悬停Hover效果。这可以通过实现IPointerEnterHandler和IPointerExitHandler接口来完成。public class CardController : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler { // ... 其他代码 ... public void OnPointerEnter(PointerEventData eventData) { if (currentState CardAnimationState.InFan) { // 放大、上浮、改变颜色等 rectTransform.localScale Vector3.one * 1.1f; // 可以播放一个轻微的向上移动的补间动画 } } public void OnPointerExit(PointerEventData eventData) { if (currentState CardAnimationState.InFan) { // 恢复原状 rectTransform.localScale Vector3.one; } } }为了效果更佳建议使用DOTween来完成这些缩放和位移动画而不是直接设置值这样会有平滑的过渡。4.4 常见问题与调试技巧问题1卡牌展开后位置不对或者重叠在一起。排查首先检查CardFanLayoutManager中的fanCenter是否正确赋值。其次在CalculateFanPosition方法中打印出计算出的dynamicRadius、dynamicTotalAngle和最终的offset值看是否符合预期。确保卡牌的锚点Pivot和RectTransform的坐标空间anchoredPositionvsposition与你计算时使用的坐标系一致。UI和3D世界坐标不能混用。问题2贝塞尔曲线运动不流畅有卡顿感。排查确保动画在Update中执行并使用Time.deltaTime来累积时间。检查animationDuration是否过短。如果使用了缓动函数尝试换一个平缓的函数如InOutSine测试。在性能分析器Profiler中查看是否在动画期间有GC Alloc垃圾分配对象池的GetCard和ReturnCard方法应避免在每帧产生新的GameObject。问题3点击卡牌没有反应。排查确认卡牌GameObject上是否有Canvas Renderer和Graphic组件如Image并且Raycast Target属性为true。检查EventSystem是否存在于场景中。在OnPointerClick方法中打一个日志确认方法是否被触发。确认卡牌的当前状态是否为InFan。问题4对象池回收后再次取出的卡牌状态异常。排查这是最经典的问题。务必在CardController.ResetCard()方法中将所有可能被修改的变量重置为初始值。特别是currentState、elapsedTime、以及Transform的位置、旋转、缩放。一个良好的实践是在卡牌Prefab上设置好一个“默认状态”ResetCard方法就是将其恢复到那个状态。实现这个扇形开牌效果的过程就像在打磨一个精致的机械装置。每一个参数半径、角度、曲线高度、动画时长都需要反复调试直到找到最符合你游戏风格的那组“黄金数值”。当看到卡牌按照你设想的弧线优雅地展开并伴随着流畅的缓动和清晰的交互反馈时那种成就感是巨大的。这不仅仅是实现了一个功能更是为你的游戏注入了灵魂。在下一篇中我们将继续探索卡牌被点击后如何飞向敌人并产生命中效果。

相关新闻

LangChain与大语言模型集成实战指南

LangChain与大语言模型集成实战指南

1. LangChain与大语言模型集成实战在当今AI技术快速迭代的背景下,大语言模型(LLM)已成为开发者工具箱中的标配。但面对市面上层出不穷的模型服务,如何高效地进行集成和切换成了实际开发中的痛点。LangChain作为AI应用开发框架,其模型抽象层恰…

2026/10/17 12:09:34 阅读更多 →
计算机毕业设计之基于SpringBoot的家电维修服务系统

计算机毕业设计之基于SpringBoot的家电维修服务系统

随着社会经济的快速发展和人们生活水平的显著提高,家电产品已广泛普及至千家万户,成为现代生活中不可或缺的一部分。然而,家电在使用过程中难免会出现各种故障或需要定期维护,传统的家电维修服务模式往往存在信息不对称、服务响应…

2026/10/18 5:57:38 阅读更多 →
BQ40Z50-R4数据闪存配置:从原理到实战的电池管理核心

BQ40Z50-R4数据闪存配置:从原理到实战的电池管理核心

1. 项目概述:深入BQ40Z50-R4的数据闪存世界如果你正在开发基于TI BQ40Z50-R4的智能电池包,那么数据闪存(Data Flash)的配置绝对是你绕不开的核心环节。这不仅仅是照着手册填几个十六进制数那么简单,它直接决定了你的电…

2026/10/18 4:43:54 阅读更多 →

最新新闻

黑通道功能安全协议:从原理到落地的完整指南

黑通道功能安全协议:从原理到落地的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 1:34:19 阅读更多 →
JavaWeb课设实战:Filter+Session权限控制与文件上传避坑指南

JavaWeb课设实战:Filter+Session权限控制与文件上传避坑指南

简介:这是一套基于JavaWeb技术栈开发的作业管理网站完整源码,面向计算机、通信、人工智能等专业的本科生及课程设计指导教师,用于支撑期末大作业、课程设计或毕业设计实践。系统采用JSPServletDruid连接池MySQL架构,涵盖用户登录、…

2026/10/19 1:34:19 阅读更多 →
助农小程序毕设技术选型:Java+MySQL+微信原生实战指南

助农小程序毕设技术选型:Java+MySQL+微信原生实战指南

简介:本资源是一套面向计算机专业本科生的毕业设计级微信小程序开发实战项目,聚焦助农扶贫场景,解决传统APP开发成本高、用户安装意愿低、存储占用大等痛点,适用于Java后端与小程序全栈学习者。压缩包共1205个文件,涵盖…

2026/10/19 1:34:19 阅读更多 →
Unity动态字体实战:用系统字体动态生成TMP SDF资产

Unity动态字体实战:用系统字体动态生成TMP SDF资产

简介:UnityNativeOSFont是一套面向Unity开发者的开源插件方案,核心解决TextMeshPro无法直接调用操作系统本地字体的问题。它通过C#脚本在运行时获取系统字体列表,并转换为TMP可用的动态字体资源,适合需要动态切换字体、本地化显示…

2026/10/19 1:34:19 阅读更多 →
嵌入式C指针入门到实践:寄存器映射、野指针与函数指针全解析

嵌入式C指针入门到实践:寄存器映射、野指针与函数指针全解析

1. 为什么要跟指针死磕:嵌入式里的那些绕不开的场景做嵌入式这行,早晚有一天你会被指针逼到墙角。我最早踩坑是在调试一块串口板卡的时候,外设寄存器手册里写着一堆偏移地址,代码里全是一长串强制类型转换的宏,不弄懂指…

2026/10/19 1:34:19 阅读更多 →
RAM盘与DISK盘真实性能对比测试方法

RAM盘与DISK盘真实性能对比测试方法

1. 项目概述:为什么一个“测速”动作值得花半天时间认真对待你有没有遇到过这样的情况:明明手里的固态硬盘标称读写速度是3500MB/s,但实际拷贝一个20GB的工程文件却要等三分钟?或者在做视频剪辑时,预览一帧要卡顿两秒&…

2026/10/19 1:33:18 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →