🎯 幽灵射手系列 · 全目录
文章目录
-
-
- [🎯 幽灵射手系列 · 全目录](#🎯 幽灵射手系列 · 全目录)
- 概述
- [1.1 项目简介](#1.1 项目简介)
- [1.2 游戏特色](#1.2 游戏特色)
- [1.3 项目目录结构](#1.3 项目目录结构)
- [1.4 核心技术栈](#1.4 核心技术栈)
- [1.5 关键设计模式](#1.5 关键设计模式)
- [1.6 项目启动流程](#1.6 项目启动流程)
-
- [1.6.1 场景加载流程](#1.6.1 场景加载流程)
- [1.6.2 入口脚本分析](#1.6.2 入口脚本分析)
-
- [1.6.2.1 login.ts(登录场景入口)](#1.6.2.1 login.ts(登录场景入口))
- [1.6.2.2 main.ts(战斗场景入口)](#1.6.2.2 main.ts(战斗场景入口))
- [1.6.3 启动流程图](#1.6.3 启动流程图)
- [1.7 框架层核心模块](#1.7 框架层核心模块)
-
- [1.7.1 Constant(常量定义)](#1.7.1 Constant(常量定义))
- [1.7.2 ClientEvent(事件系统)](#1.7.2 ClientEvent(事件系统))
- [1.7.3 PlayerData(玩家数据管理)](#1.7.3 PlayerData(玩家数据管理))
- [1.7.4 UIManager(界面管理)](#1.7.4 UIManager(界面管理))
- [1.7.5 ResourceUtil(资源管理)](#1.7.5 ResourceUtil(资源管理))
- [1.7.6 AudioManager(音频管理)](#1.7.6 AudioManager(音频管理))
- [1.8 战斗系统核心模块](#1.8 战斗系统核心模块)
-
- [1.8.1 GameManager(游戏管理)](#1.8.1 GameManager(游戏管理))
- [1.8.2 Player(玩家控制)](#1.8.2 Player(玩家控制))
- [1.8.3 Monster(怪物控制)](#1.8.3 Monster(怪物控制))
- [1.8.4 MapManager(地图管理)](#1.8.4 MapManager(地图管理))
- [1.8.5 Arrow(箭矢控制)](#1.8.5 Arrow(箭矢控制))
- [1.9 技能系统](#1.9 技能系统)
-
- [1.9.1 技能分类体系](#1.9.1 技能分类体系)
- [1.9.2 玩家技能详解](#1.9.2 玩家技能详解)
-
- [1.9.2.1 形态技能](#1.9.2.1 形态技能)
- [1.9.2.2 数值技能](#1.9.2.2 数值技能)
- [1.9.2.3 Buff技能](#1.9.2.3 Buff技能)
- [1.9.2.4 触发技能](#1.9.2.4 触发技能)
- [1.9.3 怪物技能详解](#1.9.3 怪物技能详解)
- [1.9.4 技能配置表结构](#1.9.4 技能配置表结构)
- [1.10 数据配置系统](#1.10 数据配置系统)
-
- [1.10.1 配置表分类](#1.10.1 配置表分类)
- [1.10.2 base.csv结构详解](#1.10.2 base.csv结构详解)
- [1.10.3 checkpoint.csv结构详解](#1.10.3 checkpoint.csv结构详解)
- [1.10.4 mapXX.csv结构详解](#1.10.4 mapXX.csv结构详解)
- [1.10.5 LocalConfig(配置表加载)](#1.10.5 LocalConfig(配置表加载))
- [1.11 UI界面系统](#1.11 UI界面系统)
-
- [1.11.1 界面结构](#1.11.1 界面结构)
- [1.11.2 界面生命周期](#1.11.2 界面生命周期)
- [1.11.3 核心界面详解](#1.11.3 核心界面详解)
-
- [1.11.3.1 homePanel(主界面)](#1.11.3.1 homePanel(主界面))
- [1.11.3.2 fightPanel(战斗界面)](#1.11.3.2 fightPanel(战斗界面))
- [1.11.3.3 revivePanel(复活界面)](#1.11.3.3 revivePanel(复活界面))
- [1.12 资源管理与性能优化](#1.12 资源管理与性能优化)
-
- [1.12.1 对象池系统(PoolManager)](#1.12.1 对象池系统(PoolManager))
- [1.12.2 资源预加载](#1.12.2 资源预加载)
- [1.12.3 性能监控](#1.12.3 性能监控)
- [1.13 实战演练](#1.13 实战演练)
-
- [1.13.1 如何添加新怪物](#1.13.1 如何添加新怪物)
- [1.13.2 如何添加新技能](#1.13.2 如何添加新技能)
- [1.13.3 如何创建新关卡](#1.13.3 如何创建新关卡)
- [1.14 项目部署与发布](#1.14 项目部署与发布)
-
- [1.14.1 构建配置](#1.14.1 构建配置)
- [1.14.2 平台适配](#1.14.2 平台适配)
- [1.14.3 性能优化建议](#1.14.3 性能优化建议)
- 附录:常用调试命令
- 总结
-
概述
本章讲解如何系统化地理解并扩展一个完整的Cocos Creator俯视角射击游戏项目,包括掌握其框架层(单例、事件、对象池)、战斗系统(玩家、怪物、技能、地图)、数据配置与UI管理等内容。
1.1 项目简介
本项目是一款基于 Cocos Creator 引擎开发的俯视角射击游戏《幽灵射手》。玩家控制角色在关卡中移动、射击敌人、收集奖励,通过不断获取技能提升战斗力,挑战更高关卡。
1.2 游戏特色
- 俯视角射击玩法:玩家控制角色自动瞄准并射击最近的敌人
- 技能系统:多种技能类型(形态变化、数值提升、Buff效果、触发技能)
- 关卡系统:多个地图场景,难度递进的关卡设计
- 敌人AI:多种怪物类型,不同的移动模式和攻击技能
- 资源管理:完善的对象池、资源加载、音频管理系统
1.3 项目目录结构
NewProject/
├── assets/ # 游戏资源目录
│ ├── res/ # 静态资源(纹理、模型、动画等)
│ ├── resources/ # 动态资源(配置表、音频、预制体等)
│ ├── scene/ # 场景文件
│ └── script/ # TypeScript脚本
│ ├── framework/ # 框架层(核心管理类)
│ ├── fight/ # 战斗系统
│ └── ui/ # UI界面
├── extensions/ # 扩展插件
└── docs/ # 学习文档
1.4 核心技术栈
| 技术 | 版本 | 说明 |
|---|---|---|
| Cocos Creator | 3.x | 游戏引擎 |
| TypeScript | 4.x | 开发语言 |
| Node.js | 14+ | 构建工具 |
1.5 关键设计模式
- 单例模式:全局管理器类(GameManager、UIManager等)
- 观察者模式:事件系统(ClientEvent)
- 对象池模式:资源复用(PoolManager)
- 状态模式:角色状态管理
1.6 项目启动流程
1.6.1 场景加载流程
游戏启动时按以下顺序加载:
- login场景 - 初始化国际化、加载资源包
- fight场景 - 主战斗场景,包含所有游戏逻辑
1.6.2 入口脚本分析
1.6.2.1 login.ts(登录场景入口)
挂载位置:login场景 -> Canvas节点
核心功能:
- 初始化i18n国际化系统
- 将Canvas设置为持久节点(跨场景保留)
- 预加载资源包(resources、main)
- 加载主战斗场景
关键代码逻辑:
typescript
start() {
this._initLanguage(); // 初始化语言
director.addPersistRootNode(this.ndCanvas); // 持久化Canvas
Constant.LOGIN_TIME = Date.now(); // 记录登录时间
// 微信平台优化加载性能
if (window.wx) {
// 并行加载资源包
Promise.all(arr).then(() => {
director.loadScene("fight");
})
} else {
director.loadScene("fight");
}
}
1.6.2.2 main.ts(战斗场景入口)
挂载位置:fight场景 -> Canvas节点
核心功能:
- 设置游戏帧率(默认60帧,低配设备30帧)
- 初始化调试模式
- 加载玩家数据和配置表
- 初始化音频系统
- 显示主界面
关键代码逻辑:
typescript
start() {
// 设置帧率
game.frameRate = frameRate;
PhysicsSystem.instance.fixedTimeStep = 1 / frameRate;
// 初始化玩家数据
PlayerData.instance.loadGlobalCache();
PlayerData.instance.loadFromCache();
// 加载CSV配置表
LocalConfig.instance.loadConfig(() => {
this._loadFinish();
});
// 初始化音频
AudioManager.instance.init();
}
1.6.3 启动流程图
用户启动游戏
│
▼
┌─────────────────────────────────┐
│ login场景加载 │
│ ├─ 初始化i18n │
│ ├─ Canvas持久化 │
│ └─ 加载fight场景 │
└─────────────────────────────────┘
│
▼
┌─────────────────────────────────┐
│ fight场景加载 │
│ ├─ 设置帧率 │
│ ├─ 加载玩家数据 │
│ ├─ 加载CSV配置表 │
│ ├─ 初始化音频 │
│ └─ 显示主界面 │
└─────────────────────────────────┘
│
▼
游戏开始
1.7 框架层核心模块
1.7.1 Constant(常量定义)
文件位置:assets/script/framework/constant.ts
功能概述:定义游戏中所有常量配置,包括:
| 常量类别 | 说明 |
|---|---|
| 游戏基础配置 | 游戏名称、版本、帧率 |
| 本地缓存Key | 玩家数据、设置、历史记录等缓存键 |
| 动画类型 | 玩家和怪物的动画状态(待机、奔跑、攻击、死亡) |
| 碰撞分组 | 物理碰撞层定义(玩家、怪物、障碍物等) |
| 事件类型 | 游戏事件名称(攻击玩家、游戏结束、刷新金币等) |
| 技能定义 | 玩家技能ID映射 |
| 音效名称 | 音效资源路径映射 |
关键代码示例:
typescript
// 碰撞分组定义
public static PHY_GROUP = {
DEFAULT: 1 << 0, // 默认
PLAYER: 1 << 1, // 玩家
COLLIDER_ITEM: 1 << 2, // 碰撞器
MONSTER: 1 << 3, // 小怪
REWARD: 1 << 4, // 奖品
MONSTER_SKILL_COLLIDER: 1 << 5, // 怪物技能
OBSTACLE: 1 << 6, // 障碍
}
// 事件类型定义
public static EVENT_TYPE = {
ATTACK_PLAYER: "attackPlayer",
ON_GAME_INIT: "onInitGame",
ON_GAME_OVER: "onGameOver",
ON_GAME_PAUSE: "onGamePause",
REFRESH_GOLD: "refreshGold",
// ...
}
1.7.2 ClientEvent(事件系统)
文件位置:assets/script/framework/clientEvent.ts
功能概述:基于观察者模式的事件分发系统,实现解耦的组件通信。
核心方法:
| 方法 | 功能 | 参数 |
|---|---|---|
on(eventName, handler, target) |
监听事件 | 事件名、回调函数、目标对象 |
off(eventName, handler, target) |
取消监听 | 事件名、回调函数、目标对象 |
dispatchEvent(eventName, ...args) |
分发事件 | 事件名、可变参数 |
使用示例:
typescript
// 监听游戏结束事件
ClientEvent.on(Constant.EVENT_TYPE.ON_GAME_OVER, this._onGameOver, this);
// 取消监听
ClientEvent.off(Constant.EVENT_TYPE.ON_GAME_OVER, this._onGameOver, this);
// 分发事件
ClientEvent.dispatchEvent(Constant.EVENT_TYPE.ON_GAME_INIT);
1.7.3 PlayerData(玩家数据管理)
文件位置:assets/script/framework/playerData.ts
功能概述:管理玩家数据的单例类,包括:
- 玩家基础信息(金币、钻石、等级)
- 技能解锁状态
- 设置配置
- 数据持久化
核心属性:
| 属性 | 类型 | 说明 |
|---|---|---|
playerInfo |
object | 玩家核心数据 |
settings |
object | 设置配置 |
history |
object | 历史记录 |
userId |
string | 用户ID |
核心方法:
typescript
// 加载本地缓存
loadFromCache()
// 创建玩家数据
createPlayerInfo()
// 更新玩家信息(增量修改)
updatePlayerInfo(key, value)
// 添加技能
addPlayerSkill(info)
// 获取未解锁技能
getLockPlyerSkill()
数据结构示例:
typescript
playerInfo = {
diamond: 0, // 钻石
gold: 0, // 金币
level: 1, // 当前关卡
highestLevel: 1, // 最高通关关卡
arrSkill: [], // 已解锁技能ID数组
createDate: Date, // 创建时间
}
1.7.4 UIManager(界面管理)
文件位置:assets/script/framework/uiManager.ts
功能概述:UI界面的统一管理,实现:
- 单例界面的显示/隐藏
- 弹窗队列管理
- 血条显示
- 血量提示
核心方法:
| 方法 | 功能 |
|---|---|
showDialog(panelPath, args, cb) |
显示UI面板 |
hideDialog(panelPath, cb) |
隐藏UI面板 |
showPlayerBloodBar() |
显示玩家血条 |
showMonsterBloodBar() |
显示怪物血条 |
showBloodTips() |
显示血量变化提示 |
界面优先级定义:
typescript
PRIORITY = {
ZERO: 0, // 最底层
BLOOD: 5, // 血条
BLOOD_TIP: 6, // 血量提示
NORMAL: 10, // 普通界面
DIALOG: 100, // 弹窗
REWARD: 200, // 奖励弹窗
WAITING: 300, // 等待界面
TIPS: 400, // 提示
}
1.7.5 ResourceUtil(资源管理)
文件位置:assets/script/framework/resourceUtil.ts
功能概述:资源加载的工具类,提供统一的资源加载接口。
核心方法:
| 方法 | 功能 |
|---|---|
loadRes(url, type) |
通用资源加载 |
loadEffectRes(path) |
加载特效预制体 |
loadModelRes(path) |
加载模型预制体 |
createUI(path, parent) |
创建UI节点 |
getUIPrefabRes(path) |
获取UI预制体 |
资源路径约定:
typescript
// 特效路径
`prefab/effect/${modulePath}`
// 模型路径
`prefab/model/${modulePath}`
// UI路径
`prefab/ui/${prefabPath}`
1.7.6 AudioManager(音频管理)
文件位置:assets/script/framework/audioManager.ts
功能概述:音频资源管理和播放控制。
核心功能:
- 背景音乐播放/暂停/停止
- 音效播放(支持同时播放多个相同音效)
- 音量控制
- 音效对象池复用
核心方法:
| 方法 | 功能 |
|---|---|
playMusic(name, loop, cb) |
播放背景音乐 |
playSound(name, loop, cb) |
播放音效 |
stopMusic() |
停止音乐 |
stopAllSound() |
停止所有音效 |
switchMusic(open) |
开关音乐 |
switchSound(open) |
开关音效 |
音效名称定义:
typescript
SOUND = {
CLICK: "click", // 按钮点击
LOOSE: "loose", // 射箭
HIT_PLAYER: "hitPlayer", // 玩家受击
GOLD_DROP: "goldDrop", // 金币掉落
REVIVE: "revive", // 复活
// ...
}
1.8 战斗系统核心模块
1.8.1 GameManager(游戏管理)
文件位置:assets/script/fight/gameManager.ts
功能概述:游戏全局状态管理,是战斗系统的核心控制器。
挂载位置 :fight场景 -> GameManager节点
核心职责:
- 游戏状态管理:开始、暂停、结束状态控制
- 关卡管理:加载地图、刷新关卡
- 玩家管理:创建玩家、重置状态
- 怪物管理:管理怪物数组、查找最近怪物
- 资源回收:关卡切换时回收所有资源
关键属性:
typescript
// 静态属性(全局访问)
isGameStart: boolean // 游戏是否开始
isGamePause: boolean // 游戏是否暂停
isGameOver: boolean // 游戏是否结束
isWin: boolean // 是否胜利
ndPlayer: Node // 玩家节点
ndBoss: Node // Boss节点
arrMonster: Node[] // 怪物数组
attackAddition: number // 敌人攻击加成
hpAddition: number // 敌人生命加成
核心方法:
| 方法 | 功能 |
|---|---|
_onGameInit() |
初始化游戏 |
_refreshLevel() |
刷新关卡 |
_createPlayer() |
创建玩家 |
_recycleAll() |
回收所有资源 |
getNearestMonster() |
获取最近怪物 |
getNearbyMonster() |
获取附近怪物 |
addGold() |
增加金币 |
游戏初始化流程:
typescript
private _onGameInit(finishCb) {
// 1. 获取关卡配置
let level = PlayerData.instance.playerInfo.level;
this.mapInfo = LocalConfig.instance.queryByID("checkpoint", level);
// 2. 设置敌人属性加成
GameManager.attackAddition = this.mapInfo.attackAddition;
GameManager.hpAddition = this.mapInfo.hpAddition;
// ...
// 3. 重置游戏状态
GameManager.isGameStart = false;
GameManager.isGamePause = false;
GameManager.isGameOver = false;
// 4. 显示加载界面并刷新关卡
UIManager.instance.showDialog("loading/loadingPanel", [], () => {
this._refreshLevel();
});
}
1.8.2 Player(玩家控制)
文件位置:assets/script/fight/player.ts
功能概述:玩家角色控制脚本,处理玩家移动、攻击、技能等逻辑。
挂载位置 :player01预制体
核心属性:
typescript
// 当前属性值
curAttackPower: number // 攻击力
curDefensePower: number // 防御力
curAttackSpeed: number // 攻击速度
curMoveSpeed: number // 移动速度
curHpLimit: number // 生命上限
// 技能状态(布尔标志)
isArrowDouble: boolean // 双重射击
isArrowPenetrate: boolean // 穿透
isArrowIce: boolean // 冰冻
isArrowFire: boolean // 灼烧
isBloodthirsty: boolean // 嗜血
isArrowLightning: boolean // 闪电
核心方法:
| 方法 | 功能 |
|---|---|
init() |
初始化玩家 |
playAction(obj) |
执行玩家动作(移动/停止) |
throwArrowToEnemy() |
向敌人射箭 |
addBlood(num, isLimit) |
增加血量 |
reduceBlood(baseInfo) |
减少血量 |
_parsePlayerSkill() |
解析玩家技能 |
玩家攻击逻辑:
typescript
private _attackMonster() {
// 获取最近的怪物作为目标
this._ndTarget = GameManager.getNearestMonster();
if (!this._ndTarget || this.isDie) return;
// 转向目标
this._moveToTargetWorPos(this._ndTarget.worldPosition);
// 播放攻击动画
this.scriptPlayerModel.playAni(Constant.PLAYER_ANI_TYPE.ATTACK, false, () => {
if (!this.scriptPlayerModel.isRunning) {
this._attackMonster(); // 循环攻击
}
});
}
// 射箭方法
public throwArrowToEnemy() {
// 设置朝向
this.node.forward = Vec3.subtract(this._forWard,
this.node.worldPosition, this._ndTarget.worldPosition)
.normalize().negative();
// 根据技能状态初始化箭
if (this.isArrowDouble) {
if (this.isArrowContinuous) {
this._initArrow("arrowDoubleContinuous");
} else {
this._initArrow("arrowDouble");
}
} else {
this._initArrow("arrowSingle");
}
}
技能解析逻辑:
typescript
private _parsePlayerSkill(isCoverSkill = false) {
let arrSkill = PlayerData.instance.playerInfo.arrSkill;
// 分类技能
let arrFormChangeSkill = arrSkill.filter(s => s.startsWith("1")); // 形态技能
let arrValueChangeSkill = arrSkill.filter(s => s.startsWith("2")); // 数值技能
let arrBuffSkill = arrSkill.filter(s => s.startsWith("3")); // Buff技能
let arrTriggerSkill = arrSkill.filter(s => s.startsWith("4")); // 触发技能
// 设置技能标志
this.isArrowDouble = arrFormChangeSkill.includes(Constant.PLAYER_SKILL.ARROW_DOUBLE);
this.isArrowIce = arrBuffSkill.includes(Constant.PLAYER_SKILL.ARROW_ICE);
// ...
// 应用数值技能效果
if (arrValueChangeSkill.length) {
let oriAttackPower = this.playerBaseInfo.attackPower;
let raiseRate = this.getValueSkillRate(Constant.PLAYER_SKILL.RAISE_ATTACK_01);
this.curAttackPower = oriAttackPower * (1 + raiseRate);
// ...
}
}
1.8.3 Monster(怪物控制)
文件位置:assets/script/fight/monster.ts
功能概述:普通怪物AI控制脚本。
挂载位置:各怪物预制体(aula、boomDragon、hellFire、magician等)
核心属性:
typescript
baseInfo: any // 怪物基础配置(从base.csv读取)
layerInfo: any // 怪物关卡配置(从mapXX.csv读取)
curMoveSpeed: number // 当前移动速度
curAttackSpeed: number // 当前攻击速度
isDie: boolean // 是否死亡
isMoving: boolean // 是否移动
_skillInfo: any // 当前技能信息
_allSkillInfo: string[] // 所有技能ID数组
怪物移动模式:
typescript
MONSTER_MOVE_PATTERN = {
RANDOM: 1, // 随机移动
FORWARD_PLAYER: 2, // 朝向玩家移动
NO_MOVE: 3, // 不移动,原地攻击
}
核心方法:
| 方法 | 功能 |
|---|---|
init(baseInfo, layerInfo) |
初始化怪物 |
playAction(obj) |
执行怪物动作 |
playHit(isArrowLaunch, isPassiveLightning) |
播放受击效果 |
releaseSkillToPlayer() |
向玩家释放技能 |
showDie() |
播放死亡动画 |
怪物攻击逻辑:
typescript
protected _attackPlayer() {
if (GameManager.scriptPlayer.isDie || this._scriptMonsterModel.isAttacking) {
return;
}
// 计算朝向和攻击位置
Vec3.subtract(this._offsetPos_2, GameManager.ndPlayer.worldPosition, this.node.worldPosition);
this.attackForward = this._offsetPos_2.normalize().negative();
this.attackPos.set(GameManager.ndPlayer.worldPosition);
// 显示预警(如果技能有预警)
if (this._allSkillInfo.length && this.skillInfo && this.skillInfo.warning) {
EffectManager.instance.showWarning(this.skillInfo.warning, scale, this).then(() => {
this.playAttackAni();
});
} else {
this.playAttackAni();
}
}
// 释放技能
public releaseSkillToPlayer() {
// 近战攻击(无技能时)
if (!this._allSkillInfo.length) {
let offsetLength = Util.getTwoNodeXZLength(this.node, GameManager.ndPlayer);
if (offsetLength <= this._minLength * this._minLengthRatio) {
GameManager.scriptPlayer.reduceBlood(this.baseInfo);
}
return;
}
// 远程技能攻击
ResourceUtil.loadEffectRes(`${this.skillInfo.resName}/${this.skillInfo.resName}`).then((prefab) => {
this._ndMonsterSkill = PoolManager.instance.getNode(prefab, GameManager.ndGameManager);
this._ndMonsterSkill.setWorldPosition(this.node.worldPosition);
this._ndMonsterSkill.forward = this.attackForward.negative();
// 根据技能类型初始化
switch (this.skillInfo.ID) {
case Constant.MONSTER_SKILL.ENERGY_BALL:
let script = this._ndMonsterSkill.getComponent(EnergyBall);
script.init(this.skillInfo, this.baseInfo, this);
break;
// ...其他技能
}
});
}
1.8.4 MapManager(地图管理)
文件位置:assets/script/fight/mapManager.ts
功能概述:关卡模型管理,负责加载地图、创建怪物/NPC/道具等。
挂载位置 :fight场景 -> mapManager节点
核心方法:
| 方法 | 功能 |
|---|---|
buildMap(mapName, progressCb, completeCb) |
构建地图 |
recycle() |
回收所有地图资源 |
_showWarpGate() |
显示传送门 |
地图构建流程:
typescript
public buildMap(mapName, progressCb, completeCb) {
// 1. 获取地图配置数据
this._arrMap = LocalConfig.instance.getTableArr(mapName);
// 2. 根据类型分组(怪物、Boss、NPC、爱心等)
for (let item of this._arrMap) {
let baseInfo = LocalConfig.instance.queryByID('base', item.ID);
if (!this._dictModuleType.hasOwnProperty(baseInfo.type)) {
this._dictModuleType[baseInfo.type] = [];
}
this._dictModuleType[baseInfo.type].push(item);
}
// 3. 批量加载并创建各类型对象
let arrPromise = [];
for (const type in this._dictModuleType) {
if (this._dictModuleType[type].length) {
arrPromise.push(this._buildModel(type));
}
}
Promise.all(arrPromise).then(() => {
completeCb && completeCb();
});
}
模块创建逻辑:
typescript
private _buildModel(type) {
return new Promise((resolve) => {
let objItems = this._dictModuleType[type];
for (let layerInfo of objItems) {
let baseInfo = LocalConfig.instance.queryByID("base", layerInfo.ID);
let modelPath = `${type}/${baseInfo.resName}`;
ResourceUtil.loadModelRes(modelPath).then((prefab) => {
// 创建父节点
let parentName = type + 'Group';
let ndParent = this.node.getChildByName(parentName) || new Node(parentName);
// 创建实例
let ndChild = PoolManager.instance.getNode(prefab, ndParent);
// 设置位置、角度、缩放
ndChild.setPosition(...);
ndChild.eulerAngles = ...;
ndChild.setScale(...);
// 初始化组件
if (baseInfo.type === Constant.BASE_TYPE.MONSTER) {
let script = ndChild.getComponent(Monster);
script.init(baseInfo, layerInfo);
GameManager.arrMonster.push(ndChild);
} else if (baseInfo.type === Constant.BASE_TYPE.BOSS) {
GameManager.arrMonster.push(ndChild);
GameManager.ndBoss = ndChild;
GameManager.scriptBoss = ndChild.getComponent(Boss);
GameManager.scriptBoss.init(baseInfo, layerInfo);
}
});
}
});
}
1.8.5 Arrow(箭矢控制)
文件位置:assets/script/fight/arrow.ts
功能概述:箭矢飞行和碰撞检测逻辑。
核心属性:
typescript
_speed: number // 飞行速度
_damage: number // 伤害值
_isPenetrate: boolean // 是否穿透
_isIce: boolean // 是否冰冻
_isFire: boolean // 是否灼烧
_isLightning: boolean // 是否闪电
_isLaunch: boolean // 是否弹射
核心方法:
| 方法 | 功能 |
|---|---|
init(speed, startPos) |
初始化箭矢 |
_onCollisionEnter(other) |
碰撞检测 |
_playHitEffect() |
播放击中特效 |
碰撞处理逻辑:
typescript
private _onCollisionEnter(other: ColliderComponent) {
let group = other.getGroup();
// 击中怪物
if (group === Constant.PHY_GROUP.MONSTER || group === Constant.PHY_GROUP.BOSS) {
let scriptMonster = other.node.getComponent(Monster) || other.node.getComponent(Boss);
scriptMonster.playHit(this._isLaunch);
// 穿透处理
if (!this._isPenetrate) {
this._destroyArrow();
return;
}
}
// 击中障碍物
if (group === Constant.PHY_GROUP.OBSTACLE) {
if (!this._isPenetrate) {
this._destroyArrow();
}
}
}
1.9 技能系统
1.9.1 技能分类体系
游戏中的技能分为四大类:
| 分类 | ID前缀 | 示例技能 | 效果说明 |
|---|---|---|---|
| 形态技能 | 10x | 双重射击、连续射击、伞型射击 | 改变箭矢形态和数量 |
| 数值技能 | 20x | 攻击力提升、攻速提升、生命上限 | 永久提升角色属性 |
| Buff技能 | 30x | 冰冻、灼烧 | 箭矢附加元素效果 |
| 触发技能 | 40x | 闪电链、嗜血、弹射 | 攻击时触发额外效果 |
1.9.2 玩家技能详解
1.9.2.1 形态技能
| 技能ID | 技能名称 | 效果 |
|---|---|---|
| 10101 | 双重射击 | 同时射出两支箭 |
| 10201 | 连续射击 | 快速连续射击 |
| 10301 | 伞型射击 | 扇形射出多支箭 |
| 10401 | 反向射击 | 向后射出箭 |
| 10501 | 侧面射击 | 向两侧射出箭 |
| 10601 | 穿透 | 箭矢可穿透敌人 |
1.9.2.2 数值技能
| 技能ID | 技能名称 | 效果 |
|---|---|---|
| 20101 | 攻击提升1 | 攻击力+25% |
| 20102 | 攻击提升2 | 攻击力+50% |
| 20201 | 闪避 | 闪避率+10% |
| 20301 | 暴击提升1 | 暴击率+5%,爆伤+10% |
| 20302 | 暴击提升2 | 暴击率+10%,爆伤+20% |
| 20401 | 攻速提升1 | 攻速+20% |
| 20402 | 攻速提升2 | 攻速+40% |
| 20501 | 生命上限 | 生命上限+20% |
| 20601 | 生命回复 | 立即回复30%生命 |
| 20701 | 移动速度 | 移速+20% |
1.9.2.3 Buff技能
| 技能ID | 技能名称 | 效果 |
|---|---|---|
| 30101 | 冰冻 | 箭矢附带冰冻效果,减缓敌人移速和攻速 |
| 30201 | 灼烧 | 箭矢附带灼烧效果,持续造成伤害 |
1.9.2.4 触发技能
| 技能ID | 技能名称 | 效果 |
|---|---|---|
| 40101 | 闪电链 | 击中敌人时向周围敌人释放闪电 |
| 40201 | 嗜血 | 击杀敌人回复2%生命上限 |
| 40301 | 弹射 | 箭矢击中后弹射到下一个目标 |
1.9.3 怪物技能详解
| 技能ID | 技能名称 | 效果 |
|---|---|---|
| 101 | 能量球 | 发射能量球追踪玩家 |
| 102 | 小火球 | 发射小型火球 |
| 103 | 直线火焰 | 喷射直线范围火焰 |
| 104 | 散射子弹 | 180度散射攻击 |
| 105 | 龙卷风 | S形移动的龙卷风 |
| 106 | 大火团 | 发射大型火球 |
| 107 | 六角散射 | 360度六角散射 |
| 108 | 激光 | 发射直线激光 |
1.9.4 技能配置表结构
playerSkill.csv结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | string | 技能唯一标识 |
| name | string | 技能名称 |
| describe | string | 技能描述 |
| value | string | 技能数值(百分比或具体值) |
| resName | string | 资源路径 |
| type | string | 技能类型(1/2/3/4) |
monsterSkill.csv结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | string | 技能唯一标识 |
| name | string | 技能名称 |
| resName | string | 资源路径 |
| warning | string | 预警类型(circle/line/strip) |
| damage | number | 伤害值 |
| speed | number | 技能飞行速度 |
| range | number | 攻击范围 |
1.10 数据配置系统
1.10.1 配置表分类
项目使用CSV文件存储游戏数据,主要包括:
| 配置表 | 用途 |
|---|---|
| base.csv | 基础实体配置(玩家、怪物、Boss、NPC、道具) |
| checkpoint.csv | 关卡配置(敌人属性加成、地图列表) |
| map001~map105.csv | 各关卡地图布局配置 |
| playerSkill.csv | 玩家技能配置 |
| monsterSkill.csv | 怪物技能配置 |
1.10.2 base.csv结构详解
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | string | 实体唯一标识 |
| name | string | 实体名称 |
| type | string | 类型(player/monster/boss/heart/npc) |
| resName | string | 资源路径 |
| position | string | 默认位置(x,y,z) |
| angle | string | 默认角度(x,y,z) |
| scale | string | 默认缩放(x,y,z) |
| attackPower | number | 攻击力 |
| defensePower | number | 防御力 |
| hp | number | 生命值 |
| attackSpeed | number | 攻击速度 |
| moveSpeed | number | 移动速度 |
| dodgeRate | number | 闪避率 |
| criticalHitRate | number | 暴击率 |
| criticalHitDamage | number | 暴击伤害 |
| movePattern | number | 移动模式 |
| goldNum | number | 掉落金币数量 |
| heartDropRate | number | 爱心掉落概率 |
1.10.3 checkpoint.csv结构详解
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | string | 关卡ID |
| mapName | string | 地图名称(多个用#分隔) |
| attackAddition | number | 敌人攻击加成 |
| defenseAddition | number | 敌人防御加成 |
| hpAddition | number | 敌人生命加成 |
| moveSpeedAddition | number | 敌人移速加成 |
| attackSpeedAddition | number | 敌人攻速加成 |
1.10.4 mapXX.csv结构详解
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | string | 实体ID(对应base.csv) |
| position | string | 在地图中的位置(可选,默认使用base配置) |
| angle | string | 在地图中的角度(可选) |
| scale | string | 在地图中的缩放(可选) |
| skill | string | 怪物技能(多个用#分隔) |
| movePattern | number | 移动模式(可选) |
1.10.5 LocalConfig(配置表加载)
文件位置:assets/script/framework/localConfig.ts
功能概述:CSV配置表的加载和查询管理。
核心方法:
| 方法 | 功能 |
|---|---|
loadConfig(callback) |
加载所有配置表 |
getTableArr(tableName) |
获取整个表数据 |
queryByID(tableName, id) |
根据ID查询数据 |
1.11 UI界面系统
1.11.1 界面结构
项目UI分为以下几类:
| 界面类别 | 包含面板 | 用途 |
|---|---|---|
| 主界面 | homePanel | 游戏主菜单 |
| 战斗界面 | fightPanel、bloodBar | 战斗HUD |
| 弹窗界面 | pausePanel、revivePanel、settingPanel、shopPanel | 功能弹窗 |
| 结算界面 | settlementPanel | 关卡结算 |
1.11.2 界面生命周期
所有UI面板遵循统一的生命周期:
typescript
// 显示面板
show(args) {
// 初始化界面元素
// 绑定事件监听
}
// 隐藏面板
hide() {
// 清理事件监听
// 保存状态(如需要)
}
1.11.3 核心界面详解
1.11.3.1 homePanel(主界面)
功能:游戏主菜单,包含:
- 开始游戏按钮
- 关卡显示
- 金币/钻石显示
- 商店入口
- 设置入口
关键逻辑:
typescript
show() {
// 更新金币和钻石显示
this.updateGold();
this.updateDiamond();
// 更新当前关卡
this.updateLevel();
// 绑定按钮事件
this.btnStart.on('click', this._onStartGame, this);
this.btnShop.on('click', this._onOpenShop, this);
}
1.11.3.2 fightPanel(战斗界面)
功能:战斗HUD,包含:
- 玩家血条
- 技能图标
- 暂停按钮
- 暂停菜单
关键逻辑:
typescript
show() {
// 监听血量变化事件
ClientEvent.on(Constant.EVENT_TYPE.REFRESH_GOLD, this.updateGold, this);
// 初始化技能图标
this.initSkillIcons();
}
1.11.3.3 revivePanel(复活界面)
功能:玩家死亡后显示的复活弹窗,提供多种复活方式。
关键逻辑:
typescript
show() {
// 更新复活选项(广告复活、分享复活等)
this.updateReviveOptions();
// 绑定事件
this.btnReviveAd.on('click', this._onReviveWithAd, this);
this.btnReviveShare.on('click', this._onReviveWithShare, this);
this.btnGiveUp.on('click', this._onGiveUp, this);
}
1.12 资源管理与性能优化
1.12.1 对象池系统(PoolManager)
功能:复用频繁创建/销毁的对象,减少内存分配和GC压力。
核心方法:
| 方法 | 功能 |
|---|---|
getNode(prefab, parent) |
从对象池获取或创建节点 |
putNode(node) |
将节点放回对象池 |
preloadPool(prefab, num) |
预加载对象池 |
使用示例:
typescript
// 获取箭矢节点
let ndArrow = PoolManager.instance.getNode(arrowPrefab, parentNode);
// 回收箭矢
PoolManager.instance.putNode(ndArrow);
1.12.2 资源预加载
策略:
- 关卡切换时预加载:预加载下一关所需的怪物技能
- 玩家技能预加载:根据玩家已解锁技能预加载对应箭矢
- 异步加载:使用Promise并行加载资源
关键代码:
typescript
// 预加载怪物技能
public preloadMonsterSkill(mapName) {
return new Promise((resolve) => {
let arrInfo = LocalConfig.instance.getTableArr(mapName);
let arrSkill = arrInfo.filter(item => item.ID.startsWith("2")) // 怪物
// 获取所有技能ID
let skillIds = arrSkill.flatMap(item => item.skill.split("#"));
// 预加载每个技能
let arrPromise = skillIds.map(id => {
let skillInfo = LocalConfig.instance.queryByID("monsterSkill", id);
return ResourceUtil.loadEffectRes(`${skillInfo.resName}/${skillInfo.resName}`);
});
Promise.all(arrPromise).then(() => resolve(null));
});
}
1.12.3 性能监控
监控指标:
- FPS帧率监控
- 内存使用监控
- 资源加载时间监控
调试模式:
typescript
// 在GameManager中开启调试模式
if (GameManager.isTesting) {
// 暴露全局对象供调试
window.GameManager = GameManager;
window.playerData = PlayerData.instance;
window.UIManager = UIManager.instance;
}
1.13 实战演练
1.13.1 如何添加新怪物
步骤1:添加基础配置(base.csv)
csv
ID,name,type,resName,position,angle,scale,attackPower,defensePower,hp,attackSpeed,moveSpeed,dodgeRate,criticalHitRate,criticalHitDamage,movePattern,goldNum,heartDropRate
2005,newMonster,monster,monster/newMonster,0,0,0,100,20,500,1,2,0.1,0.1,1.5,1,10,0.3
步骤2:创建怪物预制体
- 在
assets/resources/prefab/model/monster/目录下创建newMonster.prefab - 添加必要组件:
Monster脚本CharacterRigid组件(物理移动)SkinnedMeshRenderer组件(渲染)- 碰撞组件
步骤3:配置怪物技能(可选)
在monsterSkill.csv中添加技能配置,或在地图配置中指定已有技能。
步骤4:在地图中使用
在对应关卡的mapXX.csv中添加:
csv
ID,position,skill
2005,10,5,0,101#102
1.13.2 如何添加新技能
步骤1:添加技能配置(playerSkill.csv)
csv
ID,name,describe,value,resName,type
10701,新技能,描述文字,0.5,arrowNew,1
步骤2:创建技能箭矢预制体
在assets/resources/prefab/model/weapon/arrow/目录下创建对应的箭矢预制体。
步骤3:在Player.ts中添加技能逻辑
typescript
// 在_parsePlayerSkill方法中添加技能检测
if (this._arrFormChangeSkill.length) {
this.isArrowDouble = this._arrFormChangeSkill.indexOf(Constant.PLAYER_SKILL.ARROW_DOUBLE) !== -1;
// 添加新技能检测
this.isArrowNew = this._arrFormChangeSkill.indexOf(Constant.PLAYER_SKILL.ARROW_NEW) !== -1;
}
// 在throwArrowToEnemy方法中添加技能逻辑
if (this.isArrowNew) {
this._initArrow("arrowNew");
}
步骤4:在Constant.ts中添加技能常量
typescript
public static PLAYER_SKILL = {
// ...已有技能
ARROW_NEW: "10701",
}
1.13.3 如何创建新关卡
步骤1:添加关卡配置(checkpoint.csv)
csv
ID,mapName,attackAddition,defenseAddition,hpAddition,moveSpeedAddition,attackSpeedAddition
12,map012#map013,1.5,1.2,1.8,1.1,1.2
步骤2:创建地图配置(map012.csv)
csv
ID,position,skill
2001,5,2,0,101
2002,15,2,0,102#103
3001,25,2,0,105#106
步骤3:测试关卡
通过调试工具设置玩家关卡并测试:
typescript
PlayerData.instance.playerInfo.level = 12;
ClientEvent.dispatchEvent(Constant.EVENT_TYPE.ON_GAME_INIT);
1.14 项目部署与发布
1.14.1 构建配置
构建前检查:
- 确保所有资源已正确导入
- 检查路径配置(resources目录必须包含所有动态加载资源)
- 确认脚本编译无错误
构建步骤:
- 打开 Cocos Creator
- 点击菜单栏
项目 -> 构建发布 - 选择目标平台(Web、微信小游戏、iOS、Android等)
- 配置构建选项
- 点击"构建"按钮
1.14.2 平台适配
微信小游戏:
- 需要配置
game.json - 需要在后台配置域名白名单
- 需要处理微信授权登录
Web平台:
- 注意跨域问题
- 优化资源加载顺序
移动端:
- 注意性能优化(帧率、内存)
- 适配不同屏幕分辨率
1.14.3 性能优化建议
- 对象池优化:复用频繁创建的对象(箭矢、特效、血条等)
- 资源预加载:关卡切换前预加载所需资源
- 纹理压缩:使用合适的纹理格式和压缩方式
- Draw Call合并:使用图集合并渲染批次
- 距离剔除:对远距离对象进行遮挡剔除
- 帧率控制:根据设备性能动态调整帧率
附录:常用调试命令
在调试模式下(GameManager.isTesting = true),可通过控制台执行以下命令:
javascript
// 查看玩家数据
playerData.playerInfo
// 查看当前游戏状态
GameManager.isGameStart
GameManager.isGamePause
GameManager.isGameOver
// 设置金币
PlayerData.instance.updatePlayerInfo('gold', 1000)
// 解锁技能
PlayerData.instance.addPlayerSkill({ID: "10101"})
// 重新初始化游戏
ClientEvent.dispatchEvent(Constant.EVENT_TYPE.ON_GAME_INIT)
// 显示调试面板
UIManager.instance.showDialog("debug/debugPanel")
总结
本项目是一个结构清晰、功能完整的射击游戏项目。通过学习本讲义,你可以:
- 理解项目架构:掌握框架层、战斗系统、UI系统的设计
- 掌握核心机制:玩家控制、怪物AI、技能系统、资源管理
- 学会扩展开发:添加新怪物、新技能、新关卡
- 理解优化策略:对象池、预加载、性能监控
建议按照章节顺序学习,先理解整体架构,再深入各模块细节,最后通过实战演练巩固知识。