SkillManager.ts 11 KB

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