
最近在整理小游戏原型时接触到了“Vibecoding”这种开发方式通过自然语言描述需求让 AI 工具生成大部分基础代码再由开发者做设计决策与代码审查。这种模式用来做玩法原型特别顺手尤其是像“山林寻宝”这种交互结构清晰的小游戏。本文要分享的就是基于单相机多视角切换方案如何一步步完成寻宝玩法的核心逻辑包括视角管理、射线检测、宝藏收集和界面反馈。不管你是刚接触游戏开发的初学者还是想尝试 AI 辅助开发的进阶玩家都能从中找到可以直接落地的代码与思路。1. 背景与核心概念1.1 什么是 VibecodingVibecoding 并不是一个新的编程语言也不是某个框架而是一种开发方式。简单说就是你用自然语言描述“我想要一个什么功能”由 AI 工具帮你写出大致可用的代码你拿到后再进行人工审查、修改和组装。举个例子你想实现“点击屏幕上的物体物体消失并加分”。传统做法是自己查 API、写射线检测、写物体管理脚本过程比较长。而用 Vibecoding 的方式你可以直接描述一句话AI 会返回一段 Unity C# 脚本虽然不是 100% 完美但往往已经涵盖了主要逻辑剩下的就靠你去调整参数、排查细节。这种方式很适合两类场景原型验证阶段游戏想法还没定型需要快速做出可玩的 Demo。个人小项目很多小游戏功能并不复杂与其从零写不如让 AI 生成骨架再补肉。当然Vibecoding 不代表完全不用思考。AI 给出的代码可能有 bug、可能不符合你的项目结构真正有价值的是你如何判断这段代码哪里需要改、为什么需要改。1.2 单相机多视角切换是什么在 Unity 中视角通常由 Camera 组件控制。单相机多视角切换指的是场景中只保留一个“逻辑主相机”但在不同时机、不同操作下通过切换相机的 Transform 位置、旋转角度或启用状态来呈现不一样的角度观察。常见的方案有两种多相机切换场景中放置多个 Camera同一时间只启用其中一个。这种方式实现简单适合不同视角差异大的场景。单相机变换只有一个 Camera通过代码修改它的位置与旋转来模拟不同视角。这种方式更省性能但需要仔细设计各个视角的坐标。山林寻宝这个项目采用第一种方案因为三种视角探索视角、俯视地图视角、宝藏特写视角差异非常大用多个 Camera 分别设置会更直观代码量也少。后续如果做优化可以再合并成单相机移动方案。2. 需求分析与功能拆分2.1 山林寻宝玩法说明这个游戏的规则很简单玩家在一片山林场景中寻找隐藏的宝藏宝藏会散落在树木、岩石、草丛之间。玩家切换视角找到宝藏点击收集全部收集完后弹出胜利提示。整个玩法可以分为三个状态探索阶段玩家以第一人称视角在山林中行走寻找宝藏的蛛丝马迹。俯视阶段切换到高空俯视视角从上方观察场景布局快速定位可能藏宝的区域。特写阶段当玩家靠近某个宝藏时切到宝藏特写视角确认宝藏位置并点击收集。这三个状态对应三个视角也就是单相机多视角切换的核心需求。2.2 为什么要做多视角切换如果只有一个固定视角玩家在山林里很容易迷失方向。加入多视角切换之后游戏的操作维度丰富了很多探索视角给你沉浸感。俯视视角帮你建立全局认知。特写视角提供精准交互。这在很多商业游戏里也是常用设计比如《塞尔达传说》系列中玩家就可以在第三人称与第一人称之间切换用来应对不同的解谜和战斗场景。小游戏虽然规模小但思路是相通的。2.3 技术选型本文采用Unity 2022.3 LTS C#这是目前比较稳定的组合支持新输入系统也兼容大量旧项目。如果你使用的是其他引擎比如 Godot 或 Cocos核心思路同样适用只是 API 不同。项目结构上我们没有引入复杂框架只使用了 Unity 自带的CameraRaycast射线检测Canvas / UI Text简单的场景物体Cube、Sphere、Cylinder 组合而成下面先从环境准备开始讲。3. 环境准备与基础搭建3.1 环境与版本说明由于每个人的开发环境不同这里给出一个比较通用的配置参考操作系统Windows 10/11 或 macOS 均可。Unity 版本Unity 2022.3 LTS 或更高版本。渲染管线内置渲染管线Built-in Render Pipeline即可不需要 URP/HDRP。输入系统旧版 Input Manager保持默认即可。版本这方面不需要死板核心功能在 Unity 2020 之后的版本都可以运行。如果你用的是 Long Term SupportLTS版本稳定性会更好。创建项目时选择3DBuilt-in Render Pipeline模板这样场景自带平行光和一个默认相机后面我们在此基础上扩展。3.2 项目目录规划好的项目结构能减少后面改代码的麻烦。我们在 Assets 下创建以下目录Assets/ ├── Scenes/ # 存放场景文件 ├── Scripts/ # 存放 C# 脚本 ├── Prefabs/ # 存放可复用物体 └── Materials/ # 存放材质这些目录在 Unity 里本质上就是文件夹右键 Assets 面板创建即可。脚本统一放在 Scripts 里场景物体组装成 Prefab 后放在 Prefabs方便后续复用。3.3 场景搭建场景搭建不是这篇的重点但为了后面的代码演示我们需要一个简单的“山林寻宝”环境创建一个 Plane 作为地面Scale 设为 (5, 1, 5)看起来就是一大片空地。用多个 Cube 模拟树木给它们不同颜色。用 Sphere 模拟岩石用 Cylinder 模拟草丛。创建 3 个宝藏用小型 Cube 或者 Capsule 表示给它们添加 Box Collider。场景搭建随意一点没关系重点是让射线检测有东西可打。另外给地面添加一个 Mesh Collider 或 Box Collider否则射线会直接穿到无限远。4. 单相机多视角切换核心实现4.1 三个视角的设计思路在场景中创建三个 Camera分别命名为MainCamera探索视角TopDownCamera俯视视角TreasureCamera特写视角它们的作用分工如下相机名称位置参考视角特点MainCamera地面附近玩家位置第一人称看到物体侧面TopDownCamera空中高处正对地面俯视 90 度全局视野TreasureCamera宝藏附近朝向宝藏近距离特写同一时间只启用一个相机其他相机通过enabled属性关闭。这样 Unity 只会渲染启用的相机不会产生重叠画面。4.2 相机切换脚本我们先写一个相机管理脚本也就是整个单相机多视角切换的核心。// 文件路径Assets/Scripts/CameraSwitcher.cs using UnityEngine; public class CameraSwitcher : MonoBehaviour { [Header(三个相机)] public Camera mainCamera; public Camera topDownCamera; public Camera treasureCamera; [Header(当前视角索引 0-探索 1-俯视 2-特写)] public int currentViewIndex 0; private void Start() { // 初始启用探索视角 SwitchToView(0); } private void Update() { // 键盘数字键快速切换视角 if (Input.GetKeyDown(KeyCode.Alpha1)) { SwitchToView(0); } if (Input.GetKeyDown(KeyCode.Alpha2)) { SwitchToView(1); } if (Input.GetKeyDown(KeyCode.Alpha3)) { SwitchToView(2); } } public void SwitchToView(int index) { currentViewIndex index; // 先把所有相机关闭再打开目标相机 if (mainCamera ! null) { mainCamera.enabled false; } if (topDownCamera ! null) { topDownCamera.enabled false; } if (treasureCamera ! null) { treasureCamera.enabled false; } switch (index) { case 0: if (mainCamera ! null) { mainCamera.enabled true; } break; case 1: if (topDownCamera ! null) { topDownCamera.enabled true; } break; case 2: if (treasureCamera ! null) { treasureCamera.enabled true; } break; default: Debug.LogWarning(未知视角索引: index); if (mainCamera ! null) { mainCamera.enabled true; } break; } } // 供外部调用获取当前启用的相机 public Camera GetActiveCamera() { switch (currentViewIndex) { case 1: return topDownCamera; case 2: return treasureCamera; default: return mainCamera; } } }这里的思路很简单每次切换时先把三个 Camera 全部关闭再按索引打开目标相机的enabled。注意关闭 Camera 组件而不是销毁 GameObject这样相机上的其他组件比如 AudioListener还可以正常工作。如果你使用多相机切换方案还有一个细节要处理场景中最好只有一个AudioListener否则 Unity 控制台会报警告。解决办法是只保留一个相机上的 AudioListener或者用脚本动态控制。4.3 触屏或鼠标点击切换除了键盘切换我们还可以让玩家点击 UI 按钮来切换视角。在 Canvas 上创建三个 Button文本分别写上“探索视角”“俯视视角”“特写视角”然后把它们的 OnClick 事件关联到 CameraSwitcher 的 SwitchToView 方法。如果你要在代码里动态创建按钮可以用下面的写法但更推荐直接在场景里手动拉引用因为更直观。// 给按钮绑定事件的示例代码放在 OnEnable 里执行 void AttachButtonListeners() { // 假设场景中有一个 Button 叫 btnTopDown UnityEngine.UI.Button btn GameObject.Find(btnTopDown).GetComponentUnityEngine.UI.Button(); btn.onClick.AddListener(() switcher.SwitchToView(1)); }关联之后玩家点击按钮就能在探索视角和俯视视角之间切换方便不同操作习惯的玩家。5. 完整寻宝流程实现5.1 宝藏管理脚本现在编写宝藏的逻辑。一个宝藏需要具备以下能力被玩家点击后收集。收集时播放反馈效果。记录是否已经被收集。// 文件路径Assets/Scripts/Treasure.cs using UnityEngine; public class Treasure : MonoBehaviour { [Header(宝藏配置)] public string treasureName 古代金币; public int score 10; [Header(收集反馈)] public GameObject collectEffectPrefab; public bool IsCollected { get; private set; } public void CollectTreasure() { if (IsCollected) { return; } IsCollected true; // 加分逻辑交由 GameManager 处理 GameManager.Instance.AddScore(score); // 生成简单的粒子反馈如果没有粒子就高亮一下 if (collectEffectPrefab ! null) { Instantiate(collectEffectPrefab, transform.position, Quaternion.identity); } else { Renderer renderer GetComponentRenderer(); if (renderer ! null) { renderer.material.color Color.green; } } // 隐藏宝藏物体表示已经收走 gameObject.SetActive(false); } }这里用了一个GameManager单例来统一管理分数后面会在 5.3 节讲到。5.2 射线检测点击收集射线检测是寻宝交互的核心。玩家点击屏幕时从当前激活的相机发射一条射线检测是否打中宝藏打中了就调用 CollectTreasure。// 文件路径Assets/Scripts/ClickManager.cs using UnityEngine; public class ClickManager : MonoBehaviour { [Header(相机切换器引用)] public CameraSwitcher switcher; [Header(检测距离)] public float rayDistance 100f; private void Update() { // 鼠标左键点击 if (Input.GetMouseButtonDown(0)) { // 根据当前视角选择从哪个相机发射线 Camera activeCamera switcher ! null ? switcher.GetActiveCamera() : Camera.main; if (activeCamera null) { Debug.LogWarning(当前没有可用的相机); return; } Ray ray activeCamera.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, rayDistance)) { Treasure treasure hit.collider.GetComponentTreasure(); if (treasure ! null) { treasure.CollectTreasure(); } else { // 打到了场景物体但没打到宝藏可以给个提示 Debug.Log(点击位置没有宝藏); } } } } }为什么这里不能直接用Camera.main因为Camera.main只会返回 Tag 为 MainCamera 的相机。如果当前启用的是 TopDownCameraCamera.main并不指向它射线就会从错误的位置发出。所以我们通过 CameraSwitcher 的 GetActiveCamera 来获取当前真正启用的相机。5.3 计分与 UI 反馈深山寻宝如果没有分数反馈玩家会缺少收集的爽快感。我们用 GameManager 统一管理游戏状态。// 文件路径Assets/Scripts/GameManager.cs using UnityEngine; using UnityEngine.UI; public class GameManager : MonoBehaviour { public static GameManager Instance { get; private set; } [Header(UI 元素)] public Text scoreText; public Text infoText; public GameObject winPanel; private int totalScore 0; private int collectedCount 0; private int totalCount 0; private void Awake() { // 单例初始化 if (Instance ! null Instance ! this) { Destroy(gameObject); return; } Instance this; } private void Start() { totalCount FindObjectsOfTypeTreasure().Length; UpdateScoreUI(); } public void AddScore(int value) { totalScore value; collectedCount; UpdateScoreUI(); if (collectedCount totalCount) { ShowWinPanel(); } } private void UpdateScoreUI() { if (scoreText ! null) { scoreText.text 分数 totalScore; } if (infoText ! null) { infoText.text 已收集 collectedCount / totalCount; } } private void ShowWinPanel() { if (winPanel ! null) { winPanel.SetActive(true); } Time.timeScale 0f; } }这里有一点需要注意使用FindObjectsOfTypeTreasure()的前提是所有未收集的宝藏都在场景中并且 GameObject 是激活状态。如果一开始有些宝藏是隐藏的这个统计就不准确。在实际项目中可以在场景中放置一个空物体把宝藏都作为它的子物体统一挂载然后用 Transform 的子物体数量来计算总数。5.4 视角切换与寻宝的联动到这里三个部分已经齐了视角切换、点击检测、分数统计。把它们串起来之后完整的游戏逻辑就是默认启用探索视角。玩家按 2 键切到俯视视角看见全局地形和发光的宝藏。按 3 键切到特写视角面向宝藏点击收集。收集完成后游戏弹出胜利面板。为了让特写视角更容易理解我们可以在宝藏旁边放一个空物体作为“视角锚点”TreasureCamera 的位置就等于锚点位置。这样每个宝藏就拥有独立视角。如果场景里只有一个 TreasureCamera想让它跟随不同宝藏可以写一个简单的跟随脚本// 文件路径Assets/Scripts/CameraLookAtTarget.cs using UnityEngine; public class CameraLookAtTarget : MonoBehaviour { public Transform target; public Vector3 offset new Vector3(0, 1.5f, -2f); private void LateUpdate() { if (target null) { return; } // 相机放在目标物体后方看向目标 transform.position target.position offset; transform.LookAt(target); } }这个脚本挂到 TreasureCamera 上把 target 指向当前选中的宝藏特写视角就会自动跟随宝藏位置。这个思路尤其适合场景中有多个宝藏的情况。6. 常见问题与排查思路在实际编码过程中新手最容易碰见下面几个问题。这里整理成表格方便你对照排查。问题现象常见原因解决思路点击宝藏没有反应射线没有打中 Collider检查宝藏是否挂有 Collider并确认 Collider 不是触发器射线方向错误使用了 Camera.main 而不是当前相机通过 CameraSwitcher 获取当前启用相机切换视角后画面黑色相机位置在封闭物体内部把相机挪到遮挡物外部或调整 Near Clipping Plane多个相机重叠显示切换时没有正确禁用其他相机在 SwitchToView 里先全部关闭再打开目标相机AudioListener 警告场景中有多个相机挂载 AudioListener只保留一个 AudioListener或用脚本动态增删宝藏 Count 为 0Treasure 脚本没有挂载到宝藏物体上检查每个宝藏物体是否都有 Treasure 组件6.1 射线检测不到宝藏这是最经典的问题。Unity 的Physics.Raycast只会检测带有 Collider 的物体。如果你给宝藏挂的是 SpriteRenderer 而不是 3D Collider射线就不会打中它。另外一个常见坑是宝藏物体的 Collider 是触发器Is Trigger true。没有特殊处理的情况下射线依然能检测到触发器但这取决于 Raycast 的QueryTriggerInteraction参数。默认情况下Physics.Raycast不检测触发器所以保险起见把宝藏 Collider 的 Is Trigger 选项保持关闭或者调用带QueryTriggerInteraction.Collide参数的重载方法。// 如果要检测触发器可以这样写 if (Physics.Raycast(ray, out hit, rayDistance, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Collide)) { // 处理点击逻辑 }6.2 切换视角后 UI 按钮无法点击如果 UI 是挂在 Canvas 上的并且 Canvas 的 Render Mode 是 Screen Space - Overlay正常情况下不会被相机切换影响。但如果你的 Canvas 使用的是 Screen Space - Camera而 Event Camera 指定的相机被切换关闭了UI 就无法接收点击。解决办法是把 Event Camera 改成不会被关闭的相机或者在切换相机时同步更新 Canvas 的 worldCamera。// 在 CameraSwitcher 里加一个事件 public System.ActionCamera OnCameraSwitched; // 切换方法最后触发 OnCameraSwitched?.Invoke(activeCamera);在 Canvas 的脚本里监听这个事件动态更新 worldCamera就能避免按钮失灵。6.3 性能问题多相机方案虽然实现简单但三个相机同时存在会有一定的性能开销因为每个相机都有自己的剔除计算和渲染循环。虽然我们关闭了非激活相机但 Transform 计算仍然存在。如果场景复杂度很高建议把未使用的相机 GameObject 直接 SetActive(false)这样 Unity 不会处理它。对应的切换时再 SetActive(true)。不过要注意SetActive 会影响相机上挂载的其他脚本比如 AudioListener所以要确保状态能正确恢复。7. Vibecoding 工程化建议7.1 如何向 AI 描述需求用 Vibecoding 开发游戏时输入提示词的质量直接关系到产出代码的质量。描述需求时可以按这个模板来功能目标我要实现什么功能。技术栈与版本Unity 2022内置渲染管线C# 脚本。交互方式鼠标点击键盘切换。性能要求不需要太高原型演示用。特殊限制不要使用第三方插件。举个例子帮我写一个 Unity C# 脚本实现单相机多视角切换。场景中有三个 Camera分别是主视角、俯视视角、特写视角。按数字键 1、2、3 切换。切换时先关闭所有相机再打开目标相机。同时提供一个方法 GetActiveCamera 返回当前激活的相机供射线检测使用。这段话包含了功能、交互方式、技术约束AI 基本能给出较准确的代码。如果你只写“给我一个相机切换脚本”AI 可能给出完全不符合需求的结果。7.2 人工审查重点AI 生成的代码不能直接沿用至少要检查以下几点空引用AI 经常生成没有 null 判断的代码。场景中缺失引用时就会报 NullReferenceException。生命周期在 Start、Update、OnEnable 里写逻辑时要确认调用顺序符合预期。性能不要在主循环里频繁 FindObject、GetComponent。兼容性AI 可能默认使用新输入系统而你的项目是旧输入系统需要对应修改。7.3 迭代节奏Vibecoding 讲究“快速试错”。你可以先让 AI 生成一个能运行的最小版本然后逐步加需求。比如第一步只做相机切换第二步做射线点击第三步加计分 UI。每一步都验证通过再进入下一步。这样做的好处是出错时你能快速定位到是哪个环节的问题而不是面对一大堆堆在一起的代码无从下手。8. 总结与下一步这篇教程从 Vibecoding 的概念出发拆解了单相机多视角切换在山林寻宝小游戏中的完整实现。核心内容包括三个相机的切换管理、基于当前激活相机的射线检测、宝藏收集逻辑与计分 UI。代码可以直接复制到 Unity 项目里运行也可以继续扩展成更复杂的玩法。接下来你可以继续尝试加入移动控制让玩家在探索视角下可以行走。加入寻宝提示比如俯视视角中宝藏会发出微光。加入倒计时让寻宝具有时间压力。把所有宝藏做成 Prefab配置不同的分数和稀有度。在实际项目开发中优先关注视角切换的稳定性和射线检测的准确性这两个点是整个寻宝体验的基础。如果你在跑 Demo 时遇到问题欢迎根据文中排查表逐项对照。如果你觉得这篇文章对你有帮助可以收藏备用后面做 AI 辅助游戏原型的时候直接翻出来看。