SkillManager.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. import { _decorator, Component, Node } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. /**
  4. * 技能等级效果配置接口
  5. */
  6. export interface SkillLevelEffects {
  7. descriptions: string[];
  8. [effectName: string]: number[] | string[];
  9. }
  10. /**
  11. * 技能数据接口
  12. */
  13. export interface SkillData {
  14. id: string;
  15. name: string;
  16. description: string;
  17. iconPath: string;
  18. maxLevel: number;
  19. currentLevel: number;
  20. levelEffects: SkillLevelEffects;
  21. }
  22. /**
  23. * 技能效果事件
  24. */
  25. export interface SkillEffectEvent {
  26. skillId: string;
  27. skillLevel: number;
  28. effectType: string;
  29. value: number;
  30. }
  31. /**
  32. * 技能管理器 - 单例模式
  33. * 负责技能数据管理和效果计算
  34. */
  35. @ccclass('SkillManager')
  36. export class SkillManager extends Component {
  37. private static _instance: SkillManager | null = null;
  38. private _skills: Map<string, SkillData> = new Map();
  39. private _eventCallbacks: Map<string, Function[]> = new Map();
  40. public static getInstance(): SkillManager | null {
  41. return SkillManager._instance;
  42. }
  43. onLoad() {
  44. if (SkillManager._instance === null) {
  45. SkillManager._instance = this;
  46. } else {
  47. this.destroy();
  48. return;
  49. }
  50. }
  51. onDestroy() {
  52. if (SkillManager._instance === this) {
  53. SkillManager._instance = null;
  54. }
  55. }
  56. /**
  57. * 初始化技能数据
  58. */
  59. public initSkills(skillsData: SkillData[]) {
  60. this._skills.clear();
  61. skillsData.forEach(skill => {
  62. // 强制将技能等级重置为0,确保每次开始新关卡时技能等级都是0
  63. const skillCopy = { ...skill };
  64. skillCopy.currentLevel = 0;
  65. this._skills.set(skill.id, skillCopy);
  66. });
  67. console.log('[SkillManager] 技能数据已初始化,所有技能等级重置为0');
  68. }
  69. /**
  70. * 获取技能等级
  71. */
  72. public getSkillLevel(skillId: string): number {
  73. const skill = this._skills.get(skillId);
  74. return skill ? skill.currentLevel : 0;
  75. }
  76. /**
  77. * 设置技能等级
  78. */
  79. public setSkillLevel(skillId: string, level: number): void {
  80. const skill = this._skills.get(skillId);
  81. if (skill) {
  82. skill.currentLevel = Math.max(0, Math.min(skill.maxLevel, level));
  83. this.notifySkillChanged(skillId);
  84. }
  85. }
  86. /**
  87. * 升级技能
  88. */
  89. public upgradeSkill(skillId: string): boolean {
  90. const skill = this._skills.get(skillId);
  91. if (skill && skill.currentLevel < skill.maxLevel) {
  92. skill.currentLevel++;
  93. this.notifySkillChanged(skillId);
  94. return true;
  95. }
  96. return false;
  97. }
  98. // ==================== 技能效果计算方法 ====================
  99. /**
  100. * 便宜单位技能效果 - 计算降价后的价格
  101. */
  102. public static calculateCheaperUnitsPrice(originalPrice: number, skillLevel: number): number {
  103. if (skillLevel <= 0) return originalPrice;
  104. const skillManager = SkillManager.getInstance();
  105. if (!skillManager) return originalPrice;
  106. const reductionRate = skillManager.getSkillEffectValue('cheaper_units', 'priceReduction', skillLevel);
  107. return originalPrice * (1 - reductionRate);
  108. }
  109. /**
  110. * 暴击几率技能效果 - 计算新的暴击率
  111. */
  112. public static calculateCritChance(baseCritChance: number, skillLevel: number): number {
  113. if (skillLevel <= 0) return baseCritChance;
  114. const skillManager = SkillManager.getInstance();
  115. if (!skillManager) return baseCritChance;
  116. const bonusCritChance = skillManager.getSkillEffectValue('crit_chance', 'critChanceIncrease', skillLevel);
  117. return Math.min(1.0, baseCritChance + bonusCritChance);
  118. }
  119. /**
  120. * 暴击伤害计算
  121. */
  122. public static calculateCritDamage(baseDamage: number, skillLevel: number): number {
  123. if (skillLevel <= 0) return baseDamage;
  124. const skillManager = SkillManager.getInstance();
  125. if (!skillManager) return baseDamage;
  126. const critDamageBonus = skillManager.getSkillEffectValue('crit_chance', 'critChanceIncrease', skillLevel);
  127. const critMultiplier = 1 + critDamageBonus;
  128. return baseDamage * critMultiplier;
  129. }
  130. /**
  131. * 治疗技能效果 - 计算增加后的生命值
  132. */
  133. public static calculateHealBonus(baseHealth: number, skillLevel: number): number {
  134. if (skillLevel <= 0) return baseHealth;
  135. const skillManager = SkillManager.getInstance();
  136. if (!skillManager) return baseHealth;
  137. const healthBonus = skillManager.getSkillEffectValue('heal', 'healthIncrease', skillLevel);
  138. return Math.floor(baseHealth * (1 + healthBonus));
  139. }
  140. /**
  141. * 计算治疗技能的即时治疗量
  142. */
  143. public static calculateInstantHeal(maxHealth: number, skillLevel: number): number {
  144. if (skillLevel <= 0) return 0;
  145. const skillManager = SkillManager.getInstance();
  146. if (!skillManager) return 0;
  147. const healthBonus = skillManager.getSkillEffectValue('heal', 'healthIncrease', skillLevel);
  148. return Math.floor(maxHealth * healthBonus);
  149. }
  150. /**
  151. * 获取治疗技能的最大血量加成
  152. */
  153. public static getHealSkillHealthBonus(skillLevel: number): number {
  154. if (skillLevel <= 0) return 0;
  155. const skillManager = SkillManager.getInstance();
  156. if (!skillManager) return 0;
  157. return skillManager.getSkillEffectValue('heal', 'healthIncrease', skillLevel);
  158. }
  159. /**
  160. * 多重射击技能效果 - 计算多射几率
  161. */
  162. public static calculateMultiShotChance(baseMultiShotChance: number, skillLevel: number): number {
  163. if (skillLevel <= 0) return baseMultiShotChance;
  164. const skillManager = SkillManager.getInstance();
  165. if (!skillManager) return baseMultiShotChance;
  166. const bonusChance = skillManager.getSkillEffectValue('multi_shots', 'multiShotChance', skillLevel);
  167. return Math.min(1.0, baseMultiShotChance + bonusChance);
  168. }
  169. /**
  170. * 多重射击子弹数量计算
  171. */
  172. public static calculateMultiShotBulletCount(baseBulletCount: number, skillLevel: number): number {
  173. if (skillLevel <= 0) return baseBulletCount;
  174. // 多重射击固定为两发子弹
  175. return 2;
  176. }
  177. /**
  178. * 能量猎手技能效果 - 计算能量值加成
  179. */
  180. public static calculateEnergyBonus(baseEnergy: number, skillLevel: number): number {
  181. if (skillLevel <= 0) return baseEnergy;
  182. const skillManager = SkillManager.getInstance();
  183. if (!skillManager) return baseEnergy;
  184. const energyBonus = skillManager.getSkillEffectValue('energy_hunter', 'energyBonus', skillLevel);
  185. const energyMultiplier = 1 + energyBonus;
  186. return baseEnergy * energyMultiplier;
  187. }
  188. /**
  189. * 球速提升技能效果 - 计算新的球速
  190. */
  191. public static calculateBallSpeed(baseBallSpeed: number, skillLevel: number): number {
  192. if (skillLevel <= 0) return baseBallSpeed;
  193. const skillManager = SkillManager.getInstance();
  194. if (!skillManager) return baseBallSpeed;
  195. const speedBonus = skillManager.getSkillEffectValue('ball_speed', 'ballSpeedIncrease', skillLevel);
  196. const speedMultiplier = 1 + speedBonus;
  197. return baseBallSpeed * speedMultiplier;
  198. }
  199. /**
  200. * 检查是否触发暴击
  201. */
  202. public static rollCriticalHit(critChance: number): boolean {
  203. return Math.random() < critChance;
  204. }
  205. /**
  206. * 检查是否触发多重射击
  207. */
  208. public static rollMultiShot(multiShotChance: number): boolean {
  209. console.log("触发概率",multiShotChance);
  210. return Math.random() < multiShotChance;
  211. }
  212. // ==================== 事件系统 ====================
  213. /**
  214. * 注册技能变化监听
  215. */
  216. public onSkillChanged(skillId: string, callback: (skillId: string, level: number) => void): void {
  217. if (!this._eventCallbacks.has(skillId)) {
  218. this._eventCallbacks.set(skillId, []);
  219. }
  220. this._eventCallbacks.get(skillId)!.push(callback);
  221. }
  222. /**
  223. * 移除技能变化监听
  224. */
  225. public offSkillChanged(skillId: string, callback: Function): void {
  226. const callbacks = this._eventCallbacks.get(skillId);
  227. if (callbacks) {
  228. const index = callbacks.indexOf(callback);
  229. if (index > -1) {
  230. callbacks.splice(index, 1);
  231. }
  232. }
  233. }
  234. /**
  235. * 通知技能变化
  236. */
  237. private notifySkillChanged(skillId: string): void {
  238. const callbacks = this._eventCallbacks.get(skillId);
  239. const skill = this._skills.get(skillId);
  240. if (callbacks && skill) {
  241. callbacks.forEach(callback => {
  242. callback(skillId, skill.currentLevel);
  243. });
  244. }
  245. }
  246. /**
  247. * 获取技能在指定等级的效果值
  248. */
  249. public getSkillEffectValue(skillId: string, effectName: string, level: number): number {
  250. const skill = this._skills.get(skillId);
  251. if (!skill || !skill.levelEffects || !skill.levelEffects[effectName]) {
  252. console.warn(`[SkillManager] 技能 ${skillId} 的效果 ${effectName} 不存在`);
  253. return 0;
  254. }
  255. const effectArray = skill.levelEffects[effectName] as number[];
  256. if (level < 0 || level >= effectArray.length) {
  257. console.warn(`[SkillManager] 技能 ${skillId} 等级 ${level} 超出范围`);
  258. return 0;
  259. }
  260. return effectArray[level];
  261. }
  262. /**
  263. * 获取技能在指定等级的描述
  264. */
  265. public getSkillDescription(skillId: string, level: number): string {
  266. const skill = this._skills.get(skillId);
  267. if (!skill || !skill.levelEffects || !skill.levelEffects.descriptions) {
  268. return skill?.description || '';
  269. }
  270. const descriptions = skill.levelEffects.descriptions;
  271. if (level < 0 || level >= descriptions.length) {
  272. return skill.description;
  273. }
  274. return descriptions[level];
  275. }
  276. /**
  277. * 获取技能当前等级的描述
  278. */
  279. public getCurrentSkillDescription(skillId: string): string {
  280. const skill = this._skills.get(skillId);
  281. if (!skill) return '';
  282. return this.getSkillDescription(skillId, skill.currentLevel);
  283. }
  284. /**
  285. * 检查技能是否已满级
  286. */
  287. public isSkillMaxLevel(skillId: string): boolean {
  288. const skill = this._skills.get(skillId);
  289. if (!skill) return false;
  290. return skill.currentLevel >= skill.maxLevel;
  291. }
  292. /**
  293. * 获取所有技能数据(用于保存)
  294. */
  295. public getAllSkillsData(): SkillData[] {
  296. return Array.from(this._skills.values());
  297. }
  298. /**
  299. * 重置所有技能等级为0(关卡切换时调用)
  300. */
  301. public resetAllSkillLevels(): void {
  302. this._skills.forEach((skill, skillId) => {
  303. if (skill.currentLevel > 0) {
  304. skill.currentLevel = 0;
  305. this.notifySkillChanged(skillId);
  306. }
  307. });
  308. console.log('[SkillManager] 所有技能等级已重置为0');
  309. }
  310. }