# 可交互草地 **Repository Path**: ttxxbb_cn/interactive-grassland ## Basic Information - **Project Name**: 可交互草地 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-10 - **Last Updated**: 2026-03-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 交互草地(Cocos Creator 3D 草地交互示例) 本工程是基于 **Cocos Creator 3.8.6** 的一个交互式草地渲染示例项目,通过自定义 `Model`、采样器与生成器,实现了近景草地动态刷新、噪声高度控制以及移动端虚拟摇杆控制角色移动等功能。 项目名称:**交互草地** --- ## 运行环境 - **引擎**: Cocos Creator 3.8.6(`package.json` 中的 `creator.version`) - **平台**: Windows / macOS(项目本身无特定平台依赖) - **语言**: TypeScript --- ## 如何打开与运行 1. 安装 Cocos Creator 3.8.6(或兼容的 3.x 版本)。 2. 在 Cocos Creator 启动器中选择 **打开项目**,路径选择本仓库根目录: `D:\交互草地可运行` 3. 打开后,在资源管理器中找到场景: - `assets/Grass.scene` 4. 选中场景后点击编辑器顶部的 **播放(预览)按钮** 即可在浏览器或内置预览中运行交互草地示例。 > 如需发布到 Web 或原生平台,可使用 Cocos Creator 的 **构建与发布** 面板根据需要进行配置。 --- ## 功能概览 - **草地渲染与生成** - 根据 GPU 是否支持 **Instancing(实例化渲染)** 自动选择不同的草地模型实现(`GrassModelInstancing` / `GrassModelNormal`)。 - 使用 `GrassSpawnerModule` 根据配置动态生成草片的网格(索引、UV 等)。 - `GrassNear` 负责基于采样器与玩家位置更新近景草地。 - **草地采样与可视范围控制** - `SampleInGrid` 在一个平面网格上随机生成点,并根据相机/角色位置对一定半径内的草样本进行筛选(只保留视野范围内的草)。 - 可以通过属性 `density`、`shownRadius`、`unitSize` 控制草的密度与可见范围。 - **角色控制与交互** - `Control` 组件负责角色/小鸟的移动与相机跟随: - 支持根据噪声贴图计算高度(双线性插值采样噪声纹理的 R 通道,使角色在“起伏地形”上移动)。 - 通过 `GrassNear.updateUserPos` 实时刷新角色周围的草地分布。 - 在 `update` 中向草地材质传递交互圆(`interateInfo1 / interateInfo2`),可实现“踩压草地”等效果。 - `JoystickController`(`assets/Scripts` 与 `assets/Scripts/ui` 各有一份实现)提供移动端虚拟摇杆: - 在屏幕上按住 / 拖动显示虚拟摇杆。 - 计算触摸方向与强度,转换为角色在 XZ 平面上的移动向量。 - 通过绑定的 `ControlNode` 驱动 `Control` 组件移动。 - **相机视角与旋转** - `Control` 中的 `_updateLook` 根据 `camDistance`、`rateX`、`rateY` 等属性控制相机距离与俯仰。 - `Spin` 组件支持通过手指左右滑动来旋转绑定节点(例如整体场景或展示模型)。 - **菜单与外链** - `Menu` 组件提供: - `switchScene(_, data: string)`:根据参数加载 `caseX` 场景。 - `openLink(_, url: string)`:在浏览器中新开标签打开指定链接。 - **工具类** - `randomHelper`:一个带种子的伪随机数工具,在草网格生成时使用固定种子保证可重现的随机形态。 --- ## 主要脚本说明 - **`assets/Scripts/grass-base.ts`** - 抽象基类 `GrassBase` 继承自 `ModelRenderer`: - 在 `onLoad` 中根据设备是否支持 Instancing 选用 `GrassModelInstancing` 或 `GrassModelNormal`。 - 调用 `GrassSpawner.spawn` 获取草片网格信息后初始化 `GrassModel`。 - 通过 `_attachToScene` / `_detachFromScene` 负责把模型加入或移出渲染场景。 - **`assets/Scripts/grass-model.ts`** - 抽象类 `GrassModel` 继承自 `renderer.scene.Model`,封装了草实例的数据结构与网格构建逻辑: - 管理实例容量(capacity)、动态顶点缓冲 `_vBuffer`、索引缓冲 `_indexBuffer`。 - `init`:根据 `GrassSpawnInfo` 初始化网格基本数据与顶点属性布局。 - `updateGrass(info: GrassSampleInfo)`:根据采样结果更新草的位置、法线、UV,并更新 IA(InputAssembler)。 - `updateVertex` / `updateIA` 为抽象方法,由具体子类实现。 - **`assets/Scripts/grass-model-normal.ts`** - 非 Instancing 实现: - `VERTEX_ATTRS`:每个草片的所有顶点都包含 `POSITION / NORMAL / TEX_COORD`。 - `updateVertex`:为每个实例的每个顶点写入对应的位置、法线和 UV。 - `updateIA`:更新顶点缓冲与索引数量,使渲染器只绘制实际存在的草片。 - **`assets/Scripts/grass-model-instancing.ts`** - Instancing 实现: - 将位置和法线作为实例流(stream 0),UV 作为静态顶点流(stream 1),利用 GPU Instancing 减少顶点数据重复。 - `prepareSubMeshDataDynamicVertex` / `prepareSubMeshDataStaticVertex` 分别准备动态实例数据与静态网格数据。 - `updateVertex` 只按实例写入一份位置和法线,`updateIA` 通过 `instanceCount` 控制实例数量。 - **`assets/Scripts/grass-spawner-module.ts` 与 `assets/Scripts/grass-spawner.ts`** - `GrassSpawnerModule`: - 实现接口 `GrassSpawner` 和 `GrassSpawnInfo`,负责生成草片的几何形状。 - 支持形状枚举 `GrassShape`:`QUAD`、`SHARP`、`Triangle`,并通过 `segment` 控制分段数。 - `spawn(seed: number)`: - 根据 `segment` 生成索引数组 `_indice`,控制草片由一条条三角形带组成。 - 按不同 `shape` 模式生成对应的 UV 布局(矩形草片、尖形草片、三角形草片等)。 - 使用 `randomHelper` 在三角形模式下随机宽度与顶点高度,使形态更加自然。 - `grass-spawner.ts`: - 定义 `GrassSpawner` 接口(提供 `spawn` 方法)和 `GrassSpawnInfo`(顶点/索引/UV 数据结构)。 - **`assets/Scripts/grass-sampler.ts` 与 `assets/Scripts/grass-near.ts`** - `grass-sampler.ts`: - 定义 `GrassSampler` 与 `GrassSampleInfo`,约定采样接口与数据格式(positions / normals / count)。 - `grass-near.ts`: - `SampleInGrid` 实现 `GrassSampler`,在一个规则网格内统一随机生成一份“基础单元”,再根据玩家位置筛选出一定半径内的实例: - `density` 控制单位面积草的数量。 - `shownRadius` 控制可见圆形区域半径。 - `unitSize` 控制基础网格单元尺寸。 - `GrassNear` 继承自 `GrassBase`: - 在 `onEnable` 中先采样一份基础网格,再调用 `updateUserPos` 按当前玩家位置筛选可见草。 - 对外暴露 `updateUserPos(x, z)`,供 `Control` 等脚本调用以更新近景草地。 - **`assets/Scripts/control.ts`** - `Control` 组件负责角色/小鸟移动、相机控制和地形高度计算: - 属性: - `focus`: 相机围绕观察的焦点节点。 - `cam`: 场景相机。 - `camDistance`: 相机距离焦点的距离。 - `speedMove`: 角色移动速度。 - `noise`: 地形高度噪声贴图。 - `terrainScale`: 世界坐标到噪声纹理坐标的缩放比例。 - `interaRadius`: 草地交互半径。 - `grassNear`: 近景草地组件。 - `bird`: 角色模型(例如小鸟),用于播放动画与朝向。 - 生命周期: - `onLoad`:拷贝噪声贴图像素数据到 `_pixels`,计算地图尺寸。 - `start`:初始化相机位置、获取草材质 `Pass` 并缓存交互参数句柄。 - `update`: - 根据 `_moveDir` 和 `_lookDir` 更新角色位置与相机视角。 - 调整角色动画状态(如空闲/飞行)。 - 通过 `interateInfo1 / interateInfo2` 向草地材质传入交互圆心和半径信息。 - 核心私有方法: - `_updatePosition()`:根据键盘/触摸输入移动角色,保证在 `mapSize` 范围内循环,并调用 `grassNear.updateUserPos` 刷新草样本。 - `_updateLook()`:根据 Y 方向增量调整相机俯仰与距离。 - `_handleTouch(evt)` / `_handleKey(evt)`:处理移动/视角输入(当前触摸与按键部分有的被注释,可按需要打开)。 - `_updateHeight()`:从噪声贴图中进行双线性插值,计算当前角色位置高度(R 通道),用于实现地形起伏。 - **`assets/Scripts/menu.ts`** - `Menu` 组件用于 UI 菜单: - `switchScene(_, data: string)`:根据传入的字符串拼出 `case${data}` 并加载对应场景。 - `openLink(_, url: string)`:打开外部链接。 - **`assets/Scripts/spin.ts`** - `Spin` 组件实现节点的“拖动旋转”: - 监听 `TOUCH_MOVE` 事件,根据手指横向位移计算角度,绕 Y 轴旋转节点。 - **`assets/Scripts/randomHelper.ts`** - `randomHelper` 类: - 使用简单线性同余算法(LCG)实现带种子伪随机数。 - `getRandom(min, max)` 返回 `[min, max]` 区间的整数,可保证同一 seed 下生成一致的随机序列。 - **`assets/Scripts/JoystickController.ts` 与 `assets/Scripts/ui/JoystickController.ts`** - 两个版本实现逻辑相似,只是引用 `Control` 的路径不同(一个为 `./control`,一个为 `../control`,分别适应不同目录结构)。 - 功能: - 在 UI 上展示/隐藏虚拟摇杆。 - 根据手指按下位置确定摇杆中心。 - 手柄在一定半径内移动,超出会被限制在圆形区域。 - 计算移动方向向量(屏幕空间)并转换为世界空间 XZ 平面的移动方向。 - 将方向写入 `_direction`,在 `update` 中驱动绑定的 `ControlNode` 节点移动,并调用其 `Control._updatePosition()` 来保持高度和草地刷新。 --- ## 项目结构(简要) - `assets/` - `Grass.scene`:主场景,包含草地、角色、相机与 UI。 - `Scripts/`:项目所有 TypeScript 脚本: - 草地相关:`grass-base.ts`、`grass-model*.ts`、`grass-spawner*.ts`、`grass-sampler.ts`、`grass-near.ts` - 控制与交互:`control.ts`、`JoystickController.ts`、`ui/JoystickController.ts`、`spin.ts`、`menu.ts` - 工具:`randomHelper.ts` - `Textures/`:草纹理、噪声纹理、高度贴图等资源。 - `Effects/`:材质/特效相关资源(用于草地着色等)。 --- ## 交互说明(示例) - **PC(键鼠)** - 如果开启键盘监听(在 `Control` 中取消相应注释): - `W / ↑`:前进 - `S / ↓`:后退 - `A / ←`:左移 - `D / →`:右移 - 鼠标/触摸拖动带有 `Spin` 组件的节点可旋转视角或模型。 - **移动端(触摸)** - 在 UI 指定区域按住并拖动,唤出虚拟摇杆,控制角色移动方向。 - 松开触摸后角色停止移动,摇杆回到中心并隐藏。 > 实际按键/触摸逻辑可根据工程中挂载组件的节点及是否注释输入代码略有不同,请以场景中节点上的组件配置为准。 --- ## 自定义与扩展思路 - **调整草地形状与密度** - 在 `GrassSpawnerModule` 上修改: - `shape`:切换 QUAD / SHARP / Triangle 草片形状。 - `segment`:改变草片分段数,影响几何精度与三角形数量。 - 在 `GrassNear` 或采样器 `SampleInGrid` 上调整: - `density`:单位面积草的数量。 - `shownRadius`:草可见半径。 - `unitSize`:网格单元大小。 - **修改交互半径与效果** - 在 `Control` 脚本上调节 `interaRadius`,并在材质中使用 `interateInfo1 / interateInfo2` 自定义草地着色逻辑(例如踩压、波纹等)。 - **替换高度贴图 / 地形形态** - 将 `Control.noise` 绑定到新的噪声贴图即可改变地形起伏形态。 - 如需实际改变角色 Y 轴高度,可在 `_updateHeight` 中根据噪声值映射回真实高度(目前示例中高度行被注释,可按需开启并配置 `terrainHeight`)。 --- ## 注意事项 - 本工程主要演示草地渲染与交互逻辑,并非完整游戏框架,部分输入逻辑、动画切换等可以根据自身项目需求进行扩展。 - 某些脚本中存在预留/注释代码(如键盘输入、动画剪辑名称等),开启前请确认与当前场景配置一致。