恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

从零打造流畅跳跃系统:Unity与Godot实现指南

  • 首页
  • 资讯中心
  • /
  • 从零打造流畅跳跃系统:Unity与Godot实现指南

相关资讯

shadcn/ui源码型组件库:从黑盒依赖到可拥有的前端开发模式 2026/10/17 13:30:13
强化学习策略优化:从单调提升理论到TRPO/PPO工程实践 2026/10/17 13:30:13
BiliTools B站下载工具完整教程:视频、番剧、弹幕、无损音乐一次存进本地 2026/10/17 13:30:13

最新资讯

SFML C++九宫幻卡游戏开发实战:轻量图形库实现逻辑益智游戏
开源BI工具Superset:从数据源连接到仪表盘的可视化实战指南
仿青藤之恋交友软件源码拆解:uni-app三端即时通讯与避坑指南
【基础IO】-4-再谈重定向
线圈天线设计实战:从电感计算到匹配调试的完整经验
红外光面部表情识别数据集解析:VOC+YOLO格式与训练实践

今日推荐

Qwen3.5-122B-A10B-singprobe幻觉检测实战:AUC 0.7806,如何实时揪出大模型一本正经的胡话?
NetSpot 实战:用信道分析与频宽优化解决 Wi-Fi 卡顿
C++ split() 字符串分割的五种实现与性能实测

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

从零打造流畅跳跃系统:Unity与Godot实现指南

