269 lines
14 KiB
Markdown
269 lines
14 KiB
Markdown
# 地图视图
|
||
|
||
<cite>
|
||
**本文档引用的文件**
|
||
- [MapViewComp.ts](file://assets/script/game/map/view/MapViewComp.ts)
|
||
- [MapViewScene.ts](file://assets/script/game/map/view/MapViewScene.ts)
|
||
- [MapLayer.ts](file://assets/script/game/map/view/map/layer/MapLayer.ts)
|
||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts)
|
||
- [SkillLayer.ts](file://assets/script/game/map/view/map/layer/SkillLayer.ts)
|
||
- [MoveUV.ts](file://assets/script/game/map/view/MoveUV.ts)
|
||
- [MapModelComp.ts](file://assets/script/game/map/model/MapModelComp.ts)
|
||
- [GameMap.ts](file://assets/script/game/map/GameMap.ts)
|
||
- [map.json](file://assets/resources/config/map/map.json)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [引言](#引言)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构概述](#架构概述)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖分析](#依赖分析)
|
||
7. [性能考虑](#性能考虑)
|
||
8. [故障排除指南](#故障排除指南)
|
||
9. [结论](#结论)
|
||
|
||
## 引言
|
||
本文档深入解析 `MapViewComp` 作为地图表现层的核心作用,涵盖地图预制体加载、地图图层管理(背景、实体、技能等)以及 UV 动画效果的实现。结合 `MapView.ts` 和 `MapViewScene.ts` 阐述地图场景的构建流程与节点组织结构。分析 `MapLayer.ts` 和 `EntityLayer.ts` 如何实现分层渲染与实体挂载。阐述 `MoveUV.ts` 实现的动态纹理偏移技术用于模拟地图流动效果。最后提供自定义地图视觉风格、添加新图层及优化渲染性能的实践指南。
|
||
|
||
## 项目结构
|
||
项目结构清晰地将地图相关逻辑分离到 `assets/script/game/map/` 目录下,采用 MVC 模式组织代码。`model` 目录存放地图数据模型,`view` 目录存放视图组件和图层管理,`view/map/layer` 子目录进一步细化了不同图层的实现。
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "地图系统"
|
||
subgraph "模型层"
|
||
MapModelComp[MapModelComp.ts]
|
||
end
|
||
subgraph "视图层"
|
||
MapViewComp[MapViewComp.ts]
|
||
MapViewScene[MapViewScene.ts]
|
||
MoveUV[MoveUV.ts]
|
||
subgraph "图层组件"
|
||
MapLayer[MapLayer.ts]
|
||
EntityLayer[EntityLayer.ts]
|
||
SkillLayer[SkillLayer.ts]
|
||
end
|
||
end
|
||
subgraph "控制层"
|
||
GameMap[GameMap.ts]
|
||
end
|
||
end
|
||
MapViewComp --> MapViewScene
|
||
MapViewScene --> MapLayer
|
||
MapViewScene --> EntityLayer
|
||
MapViewScene --> SkillLayer
|
||
MapViewComp --> MoveUV
|
||
GameMap --> MapModelComp
|
||
GameMap --> MapViewComp
|
||
```
|
||
|
||
**Diagram sources**
|
||
- [MapViewComp.ts](file://assets/script/game/map/view/MapViewComp.ts)
|
||
- [MapViewScene.ts](file://assets/script/game/map/view/MapViewScene.ts)
|
||
- [MapLayer.ts](file://assets/script/game/map/view/map/layer/MapLayer.ts)
|
||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts)
|
||
- [SkillLayer.ts](file://assets/script/game/map/view/map/layer/SkillLayer.ts)
|
||
- [MoveUV.ts](file://assets/script/game/map/view/MoveUV.ts)
|
||
- [MapModelComp.ts](file://assets/script/game/map/model/MapModelComp.ts)
|
||
- [GameMap.ts](file://assets/script/game/map/GameMap.ts)
|
||
|
||
**Section sources**
|
||
- [MapViewComp.ts](file://assets/script/game/map/view/MapViewComp.ts)
|
||
- [MapViewScene.ts](file://assets/script/game/map/view/MapViewScene.ts)
|
||
- [MapLayer.ts](file://assets/script/game/map/view/map/layer/MapLayer.ts)
|
||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts)
|
||
- [SkillLayer.ts](file://assets/script/game/map/view/map/layer/SkillLayer.ts)
|
||
- [MoveUV.ts](file://assets/script/game/map/view/MoveUV.ts)
|
||
- [MapModelComp.ts](file://assets/script/game/map/model/MapModelComp.ts)
|
||
- [GameMap.ts](file://assets/script/game/map/GameMap.ts)
|
||
|
||
## 核心组件
|
||
`MapViewComp` 是地图表现层的核心组件,负责协调地图场景的初始化和生命周期管理。它通过 `MapViewScene` 组件访问各个地图图层,并在 `start` 方法中建立引用关系。`MapModelComp` 定义了地图的基本属性,如初始地图编号和地图显示预制体路径。`GameMap` 类作为 ECS 实体,整合了模型和视图组件,提供地图加载的入口方法。
|
||
|
||
**Section sources**
|
||
- [MapViewComp.ts](file://assets/script/game/map/view/MapViewComp.ts#L1-L45)
|
||
- [MapModelComp.ts](file://assets/script/game/map/model/MapModelComp.ts#L1-L43)
|
||
- [GameMap.ts](file://assets/script/game/map/GameMap.ts#L1-L36)
|
||
|
||
## 架构概述
|
||
地图系统采用基于 ECS(Entity-Component-System)架构的设计模式,将地图数据(Model)、视图(View)和控制逻辑(Controller)分离。`GameMap` 实体持有 `MapModelComp` 和 `MapViewComp` 组件,实现了数据与表现的解耦。地图场景由 `MapViewScene` 组件管理,它通过属性装饰器关联了多个图层组件,包括 `MapLayer`(背景层)、`EntityLayer`(实体层)和 `SkillLayer`(技能层),形成了清晰的层次化结构。
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class GameMap {
|
||
+MapModel : MapModelComp
|
||
+MapView : MapViewComp
|
||
+load() : void
|
||
}
|
||
class MapModelComp {
|
||
+id : number
|
||
+resPrefab : string
|
||
+reset() : void
|
||
}
|
||
class MapViewComp {
|
||
+scene : MapViewScene
|
||
+start() : void
|
||
+update(dt : number) : void
|
||
}
|
||
class MapViewScene {
|
||
+camera : Camera
|
||
+mapLayer : MapLayer
|
||
+entityLayer : EntityLayer
|
||
+SkillLayer : SkillLayer
|
||
+isFollowPlayer : boolean
|
||
+ratio : Vec2
|
||
+init() : void
|
||
+update(dt : number) : void
|
||
}
|
||
class MapLayer {
|
||
+bgImg : Sprite
|
||
+init() : void
|
||
+clear() : void
|
||
+bgImage : Sprite
|
||
+width : number
|
||
+height : number
|
||
}
|
||
class EntityLayer {
|
||
+timer : Timer
|
||
+update(dt : number) : void
|
||
+clear() : void
|
||
}
|
||
class SkillLayer {
|
||
+light : Prefab
|
||
+doSkill() : void
|
||
+clear() : void
|
||
}
|
||
GameMap --> MapModelComp : "包含"
|
||
GameMap --> MapViewComp : "包含"
|
||
MapViewComp --> MapViewScene : "引用"
|
||
MapViewScene --> MapLayer : "引用"
|
||
MapViewScene --> EntityLayer : "引用"
|
||
MapViewScene --> SkillLayer : "引用"
|
||
```
|
||
|
||
**Diagram sources**
|
||
- [GameMap.ts](file://assets/script/game/map/GameMap.ts#L1-L36)
|
||
- [MapModelComp.ts](file://assets/script/game/map/model/MapModelComp.ts#L1-L43)
|
||
- [MapViewComp.ts](file://assets/script/game/map/view/MapViewComp.ts#L1-L45)
|
||
- [MapViewScene.ts](file://assets/script/game/map/view/MapViewScene.ts#L1-L77)
|
||
- [MapLayer.ts](file://assets/script/game/map/view/map/layer/MapLayer.ts#L1-L47)
|
||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts#L1-L39)
|
||
- [SkillLayer.ts](file://assets/script/game/map/view/map/layer/SkillLayer.ts#L1-L48)
|
||
|
||
## 详细组件分析
|
||
|
||
### MapViewComp 分析
|
||
`MapViewComp` 组件作为地图视图的主控制器,负责地图场景的初始化和事件监听。在 `onLoad` 方法中,它可以监听全局事件,如角色添加或技能使用。`start` 方法中,它通过 `getComponent` 获取 `MapViewScene` 的引用,建立与地图场景的连接。该组件还包含一个 `Timer` 实例,可用于周期性任务的调度。
|
||
|
||
**Section sources**
|
||
- [MapViewComp.ts](file://assets/script/game/map/view/MapViewComp.ts#L1-L45)
|
||
|
||
### MapViewScene 分析
|
||
`MapViewScene` 组件是地图场景的核心逻辑容器,它通过 Cocos Creator 的属性系统(`@property`)将场景中的各个节点和组件关联起来。这包括摄像机(`camera`)、背景层(`mapLayer`)、实体层(`entityLayer`)和技能层(`SkillLayer`)。`isFollowPlayer` 属性控制摄像机是否跟随玩家移动。`reset` 方法用于清理各个图层的状态,确保地图切换时的干净环境。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant LoadingView as LoadingViewComp
|
||
participant GameMap as GameMap
|
||
participant MapView as MapViewComp
|
||
participant MapViewScene as MapViewScene
|
||
LoadingView->>GameMap : map.load()
|
||
GameMap->>Oops : oops.res.load(resPrefab)
|
||
Oops-->>GameMap : Prefab
|
||
GameMap->>GameMap : instantiate(res)
|
||
GameMap->>GameMap : add(map.getChildByName("map").getComponent(MapViewComp))
|
||
MapView->>MapView : start()
|
||
MapView->>MapView : getComponent(MapViewScene)
|
||
MapViewScene->>MapViewScene : 初始化各图层引用
|
||
```
|
||
|
||
**Diagram sources**
|
||
- [MapViewScene.ts](file://assets/script/game/map/view/MapViewScene.ts#L1-L77)
|
||
- [GameMap.ts](file://assets/script/game/map/GameMap.ts#L1-L36)
|
||
- [LoadingViewComp.ts](file://assets/script/game/initialize/view/LoadingViewComp.ts#L1-L90)
|
||
|
||
### MapLayer 分析
|
||
`MapLayer` 组件负责管理地图的背景图像。它通过 `@property(Sprite)` 装饰器引用一个 Sprite 组件(`bgImg`),用于显示地图背景。`init` 方法根据背景图的尺寸设置自身的宽高,`clear` 方法则用于清除当前的背景图片。`width` 和 `height` 属性通过访问 `bgImg` 的 `UITransform` 组件来获取实际尺寸。
|
||
|
||
**Section sources**
|
||
- [MapLayer.ts](file://assets/script/game/map/view/map/layer/MapLayer.ts#L1-L47)
|
||
|
||
### EntityLayer 分析
|
||
`EntityLayer` 组件管理地图上的所有游戏实体,如角色、怪物等。其 `update` 方法中包含一个定时器(`timer`),可用于定期执行深度排序等操作,以确保实体的正确渲染顺序。`clear` 方法遍历并清理所有子节点,为地图切换做准备。注释中提到深度排序可能成为性能瓶颈,建议在必要时优化为非每帧执行。
|
||
|
||
**Section sources**
|
||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts#L1-L39)
|
||
|
||
### MoveUV 分析
|
||
`MoveUV` 组件实现了动态纹理偏移效果,用于模拟水流、云层移动等视觉效果。它通过 `moveSpeedX` 和 `moveSpeedY` 属性控制纹理在 X 和 Y 方向上的移动速度。在 `update` 方法中,它获取 `Sprite` 组件的 `spriteFrame`,修改其 `rect` 的 `x` 和 `y` 值,从而实现 UV 坐标的偏移。`wrapMode` 属性确保纹理在边缘处重复,形成无缝滚动效果。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start([MoveUV.update]) --> GetSprite["获取Sprite组件"]
|
||
GetSprite --> CheckWrapMode{"WrapMode变化?"}
|
||
CheckWrapMode --> |是| UpdateWrap["更新纹理WrapMode"]
|
||
CheckWrapMode --> |否| UpdateRect["更新Rect坐标"]
|
||
UpdateWrap --> UpdateRect
|
||
UpdateRect --> ApplyRect["设置spriteFrame.rect"]
|
||
ApplyRect --> MarkUpdate["标记渲染数据更新"]
|
||
MarkUpdate --> End([结束])
|
||
```
|
||
|
||
**Diagram sources**
|
||
- [MoveUV.ts](file://assets/script/game/map/view/MoveUV.ts#L1-L50)
|
||
|
||
## 依赖分析
|
||
地图系统依赖于 Cocos Creator 引擎的核心模块(如 `cc`),以及项目中的 `oops-plugin-framework` 框架。`MapViewComp` 和 `MapViewScene` 依赖于 `oops` 对象进行资源加载和消息通信。`EntityLayer` 和 `SkillLayer` 依赖于框架中的 `Timer` 类。各图层组件之间通过 `MapViewScene` 进行协调,没有直接的相互依赖,保证了模块的独立性。
|
||
|
||
```mermaid
|
||
graph LR
|
||
MapViewComp --> oops[Oops Framework]
|
||
MapViewScene --> oops
|
||
EntityLayer --> Timer[Timer Class]
|
||
SkillLayer --> Timer
|
||
SkillLayer --> oops
|
||
MapViewComp --> MapViewScene
|
||
MapViewScene --> MapLayer
|
||
MapViewScene --> EntityLayer
|
||
MapViewScene --> SkillLayer
|
||
GameMap --> MapModelComp
|
||
GameMap --> MapViewComp
|
||
GameMap --> oops
|
||
```
|
||
|
||
**Diagram sources**
|
||
- [MapViewComp.ts](file://assets/script/game/map/view/MapViewComp.ts#L1-L45)
|
||
- [MapViewScene.ts](file://assets/script/game/map/view/MapViewScene.ts#L1-L77)
|
||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts#L1-L39)
|
||
- [SkillLayer.ts](file://assets/script/game/map/view/map/layer/SkillLayer.ts#L1-L48)
|
||
- [GameMap.ts](file://assets/script/game/map/GameMap.ts#L1-L36)
|
||
|
||
**Section sources**
|
||
- [MapViewComp.ts](file://assets/script/game/map/view/MapViewComp.ts#L1-L45)
|
||
- [MapViewScene.ts](file://assets/script/game/map/view/MapViewScene.ts#L1-L77)
|
||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts#L1-L39)
|
||
- [SkillLayer.ts](file://assets/script/game/map/view/map/layer/SkillLayer.ts#L1-L48)
|
||
- [GameMap.ts](file://assets/script/game/map/GameMap.ts#L1-L36)
|
||
|
||
## 性能考虑
|
||
- **深度排序**: `EntityLayer` 和 `SkillLayer` 中的每帧深度排序可能成为性能瓶颈,尤其是在实体数量众多时。建议根据实际需求,将排序频率降低(如每0.2秒一次)或采用空间分区等更高效的排序算法。
|
||
- **纹理重复**: `MoveUV` 组件通过修改 `spriteFrame.rect` 来实现动画,这是一种轻量级的方法,避免了创建额外的动画帧,对性能友好。
|
||
- **资源加载**: `GameMap.load()` 方法异步加载地图预制体,避免了主线程阻塞,保证了游戏的流畅性。
|
||
- **节点清理**: `MapViewScene.reset()` 方法显式清理各图层的子节点,防止内存泄漏。
|
||
|
||
## 故障排除指南
|
||
- **地图未显示**: 检查 `MapModelComp.resPrefab` 路径是否正确,确认预制体资源已正确导入。
|
||
- **UV动画无效**: 确保应用 `MoveUV` 组件的精灵(Sprite)的纹理(Texture)Wrap Mode 设置为 `REPEAT`,否则偏移效果将不可见。
|
||
- **实体层排序异常**: 如果发现实体渲染顺序错误,检查 `EntityLayer.update()` 中的排序逻辑是否被正确执行,或尝试调整 `Timer` 的间隔。
|
||
- **摄像机不跟随**: 确认 `MapViewScene.isFollowPlayer` 属性已启用,并检查摄像机跟随的逻辑是否在其他地方被实现(当前代码中未找到具体实现)。
|
||
|
||
**Section sources**
|
||
- [MapModelComp.ts](file://assets/script/game/map/model/MapModelComp.ts#L1-L43)
|
||
- [MoveUV.ts](file://assets/script/game/map/view/MoveUV.ts#L1-L50)
|
||
- [EntityLayer.ts](file://assets/script/game/map/view/map/layer/EntityLayer.ts#L1-L39)
|
||
- [MapViewScene.ts](file://assets/script/game/map/view/MapViewScene.ts#L1-L77)
|
||
|
||
## 结论
|
||
本项目中的地图视图系统设计清晰,采用 MVC 和 ECS 模式实现了良好的代码组织和可维护性。`MapViewComp` 和 `MapViewScene` 协同工作,构建了地图场景的骨架。通过 `MapLayer`、`EntityLayer` 和 `SkillLayer` 等组件实现了分层渲染,便于管理和优化。`MoveUV` 组件提供了一种简单有效的动态纹理动画方案。开发者可以基于此架构轻松扩展新功能,如添加新的图层类型或实现更复杂的地图特效。 |