发布时间:2026/10/17 13:30:13
从零打造流畅跳跃系统:Unity与Godot实现指南 1. 背景当玩家在悬崖边问出那句“我也要跳吗”在很多动作游戏和跑酷游戏里玩家都会在某个瞬间盯着屏幕里站在悬崖边、楼顶边缘或平台尽头的角色犹豫着问出一句“我也要跳吗”这句看似普通的话其实牵涉到游戏开发中最基础也最考验手感的一门技术——跳跃系统。跳跃看似只是一个“让角色离开地面再落回来”的简单行为但它背后涉及物理模拟、输入缓冲、地面检测、状态机、动画同步等一整套逻辑。做得好的跳跃系统玩家会觉得角色“指哪打哪”做得差的跳跃系统哪怕只是踩空一个平台都会让整款游戏的体验大打折扣。这里就不得不提到在移动系统上被誉为“天花板”的游戏之一Titanfall 2很多玩家习惯缩写为 TTF2以便和另一款缩写同为 TF2 的 Team Fortress 2 区分开。TTF2 的跑酷系统让玩家可以完成蹬墙跑、蹬墙跳、二段跳、滑铲等一系列流畅动作真正实现了“只要你想跳处处都可以跳”。很多开发者都在研究它的移动系统想在自己的项目中复刻那种流畅手感。本文就以“我也要跳吗”这句灵魂拷问为切入点从零开始拆解跳跃系统的实现原理并给出 Unity 与 Godot 两套可运行代码同时对标 Titanfall 2 的移动系统设计思路。无论你是刚开始学习游戏开发的新手还是正在调优角色手感的开发者这篇文章都能提供一份值得收藏的实战参考。1.1 跳跃的本质是什么先给一个最朴素的解释跳跃的本质就是给角色施加一个瞬间向上的速度然后让重力把这个速度一点一点消耗掉直到角色回到地面。在真实世界里跳跃高度取决于起跳瞬间腿部的蹬地力量。在游戏世界里我们不需要模拟肌肉发力只需要做两件事在某一帧给角色一个向上的初速度。之后每一帧根据重力加速度修改这个速度并让重力把角色拉回地面。只要控制好速度和加速度的数值玩家就会感觉“这个角色能跳起来”。1.2 为什么跳跃系统这么难做好既然原理这么简单为什么跳跃系统的“手感”差异会那么大问题在于跳跃不是孤立发生的它要同时协调以下要素要素说明物理参数重力、起跳速度、滞空时间直接决定角色跳多高、飘不飘。输入响应玩家按下跳跃键到角色起跳之间是否存在明显延迟。地面检测角色是否站在地面上决定了能不能触发跳跃。状态管理角色当前是待机、奔跑、下落还是着地不同状态下跳跃行为不同。动画表现起跳、滞空、落地三段动画切换是否自然。镜头与特效镜头晃动、起跳粒子效果会直接影响使用者对“力量感”的感知。任何一个环节处理得不好玩家都会觉得“手感不对”。所以跳跃系统从来不是一个简单的velocity.y 5就能解决的问题。2. 环境准备与引擎选型本文会同时给出 Unity 和 Godot 两套示例。选择这两个引擎的原因很简单Unity 是目前商业项目中使用最广泛的引擎之一资料丰富而 Godot 4 作为开源引擎轻量免费非常适合快速做原型验证。2.1 引擎与版本说明工具说明Unity本文示例基于 Unity 2022.3 LTS 版本使用 C# 编写脚本。Godot本文示例基于 Godot 4.x使用 GDScript 编写脚本。操作系统Windows / macOS / Linux 均可不影响代码逻辑。需要说明的是跳跃系统本身并不强依赖具体的引擎版本。如果你使用的是 Unity 2021 或 Godot 3.x只要把对应的 API 替换成兼容版本整体逻辑是通用的。2.2 示例项目结构在 Unity 中建议创建如下目录结构Assets/ ├── Scripts/ │ ├── PlayerMovement.cs // 基础跳跃 │ ├── ParkourMovement.cs // 二段跳、蹬墙跳扩展 │ └── MovementProfile.cs // 可配置参数文件 ├── Scenes/ │ └── JumpDemo.unity // 测试场景 └── Prefabs/ └── Player.prefab // 玩家角色在 Godot 中结构可以更简单jump_demo/ ├── player/ │ ├── player.gd // 角色控制脚本 │ └── player.tscn // 角色场景 └── test_world.tscn // 测试场景3. 核心概念拆解重力、速度和地面检测在写代码之前先弄清楚三个核心概念的数学关系。3.1 重力与起跳速度的换算假设我们想让角色跳起来 2 米高重力加速度是gravity -30那么起跳初速度应该给多少根据物理公式v² -2 * gravity * jumpHeight重力取负数所以这里要加负号才能得到正数。在代码里写出来就是velocity.y Mathf.Sqrt(-2f * gravity * jumpHeight);这个换算公式非常实用。我们可以在编辑器里直观地拖一个“跳跃高度”参数而不需要让策划去理解速度值。3.2 为什么用 “isGrounded” 而不是 “velocity.y 0”有些新手在判断角色是否在地面时会写成if (controller.velocity.y 0)。这是一个典型的误区。角色在下落过程中由于浮点精度问题velocity.y很少会精确等于 0而且在连续按跳跃键时用速度判断很容易漏判。正确做法是通过物理引擎的碰撞检测来查询“脚底是否接触地面”。在 Unity 的CharacterController中引擎已经提供了isGrounded属性在 Godot 的CharacterBody3D中move_and_slide()调用之后可以通过is_on_floor()查询。3.3 一帧一物理的更新方式在 Unity 中物理更新默认发生在FixedUpdate中。但大多数新手习惯把移动代码写在Update中这会导致物理不同步。更稳的做法是把水平移动和跳跃输入都放在Update中读取然后把实际位移放到FixedUpdate中执行。当然如果只是做原型用CharacterController.Move()放在Update中也能工作但为了手感一致最好统一物理更新频率。4. 实战一Unity 中实现一套基础跳跃系统接下来进入代码环节。我们先从最基础的“单次跳跃”开始然后逐步扩展二段跳和蹬墙跳。4.1 在 Unity 中创建角色控制器首先在场景中创建一个 Capsule。调整 Capsule 的高度为 2半径为 0.5。在 Inspector 中添加CharacterController组件。Unity 会自动把 Capsule 的 Collider 替换为 CharacterController。把 Main Camera 放在角色肩膀附近方便观察方位。4.2 编写基础移动与跳跃脚本在Assets/Scripts下创建PlayerMovement.cs写入以下完整代码。// 文件路径Assets/Scripts/PlayerMovement.cs using UnityEngine; public class PlayerMovement : MonoBehaviour { [Header(移动参数)] public float moveSpeed 8f; [Header(跳跃参数)] public float jumpHeight 2f; public float gravity -30f; [Header(连跳参数)] [Tooltip(最大跳跃次数1表示只能跳一次2表示二段跳)] public int maxJumpCount 1; private CharacterController controller; private Vector3 velocity; private int jumpCount; private void Start() { controller GetComponentCharacterController(); } private void Update() { // 1. 读取水平输入 float horizontal Input.GetAxis(Horizontal); float vertical Input.GetAxis(Vertical); Vector3 move transform.right * horizontal transform.forward * vertical; controller.Move(move * moveSpeed * Time.deltaTime); // 2. 跳跃输入检测 if (Input.GetButtonDown(Jump) jumpCount maxJumpCount) { // 用跳跃高度反推起跳速度 velocity.y Mathf.Sqrt(-2f * gravity * jumpHeight); jumpCount; } // 3. 重力计算 if (controller.isGrounded) { // 落地后重置垂直速度和跳跃次数 velocity.y 0f; jumpCount 0; } else { velocity.y gravity * Time.deltaTime; } // 4. 应用垂直位移 controller.Move(velocity * Time.deltaTime); } }这段脚本的完整流程是每次Update读取 WASD 或方向键输入计算水平方向移动。检测到跳跃键按下并且当前剩余跳跃次数大于 0 时给角色施加向上初速度。判断角色是否落地。如果落地则重置velocity.y和jumpCount避免下落过程中无限按跳。角色在空中时持续叠加重力让角色自然回落。4.3 测试与验证把脚本挂到 Capsule 上点击 Play。此时你可以在一个平面上用 WASD 移动按空格跳跃。预期结果角色能够跳起来并在滞空一段时间后落回地面。落地后可以再次跳跃。如果在空中连续按空格因为jumpCount已经用完不会二次起跳。这里有一个细节值得注意所有代码使用的是Time.deltaTime而不是Time.fixedDeltaTime。如果后续需要把移动逻辑迁移到FixedUpdate需要把Time.deltaTime改成Time.fixedDeltaTime并写在FixedUpdate方法内部。5. 实战二从基础跳跃扩展到二段跳与蹬墙跳有了基础跳跃之后就可以开始扩展更符合“跑酷手感”的移动系统了。二段跳和蹬墙跳是 Titanfall 2 移动系统的核心组成部分也是很多动作游戏的标配。5.1 修改跳跃代码支持多段跳前面其实已经为多段跳预留了参数maxJumpCount你只需要在 Inspector 中把Max Jump Count改成 2角色就能二段跳。如果你希望二段跳的高度和首跳不同可以增加一个多段跳高度参数[Header(连跳参数)] public float doubleJumpHeight 1.5f; if (Input.GetButtonDown(Jump) jumpCount maxJumpCount) { // 第一次跳使用 jumpHeight后续跳使用 doubleJumpHeight float currentJumpHeight (jumpCount 0) ? jumpHeight : doubleJumpHeight; velocity.y Mathf.Sqrt(-2f * gravity * currentJumpHeight); jumpCount; }5.2 实现蹬墙跳蹬墙跳是跑酷游戏中最重要的位移手段之一。它的行为逻辑是角色在空中贴近墙壁时玩家按下跳跃键角色获得一个“向外弹开”的速度同时向上跳起。在 Unity 中使用CharacterController时最简单的墙面检测方法是发射一条射线。下面是核心逻辑可以作为PlayerMovement.cs的扩展// 文件路径Assets/Scripts/ParkourMovement.cs using UnityEngine; public class ParkourMovement : PlayerMovement { [Header(蹬墙跳参数)] public float wallCheckDistance 0.3f; public float wallJumpHeight 2f; public float wallJumpForwardForce 6f; private bool IsTouchingWall(out Vector3 wallNormal) { wallNormal Vector3.zero; Vector3[] directions { transform.forward, -transform.forward, transform.right, -transform.right }; foreach (Vector3 dir in directions) { if (Physics.Raycast(transform.position, dir, wallCheckDistance)) { RaycastHit hit; Physics.Raycast(transform.position, dir, out hit, wallCheckDistance); wallNormal hit.normal; return true; } } return false; } private void Update() { // 这是核心片段把原有 Update 替换成支持蹬墙跳的版本 if (Input.GetButtonDown(Jump)) { if (IsTouchingWall(out Vector3 wallNormal)) { velocity.y Mathf.Sqrt(-2f * gravity * wallJumpHeight); velocity wallNormal * wallJumpForwardForce; } else if (jumpCount maxJumpCount) { velocity.y Mathf.Sqrt(-2f * gravity * jumpHeight); jumpCount; } } } }需要说明的是上面的类继承关系在示例中并不完美实际项目中更推荐把移动逻辑抽到一个独立的控制组件里而不是靠继承。这里展示的是核心思路向墙壁法线方向施加一个水平速度再垂直向上跳就完成了蹬墙跳。5.3 为什么跑酷游戏需要“蹬墙跳”在 Titanfall 2 中蹬墙跳不只是一个炫技动作它还是维持移动节奏的关键。蹬墙跳可以让玩家在跳跃过程中不落地就改变方向从而在高楼之间连续穿梭。从工程角度理解蹬墙跳本质上是“给角色额外一次改变速度方向的机会”。普通跳跃只能改变垂直方向而蹬墙跳可以改变水平方向和垂直方向。如果你的游戏里有追逐战、计时关卡或探索收集要素蹬墙跳会极大地丰富玩家的位移手段。6. 实战三Godot 4 中实现跳跃系统如果你偏好轻量级引擎或者只是想快速验证手感可以用 Godot 4 在三分钟内做出一个可以跑跳的角色。6.1 创建项目打开 Godot 4新建一个 3D 场景。添加一个CharacterBody3D作为玩家根节点再添加一个CollisionShape3D子节点形状选择BoxShape3D或CapsuleShape3D。为了看到角色可以给根节点挂一个MeshInstance3D里面加载一个BoxMesh或者CapsuleMesh。6.2 编写角色控制脚本在player节点上挂载脚本命名为player.gd。# 文件路径player/player.gd extends CharacterBody3D export var speed: float 8.0 export var jump_height: float 2.0 var gravity: float ProjectSettings.get_setting(physics/3d/default_gravity) func _physics_process(delta): # 读取水平输入需要在输入映射中配置 move_left/move_right 等动作 var input_dir : Input.get_vector(move_left, move_right, move_forward, move_back) var direction : (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() # 水平移动 velocity.x direction.x * speed velocity.z direction.z * speed # 跳跃与重力 if is_on_floor() and Input.is_action_just_pressed(jump): velocity.y sqrt(-2.0 * gravity * jump_height) else: velocity.y - gravity * delta move_and_slide()6.3 配置输入映射在 Godot 中默认可能没有move_left、jump这些动作。你需要在项目设置中配置动作名称按键move_leftA / 左方向键move_rightD / 右方向键move_forwardW / 上方向键move_backS / 下方向键jump空格配置完成后运行场景角色就可以移动和跳蹲了。6.4 Godot 中的多段跳扩展Godot 的CharacterBody3D没有isGrounded属性对应的 API 是is_on_floor()而且必须在move_and_slide()调用之后查询才有效。这是很多新手容易犯的错误。如果你想在 Godot 中实现二段跳只需要加一个计数变量var jump_count : 0 export var max_jump_count : 2 func _physics_process(delta): if is_on_floor(): jump_count 0 if Input.is_action_just_pressed(jump) and jump_count max_jump_count: velocity.y sqrt(-2.0 * gravity * jump_height) jump_count 1思路和 Unity 版本完全一致核心就是“落地重置次数空中按跳才消耗次数”。7. 手感调优土狼时间、跳跃缓冲与重力缩放代码能跑起来只是开始。要让玩家觉得“跳跃很跟手”还需要在细节上做大量调优。这里介绍三个最常用的手感调优技巧。7.1 土狼时间Coyote Time土狼时间借用了《猫和老鼠》里土狼冲出悬崖边缘却不会立刻掉下去的经典桥段在游戏中表现为当角色刚走出平台边缘的一小段时间内系统仍然认为角色“站在地面”允许玩家起跳。这个机制让玩家在“差一点点就掉下去”的边缘也能跳起来极大地提升了容错率。private float lastGroundedTime; private float coyoteTime 0.1f; if (controller.isGrounded) { lastGroundedTime Time.time; } if (Input.GetButtonDown(Jump) Time.time - lastGroundedTime coyoteTime) { velocity.y Mathf.Sqrt(-2f * gravity * jumpHeight); }7.2 跳跃缓冲Jump Buffer跳跃缓冲的意思是当玩家在未落地时提前按下了跳跃键系统并不立刻丢弃这次按键而是记录下这次输入。在接下来一小段时间内如果角色落地了系统会自动触发跳跃。这解决了玩家“明明按了跳却没跳出来”的挫败感。private float lastJumpPressedTime; private float jumpBufferTime 0.1f; if (Input.GetButtonDown(Jump)) { lastJumpPressedTime Time.time; } if (Time.time - lastJumpPressedTime jumpBufferTime controller.isGrounded) { velocity.y Mathf.Sqrt(-2f * gravity * jumpHeight); lastJumpPressedTime -100f; // 防止多次触发 }7.3 更细的垂直重力调节纯粹使用一个固定重力角色在上升和下落阶段会使用相同的加速度。但实际上许多动作游戏会让上升阶段重力小于下落阶段重力。这样上升过程显得轻盈落地方过程更快、更利落。public float fallMultiplier 2f; if (velocity.y 0) { velocity.y gravity * fallMultiplier * Time.deltaTime; } else { velocity.y gravity * Time.deltaTime; }这也是为什么很多游戏里轻按跳跃和长按跳跃角色跳出的高度和速度感完全不同。8. 对标 Titanfall 2从“跳一下”到整套移动系统Titanfall 2 的移动系统之所以被封神并不是因为它单独某个动作做得多么复杂而是因为它的几个基础动作被设计成可以“无限衔接”。拆开看核心无非就是下表中的几件套。动作功能工程价值二段跳在空中多一次转向和上升机会提供了容错和方向调整空间蹬墙跑Wall Run角色可沿墙面水平奔跑一段时间让垂直关卡成为可能蹬墙跳Wall Jump从墙上向外弹射把墙面变成“跳板”滑铲Slide落地后快速滑动减少落地停顿保持动量空中加速在玩家移动、转向时保留或增加动量让移动越玩越熟练从实现角度来说蹬墙跑的难点在于“墙面判定”和“奔跑状态切换”。当你检测到角色在一定高度贴墙且按着前进方向就让角色沿墙面切线方向移动同时把重力的影响减半一旦玩家按下反向就可以衔接蹬墙跳。这种系统化设计思路完全可以迁移到我们自己的项目之中。比如你不需要一开始就实现全部动作可以先完成稳定的基础跳跃。二段跳。蹬墙跳。这三步做完之后角色在垂直关卡中的可玩性已经能够大幅提升。之后再加入滑铲来衔接落地就是一套低配版的跑酷移动系统了。9. 常见问题与排查思路跳跃系统虽然代码量不大但新手在实现过程中很容易踩坑。下面整理一份排查清单。问题现象常见原因解决思路角色按下跳跃键没有反应Input 映射未配置、IsGrounded 一直为 false检查输入映射绘制地面检测射线可视化角色能跳一次但空中不能二段跳maxJumpCount 未设置为 2修改连跳次数参数角色跳得很高但下落很慢重力数值太小调大gravity的绝对值或者增加落地重力倍率角色走到平台边缘还会跳起来土狼时间设置过长把 Coyote Time 控制在 0.05~0.15 秒之间偶尔按了跳没反应跳跃输入被某一帧消费掉了加入跳跃缓冲机制处理提前按键角色撞到天花板后卡住CharacterController 与天花板碰撞导致垂直速度被抵消给垂直移动单独设置速度上限蹬墙跳一直触发不了射线检测的方向不对在 Scene 视图中用Debug.DrawRay画出射线这里特别强调一下地面检测的问题。在 Unity 的CharacterController中isGrounded只有在角色脚下接触碰撞体时才为true。如果你的场景中角色和地面之间有一个微小缝隙那么地面检测会失效。解决方法是把角色模型的视觉部分稍微抬高让胶囊体的底部贴合地面。10. 最佳实践与工程建议当跳跃系统开始工作之后接下来的目标是让它进可复用、环境可配置、不会给项目埋雷。这里有五条工程建议适合在实际项目中参考。10.1 把跳跃参数配置化不要把所有参数硬编码在角色脚本里。建议使用ScriptableObject或 JSON 配置文件把moveSpeed、jumpHeight、gravity、maxJumpCount、coyoteTime、jumpBufferTime等参数统一管理。好处是策划和美术可以独立调参不需要每次找你改代码重新编译也让不同角色之间的手感对比变得更简单。10.2 输入与物理分离读取输入的操作放在Update或轮询逻辑中而真正驱动物理位移的操作应该发生在物理更新阶段。严格来说Unity 中推荐在Update里读输入、在FixedUpdate里应用移动Godot 中则统一写在_physics_process中。这样处理避免了帧率波动导致的跳跃高度不稳定也让物理表现与动画表现更容易同步。10.3 动画状态机及时切换跳跃的手感不只看物理数值动画也会影响玩家对“是否跟手”的判断。在起跳瞬间角色的动画如果还停留在跑步姿态玩家会觉得“跳慢了半拍”。建议在状态机中至少划分出Idle、Run、Jump、Fall、Land五个状态并在关键节点起跳、落地触发过渡。10.4 网络同步时不要直接同步坐标如果你的项目是多人在线游戏那么直接在网络上同步角色坐标会导致移动抖动和穿模。更稳的做法是每个客户端只负责自己的输入和预测。服务器使用相同的跳跃物理参数做权威模拟。对于其他玩家使用移动目标点的插值同步来平滑显示。这里不展开讲网络架构但记住一点跳跃系统在单机原型中可以在Update中任意修改velocity.y在网络分布式架构中必须以固定物理步长模拟否则会出现“每个人看到的跳跃高度不一样”的诡异问题。10.5 善用可视化调试在开发过程中将地面检测射线、墙面检测射线、垂直速度值绘制到 Scene 视图里可以极大提升排查效率。善用Debug.DrawRay或 Godot 的draw_debug_line比反复 Play/Stop 工程要高效得多。11. 总结与课后练习回到开头的那个问题“我也要跳吗”作为玩家站在悬崖边问出这句话意味着游戏成功地激起了玩家探索的欲望。作为开发者这句话其实是我们在设计跳跃系统时始终要追求的目标让玩家敢于跳、愿意跳、跳了还想再跳。本文从跳跃系统的基本原理出发先后完成了 Unity 和 Godot 两套基础跳跃实现再扩展了二段跳、蹬墙跳等跑酷动作并通过土狼时间、跳跃缓冲等细节调整优化手感。最后对标 Titanfall 2 的移动系统梳理了整套跑酷动作的组成方式和工程实现思路。如果你正在学习跳跃系统建议动手做下面这个练习用 Godot 或 Unity 搭一个包含高低平台、墙壁和深坑的小关卡。为角色实现基础跳跃 二段跳 蹬墙跳。再加上土狼时间和跳跃缓冲尝试将“从起跳到落地”的手感调试到自己满意。观察你调参的过程中哪些参数值会在“跳不起来”和“飘得离谱”之间产生极大反差记录下来作为自己的经验数据。等你把这一套跑完再回过来看 Titanfall 2 的移动系统会发现它不过是把同样一套逻辑打磨到了极致。所谓好的手感其实没有天赋只有一遍又一遍的参数修正和状态调整。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号